大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是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)地址。

  对于内嵌 Flash 的 MCU 来说,初始中断向量表一般会被要求固定链接到 Flash 起始地址处,因为系统启动总是从 Flash 起始地址获取第 0(初始栈)、1个向量(初始PC,复位函数ResetHandler)来开始应用程序代码的执行。对于一些包含 BootROM 或者没有内部 Flash 的 MCU,初始中断向量表也许可以放到 Flash 中的其他地址处,这要取决于具体芯片设计。

  当应用程序执行起来后,如果发生了中断,系统会根据发出请求的外设中断号来中断向量表里找到对应的外设中断响应函数并去执行。Cortex-M 内核(除了CM0)模块 SCB 里有个专门的 VTOR 寄存器用来控制中断向量表首地址(注意,地址需要 128 字节对齐),程序运行起来后用户可以配置 SCB->VTOR 寄存器来重设中断向量表地址。

二、重定向中断向量表的方法

  现在我们以恩智浦 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 寄存器。

        THUMB

        PUBWEAK Reset_Handler
SECTION .text:CODE:REORDER:NOROOT(2)
Reset_Handler
CPSID I ; Mask interrupts
LDR R0, =0xE000ED08 ; 即 SCB->VTOR
LDR R1, =__vector_table ; section .intvec 段首地址
STR R1, [R0]
LDR R2, [R1]
MSR MSP, R2
LDR R0, =SystemInit
BLX R0
CPSIE I ; Unmask interrupts
LDR R0, =__iar_program_start
BX R0

  复位函数里用到的 __vector_table 值取决于 MIMXRT1176xxxxx_cm7_flexspi_nor.icf 链接文件里如下语句设置。由于 i.MXRT1170 没有内部 Flash,分配给外部 NOR Flash (挂在 FlexSPI1 外设上)的系统映射起始地址是 0x30000000,而 0x30002000 是 BootROM 能支持的应用程序初始中断向量表地址之一(在 IVT 启动头里指示)。

define symbol m_interrupts_start       = 0x30002000;
define symbol m_interrupts_end = 0x300023FF; define exported symbol __VECTOR_TABLE = m_interrupts_start; place at address mem: m_interrupts_start { readonly section .intvec };

  编译工程后在对应生成的 iled_blinky_cm7.map 映射文件里可以找到初始中断向量表最终链接地址。为了便于后续分析问题,我们将定时器中断响应函数地址也一并列出来:

*******************************************************************************
*** PLACEMENT SUMMARY
*** "A0": place at address 0x3000'2000 { ro section .intvec }; Section Kind Address Size Object
------- ---- ------- ---- ------
"A0": 0x400
.intvec ro code 0x3000'2000 0x400 startup_MIMXRT1176_cm7.o [1]
- 0x3000'2400 0x400 *******************************************************************************
*** ENTRY LIST
*** Entry Address Size Type Object
----- ------- ---- ---- ------
SysTick_Handler 0x3000'5767 0x10 Code Gb led_blinky.o [1]
__VECTOR_TABLE {Abs} 0x3000'2000 Data Gb <internal module>
__Vectors 0x3000'2000 -- Gb startup_MIMXRT1176_cm7.o [1]
__Vectors_End 0x3000'2400 Data Gb startup_MIMXRT1176_cm7.o [1]
__Vectors_Size {Abs} 0x400 -- Gb startup_MIMXRT1176_cm7.o [1]
__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。

__ramfunc void SysTick_Handler(void)
{
if (g_systickCounter != 0U)
{
g_systickCounter--;
}
}
*******************************************************************************
*** ENTRY LIST
*** Entry Address Size Type Object
----- ------- ---- ---- ------
SysTick_Handler 0x1 0x14 Code Gb led_blinky.o [1]

  现在我们尝试在代码里纯手工搬移中断向量表,找一块空闲的 RAM 区域(比如 0x20000000 - 0x200003FF),将中断向量表内容直接手工拷贝过去即可,示例代码如下。主函数里一开始就调用一下这个 relocate_vector_table() 函数即可,修改后的工程下载进板卡运行一切正常,表明中断重定向操作成功了。

extern uint32_t __VECTOR_TABLE[];

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

  至此,Cortex-M中断向量表原理及其重定向方法痞子衡便介绍完毕了,掌声在哪里~~~

欢迎订阅

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

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

痞子衡嵌入式:嵌入式Cortex-M中断向量表原理及其重定向方法的更多相关文章

  1. 痞子衡嵌入式:嵌入式Cortex-M中断向量表对齐原则的深入研究

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是Cortex-M中断向量表对齐原则. 今天这篇文章的内容主要来自于五年前做 Kinetis K32W 系列双核启动时的发现,最近正好有同 ...

  2. 痞子衡嵌入式:飞思卡尔i.MX RTyyyy系列MCU外设那些事(2)- 善变的FlexRAM

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是飞思卡尔i.MX RTyyyy系列MCU的FlexRAM外设. 本文是外设系列第二篇,上一篇讲的是离内核最近的高速缓存L1 Cache, ...

  3. 痞子衡嵌入式:恩智浦i.MX RT1xxx系列MCU硬件那些事(2.3)- 串行NOR Flash下载算法(J-Link工具篇)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是J-Link工具下i.MXRT的串行NOR Flash下载算法设计. 在i.MXRT硬件那些事系列之<在串行NOR Flash X ...

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

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

  5. 痞子衡嵌入式:在串口波特率识别实例里逐步展示i.MXRT上提升代码执行性能的十八般武艺

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是在串口波特率识别实例里逐步展示i.MXRT上提升代码执行性能的十八般武艺. 恩智浦 MCU SE 团队近期一直在加班加点赶 SBL 项目 ...

  6. 痞子衡嵌入式:嵌入式里堆栈原理及其纯C实现

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家讲的是嵌入式里堆栈原理及其纯C实现. 今天给大家分享的这篇还是2016年之前痞子衡写的技术文档,花了点时间重新编排了一下格式.栈这种结构在嵌入式 ...

  7. 痞子衡嵌入式:飞思卡尔i.MX RTyyyy系列MCU硬件那些事(2.2)- 在串行NOR Flash XIP调试原理

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是飞思卡尔i.MX RTyyyy系列EVK在串行NOR Flash调试的原理. 本文是i.MXRT硬件那些事系列第二篇的续集,在第二篇首集 ...

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

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

  9. 痞子衡嵌入式:ARM Cortex-M文件那些事(1)- 源文件(.c/.h/.s)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家讲的是嵌入式开发里的source文件. 众所周知,嵌入式开发属于偏底层的开发,主要编程语言是C和汇编.所以本文要讲的source文件主要指的就是 ...

随机推荐

  1. theUnforgiven——项目冲刺

    这个作业属于哪个课程 https://edu.cnblogs.com/campus/zswxy/computer-science-class1-2018/ 小组号和队名 8组theUnforgiven ...

  2. ffmpeg入门到实战-ffmpeg是怎么转码的?

    阅读目录 视频是怎么被播放的? ffmpeg命令的格式 ffmpeg转码输出的过程 视频是怎么被播放的? 我们知道,当下大多数播放器都是基于ffmpeg二次开发的.你有没有想过,你用播放器打开一个视频 ...

  3. linux下 大日志文件查看与搜索---less

    场景 有一个几十m的大日志文件,里边的记录是按时间排序的. 现在需要找到其中,不知道在什么位置的一条错误消息.这时候,想把内容拷出来都费劲,就算拷出来了,一般的编辑器也难以hold住这么大的文件.这时 ...

  4. external-provisioner源码分析(3)-组件启动参数分析

    更多ceph-csi其他源码分析,请查看下面这篇博文:kubernetes ceph-csi分析目录导航 external-provisioner源码分析(3)-组件启动参数分析 本文将对extern ...

  5. 18、通过yum命令只下载rpm包不安装

    18.1.说明: 经常遇到服务器没有网络的情况下部署环境,或者创建自己的 yum 仓库等,这时就需要下载 rpm 包. 18.2.方法一,yumdownloader(推荐): 如果只想通过 yum 下 ...

  6. iOS工程师如何恍然大悟?

    聊聊行情?为什么总有人在乎旁人的看法而忽略自己的初衷? 虽然iOS开发市场说不上好但也绝不算坏,想没想过那些煽风点火说iOS不行的人在做什么? 真的转行从头开始? 错.大错特错! 在劝退你的同时他们会 ...

  7. Https:创建部署SSL证书进行双向认证

    一.前言 建立客户端与服务器的Https的连接需要证书进行双向验证后,才可访问.   二.证书类型 不同数字证书部署在服务器上后,用户浏览器访问网站时,展示如下: 1.无证书时 显示不安全标识. 2. ...

  8. php操作redis集群哨兵模式

    前段时间项目里正好用到了redis的集群哨兵部署,因为此前并无了解过,所以一脸懵逼啊,查阅了几篇资料,特此综合总结一下,作为记录. 写在前沿:随着项目的扩张,对redis的依赖也越来越大,为了增强re ...

  9. FastTunnel-开源内网穿透框架

    FastTunnel - 打造人人都能搭建的内网穿透工具 FastTunnel是用.net core开发的一款跨平台内网穿透工具,它可以实现将内网服务暴露到公网供自己或任何人访问. 与其他穿透工具不同 ...

  10. yoyogo v1.7.5 发布, 独立依赖注入DI

    YoyoGo v1.7.5 YoyoGo (Go语言框架) 一个简单.轻量.快速.基于依赖注入的微服务框架( web .grpc ),支持Nacos/Consoul/Etcd/Eureka/k8s / ...