使用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中的代码。
      在这里插入图片描述
    • 🍁复位后,检测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


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部