基于STM32L476的IAP升级
基于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程序直接启动用户应用程序时:
- IAP程序将主堆栈指针设置为应用程序地址。
- 下一条指令执行就会跳转到应用程序(无条件分支)。
- 然后,应用程序将其自己的中断向量表设置为活动状态。
用户应用程序(app)需注意事项:
- 使用工具链链接程序文件将程序加载地址设置为0x08008000
- 使用“ NVIC_SetVectorTable”将向量表定位在地址0x08008000上
功能。- 这里在system_stm32l4xx.c中修改
VECT_TAB_OFFSET
宏即可,VECT_TAB_OFFSET
宏必须为0x200的倍数
- 这里在system_stm32l4xx.c中修改
二、STM32L476的内部flash结构及其启动方式
参考ST官方手册(RM0351),STM32L476内部1M的flash被划分为两个BANK:
- 当选择从Information block中的系统储存器(System memory)启动时,即启动利用串口下载代码的固件(Embedded boot loader,出厂后已经固化)
- 当选择从主储存器(Main memory)启动时,默认会从主存储器(Main memory)的BANK1启动
- 设置
FLASH_OPTR
寄存器的BFB2
位为1,能够改变启动方式为主存储器(Main memory)的BANK2FLASH_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中的BFB2,后面需要用到
HAL库中关于选项字节的编程:
- HAL_FLASH_Unlock解锁flash
- HAL_FLASH_OB_Unlock解锁选项字节
- HAL_FLASHEx_OBGetConfig获得系统中已经存在的选项字节参数
- while(HAL_FLASHEx_OBProgram(&obData) != HAL_OK)写入修改后的选项字节
- HAL_FLASH_OB_Lock锁定选项字节
- 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 贼坑