大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是Cortex-M中断向量表对齐原则

  今天这篇文章的内容主要来自于五年前做 Kinetis K32W 系列双核启动时的发现,最近正好有同事碰到了 ARM Cortex-M 中断向量表对齐问题,于是痞子衡想起了这事(感慨自己记性还挺好),翻出了五年前的邮件,将当时测试结果重新整理成文。

  前段时间痞子衡刚写了篇 《Cortex-M中断向量表原理及其重定向方法》,简单介绍了中断向量表工作机制,今天咱们接着来聊聊这个中断向量表对齐的事:

一、Cortex-M中断向量表对齐原则

  中断向量表就是一个集中保存系统全部中断处理函数(xxxIRQHandler)地址的常量数组(函数地址要占 4 个字节,因此数组中每个元素大小为 4 字节),表中元素编号如下:

1. 中断向量表第 0 - 1 个向量比较特殊,是程序初始 SP 和 PC 值
2. 中断向量表第 2 - 15 个向量是系统中断,IRQ 编号为 -14 到 -1
3. 中断向量表第 16 个向量开始是厂商自定义外设中断,IRQ 编号为 0 到 n
- 对于 Cortex-M0/0+/1, ARM 建议的 n 值最大为 15(实际一般厂商都会扩展)
- 对于 Cortex-M3/4/7/23, ARM 建议的 n 值最大为 239
- 对于 Cortex-M33/35P/55, ARM 建议的 n 值最大为 479

  Cortex-M 内核(除了CM0)模块 SCB 里有个专门的 VTOR 寄存器用来控制中断向量表首地址,程序运行起来后用户可以配置 SCB->VTOR 寄存器来重设中断向量表地址。

  SCB->VTOR 寄存器低 7bit 是保留的(永远0),所以中断向量表首地址一定要是 128 字节(0x80)对齐的,这个毫无疑问!但是仅仅 128 字节对齐就行了吗?这个是要看情况的,如下 Cortex-M Generic User Guide 手册里关于 VTOR 寄存器描述里有这样一段话(红框内),这段话的意思是向量表首地址需要按 0x80 向上对齐(还得是 2 的整数幂)以覆盖项目中实际用到的数值最大中断号(xxx_IRQn)。

  • Note: 比如项目中实际用到最大外设中断为 IRQ20,则最小向量表大小为(16 + 21)* 4 字节,那么向量表首地址需要至少以 0x100 对齐。

二、Cortex-M中断向量表不对齐的后果

  如果中断向量表首地址没有按规定对齐,会发生什么后果呢?我们找一块板卡来实测下,选择的芯片是恩智浦 i.MXRT1011,这是颗 Cortex-M7 内核的 MCU,除了 16 个系统中断外,还包含 80 个外设中断,中断向量表里一共 96 个有效中断,见如下 startup_MIMXRT1011.s 文件中具体中断响应函数定义:

  因为 i.MXRT1011 里一共 96 个中断,按规定,中断向量表首地址至少要按 0x200 对齐。我们现在故意不按规定来设对齐,先选择一个测试工程 \SDK_2.10.0_EVK-MIMXRT1010\boards\evkmimxrt1010\demo_apps\hello_world\iar(flexspi_nor_build),修改 hello_world.c 文件,加一个 relocate_vector_table() 函数,将中断向量表重定向到 NEW_VECTOR_ADDRESS:

#define NEW_VECTOR_ADDRESS (0x00000080)

extern uint32_t __VECTOR_TABLE[];
void relocate_vector_table(void)
{
__disable_irq();
// 将 0x60002000 处的初始中断向量表拷贝到新地址 NEW_VECTOR_ADDRESS
memcpy((void *)NEW_VECTOR_ADDRESS, (void *)__VECTOR_TABLE, 0x180);
// 将 VTOR 指向 NEW_VECTOR_ADDRESS
SCB->VTOR = NEW_VECTOR_ADDRESS;
__enable_irq();
} int main(void)
{
relocate_vector_table(); // 其余代码
}

  万事俱备,我们现在需要使能一些中断来验证,痞子衡分别选取了 SysTick、LPUART1、GPT2、WDOG2、TEMP_LOW_HIGH、WDOG1 六个中断,它们的使能代码都可以从 SDK\boards\evkmimxrt1010\driver_examples\ 里找到,这里不予赘述。

2.1 测试以 0x80 对齐的中断向量表

  将 NEW_VECTOR_ADDRESS 设为 ITCM 偏移 0x80 处,则中断向量表被重定向到了按 0x80 对齐的地方,分别测试选定的 6 个中断,最终结果如下:SysTick、TEMP_LOW_HIGH、WDOG1 中断响应是正常的,而 LPUART1、GPT2、WDOG2 实际响应的中断函数却是 MemManage、SysTick、DMA13 位置,这里出现了异常。

#define NEW_VECTOR_ADDRESS (0x00000080)

2.2 测试以 0x100 对齐的中断向量表

  将 NEW_VECTOR_ADDRESS 设为 ITCM 偏移 0x100 处,则中断向量表被重定向到了按 0x100 对齐的地方,分别测试选定的 6 个中断,最终结果如下:SysTick、LPUART1、GPT2、WDOG2 中断响应是正常的,而 TEMP_LOW_HIGH、WDOG1 实际响应的中断函数却是 SysTick、DMA10 位置,还是出现了异常。

#define NEW_VECTOR_ADDRESS (0x00000100)

2.3 测试以 0x180 对齐的中断向量表

  将 NEW_VECTOR_ADDRESS 设为 ITCM 偏移 0x180 处,则中断向量表被重定向到了按 0x180 对齐的地方,实测效果跟 2.1 节一致。

#define NEW_VECTOR_ADDRESS (0x00000180)

2.4 测试以 0x200 对齐的中断向量表

  将 NEW_VECTOR_ADDRESS 设为 ITCM 偏移 0x200 处,则中断向量表被重定向到了按 0x200 对齐的地方,6 个中断都能正常响应,毕竟是符合 ARM 手册里对齐规定。

#define NEW_VECTOR_ADDRESS (0x00000200)

2.5 测试结果总结

  因为 i.MXRT1011 最多仅 96 个有效中断,有些对齐测试不能完全覆盖,痞子衡后来又在 i.MXRT1176 上(最多 234 个有效中断)以同样方式测了一遍,最终总结到现象如下:

1. 当中断向量表以 0x80 对齐时:
- 表中 (2n*0x80)/4 处开始的连续 32 个中断均能够正常响应,n 可取值 0 - 7
- 表中 ((2n+1)*0x80)/4 处开始的连续 32 个中断发生时,实际响应的却是表中((2n*0x80)/4 处对应的连续 32 个中断函数
2. 当中断向量表以 0x100 对齐时:
- 表中 (2n*0x100)/4 处开始的连续 64 个中断均能够正常响应,n 可取值 0 - 4
- 表中 ((2n+1)*0x100)/4 处开始的连续 64 个中断发生时,实际响应的却是表中((2n*0x100)/4 处对应的连续 64 个中断函数
3. 当中断向量表以 0x200 对齐时:
- 表中 (2n*0x200)/4 处开始的连续 128 个中断均能够正常响应,n 可取值 0 - 1
- 表中 ((2n+1)*0x200)/4 处开始的连续 128 个中断发生时,实际响应的却是表中((2n*0x200)/4 处对应的连续 128 个中断函数
4. 当中断向量表以 0x400 对齐时:
- 表中前 256 个中断均能够正常响应
- 推测表中第 256 - 511 个中断发生时,实际响应的是表中 0 - 255 个中断
5. 当中断向量表以 0x800 对齐时:
- 表中前 512 个中断均能够正常响应 6. 当中断向量表以 0x180 对齐时:未详尽测试,效果似乎与以 0x80 对齐一致
7. 当中断向量表以 0x280 对齐时:未详尽测试,第 100 个中断误触发第 68 个中断函数,第 136 个中断触发 HardFault
8. 当中断向量表以 0x300 对齐时:未详尽测试,第 100/136 个中断均触发 HardFault
...

  至此,Cortex-M中断向量表对齐原则痞子衡便介绍完毕了,掌声在哪里~~~

欢迎订阅

文章会同时发布到我的 博客园主页CSDN主页知乎主页微信公众号 平台上。

微信搜索"痞子衡嵌入式"或者扫描下面二维码,就可以在手机上第一时间看了哦。

痞子衡嵌入式:嵌入式Cortex-M中断向量表对齐原则的深入研究的更多相关文章

  1. 痞子衡嵌入式:改动i.MXRT1xxx里IOMUXC_GPR寄存器保留位可能会造成系统异常

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是改动i.MXRT1xxx里IOMUXC_GPR寄存器保留位可能会造成系统异常. 痞子衡的嵌入式技术交流群里有一位非常活跃的朋友(网名:文 ...

  2. 痞子衡嵌入式:一个奇怪的Keil MDK下变量链接强制对齐报错问题(--legacyalign)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是一个奇怪的Keil MDK下变量链接强制对齐报错问题. 痞子衡最近一直在参与恩智浦SBL项目(就是一个适用LPC和i.MXRT的完整OT ...

  3. 痞子衡嵌入式:嵌入式Cortex-M中断向量表原理及其重定向方法

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是Cortex-M中断向量表原理及其重定向方法. 接着前文 <嵌入式Cortex-M裸机环境下临界区保护的三种实现> 继续聊, ...

  4. 痞子衡嵌入式:链接函数到8字节对齐地址或可进一步提升i.MXRT内核执行性能

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是i.MXRT上进一步提升代码执行性能的经验. 今天跟大家聊的这个话题还是跟痞子衡最近这段时间参与的一个基于i.MXRT1170的大项目有 ...

  5. 痞子衡嵌入式:ARM Cortex-M文件那些事(2)- 链接文件(.icf)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家讲的是嵌入式开发里的linker文件. 在前一节课源文件(.c/.h/.s)里,痞子衡给大家系统地介绍了source文件,source文件是嵌入 ...

  6. 痞子衡嵌入式:利用i.MXRT1060,1010上新增的FlexSPI地址重映射(Remap)功能可安全OTA

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT部分型号上新增的FlexSPI Remap功能. OTA升级设计几乎是每个量产客户都绕不开的话题,产品发布后免不了要做固件( ...

  7. 痞子衡嵌入式:MCUBootUtility v3.4发布,支持串行NAND

    -- 痞子衡维护的 NXP-MCUBootUtility 工具距离上一个大版本(v3.3.0)发布过去 4 个多月了,这一次痞子衡为大家带来了版本升级 v3.4.0,这个版本主要有几个非常重要的更新需 ...

  8. 痞子衡嵌入式:极易上手的可视化wxPython GUI构建工具(wxFormBuilder)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是wxPython GUI构建工具wxFormBuilder. 一.手工代码布局GUI界面的烦恼 如果你曾经设计过上位机软件GUI界面,初 ...

  9. 痞子衡嵌入式:恩智浦MCU安全加密启动一站式工具NXP-MCUBootUtility用户指南

    NXP MCU Boot Utility English | 中文 1 软件概览 1.1 介绍 NXP-MCUBootUtility是一个专为NXP MCU安全加密启动而设计的工具,其特性与NXP M ...

随机推荐

  1. ceph介绍和安装

    目录 1.Ceph简介 2.Ceph的特点 3.Ceph的缺点 4.架构与组件 4.1.组件介绍 4.2.存储过程 5.部署 5.1 设置主机名.配置时间同步 5.2 配置添加清华源 5.3 初始化c ...

  2. 关于shell脚本——条件测试、if语句、case语句

    目录 一.条件测试 1.1.表达说明 1.2.test命令 文件测试 1.3.整数值比较 1.4.字符串比较 1.5.逻辑测试 二.if语句 2.1.单分支结构 2.2.双分支结构 2.3.多分支结构 ...

  3. Spring源码解析之ConfigurationClassPostProcessor(一)

    ConfigurationClassPostProcessor 在前面一个章节,笔者和大家介绍了在构造一个应用上下文时,spring会执行到PostProcessorRegistrationDeleg ...

  4. 自定义流式布局:ViewGroup的测量与布局

    目录 1.View生命周期以及View层级 1.1.View生命周期 1.2.View层级 2.View测量与MeasureSpec类 2.1.MeasureSpec类 2.2.父View的限制 :测 ...

  5. Maven无法下载com.oracle:ojdbc.jar解决方法

    Maven无法下载com.oracle:ojdbc.jar解决方法 从maven仓库中下载失败,可以搭建私服nexus,也可以将jar下载到本地然后导入local_repository 使用maven ...

  6. Java调用阿里云短信接口发送手机验证码

    前五步可参考阿里云服务文档:https://help.aliyun.com/document_detail/59210.html?spm=a2c4g.11174283.4.1.2b152c42DoJ7 ...

  7. docker部署mysql5-7-31

    快速开始 docker run -itd --name mysql-test -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql docker-compo ...

  8. 十二:Servlet3.0的注解

    1.@WebListener注解 表示的就是我们之前的在xml中配置的 <listener> <listener-class>ListenerClass</listene ...

  9. 区间k大数训练

    问题描述 给定一个序列,每次询问序列中第l个数到第r个数中第K大的数是哪个. 输入格式 第一行包含一个数n,表示序列长度. 第二行包含n个正整数,表示给定的序列. 第三个包含一个正整数m,表示询问个数 ...

  10. 学习Java的9张思维导图

    转自:https://blog.csdn.net/aitaozi11/article/details/79652943 网上搜集了java的学习思维导图,分享给大家. 01.Java程序设计(基础) ...