IAP升级方法
IAP升级时需要关闭总中断
TM32在使用时有时需要禁用全局中断,比如MCU在升级过程中需禁用外部中断,防止升级过程中外部中断触发导致升级失败。
ARM MDK中提供了如下两个接口来禁用和开启总中断:
__disable_irq(); // 关闭总中断
__enable_irq(); // 开启总中断 但测试发现这样一个问题,在关闭总中断后,如果有中断触发,虽然此时不会引发中断,但在调用__enable_irq()开启总中断后,MCU会立即处理之前触发的中断。
这说明__disable_irq()只是禁止CPU去响应中断,没有真正的去屏蔽中断的触发,中断发生后,相应的寄存器会将中断标志置位,在__enable_irq()开启中断后,由于相应的中断标志没有清空,因而还会触发中断。
所以要想禁止所有中断,必须对逐个模块的中断进行 Disable操作,由于每个模块中断源有很多,对逐个中断Disable的话比较复杂,较为简单的方法是通过 XXX_ClearITPendingBit()清除中断标志或者直接通过XXX_DeInit()来清除寄存器的状态。这样在 __enable_irq()开启总中断后,MCU就不会响应之前触发的中断了。
检测栈顶指针
bootloader跳跃到APP程序的时候,会进行栈顶指针的检测,栈顶指针也就是我们程序能够运行的最大空间
if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)//检测栈顶指针
{
/* Jump to user application */
/*ApplicationAddress为用户程序的栈地址,+4便为用户程序的复位中断向量地址*/
JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
Jump_To_Application = (pFunction) JumpAddress;
/* Initialize user application's Stack Pointer */
__set_MSP(*(__IO uint32_t*) ApplicationAddress);
/*执行用户空间的复位中断向量函数,里面主要是进行系统时钟配置,执行用户空间的main函数数*/
Jump_To_Application();
}
在保存了一个完整的 APP 到了对应的位置后,我们需要对栈顶进行检查操作,初步检查程序设置正确再进行跳转。我们以 Flash APP 为例,用 bin 文件查看工具。可以看到 bin 的内容默认为小端结构
。
0x2000 0818就是栈顶指针
0x0801 0289是app的Reset_Handler函数地址
程序在运行过程中,0x20000000是我们SRAM运行的起始地址,空间是128KB,也就是0x20000000-0X2001FFFF这个范围。 所以*(__IO uint32_t*)USBD_DFU_APP_DEFAULT_ADD) ,这句话的意思是取得用户地址空间存放的数据,这个空间就是0x08010000,当APP运行的程序栈顶指针落在SRAM区域时,也就是0x20000000到0X2001FFFF这个区间时候,这个时候即是有效的栈顶指针,由于开始的地址是0x20000000,而结束的地址是0X2001FFFF,我们只要判断它的高16位,即是确定这个地址范围在从0x2000开始。