【固件升级】中断向量表(一)

使用STM32举例说明:

1. 正常向量表

STM32F1 的内部闪存(FLASH)地址起始于 0x08000000,一般情况下,程序文件就从此地址开始写入
STM32F1 是基于 Cortex-M3 内核的微控制器,其内部通过一张“中断向量表”来响应中断
程序启动后,将首先从“中断向量表”取出 复位中断向量 执行 复位中断程序 完成启动
“中断向量表”的起始地址是 0x08000004
当中断来临,STM32F1 的内部硬件机制亦会自动将 PC 指针定位到“中断向量表”处
并根据中断源取出对应的中断向量执行中断服务程序

  1. STM32F1 在复位后,先从 0X08000004 地址取出复位中断向量的地址,跳转到复位中断服务程序
  2. 在复位中断服务程序执行完之后,会跳转到我们的 main 函数
  3. (见下代码)
  4. 而我们的 main 函数一般都是一个死循环
  5. 在 main 函数执行过程中,如果收到中断请求(发生重中断)此时 STM32F1 强制将 PC 指针指回中断向量表处
  6. 根据中断源进入相应的中断服务程序
  7. 在执行完中断服务程序以后,程序再次返回 main 函数执行
  • 从下面可以清晰的看到是从复位中断函数跳转到主函数
; Reset handler
Reset_Handler   PROC                          ; 定义处理器复位中断服务程序
                EXPORT  Reset_Handler           ; 导出此复位处理函数,使其在链接器脚本和其他文件中可见
                [WEAK]                        ; 标记为弱符号,允许其他地方重定义或覆盖此符号
                IMPORT  __main                 ; 引入主函数__main的声明,以便调用
                IMPORT  SystemInit             ; 引入系统初始化函数SystemInit的声明
                LDR     R0, =SystemInit        ; 加载SystemInit函数的地址到寄存器R0
                BLX     R0                     ; 调用SystemInit函数进行系统初始化,BLX指令同时将状态寄存器切换到Thumb状态
                LDR     R0, =__main            ; 加载主函数__main的地址到寄存器R0
                BX      R0                     ; 调用主函数__main开始执行应用程序,BX指令将状态寄存器切换到ARM状态
                ENDP                           ; 结束过程

在这里插入图片描述

2. 升级向量表

  1. STM32F1 复位后,还是从 0X08000004 地址取出复位中断向量的地址,并跳转到复位中断服务程序
  2. 在运行完复位中断服务程序之后跳转到 IAP 的 main 函数
  3. 在执行完 IAP 以后
  4. (即将新的 APP 代码写入 STM32F1灰底部分。新APP的复位中断向量起始地址为 0X08000004+N+M)
  5. 跳转至新写入程序的复位向量表
  6. 取出新APP的复位中断向量的地址
  7. 并跳转执行新程序的复位中断服务程序
  8. 随后跳转至新程序的 main 函数
  9. main 函数为一个死循环
  10. 注意到此时 STM32F1 的 FLASH,在不同位置上,共有两个中断向量表
  11. 在 main 函数执行过程中,
  12. 如果 CPU 得到一个中断请求
  13. PC 指针仍强制跳转到地址0X08000004 中断向量表处,而不是新APP的中断向量表
  14. 程序再根据我们设置的中断向量表偏移量,跳转到对应中断源新的中断服务程序中
  15. 在执行完中断服务程序后,程序返回 main 函数继续运行

在这里插入图片描述

  • 新程序必须在 IAP 程序之后的某个偏移量为 x 的地址开始
  • 必须将新程序的中断向量表相应的移动,移动的偏移量为 x
  • 并且偏移量为 0X200的倍数即可

3. .APP 程序起始地址设置方法

在这里插入图片描述
默认的条件下,图中 IROM1 的起始地址(Start)一般为 0X08000000,大小(Size)为 0X80000,
即从 0X08000000 开始的 512K 空间为我们的程序存储区。
而图中,我们设置起始地址(Start)为 0X08010000,即偏移量为 0X10000(64K 字节),
因而,留给 APP 用的 FLASH 空间(Size)只有 0X80000-0X10000=0X70000(448K 字节)大小了。
设置好 Start 和 Szie,就完成 APP 程序的起始地址设置。
理论上我们只需要确保 APP 起始地址在 Bootloader之后,并且偏移量为 0X200
的倍数即可(相关知识,请参考:http://www.openedv.com/posts/list/392.htm)。这里我们选择 64K
(0X10000)字节,留了一些余量,方便 Bootloader 以后的升级修改

4. 中断向量表设置偏移

/**
  * @brief  Setup the microcontroller system                  // 设置微控制器系统
  *         Initialize the Embedded Flash Interface, the PLL // 初始化嵌入式闪存接口和PLL
  *         and update the SystemCoreClock variable.         // 更新SystemCoreClock变量
  * @note   This function should be used only after reset.   // 注意: 此函数仅应在复位后使用
  * @param  None                                             // 没有参数
  * @retval None                                             // 没有返回值
  */
void SystemInit (void)
{
#if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG) // 如果是STM32F1系列中的某些型号
  #ifdef DATA_IN_ExtSRAM // 如果数据存储在外部SRAM中
    SystemInit_ExtMemCtl(); // 初始化外部内存控制
  #endif /* DATA_IN_ExtSRAM */
#endif 

  /* Configure the Vector Table location -------------------------------------*/ // 配置向量表位置
#if defined(USER_VECT_TAB_ADDRESS) // 如果用户自定义了向量表地址
  SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; // 设置SCB的VTOR寄存器以重定位向量表到内部SRAM
#endif /* USER_VECT_TAB_ADDRESS */
}

系统启动的时候,会首先调用 SystemInit 函数初始化时钟系统
SystemInit 还完成了中断向量表的设置,我们可以打开 SystemInit 函数
看看函数体的结尾处

#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

VTOR 寄 存 器 存 放 的 是 中 断 向 量 表 的 起 始 地 址
默 认 的 情 况
VECT_TAB_SRAM 是没有定义,
所以执行
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET
对于 FLASH APP,
我们设置为 FLASH_BASE+偏移量 0x10000,
所以我们可以在 SystemInit 函数里面修改 SCB->VTOR 的值
当然为了尽可能不修改系统级别文件,
我们可以也可以在 FLASH APP 的 main 函数最开头处添加如下代码
实现中断向量表的起始地址的重设

SCB->VTOR = FLASH_BASE | 0x10000;

以上是 FLASH APP 的情况,当使用 SRAM APP 的时候,我们设置起始地址为:
SRAM_BASE+0x1000,同样的方法,
我们在 SRAM APP 的 main 函数最开始处,添加下面代码:

SCB->VTOR = SRAM_BASE | 0x1000;
  • 第二种
    将中断向量表移动的方法是在程序中加入函数
    void NVIC_SetVectorTable(u32 NVIC_VectTab, u32 Offset);
    其中参数NVIC_VectTab为中断向量表起始位置,而参数Offset则为地址偏移量,
    如将中断向量表移至0x8002000处,则应调用该函数如下:
    void NVIC_SetVectorTable(0x8000000, 0x2000);
    同时有必要提醒
    此函数只会修改STM32程序中用于存储中断向量的结构体变量,
    而不会实质地改变中断向量表在闪存中的物理位置

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值