- #ifdef VECT_TAB_SRAM
- SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET;
- #else
- SCB->VTOR = FMC_BASE | VECT_TAB_OFFSET;
- #endif
若APP产生了中断,其对应的中断执行流程如下。
因为APP有自己的中断向量表,所以当APP产生中断时,会直接从VTOR所设置的地址查找中断向量表,执行对应的中断服务函数。
如下是KEIL的配置,只需设置APP的FLASH的起始地址即可。
2. 无VTOR寄存器
有些芯片内核没有VTOR寄存器,即使这样,仍然有两种方式可以进行中断的相关处理,一种是中断向量表重映射,另一种是中断服务函数重定位。
2.1 中断向量表重映射
由于没有VTOR寄存器,所以我们可以在APP代码中,先将APP的中断向量表从FLASH中复制到RAM里,再将RAM区映射到vector table区域。
以下是中断向量表重映射的相关寄存器。
(1)当MEM_MODE=00/10时,MainFlash映射到地址0x00000000,即地址0x08000000映射到0x00000000.
(2)当MEM_MODE=01时,SystemFlash映射到地址0x00000000,也就是芯片自带的Bootloader代码部分会映射到地址0x00000000,即0x1FFFC800映射到地址0x00000000.
(3)当MEM_MODE=11时,SRAM映射到地址0x00000000,也就是内存地址0x20000000映射到地址0x00000000.
那么,中断向量表的固定地址是多少呢?在ARM官网上我们找到如下信息:
也就是说,在没有VTOR寄存器时,中断向量表的地址固定在地址0x00000000上。
在这个过程中,中断的调用过程如下:
->产生中断
->CPU固定到地址0x00000000上找中断入口函数,由于映射关系,实际上是在从映射地址上寻找,即0x20000000。
->找到并执行中断例程
若使用这种方式进行IAP的固件升级,则必须在APP中将中断向量表拷贝到SRAM,并将系统重映射到SRAM,这样才能使中断恢复正常工作。
如下为实现IAP跳转的代码:
- /*!
- * [url=home.php?mod=space&uid=247401]@brief[/url] Jump to user application
- *
- * @param Application : APP1 or APP2
- *
- * @retval None
- *
- * @note
- */
- void Jump_to_App(uint8_t Application)
- {
- uint32_t address;
- /* Lock the Program memory */
- FMC_Lock();
- if(Application == APP1)
- {
- address = USER_APP1_START_ADDRESS;
- }
- else
- {
- address = USER_APP2_START_ADDRESS;
- }
- /* Jump to user application */
- JumpAddress = *(__IO uint32_t *) (address + 4);
- Jump_To_Application = (pFunction) JumpAddress;
- /* Initialize user application's Stack Pointer */
- __set_MSP(*(__IO uint32_t *) address);
- /* Jump to application */
- Jump_To_Application();
- }
其具体的中断服务函数的实现流程如下图所示:
当APP产生中断时,系统会选择根据MEM的映射方式,去0x00000000查找中断向量表,执行其对应的中断服务函数。
如下为KEIL的相关配置:
为什么设置IRAM1的Start地址为0x200000C0?
RAM区是用来存放程序运行时的一些变量,设置RAM区地址从0x200000C0,是因为0x20000000处存放了中断向量表,这是为了防止中断向量表被变量重新覆写。
2.2中断服务函数重定位
这种方式下,它并没有将中断向量表重映射,而是将中断服务函数进行了重定位,直接跳转到对应的中断服务函数。
在IAP程序中定义APP_interrupt_vector_addr(存储在0x20000000)变量,用于处理IAP中断函数,以响应正确的中断,该变量是一个标志位。
各个工程均需初始化变量FLASH_interrupt_vector(存储在0x20000004)变量,用于指向当前系统所需的中断服务函数,该变量是一个标志位。
如下为IAP的中断服务函数,目的是为了判断当前是哪个APP发生了中断,跳转到对应APP的中断服务函数.
同时在APP1中,更改FLASH_interrupt_vector,设置为APP1_INTERRUPT_VECTOR,代表指向APP1的中断向量表。
具体的执行流程图如下:
当APP产生中断时,其具体的执行流程如下:
在这种情况下,当APP产生中断时,会去查找IAP的中断向量表,在IAP的中断服务函数里直接跳转到APP的中断服务函数。
如下为KEIL的相关配置。
为什么设置IRAM1的start值为0x20000008 ?
因为在0x20000000处存放了两个常量,常量类型为uint32_t,故一个变量占4个字节,两个常量占8个字节,这两个常量在程序运行时是不能被轻易修改的。
程序运行时,会在RAM区生成一些数据,为了防止这两个常量被这些数据覆盖,从而影响后续的中断响应及中断服务函数的跳转。
3. 相关例程
附件中含上述3种情况的例程,有需要的可查看。
以上,就是本次分享的内容了,如有问题,欢迎讨论。