0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Cortex-M0中断向量重定位的高效方法

麦克泰技术 来源:嵌入式系统专家之声 2023-12-05 11:05 次阅读

IAP ( In Application Programming )功能为产品软件升级提供了一个方便快捷的接口。用户可以通过串口、USBCAN总线[1]而无需使用编程器即可实现产品的软件更新,甚至可以通过以太网[2]或者无线网络[3]实现产品软件的远程升级,大大方便了产品的功能迭代,提升了产品的易用性。

Bootloader(以下简称Boot)俗称引导程序,是实现IAP功能的核心。Application(简称App)即用户应用程序,负责实现产品功能。Boot和App这两个独立的程序在同一芯片中运行,有各自的中断向量表,但中断号相同。在由Boot进入到App后,如何使App下的中断能正确响应?这是所有IAP都需要面对的问题,而解决问题的关键在于实现中断向量的重定位。不同MCU根据自身硬件特性不同,实现中断向量重定位的方法存在着重大区别。

1Cortex-M3 架构MCU中断向量重定位

Nested Vectored Interrupt Controller(NVIC)即嵌套向量中断控制器,是Cortex-M内核的一部分,它管理和处理所有的异常和中断。Cortex-M3中的NVIC,在地址0xE000 ED08处是一个Vector Table Offset Register(VTOR)即中断向量表偏移量寄存器,通过修改它的值就能重新定位向量表[4]。

进入App运行后,只要在使能中断功能前设置VTOR寄存器值为App起始地址即可实现中断向量表的重定位。参考文献[5]分析了Cortex-M3 单片机中断向量重定位的执行过程。Cortex-M4内核中也有VTOR寄存器,因而在这些内核MCU上实现中断向量的重定位十分便捷、高效。

2Cortex-M0 架构MCU中断向量重定位

适中的性能、极低的能耗、低廉的价格使得Cortex-M0架构MCU应用非常广泛,尤其是在物联网传感器、电动工具、电子测量、家电行业[6]。因为Cortex-M0中的NVIC没有VTOR寄存器,所以此类型的MCU中断向量重定位变得不容易。

2.1STM32F030中断向量重定位

STM32F030基于Cortex-M0架构,厂商为该系列的MCU赋予了一个特性:启动地址支持重映射。通过设置芯片Boot引脚电平,使得程序可从内部Flash或内部RAM启动。芯片的SYSCFG_CFGR1寄存器也保存了设置状态,通过修改这个寄存器的值,即可重新引导程序[7]。

基于地址可以重新映射的特性,在App使能中断功能前,将中断向量表复制到内部RAM的起始地址,再设置SYSCFG_CFGR1寄存器,使其从RAM中启动,即可以实现中断向量的重定位。

2.2普通Cortex-M0架构MCU实现IAP的困境

并非所有Cortex-M0内核的单片机都支持地址重映射,因为这并不是内核功能的一部分[8]。市场上存在大量使用Cortex-M0内核的专用MCU,如某些电机控制的专用MCU。它们不像STM32F030那样具备地址重新映射的特性,因此不能使用2.1中的方法实现中断向量的重定位。

因此,实现中断向量的重定位成为此类基于Cortex-M0架构MCU实现IAP功能的最大障碍。相关研究资料较少,参考文献[9]给出了一种基于RAM的中断跳转方法,不过效率有待提升。

3中断向量重定位的通用方法

本文给出了实现中断向量重定位的一种通用方法。该方法不依赖于MCU自身硬件特性,而是基于纯软件实现。同时结合STM32F030和Keil开发环境,详细介绍了该方法的原理,给出了相关代码。

3.1梯子函数

给每一个中断向量增加这样一段程序:该程序负责获取App中对应中断服务函数的入口地址,然后跳转到该地址运行,从而运行App的中断服务程序。这种功能的程序像是从Boot中断向量通向App中断服务函数的梯子,因此称它为“梯子函数”。Boot中断向量表中的每一个中断向量保存的是对应梯子函数的入口地址。

3.2中断向量重定位过程

图1给出了基于该方法进行中断向量重定位的跳转流程图。App运行期间产生中断,仍会从Boot中断向量表取得相应的中断向量。不过此时实际获取的是梯子函数的入口地址,然后借助梯子函数实现向App中断服务程序跳转的目标。

cb891e8a-931a-11ee-939d-92fbcf53809c.jpg

图1中断向量表重定位通用方法

以RTC中断为例,当App运行时产生了该中断,则会从Boot的中断向量表找到RTC中断的梯子函数入口地址并跳转到该地址运行,如箭头①和②所示。RTC中断的梯子函数则会从App中的RTC中断向量加载对应的RTC中断服务程序的入口地址,如箭头③所示。最后跳转到该地址,运行App的RTC中断服务程序,如箭头④所示。

3.3梯子函数的实现

梯子函数是实现从Boot中断向量到App中断服务程序跳转的关键。程序采用汇编代码实现,一个中断向量对应着一个梯子函数。部分梯子函数编写的示例如下:

cb9bc666-931a-11ee-939d-92fbcf53809c.jpg

同样以RTC_IRQHandler为例,0x0800 2000为App的起始地址,对应图1中APP_BASE的值。0x48为RTC中断向量的偏移地址。Line7将RTC中断向量偏移地址加载到r0寄存器。Line8将App的RTC中断处理函数地址加载到r1寄存器。Line9通过bx指令实现跳转到App的RTC_IRQHandler中断服务程序入口处的目标。

通过在Boot中为各个中断向量设置梯子函数,借助梯子函数的桥梁作用实现中断向量表的重定位。基于该方法在STM32F030上进行了IAP功能验证,App的中断功能运行正常,验证了这一方法的可行性。

4 中断向量重定位改进方法1

4.1存在的问题

一个梯子函数需要两条ldr指令和一条bx指令,分别需要2个和3个指令周期[10],因此一个梯子函数共需要7个指令周期。此外Flash的时钟频率一般比CPU时钟低很多。如STM32F030的CPU时钟频率高于24 MHz时,访问Flash需要插入一个等待周期[11]。

综上,进入App中断服务函数运行前,将会引入较大的时间开销。当要求中断能快速响应或者存在诸如ADC采样之类的高频中断,这种中断向量重定位方法会引发系统性能的明显下降,为此需要对中断向量重定位的方法进行改进。

4.2改进原理

改进分为两方面:一是减少梯子函数所需的指令,二是将梯子函数移到内部RAM中运行。

Boot与App中各有一份梯子函数用于中断向量的重定位。Boot中的梯子函数用于对无速度要求的中断向量重定位,其工作原理和执行效果与前文相同。App中的梯子函数为需要降低中断响应延迟,提高中断处理性能的中断重定位。改进方法1中断向量表重定位执行过程如图2所示。

cbaa50d2-931a-11ee-939d-92fbcf53809c.jpg

图2改进方法1中断向量表重定位执行过程

仍以RTC_IRQHandler中断为例,此时该中断向量的梯子函数RTC_IRQHandler_App位于RAM中,且地址固定为0x2000 0001。同时Boot中对应RTC_IRQHandler中断向量的单元保存了该地址。当App运行过程中发生了RTC中断时,MCU会从Boot中的RTC_IRQHandler中断向量取得0x2000 0001地址,并跳转到App下RTC中断的梯子函数入口运行,对应箭头①和②。梯子函数会从App的中断向量表中取得RTC_IRQHandler中断服务函数地址,如箭头③所示,最终跳转到App的RTC中断服务程序入口处运行,如箭头④所示。

4.3App中的梯子函数

App所使用的梯子函数示例如下:

cbbde0b6-931a-11ee-939d-92fbcf53809c.jpg

其中,Line1定义了名为“ladder_app”的代码段。Lin6定义了RTC_IRQHandler_App函数,共两条汇编指令。首先将App下的RTC_IRQHandler中断服务函数地址加载到R0寄存器中,接着跳转到该地址运行。相比于改进之前,此时只需要LDR和BX两条指令,总计只需要5个指令周期。同时该段代码在RAM中运行,不受Flash等待周期限制。

4.4App的分散加载设置

通过分散加载可使得APP中的梯子函数始终位于RAM固定地址,而与具体的应用程序无关。STM32F030在Keil下的分散加载文件如下:

cc006206-931a-11ee-939d-92fbcf53809c.jpg

其中Line10将“ladder_app”代码段加载到0x2000 0000地址,长度为128字节。若App中梯子函数较多,则预留空间需要相应增大,反之亦然。

梯子函数的入口地址可以从工程编译成功后的map文件获取。如图3所示,RTC_IRQHandler_App函数的入口地址为0x2000 0001,这就是前文Boot中RTC_IRQHandler向量保存的地址来源。

cc1571e6-931a-11ee-939d-92fbcf53809c.jpg

图3 梯子函数与中断服务函数入口地址

5中断向量重定位改进方法2

前文讨论了将梯子函数搬移到RAM中运行,从而大幅降低进入用户中断服务程序的时间开销的改进方法。本节讨论再改进的方法,进一步压缩梯子函数的时间开销,提高进入中断程序的效率。

5.1梯子函数的改进

经过改进的梯子函数代码如下:

cc206150-931a-11ee-939d-92fbcf53809c.jpg

可以看出,只需要通过一条B指令,就可以跳转到中断服务函数入口。该指令执行只需要3个时钟周期,进一步降低了梯子函数运行所需要的时间开销。

B指令是相对跳转指令,用于无条件跳转,其支持跳转地址范围为PC-2046~PC+2046[4]。因此中断服务函数必须也位于内部RAM中,且距对应的梯子函数的跳转指令地址必须在2046字节之内。这一条件是容易满足的,毕竟不是所有的中断服务程序都需要这么做,而只是个别时间敏感、高频的中断需要按照这种方法处理。

5.2中断服务函数约束条件

为实现中断处理函数的地址约束,在编写相关中断处理函数时,需要添加约束属性。通过为函数设置section属性将中断服务程序放入自定义名称为“ramfunc_isr”的输入段。除此之外,与普通的中断处理函数无其他差别。如在Keil环境下,对于RTC中断处理函数写法如下:

5.3分散加载文件

改进方法2的分散加载文件设置如下:

cc3124f4-931a-11ee-939d-92fbcf53809c.jpg

与改进方法1的分散加载文件相比,多了Line12的内容,即将“ramfunc_isr”段的内容从地址0x2000 0080开始放置。

图4给出了map文件的部分内容,可以看出,梯子函数RTC_IRQHandler_App入口地址为0x2000 0001,Timer3_IRQHandler_App入口地址为0x2000 0003。此时App的一个中断梯子函数占用存储空间大小仅为2字节。实际的中断处理函数的入口地址分别为0x200 00081和0x2000 008d,均位于RAM中,紧接在梯子函数之后,相对地址也远小于2046 B,满足该改进方法的使用要求。

cc4aafb4-931a-11ee-939d-92fbcf53809c.png

图4 梯子函数与中断服务函数入口地址

6结 语

表1对文中提出的中断向量重定位的通用方法及其两种改进方法进行了对比,总结了3种方法的各自特点,实际上3三种方法可以混合使用。比如将高频的ADC采样中断使用改进方法2进行ADC中断向量的重定位,此时ADC中断额外的时间开销最小,同时由于该中断服务程序在RAM中运行,性能也将大幅提高。将中频的定时器中断使用改进方法1进行中断向量重定位,其他普通的中断向量采样通用方法进行重定位。

表1 中断向量重定位3种方法对比

cc5db942-931a-11ee-939d-92fbcf53809c.jpg

基于本文提出的中断向量表重定位方法,在STM32F030和Keil开发环境下进行了验证,结果正确。此外,在其他品牌的基于Cortex-M0内核的MCU上进行了验证,也取得了成功。目前基于该方法实现的IAP功能已经在产品上批量使用,效果较好。

文中提出的中断向量重定位的方法虽然是以Cortex-M0内核的MCU为对象进行讨论和测试的,但是其不依赖于硬件的特殊性,因此也可以在其他内核的MCU上进行推广应用。

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • mcu
    mcu
    +关注

    关注

    146

    文章

    16022

    浏览量

    343687
  • 控制器
    +关注

    关注

    112

    文章

    15239

    浏览量

    171229
  • 嵌入式
    +关注

    关注

    4983

    文章

    18295

    浏览量

    288594
  • 中断
    +关注

    关注

    5

    文章

    884

    浏览量

    41030
  • Cortex-M0
    +关注

    关注

    4

    文章

    122

    浏览量

    38356

原文标题:Cortex-M0中断向量重定位的高效方法

文章出处:【微信号:麦克泰技术,微信公众号:麦克泰技术】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    MM32 IAP中断向量定义

    = FLASH_BASE | VECT_TAB_OFFSET;该寄存器的值来实现中断向量表的定义。但用户反馈在MM32L0xx系列以Cortex-M0为内核的单片机
    发表于 02-01 17:22

    Linux ARM中断向量定位硬件平台分析

    Linux ARM 中断向量定位分析
    发表于 07-19 12:34

    为什么中断向量定位

    中断向量为什么要定位
    发表于 08-21 23:16

    灵动微课堂 (第176讲) | Cortex-M0中断控制和系统控制(二)

    每一个外部中断都有一个对应的优先级寄存器,Cortex-M0NVIC-IPR共有8个寄存器,而每个寄存器管理4个IRQ中断,所以M0的IR
    发表于 07-29 18:49

    STM32中断向量偏移总结

    STM32中断向量偏移总结一下在IAP升级APP程序的中断向量表的偏移讲解中断偏移之前先看一下程序的启动流程STM32F4 的内部闪存(FLASH)地址起始于
    发表于 08-13 08:59

    有什么方法可以对STM32中断向量表偏移地址进行配置呢

    如何去定位向量表的库函数呢?有什么方法可以对STM32中断向量表偏移地址进行配置呢?
    发表于 11-16 08:08

    基于Cortex-M0中断系统的IP集成与中断服务函数设计

    为极术线上技术分享干货汇总(含PPT下载及视频回放及线下活动资料下载,持续更新,欢迎收藏~整理:极术社区集创赛Arm杯彭吉安-(集创赛)基于Cortex-M0中断系统的IP集成与中断服务函数设计彭吉安-(集创赛)AHB-Lite
    发表于 12-14 07:15

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

    关注+星标公众号,不错过精彩内容来源| 痞子衡嵌入式一、Cortex-M中断向量表对齐原则中断向量表就是一个集中保存系统全部中断处理函数(xxxIRQHandler)地址的常量数组(函
    发表于 01-25 07:10

    Cortex-M中断向量表对齐的原则是什么?

    Cortex-M中断向量表对齐的原则是什么?
    发表于 01-26 08:09

    跳转APP后的中断向量表在定位前开启了中断怎么办

    在RT的官网文档里面有个STM32通用BOOT,说定位中断向量方法如下:static int ota_app_vtor_reconfig(void){#define
    发表于 08-03 10:08

    ch573在IAP和APP使用UASRT1,是不是要中断向量定位才能APP里面使用 ?

    ch573 我在IAP和APP使用UASRT1,定时0中断,是不是要中断向量定位才能APP里面使用 ,能不能提供例子
    发表于 09-20 06:47

    MPC5748G ENET0中断向量偏移量问题求解?

    ENET0中断向量地址有点混乱。用户手册 (v7.1) 说 中断向量位于 0x1348,Group1 位于 0x1370。随后的
    发表于 03-16 08:35

    一文了解Cortex-M中断向量表对齐原则

    到 -13. 中断向量表第 16 个向量开始是厂商自定义外设中断,IRQ 编号为 0 到 n - 对于 Cortex-M0/0+/1, ARM 建议的 n 值最大
    的头像 发表于 10-19 11:06 4139次阅读
    一文了解<b class='flag-5'>Cortex</b>-M<b class='flag-5'>中断向量</b>表对齐原则

    一文了解Cortex-M中断向量表对齐原则

    关注+星标公众号,不错过精彩内容来源| 痞子衡嵌入式一、Cortex-M中断向量表对齐原则中断向量表就是一个集中保存系统全部中断处理函数(xxxIRQHandler)地址的常量数组(函
    发表于 12-01 12:21 9次下载
    一文了解<b class='flag-5'>Cortex</b>-M<b class='flag-5'>中断向量</b>表对齐原则

    Cortex-M中断向量表原理及其重定向方法~

    大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是Cortex-M中断向量表原理及其重定向方法。接着前文《嵌入式Cortex-M裸机环境下临界区保护的三种实现》继续聊,嵌
    发表于 12-01 12:21 9次下载
    <b class='flag-5'>Cortex</b>-M<b class='flag-5'>中断向量</b>表原理及其重定向<b class='flag-5'>方法</b>~