STM32-IAP

文章转载自 Alson

网上关于讲解 STM32 IAP 的资料非常多,这里只分析笔者自己对 STM32 IAP 的理解

STM32 IAP 的全称为 in-application programming,目的就是通过 应用 来更新 内容内容 包括但不限于:

  • 内部 FLASH 中的固件
  • 外挂 FLASH 中的数据,例如字库、图片、设备的一些产品信息等
  • 外挂 EEPROM 中的数据,例如字库、图片、设备的一些产品信息等
  • 外部连接的设备的参数配置,例如传感器参数等

文档以更新内部 FLASH 中的固件为例进行讲解

IAP

官方例程

IAP example 最好还是参考 ST 官方发布的 example。官方 IAP example 一般都会包含 代码 和对应的 Application Note,二者结合可以快速实现自己的 IAP。

以笔者最近在使用的 STM32F103RCT6 为例,介绍如何在 ST 官网寻找到对应的或者相似的 IAP example。

  1. 在 ST 官网中的 Tools&Software —> Embedded Software —> MCU & MPU Embedded Software —> STM32 Embedded Software

    STM32_Embedded_Software

  2. STM32 Standard Peripheral Library Expansion

    STM32_Standard_Peripheral_Library_Expansion

    这里面会包含一些 STM32 的一些 examples。

  3. Product selector

    Product_Selector

    在搜索栏中输入 IAP,会得到基于 STM32 MCU 的 IAP examples。一般 IAP 的 Middleware 都是 Bootloader。如果有网络功能的话也可以参考 Middleware 是 Bootloader, TCP/IP 的。

    笔者使用的是 STM32F103RCT6,没有完全对应的 example。所以这里可以参考 STM32, STM32L1 的。注意下载下来的固件是基于 KEIL v4 版本的,用 KEIL v5 打开的话一般推荐使用 Install Legacy Support 方式

  4. Get Software

    Get_Software

    这里下载的是固件,一般来说还会有对应的 Application Note。这里的固件是基于 ST 官方开发板,通过 USART 实现 IAP,重点关注 IAP 的实现逻辑

  5. Documentation

    Documentation

    这里的 Application Note AN3310 就是对刚才下载的固件的应用说明,阅读 AN3310 可以帮助我们快速入门 IAP。

实现

以笔者最近在使用的 STM32F103RCT6 为例,Flash 大小为 256KB。以下内容结合 AN3310 文档和 STM32F103RCT6 实际情况结合完成,并非完全针对 STM32 IAP example。

文档的最终目的是将 STM32 IAP example 移植到笔者使用的 STM32F103RCT6 上,并去除掉一些无关逻辑,只实现以下逻辑

  • MCU 上电等待 USART 传输过来的应用固件
  • 应用固件传输完成后,通过 USART 输入指令跳转到应用

IAP 的实现逻辑很简单。AN3310 文档中 User program conditions 章节介绍了 IAP 的原理。

Flash_Memory

简单的说就是整个 Flash 被逻辑上分为三个区域:

  1. IAP Code (必须放在 Flash 起始地址 0x00000000 处,即 Map 后的逻辑地址为 0x08000000)
  2. User Code 1
  3. User Code 2 (可选)

系统上电后首先运行 IAP Code 处的代码,根据一些条件有所选择的执行逻辑:

  1. 更新 Flash 固件
  2. 运行 User Code 1 中的代码
  3. 运行 User Code 2 中的代码 (可选)

分析

AN3310 文档中可知,IAP Code 放置于 Flash 起始地址 0x00000000 处,即 Map 后的逻辑地址为 0x08000000 处,大小为 12KB。应用固件放置于 Flash 起始地址 0x00003000 处,即 Map 后的逻辑地址为 0x8003000,大小为 500KB。

Flash_Memory_Usage

通过对 main 函数的分析及结合 AN3310 文档,官方 IAP example 通过 USART1 接收应用固件,协议为 YMODEM,通过 USART1 接收输入指令来执行不同的操作。

/**
  * @brief  Main program.
  * @param  None
  * @retval None
  */
int main(void)
{ 
  /* Unlock the Flash Program Erase controller */
  FLASH_If_Init();

  /* Initialize Key Button mounted on STM32L15xx-EVAL board */
  STM_EVAL_PBInit(BUTTON_KEY, BUTTON_MODE_GPIO);

  /* Test if Key push-button on STM32L15xx-EVAL Board is pressed */
  if (STM_EVAL_PBGetState(BUTTON_KEY) != 0x00)
  { 
    /* Execute the IAP driver in order to reprogram the Flash */
    IAP_Init();
    /* 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)
  {}
}

了解了官方 IAP example 的逻辑之后,仅需要将 IAP example 下的 C 源文件及头文件直接拷贝到自己的工程中即可。

  1. common.c
  2. flash_if.c
  3. menu.c
  4. ymodem.c

移植这部分没什么可以说的,无非就是将代码里面的一些 STM32L1 库函数中的 API 替换成 STM32F1 库函数中的 API 即可。

问题总结

  1. 从 IAP 中跳转到 APP 中一般参考官方 IAP example 中的跳转代码即可。不过官方 IAP example 中是没有关中断的操作,不过笔者在参考网上诸多资料后发现在某些情况下由于在跳转的过程中发生了中断导致 IAP 跳转 APP 失败(笔者没遇到过),为了保险起见,建议还是在跳转之前调用 __disable_irq(); 关闭中断,在 APP 中调用 __enable_irq(); 开启中断。

    if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000) {
    	__disable_irq();
    
    	JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);
    	/* Jump to user application */
    	Jump_To_Application = (pFunction) JumpAddress;
    	/* Initialize user application's Stack Pointer */
    	__set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
    	Jump_To_Application();
    }
    
  2. IAP 和 APP 是单独的中断向量表。对于 APP,一般启动文件中 Reset_Handler 会在调用 __main 之前调用 SystemInit 接口,在 SystemInit 中有关闭中断和设置中断向量表的操作:

    ; Reset handler
    Reset_Handler   PROC
    				EXPORT  Reset_Handler             [WEAK]
    				IMPORT  __main
    				IMPORT  SystemInit
    				LDR     R0, =SystemInit
    				BLX     R0               
    				LDR     R0, =__main
    				BX      R0
    				ENDP
    
    /**
      * @brief  Setup the microcontroller system
      *         Initialize the Embedded Flash Interface, the PLL and update the 
      *         SystemCoreClock variable.
      * @note   This function should be used only after reset.
      * @param  None
      * @retval None
      */
    void SystemInit (void)
    {
      ...
    
    #ifdef STM32F10X_CL
      /* Reset PLL2ON and PLL3ON bits */
      RCC->CR &= (uint32_t)0xEBFFFFFF;
    
      /* Disable all interrupts and clear pending bits  */
      RCC->CIR = 0x00FF0000;
    
      /* Reset CFGR2 register */
      RCC->CFGR2 = 0x00000000;
    #elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
      /* Disable all interrupts and clear pending bits  */
      RCC->CIR = 0x009F0000;
    
      /* Reset CFGR2 register */
      RCC->CFGR2 = 0x00000000;      
    #else
      /* Disable all interrupts and clear pending bits  */
      RCC->CIR = 0x009F0000;
    #endif /* STM32F10X_CL */
    
    ...
    
    #ifdef VECT_TAB_SRAM
      SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
    #else
      SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
    #endif 
    }
    

    所以在 APP 中,可以将宏 VECT_TAB_OFFSET 设置为实际的 APP 固件偏移量或者直接在 main 函数开始处显示设置中断向量表。(笔者这里中断向量表的偏移地址为 0x3000)

    SCB->VTOR = FLASH_BASE | 0x3000;
    
  3. YMODEM 上位机可以使用开源工具 WindTerm

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值