使用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 image

  Image Entry point : 0x08000131

  Load 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        Object

    0x08000000   0x08000000   0x00000130   Data   RO         1821    RESET               startup_stm32f10x_hd.o
    0x08000130   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.
  *
  * <h2><center>&copy; COPYRIGHT 2010 STMicroelectronics</center></h2>
  */

/** @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);	//PC8
    STM_EVAL_LEDInit(LED4);  //PC9
		delay_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
  • 12
    点赞
  • 85
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值