查看: 5685|回复: 1

[分享] [痞子衡]Cortex-M中断向量表原理及其重定向方法

[复制链接]
  • TA的每日心情
    开心
    2025-7-11 08:53
  • 签到天数: 301 天

    连续签到: 2 天

    [LV.8]以坛为家I

    3920

    主题

    7538

    帖子

    0

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    39928
    最后登录
    2025-8-20
    发表于 2021-8-11 10:26:52 | 显示全部楼层 |阅读模式
    Cortex-M中断向量表原理及其重定向方法


    大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是Cortex-M中断向量表原理及其重定向方法。


    接着前文 《嵌入式Cortex-M裸机环境下临界区保护的三种实现》 继续聊,嵌入式代码设计里有时候一些特殊操作(比如 XIP 下 Flash 擦写、低功耗模式切换)不能被随意打断,或者一些共享数据区不能被无序访问(A 任务正在读,B 任务却要写),这时候我们可以利用系统全局中断开关控制来实现所谓的临界区保护。


    但有些场景下开关系统全局中断这种方法并不总是很凑效,比如 XIP 下 Flash 擦写这种情况,如果项目里还有一个后台定时器(比如SysTick)在实时运行,擦除 Flash 期间(这个时间可能会很长)我们直接关闭系统全局中断,会导致定时器中断无法响应,系统计时会出偏差,对于这种情况,我们显然不能关闭系统全局中断。


    为了在 Flash 擦写期间系统还能够及时响应定时器中断(执行中断响应函数),我们需要将定时器中断响应函数及其相关代码像 Flash IAP 操作代码一样都链接到 RAM 里执行,此外还需要将中断向量表也重定向到 RAM 里才行。今天痞子衡就来聊一聊重定向中断向量表的方法:


    一、Cortex-M中断向量表简介
    熟悉 ARM Cortex-M 处理器的朋友应该都对下面这张表有所了解,这就是中断向量表,表中每个向量大小都是 4 字节,除了第 0 个向量外,其余向量都是函数地址,这个表集中保存了系统全部的中断处理函数(xxxIRQHandler)地址。
    11.png
    对于内嵌 Flash 的 MCU 来说,初始中断向量表一般会被要求固定链接到 Flash 起始地址处,因为系统启动总是从 Flash 起始地址获取第 0(初始栈)、1个向量(初始PC,复位函数ResetHandler)来开始应用程序代码的执行。对于一些包含 BootROM 或者没有内部 Flash 的 MCU,初始中断向量表也许可以放到 Flash 中的其他地址处,这要取决于具体芯片设计。


    当应用程序执行起来后,如果发生了中断,系统会根据发出请求的外设中断号来中断向量表里找到对应的外设中断响应函数并去执行。Cortex-M 内核(除了CM0)模块 SCB 里有个专门的 VTOR 寄存器用来控制中断向量表首地址(注意,地址需要 128 字节对齐),程序运行起来后用户可以配置 SCB->VTOR 寄存器来重设中断向量表地址。
    12.png
    二、重定向中断向量表的方法
    现在我们以恩智浦 i.MXRT1170 型号为例介绍重定向中断向量表的方法,在 \SDK_2.9.1_MIMXRT1170-EVK\boards\evkmimxrt1170\demo_apps\led_blinky\cm7\iar 工程上示例。


    2.1 与中断向量表相关的文件
    这个 led_blinky 工程里跟中断向量表有关的一共两个文件,一是 startup_MIMXRT1176_cm7.s 启动文件,这里面存放了中断向量表实体定义,以及复位函数 ResetHandler(),从复位函数里你可以看到上来就先重置了一遍 SCB->VTOR 寄存器。
    1. THUMB

    2.         PUBWEAK Reset_Handler
    3.         SECTION .text:CODE:REORDER:NOROOT(2)
    4. Reset_Handler
    5.         CPSID   I               ; Mask interrupts
    6.         LDR     R0, =0xE000ED08      ; 即 SCB->VTOR
    7.         LDR     R1, =__vector_table  ; section .intvec 段首地址
    8.         STR     R1, [R0]
    9.         LDR     R2, [R1]
    10.         MSR     MSP, R2
    11.         LDR     R0, =SystemInit
    12.         BLX     R0
    13.         CPSIE   I               ; Unmask interrupts
    14.         LDR     R0, =__iar_program_start
    15.         BX      R0
    复制代码
    复位函数里用到的 __vector_table 值取决于 MIMXRT1176xxxxx_cm7_flexspi_nor.icf 链接文件里如下语句设置。由于 i.MXRT1170 没有内部 Flash,分配给外部 NOR Flash (挂在 FlexSPI1 外设上)的系统映射起始地址是 0x30000000,而 0x30002000 是 BootROM 能支持的应用程序初始中断向量表地址之一(在 IVT 启动头里指示)。
    1. define symbol m_interrupts_start       = 0x30002000;
    2. define symbol m_interrupts_end         = 0x300023FF;

    3. define exported symbol __VECTOR_TABLE          = m_interrupts_start;

    4. place at address mem: m_interrupts_start    { readonly section .intvec };
    复制代码
    编译工程后在对应生成的 iled_blinky_cm7.map 映射文件里可以找到初始中断向量表最终链接地址。为了便于后续分析问题,我们将定时器中断响应函数地址也一并列出来:
    1. *******************************************************************************
    2. *** PLACEMENT SUMMARY
    3. ***

    4. "A0":  place at address 0x3000'2000 { ro section .intvec };

    5.   Section              Kind         Address    Size  Object
    6.   -------              ----         -------    ----  ------
    7. "A0":                                         0x400
    8.   .intvec              ro code  0x3000'2000   0x400  startup_MIMXRT1176_cm7.o [1]
    9.                               - 0x3000'2400   0x400

    10. *******************************************************************************
    11. *** ENTRY LIST
    12. ***

    13. Entry                       Address   Size  Type      Object
    14.   -----                       -------   ----  ----      ------
    15. SysTick_Handler         0x3000'5767   0x10  Code  Gb  led_blinky.o [1]
    16. __VECTOR_TABLE {Abs}    0x3000'2000         Data  Gb  <internal module>
    17. __Vectors               0x3000'2000          --   Gb  startup_MIMXRT1176_cm7.o [1]
    18. __Vectors_End           0x3000'2400         Data  Gb  startup_MIMXRT1176_cm7.o [1]
    19. __Vectors_Size {Abs}          0x400          --   Gb  startup_MIMXRT1176_cm7.o [1]
    20. __vector_table          0x3000'2000         Data  Gb  startup_MIMXRT1176_cm7.o [1]
    复制代码
    2.2 中断重定向函数示例
    定时器中断响应函数 SysTick_Handler() 链接在 Flash 里显然是不行的,我们利用 IDE 特性(对于IAR,是 __ramfunc 修饰符)将其链接到 RAM 里(MIMXRT1176xxxxx_cm7_flexspi_nor.icf 里定义了 TEXT2_region: 0x0 - 0x3FFFF 空间存放 section .textrw 段), 重新编译工程,查看映射文件可以看到新分配的地址是 0x1。
    1. __ramfunc void SysTick_Handler(void)
    2. {
    3.     if (g_systickCounter != 0U)
    4.     {
    5.         g_systickCounter--;
    6.     }
    7. }
    复制代码
    1. *******************************************************************************
    2. *** ENTRY LIST
    3. ***

    4. Entry                       Address   Size  Type      Object
    5.   -----                       -------   ----  ----      ------
    6. SysTick_Handler                 0x1   0x14  Code  Gb  led_blinky.o [1]
    复制代码
    现在我们尝试在代码里纯手工搬移中断向量表,找一块空闲的 RAM 区域(比如 0x20000000 - 0x200003FF),将中断向量表内容直接手工拷贝过去即可,示例代码如下。主函数里一开始就调用一下这个 relocate_vector_table() 函数即可,修改后的工程下载进板卡运行一切正常,表明中断向量表重定向操作成功了。
    1. extern uint32_t __VECTOR_TABLE[];

    2. void relocate_vector_table(void)
    3. {
    4.     __disable_irq();
    5.     // 将 0x30002000 处的初始中断向量表拷贝到新地址 0x20000000
    6.     memcpy((void *)0x20000000, (void *)__VECTOR_TABLE, 0x400);
    7.     // 将 VTOR 指向 0x20000000
    8.     SCB->VTOR = 0x20000000;
    9.     __enable_irq();
    10. }

    11. int main(void)
    12. {
    13.     relocate_vector_table();

    14.     // 其余代码
    15. }
    复制代码
    至此,Cortex-M中断向量表原理及其重定向方法痞子衡便介绍完毕了,掌声在哪里~~~





    qiandao qiandao
    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    昨天 10:40
  • 签到天数: 2402 天

    连续签到: 111 天

    [LV.Master]伴坛终老

    84

    主题

    2万

    帖子

    3

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    22319
    最后登录
    2025-8-20
    发表于 2021-8-11 11:04:03 | 显示全部楼层
    学习了
    该会员没有填写今日想说内容.
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-8-21 07:38 , Processed in 0.090389 second(s), 23 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表