基于STM32L476的IAP升级

一、原理

基本概念:

ICP/ISP: 即在线编程(in-circuit programming)有时也叫系统编程(In System Programming)在,用于通过JTAG、SWD协议或引导加载程序(BootLoader)将用户应用程序加载到微控制器中,从而更新flash的全部内容。 ICP提供了快速有效的设计迭代,并消除了不必要的封装处理或设备插槽。

IAP: 即应用内编程(in-application programming)。与ICP方法相比,应用内编程(IAP)可以使用微控制器支持的任何通信接口(I / O,USB,CAN,UART,I2C,SPI等)将编程数据下载到存储器中。当应用程序(即IAP程序)运行时,用户能够对Flash存储器进行重新编程。 但是,应用程序(即IAP程序)的一部分必须事先通过ICP烧录在flash中。如果在flash操作期间发生设备复位,则不能保证flash中的内容。

发生复位时,程序计数器(PC指针)将设置为IAP驱动程序的地址。它应该是一个简洁的代码,用于检查特定状态,例如,按下了组合键。满足此条件后,IAP驱动程序要么去更新用户应用程序,要么直接(通常默认情况下)执行用户应用程序。

用户应用程序需要与IAP驱动程序分开。最实用的解决方案是将IAP驱动程序代码放在程序存储器(flash)的开头,并将用户代码放在下一个空闲Flash存储块、扇区或页面的开头,这样可以独立在两个区域上都将配置内存保护。本文中,IAP是通过USART而不是更高级的通信接口执行的,因此可以最大程度地减少内存占用。

用户应用程序可能具有独立的堆栈和中断向量(两者都是推荐的,但不是强制性的)(参见下图)。当IAP程序直接启动用户应用程序时:

  1. IAP程序将主堆栈指针设置为应用程序地址。
  2. 下一条指令执行就会跳转到应用程序(无条件分支)。
  3. 然后,应用程序将其自己的中断向量表设置为活动状态。

IAP程序

用户应用程序(app)需注意事项:

  1. 使用工具链链接程序文件将程序加载地址设置为0x08008000
  2. 使用“ NVIC_SetVectorTable”将向量表定位在地址0x08008000上
    功能。
    1. 这里在system_stm32l4xx.c中修改VECT_TAB_OFFSET宏即可,VECT_TAB_OFFSET宏必须为0x200的倍数

二、STM32L476的内部flash结构及其启动方式

参考ST官方手册(RM0351),STM32L476内部1M的flash被划分为两个BANK:

flash

  • 当选择从Information block中的系统储存器(System memory)启动时,即启动利用串口下载代码的固件(Embedded boot loader,出厂后已经固化)
  • 当选择从主储存器(Main memory)启动时,默认会从主存储器(Main memory)的BANK1启动
  • 设置FLASH_OPTR寄存器的BFB2位为1,能够改变启动方式为主存储器(Main memory)的BANK2
    • FLASH_OPTR寄存器的默认值来自Information block中的Option bytes(只读,默认固化为0xFFEF F8AA,其中BFB2位默认为0)
    • 不管从BANK1还是BANK2启动,最后都会将BANK1或BANK2映射到0x0000 0000(这里是boot memory space,引导存储空间)去,系统会认为代码存放在0x0000 0000处

当从主存储器(Main memory)的BANK2启动时,BANK1和BANK2会进行交换,所以用户应用程序的初始化代码需要将NVIC异常向量表和偏移寄存器设置为BANK2交换后的地址,即原来BANK1所在的地址:0x0800 0000

选项字节

STM32L476中具体的选项字节(Information block中的Option bytes):

选项字节

其中USER OPT和RDP为:

USER OPT和RDP

这里多留意USER OPT中的BFB2,后面需要用到

HAL库中关于选项字节的编程:

  1. HAL_FLASH_Unlock解锁flash
  2. HAL_FLASH_OB_Unlock解锁选项字节
  3. HAL_FLASHEx_OBGetConfig获得系统中已经存在的选项字节参数
  4. while(HAL_FLASHEx_OBProgram(&obData) != HAL_OK)写入修改后的选项字节
  5. HAL_FLASH_OB_Lock锁定选项字节
  6. HAL_FLASH_Lock锁定flash

FLASH_OBProgramInitTypeDef结构体参数:

  • OptionType:设置选项字节的类型
    • OPTIONBYTE_WRP:设置WRP
    • OPTIONBYTE_RDP:设置RDP
    • OPTIONBYTE_USER:设置USER
    • OPTIONBYTE_PCROP:设置PCROP
  • WRPArea:设置WRP时,选择是BANKx的AREAA还是AREAB
  • WRPStartOffset
  • WRPEndOffset
  • RDPLevel:设置RDP时的度保护等级(OB_RDP_LEVEL_0、1、2三种等级)
  • USERType:设置USER时,设置的各种参数(如OB_USER_BFB2)
  • USERConfig:具体的USER配置(如OB_BFB2_ENABLE)
  • PCROPConfig:设置PCROP时使用
  • PCROPStartAddr
  • PCROPEndAddr

三、基于双bank的IAP设计

优点:

  • 可以更新加载程序(IAP)代码
  • 如果加载失败,则原始代码仍然有效(操作可以是“原子的”)
  • 基于该方案的设备无需通过定义加载程序状态去启动app

用户代码可访问STM32L4和STM32G4的FB_MODE寄存器或STM32L0的UFB的寄存器。 系统配置寄存器中的该位控制存储器映射(Remap)和别名(Alias)。 双存储区启动机制也使用它,并且在足够小心的情况下,它也可以用于实时现场升级。

映射和别名

1、用户代码选择启动存储区

用户代码可以通过访修改SYSCFG寄存器修改存储区的映射关系(L0为SYSCFG_DFGR1中的UFB标志位,L4为SYSCFG_MEMRMP中的FB_MODE标志位),同时还能根据该标志位分辨出目前在使用哪个存储区。

(Bit 8)FB_MODE: Flash Bank mode selection

0: Flash Bank 1 mapped at 0x0800 0000 (and aliased @0x0000 0000) and Flash Bank 2
mapped at 0x0808 0000 (and aliased at 0x0008 0000)
1: Flash Bank2 mapped at 0x0800 0000 (and aliased @0x0000 0000) and Flash Bank 1
mapped at 0x0808 0000 (and aliased at 0x0008 0000)

注意

  • 在修改FB_MODE改变映射关系后,必须重置向量表

2、自动选择启动存储区

复位后,如果FLASH_OPTR寄存器的BFB2位为1(BOOTx引脚设置为主存储区启动),将调用系统储存器(System memory)中的BootLoader来检测BANK2中的代码是否有效(检测BANK2中第一个字节是否包含有效的堆栈指针地址),若有效则从BANK2启动

(Bit 20)BFB2: Dual-bank boot

0: Dual-bank boot disable
1: Dual-bank boot enable

注意

  • 修改该标志位必须通过STM32 ST-LINK Utility软件设置选项字节 坑啊
  • 同时,通过STM32 ST-LINK Utility软件设置BFB2标志位后会自动写保护BANK2 贼坑