使用STM32F103的串口实现IAP程序升级功能
使用STM32F103的串口实现IAP程序升级功能
- 🎬IAP程序烧录全过程演示:

✨这几天折腾IAP升级功能,狂补了很多相关BootLoader相关的知识。本来最想实现IAP升级程序的方式是,基于SPI通讯的SD卡,借助挂载的FatFS文件系统,来实现对目标stm32芯片的自身程序的升级,奈何没有实现,只能求其次,先来通过官方现有的串口实现IAP程序升级功能的学习作为跳板。加深对flash读写操作流程的熟悉。
- 🔧支持串口Ymodem传输协议的工具推荐:
SecureCRT(建议安装9.0以下的,有和谐版本的,当然如果支持作者可以付费购买此工具使用) - 📍ST官方相关应用文档:文件编号:AN2557 《使用STM32F10xxx的USART实现在应用中编程》:
https://www.st.com/resource/en/application_note/cd00161640-stm32f10x-in-application-programming-using-the-usart-stmicroelectronics.pdf - 🌿论坛下载地址
https://www.stmcu.com.cn/Designresource/detail/document/705747 - 📍ST官方相对应的示例程序包:
https://www.st.com/content/st_com/en/search.html#q=AN2557-t=tools-page=1

- 🌿📖相关文档阅读推荐:《STM32 MCU IAP例程跳转到APP代码简要分析》
📓BootLoader相关知识
- 🌿系统在上电或复位时通常都CPU是从地址0x00000000处开始执行,ARM内核把0x00000000地址上的存储单元映射到了新的地址0x08000000上。CPU存取0x08000000就是存取0x00000000上的物理存储单元。而在这个地址处安排的通常就是系统的BootLoader程序。

- 🌿程序所占空间大小
🔖在每个工程通过编译后所产生的.map文件中可以找到相关的信息:
==============================================================================Memory Map of the imageImage Entry point : 0x08000131Load Region LR_IROM1 (Base: 0x08000000, Size: 0x00001cac, Max: 0x00040000, ABSOLUTE)Execution Region ER_IROM1 (Exec base: 0x08000000, Load base: 0x08000000, Size: 0x00001c28, Max: 0x00040000, ABSOLUTE)Exec Addr Load Addr Size Type Attr Idx E Section Name Object0x08000000 0x08000000 0x00000130 Data RO 1821 RESET startup_stm32f10x_hd.o0x08000130 0x08000130 0x00000000 Code RO 1826 * .ARM.Collect$$$$00000000 mc_w.l(entry.o)0x08000130 0x08000130 0x00000004 Code RO 1833 .ARM.Collect$$$$00000001 mc_w.l(entry2.o)0x08000134 0x08000134 0x00000004 Code RO 1836 .ARM.Collect$$$$00000004 mc_w.l(entry5.o)0x08000138 0x08000138 0x00000000 Code RO 1838 .ARM.Collect$$$$00000008 mc_w.l(entry7b.o)0x08000138 0x08000138 0x00000000 Code RO 1840 .ARM.Collect$$$$0000000A mc_w.l(entry8b.o)0x08000138 0x08000138 0x00000008 Code RO 1841 .ARM.Collect$$$$0000000B mc_w.l(entry9a.o)0x08000140 0x08000140 0x00000000 Code RO 1843 .ARM.Collect$$$$0000000D mc_w.l(entry10a.o)0x08000140 0x08000140 0x00000000 Code RO 1845 .ARM.Collect$$$$0000000F mc_w.l(entry11a.o)0x08000140 0x08000140 0x00000004 Code RO 1834 .ARM.Collect$$$$00002712 mc_w.l(entry2.o)
-
其中
Load Region LR_IROM1 (Base: 0x08000000, Size: 0x00001cac, Max: 0x00040000, ABSOLUTE)描述了程序所占起始位置,以及空间。 -
⚡要实现IAP功能,不仅需要原目标芯片里面的程序做好程序运行地址部署,还要在带准备升级的程序地址上,做好相对应的匹配才行。
-
🌿已经写入程序的目标芯片,复位后,在从主闪存存储器启动模式下,程序都是地址:
0x08000000开始运行。

- 🌿IAP升级程序中,需要重新映射的偏移地址以及中断向量表。


🛠程序配置
- 🌿对stm32目标芯片使用ST-linkV2烧录程序时,烧录地址时默认:
0x8000000

- 🌿对stm32目标芯片IAP升级程序:需要调用ASF转BIN文件指令,用于通过串口给目标芯片升级使用的程序文件。(当然这个程序可以是上面的原始工程,修改程序后(修改程序运行的起始地址,以及程序代码中重映射中断向量表偏移地址),生成BIN文件。来作为IAP升级文件,这里使用的是另外一个示例工程生成的IAP升级文件)

-
- 👉🏻调用asf转BIN文件指令:(需要指定fromelf.exe程序的绝对路径,根据个人安装Keil目录而定)
C:\Keil_v5\ARM\ARMCC\bin\fromelf.exe --bin -o ./STM32100E-EVAL/test.bin ./STM32100E-EVAL/test.axf


⛳IAP升级和SecureCRT使用
- 🔨SecureCRT配置串口以及参数:


-
📐Ymodem协议模式配置:


-
🏳🌈本例程烧录原始程序后,如需进入IAP升级界面,需要在硬件复位的时候,按住PB9按键让其下拉到GND,原始程序时复位后,检测PB9如果是低电平,则进入IAP升级模式。
-
- 🍁没有进入升级模式下,打印信息就是跑的主循环while中的代码。

- 🍁没有进入升级模式下,打印信息就是跑的主循环while中的代码。
-
- 🍁复位后,检测PB9如果是低电平,则进入IAP升级模式:

- 🍁复位后,检测PB9如果是低电平,则进入IAP升级模式:
-
在进入IAP模式后,输入数字
1,则进入等待上传升级文件模式: -

-
🌿在SecureCRT界面菜单上找到
Tranfer菜单下的Send Ymodem,进行BIN文件的上传。

-
🌿BIN文件上传成功后,打印信息:

-
🌿输入字符
C,将程序跳转到新的目标程序地址。 -
🌿到此已完成对芯片的IAP升级。
📝IAP main主程序
/********************************************************************************* @file IAP/src/main.c* @author MCD Application Team* @version V3.3.0* @date 10/15/2010* @brief Main program body******************************************************************************* @copy** 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 2010 STMicroelectronics
*//** @addtogroup IAP* @{*//* Includes ------------------------------------------------------------------*/
#include "common.h"/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
extern pFunction Jump_To_Application;
extern uint32_t JumpAddress;static u8 fac_us=0; //us延时倍乘数
static u16 fac_ms=0; //ms延时倍乘数,在ucos下,代表每个节拍的ms数
/* Private function prototypes -----------------------------------------------*/
static void IAP_Init(void);
void delay_init(u8 SYSCLK);//延时初始化函数
void delay_us(u32 nus);//微秒延时
void delay_ms(u16 nms);//毫秒延时
/* Private functions ---------------------------------------------------------*/
void delay_init(u8 SYSCLK)
{SysTick->CTRL&=~(1<<2); //SYSTICK使用外部时钟源 fac_us=SYSCLK/8; //不论是否使用OS,fac_us都需要使用fac_ms=(u16)fac_us*1000; //非OS下,代表每个ms需要的systick时钟数
} //延时nus
//nus为要延时的us数.
void delay_us(u32 nus)
{ u32 temp; SysTick->LOAD=nus*fac_us; //时间加载 SysTick->VAL=0x00; //清空计数器SysTick->CTRL=0x01 ; //开始倒数 do{temp=SysTick->CTRL;}while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达 SysTick->CTRL=0x00; //关闭计数器SysTick->VAL =0X00; //清空计数器
}
//延时nms
//注意nms的范围
//SysTick->LOAD为24位寄存器,所以,最大延时为:
//nms<=0xffffff*8*1000/SYSCLK
//SYSCLK单位为Hz,nms单位为ms
//对72M条件下,nms<=1864
void delay_ms(u16 nms)
{ u32 temp; SysTick->LOAD=(u32)nms*fac_ms; //时间加载(SysTick->LOAD为24bit)SysTick->VAL =0x00; //清空计数器SysTick->CTRL=0x01 ; //开始倒数 do{temp=SysTick->CTRL;}while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达 SysTick->CTRL=0x00; //关闭计数器SysTick->VAL =0X00; //清空计数器
}
/*** @brief Main program.* @param None* @retval None*/
int main(void)
{/* Flash unlock */FLASH_Unlock();/* Initialize Key Button mounted on STM3210X-EVAL board */STM_EVAL_PBInit(BUTTON_KEY, BUTTON_MODE_GPIO);
// STM_EVAL_LEDInit(LED1); //PC6
// STM_EVAL_LEDInit(LED2); //PC7
// STM_EVAL_LEDInit(LED3); //PC8STM_EVAL_LEDInit(LED4); //PC9delay_init(72); //延时初始化IAP_Init(); //这里其实做的就是对串口1进行初始化SerialPutString("Hello world \r\n");/* Test if Key push-button on STM3210X-EVAL Board is pressed PB7*/if(STM_EVAL_PBGetState(BUTTON_KEY) == 0x00) //GPIOB --> PB9{/* If Key is pressed *//* Execute the IAP driver in order to re-program the Flash */
// IAP_Init();SerialPutString("\r\n======================================================================");SerialPutString("\r\n= (C) COPYRIGHT 2010 STMicroelectronics =");SerialPutString("\r\n= =");SerialPutString("\r\n= In-Application Programming Application (Version 3.3.0) =");SerialPutString("\r\n= =");SerialPutString("\r\n= By MCD Application Team =");SerialPutString("\r\n======================================================================");SerialPutString("\r\n\r\n");Main_Menu();}/* Keep the user application running */else{/* Test if user code is programmed starting from address "ApplicationAddress" */if(((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000) == 0x20000000)//检查栈顶地址是否合法.{/* Jump to user application */JumpAddress = *(__IO uint32_t*)(ApplicationAddress + 4);//用户代码区第二个字为程序开始地址(复位地址) Jump_To_Application = (pFunction) JumpAddress;/* Initialize user application's Stack Pointer */__set_MSP(*(__IO uint32_t*) ApplicationAddress);//初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)Jump_To_Application();//跳转到APP.}}while(1){delay_ms(500);SerialPutString("IAP main test!\r\n");STM_EVAL_LEDToggle(LED4);}
}/*** @brief Initialize the IAP: Configure RCC, USART and GPIOs.* @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 = 115200;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);
}#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 2010 STMicroelectronics *****END OF FILE****/
📚程序源码
链接:https://pan.baidu.com/s/1bw2gjSS6_Vq48_PtkxakLQ
提取码:298k
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
