实现STM32F405的串口IAP

STM32串口IAP过程简介

IAP包括两部分程序:BootLoader和Application(用户程序)。

IAP的原理是STM32上电后默认从0x8000000地址开始执行,所以在0x8000000到0x08003FFF这一段放BootLoader程序,大小为16K。BootLoader程序是用下载器烧录进去的,本文档不做详细介绍。

上电后BootLoader运行起来,会在一定时限内(默认3秒)不停监测串口收到的数据是否连续收到n个“s”(小写字母s,默认5个)。如果收到了,就转入串口IAP等待接收.bin升级包,接收过程使用Ymodem协议。如果到超时仍未接收到,就直接跳转到用户程序(Application)开始执行,用户程序的存储起始位置是0x08004000。

BootLoader程序

ST官方有该程序的例程,  STM32F4 in-application programming (IAP) using the USART (AN3965)

下载地址:

https://www.st.com/content/st_com/en/products/embedded-software/mcus-embedded-software/stm32-embedded-software/stm32-standard-peripheral-library-expansion/stsw-stm32067.html

该程序默认是上电时检测GPIO的电平控制是否进行IAP升级,但这种操作并不实用。对该程序的main.c进行修改,以支持上电后检测串口发送5个s就可以控制升级,代码如下:

/**
  ******************************************************************************
  * @file    STM32F4xx_IAP/src/main.c 
  * @author  MCD Application Team
  * @version V1.0.0
  * @date    10-October-2011
  * @brief   Main program body
  ******************************************************************************
  * @attention
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * 

© COPYRIGHT 2011 STMicroelectronics

****************************************************************************** */ /** @addtogroup STM32F4xx_IAP * @{ */ /* Includes ------------------------------------------------------------------*/ #include "common.h" #include "menu.h" #include "stm324xg_eval.h" #include /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ extern pFunction Jump_To_Application; extern uint32_t JumpAddress; /* Private function prototypes -----------------------------------------------*/ static void IAP_Init(void); static uint8_t IAP_UserAccessTimeout(uint32_t ms); /* Macro define */ #define DEF_HAVE_ACCESS 1 #define DEF_ACCESS_SUCCESS_CNT 5 #define DEF_WAIT_IAP_TIME_MS 3000 /* Private functions ---------------------------------------------------------*/ /** * @brief Main program. * @param None * @retval None */ int main(void) { /* Unlock the Flash Program Erase controller */ FLASH_If_Init(); /* Initialize system Tick */ delay_init(); //=====Ö÷Ƶ168M /* Initialize Key Button mounted on STM324xG-EVAL board */ // STM_EVAL_PBInit(BUTTON_KEY, BUTTON_MODE_GPIO); /* Initialize LED */ STM_EVAL_LEDInit(LED2); /* Execute the IAP driver in order to reprogram the Flash */ IAP_Init(); /* Wait for user access IAP program */ if (IAP_UserAccessTimeout(DEF_WAIT_IAP_TIME_MS) == DEF_HAVE_ACCESS) { /* Display main menu */ Main_Menu (); } /* Keep the user application running */ else { /* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */ if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000) { /* Jump to user application */ JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4); Jump_To_Application = (pFunction) JumpAddress; /* Initialize user application's Stack Pointer */ __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS); Jump_To_Application(); } } while (1) {} } /** * @brief Initialize the IAP: Configure USART. * @param None * @retval None */ void IAP_Init(void) { USART_InitTypeDef USART_InitStructure; /* USART resources configuration (Clock, GPIO pins and USART registers) ----*/ /* USART configured as follow: - BaudRate = 115200 baud - Word Length = 8 Bits - One Stop Bit - No parity - Hardware flow control disabled (RTS and CTS signals) - Receive and transmit enabled */ USART_InitStructure.USART_BaudRate = 460800; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; STM_EVAL_COMInit(COM1, &USART_InitStructure); } /** * @brief Wait for user access IAP program. * @param ms:the max time to wait * @retval have or not have user access (DEF_HAVE_ACCESS or no DEF_HAVE_ACCESS) */ uint8_t IAP_UserAccessTimeout(uint32_t ms) { uint8_t key = 0; uint16_t cnt = 0; uint8_t rc; while(--ms){ if (SerialKeyPressed((uint8_t*)&key)){ if (key == 's'){ cnt++; if (cnt >= DEF_ACCESS_SUCCESS_CNT){ break; } } else{ cnt = 0; } } delay_ms(1); if (ms%500 == 0){ STM_EVAL_LEDToggle(LED2); } } STM_EVAL_LEDOn(LED2); /* Have received right characters */ if (ms != 0){ SerialPutString("Are You Sure You Want To Download Image To the Internal Flash ?(y/n) \r\n"); while(1){ key = GetKey(); if ((key == 'y') || (key == 'Y')){ SerialPutString("y \r\n\n"); rc = DEF_HAVE_ACCESS; break; } else { if((key == 'n') || (key == 'N')){ SerialPutString("n \r\nIAP Cancled. Loading The user application... \r\n"); delay_ms(1); rc = !DEF_HAVE_ACCESS; break; } } } } /* Have not received right characters */ else { rc = !DEF_HAVE_ACCESS; } STM_EVAL_LEDOff(LED2); return rc; } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t* file, uint32_t line) { /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* Infinite loop */ while (1) { } } #endif /** * @} */ /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/

增加一个delay.c文件:

#include "delay.h"
////////////////////////////////////////////////////////////////////////////////// 

static u8  fac_us=0;										   
static u16 fac_ms=0;							
			   
void delay_init(void)
{
	RCC_ClocksTypeDef RCC_ClocksStatus;
	RCC_GetClocksFreq(&RCC_ClocksStatus);
	u8 SYSCLK = (u8)(RCC_ClocksStatus.SYSCLK_Frequency/1000000);
 	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); 
	fac_us=SYSCLK/8;						
	fac_ms=(u16)fac_us*1000;				  
}								    


void delay_us(u32 nus)
{		
	u32 temp;	    	 
	SysTick->LOAD=nus*fac_us; 				  		 
	SysTick->VAL=0x00;        				
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; 	 
	do
	{
		temp=SysTick->CTRL;
	}while((temp&0x01)&&!(temp&(1<<16)));	  
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; 
	SysTick->VAL =0X00;       				 
}


void delay_xms(u16 nms)
{	 		  	  
	u32 temp;		   
	SysTick->LOAD=(u32)nms*fac_ms;			
	SysTick->VAL =0x00;           			
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;          
	do
	{
		temp=SysTick->CTRL;
	}while((temp&0x01)&&!(temp&(1<<16)));	   
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;       
	SysTick->VAL =0X00;     		  			  	    
} 

//nms:0~65535
void delay_ms(u16 nms)
{	 	 
	u8 repeat=nms/540;						
	u16 remain=nms%540;
	while(repeat)
	{
		delay_xms(540);
		repeat--;
	}
	if(remain)delay_xms(remain);
} 

			 

相应的头文件delay.h:

#ifndef __DELAY_H
#define __DELAY_H 			   
#include 
////////////////////////////////////////////////////////////////////////////////// 	 
void delay_init(void);
void delay_ms(u16 nms);
void delay_us(u32 nus);

#endif

注意修改成自己板子的晶振频率和串口:

实现STM32F405的串口IAP_第1张图片

至此BootLoader基本就不需要其他修改了。

修改Application(用户程序),增加对IAP的支持

1. 首先增加IAP分组:

实现STM32F405的串口IAP_第2张图片

增加如下IAP_BIN分组:

实现STM32F405的串口IAP_第3张图片

2.切换到该分组,点击组配置:

实现STM32F405的串口IAP_第4张图片

把Flash起始地址设为0x8004000,长度设为0xFC000

实现STM32F405的串口IAP_第5张图片

3. 在User标签下增加一个生成bin文件的命令:

$K\ARM\ARMCC\bin\fromelf.exe --bin --output=Bin\@L.bin !L

实现STM32F405的串口IAP_第6张图片

4. 在C/C++标签下增加IAP_BIN宏定义:

实现STM32F405的串口IAP_第7张图片

5. 在system_stm32f4xx.c文件中修改VECT_TAB_OFFSET的定义:

代码如下:

#if defined IAP_BIN

#define VECT_TAB_OFFSET  0x4000 /*!< Vector Table base offset field.

                                   This value must be a multiple of 0x200. */

#else

#define VECT_TAB_OFFSET  0x0000 /*!< Vector Table base offset field.

                                   This value must be a multiple of 0x200. */

#endif

实现STM32F405的串口IAP_第8张图片

6. 至此,用户程序修改完成。注意:平时开发和调试时用烧写器下载程序,还是用原来的分组。IAP_BIN分组是专给IAP使用的。

7. 如果要制作IAP程序给客户远程升级,注意编译时要切在IAP_BIN组下,点击全部重新编译,就会生成升级用的bin文件:

实现STM32F405的串口IAP_第9张图片

在当前的工程目录下会多出来一个bin文件夹,里面就是可以用于升级的程序文件。

实现STM32F405的串口IAP_第10张图片

客户的IAP使用过程

1. 安装SecureCRT,打开SecureCRT,找到串口,设置如下:

实现STM32F405的串口IAP_第11张图片

2. 给电路板上电,在3秒内一直按着键盘上的小写“s”键。注意大小写!

3. 出现询问是否进行IAP升级,按y:

4. 出现操作菜单,按1:

实现STM32F405的串口IAP_第12张图片

5. 出现等待接收的提示:

点击Transfer,找到Send Ymodem...,点击:

实现STM32F405的串口IAP_第13张图片

找到之前生成的bin文件,点Add,然后点OK确认,将发送文件给电路板。等待3~5秒钟握手时间,下载开始:

6. 升级成功,继续出现菜单,按3,即进入用户程序开始运行:

实现STM32F405的串口IAP_第14张图片

 

 

 

 

你可能感兴趣的:(STM32/CM3)