Cortex-A7:ARM官方推荐的嵌套中断实现机制

0 参考资料

ARM Cortex-A(armV7)编程手册V4.0.pdf
ARM体系结构与编程第2版

1 前言

Cortex-M系列内核MCU中断硬件原生支持嵌套中断,开发者不需要为了实现嵌套中断而进行额外的工作。但在Cortex-A7中,硬件原生是不支持嵌套中断的,这从Cortex-A7中断向量表中仅为外部中断设置了一个中断向量可以看出。本文介绍ARM官方推荐使用的嵌套中断实现机制,以通过软件方式在Cortex-A7上实现中断嵌套。

2 ARM官方推荐的嵌套中断实现机制

2.1 概述

什么是中断嵌套?

中断嵌套是指中断系统正在执行一个中断服务时,有另一个优先级更高的中断提出中断请求,这时会暂时中止当前正在执行的级别较低的中断源的服务程序,去处理级别更高的中断源,待处理完毕,再返回到被中断了的中断服务程序继续执行的过程。

如何在Cortex-A7上实现嵌套中断?

Cortex-A7硬件原生不支持嵌套中断,按照ARM官方说法实现嵌套中断需要软件实现。

在Cortex-A7上实现嵌套中断的核心思想是什么?

在Cortex-A7上实现嵌套中断的核心思想就是在进入IRQ模式后保存一些必要的信息,然后切换到使能IRQ的特权模式(如系统模式),使得新的中断能够被CPU响应。为了方便操作,一般在进入main函数前就切换到特权模式,在进入IRQ模式后我们切换到同一种特权模式。

为什么不直接在IRQ模式下使能IRQ实现嵌套中断即可?

之所以不能直接在IRQ模式下使能IRQ有很多原因,其中最重要的一个就是因为在下一个IRQ中断到来时会保存错误的CPSR(当前程序状态寄存器)到SPSR_irq(IRQ模式下的程序状态保存寄存器)中,会将中断前的现场破坏掉。

上述问题可以通过下图描述:
在这里插入图片描述

2.2 嵌套中断实现步骤

说明:
进入main函数前就处于系统模式(特权模式),进入IRQ时同样切换到系统模式。

2.2.1 保存上下文

在使能IRQ之前,我们需要保存上下文。包括返回地址及SPSR_irq(IRQ模式下的程序状态保存寄存器)。

2.2.2 确定中断源并失能中断

确定中断源,并将中断失能,防止产生新的同样的中断(对于嵌套中断来说,只有比当前抢占优先级更高的中断才能抢占执行)。

2.2.3 切换到失能IRQ模式的系统模式

系统模式可以操作一些特殊寄存器。这时IRQ仍然处于失能状态。

2.2.4 将LR入栈然后再使能IRQ

为什么需要将LR入栈:
第一次进入IRQ模式前处于系统模式,LR保存的是系统模式下的程序返回地址。为了防止进入系统模式后使用BL指令(BL指令会将LR的值设置为子函数下一条指令地址)破坏LR的值,需要将LR入栈保护起来。否则LR的值被修改后,IRQ执行完毕后将无法返回中断打断位置的下一条指令位置。
将LR入栈之后,便可以使能IRQ,这时便处于使能IRQ的系统模式。

2.2.5 根据中断源执行相应的中断服务函数

这时IRQ已经使能,如果发生了更高抢占优先级的中断,应该抢占当前中断执行。

2.2.6 执行完中断服务函数后将LR出栈

在完成了中断服务函数后首先进入失能IRQ的系统模式,将入栈的LR出栈。

2.2.7 恢复到IRQ模式并返回到中断打断位置

进入失能IRQ的IRQ模式,到这里来嵌套中断的工作宣告结束,根据SPSR_irq(IRQ模式下的程序状态保存寄存器)恢复中断打断前的CPSR(当前程序状态寄存器),将保存在IRQ模式的LR的值写入PC,返回中断打断位置。

2.2.8 ARM官方示例汇编程序

IRQ_Handler
		SUB lr, lr, #4
		SRSFD sp!, #0x1f 	@ use SRS to save LR_irq and SPSR_irq in one step onto the
							@ System mode stack
	CPS #0x1f 				@ Use CPS to switch to system mode
	PUSH {r0-r3, r12} 		@S tore remaining AAPCS registers on the System mode stack
	AND r1, sp, #4 			@ Ensure stack is 8-byte aligned. Store adjustment and
							@ LR_sys to stack
	SUB sp, sp, r1
	PUSH {r1, lr}
	BL 						@ identify_and_clear_source
	CPSIE i 				@ Enable IRQ with CPS
	BL C_irq_handler
	CPSID i 				@ Disable IRQ with CPS
	POP {r1, lr} 			@ Restore LR_sys
	ADD sp, sp, r1 			@ Unadjust stack
	POP {r0-r3, r12} 		@ Restore AAPCS registers
	RFEFD sp! 				@ Return using RFE from the System mode stack.

3 总结

(1)为实现嵌套中断必须通过切换到特权模式实现,且在main函数之前就设置为相同的特权模式(如系统模式)。
(2)开发者需要自行根据中断抢占优先级决定触发的中断是否有资格运行。
(3)使用软件方式实现嵌套中断相比非嵌套中断处理方式会多不少指令,效率有所下降。
(4)开发者需要自行根据中断嵌套规则,决定新中断是否有资格抢占执行。
(5)相比于硬件原生支持嵌套中断,软件实现嵌套中断不但效率低下还非常容易出错。

<think>我们面对的是在特定工具链环境(toolchain-arm_cortex-a7_gcc-5.2.0_musl-1.1.16_eabi)下编译时,头文件`wide-int.h`报错`too many template-parameter-lists`的问题。这个错误通常发生在C++模板代码中,表示模板声明中出现了多余的`template<...>`参数列表。 根据之前的分析,错误原因可能是模板特化或嵌套模板的语法问题。由于工具链使用的是GCC 5.2.0,这个版本对模板语法的要求相对严格,需要特别注意模板特化的写法。 ### 解决步骤 #### 1. 定位错误代码 打开`wide-int.h`文件,找到第370行附近(错误提示的行号)。检查附近的模板代码,特别是模板特化或嵌套模板的部分。 #### 2. 检查模板特化语法 错误示例可能如下: ```cpp template<typename T> template<> // 多余的template<>,导致错误 class SomeClass<T> { // ... }; ``` 修正方法:全特化时,只需一个`template<>`,且必须紧接在类定义之前: ```cpp // 主模板 template<typename T> class SomeClass { // ... }; // 全特化:针对特定类型(如int)的特化 template<> class SomeClass<int> { // ... }; ``` #### 3. 检查嵌套模板 如果是嵌套模板的特化,注意分层声明: ```cpp template<typename Outer> class OuterClass { template<typename Inner> class InnerClass { // ... }; }; // 特化内层模板(例如针对Inner为指针的情况) template<typename Outer> template<typename Inner> class OuterClass<Outer>::InnerClass<Inner*> { // 偏特化 // ... }; ``` 注意:这里有两层`template`声明,分别对应外层和内层的模板参数。 #### 4. 针对GCC 5.2.0的兼容性处理 GCC 5.2.0对模板的支持已经比较完善,但仍需注意: - **C++标准模式**:确保编译时启用了适当的C++标准(如C++11)。可以在编译命令中添加`-std=c++11`。 - **语法严格性**:GCC 5.2.0对模板语法的检查比较严格,多余的`template<>`或错误的嵌套都会报错。 #### 5. 修改代码 假设在`wide-int.h`的370行附近发现如下错误代码: ```cpp template<typename T> template<> // 这里多了一个template<>,导致错误 class wide_int_traits<T> { // ... }; ``` 修正为: ```cpp // 如果是全特化,去掉多余的template<>,并指定特化的类型 template<> class wide_int_traits<int> { // 假设是针对int的特化 // ... }; ``` ### 完整解决方案 1. **编辑头文件**:修改`wide-int.h`中出错的模板特化部分,确保语法正确。 2. **重新编译**:保存修改后重新编译项目。 ### 注意事项 - 如果`wide-int.h`是第三方库的文件,建议检查是否有官方补丁或更新版本。 - 如果问题依然存在,可以尝试在编译命令中强制指定C++标准,例如:`-std=c++11`或`-std=c++14`。 ### 相关问题 1. 如何正确编写C++模板特化以适应不同编译器? 2. GCC 5.2.0在C++模板支持上有哪些已知问题? 3. 如何为嵌入式交叉编译工具链更新头文件或库? 请根据实际代码结构调整修改。如果问题复杂,建议提供具体的错误代码片段以便进一步分析。</think>### 解决 `wide-int.h:370:10: error: too many template-parameter-lists` 错误(针对 toolchain-arm_cortex-a7_gcc-5.2.0_musl-1.1.16_eabi) 此错误发生在 GCC 5.2.0 工具链环境下,表示模板声明中出现了多余的 `template<...>` 参数列表。以下是针对该工具链的完整解决方案: --- #### 1. **定位问题代码** 在 `wide-int.h` 文件中找到第 370 行附近的模板代码(通常 ±5 行)。错误通常表现为: ```cpp // ❌ 错误模式(GCC 5.2.0 不接受的语法) template<typename T> template<> // 多余的 template<> 声明 class wide_int_specialization { ... }; ``` --- #### 2. **修正模板特化语法**(关键步骤) GCC 5.2.0 对模板语法要求严格,需按以下方式修正: ```diff // 修正前(错误) template<typename T> - template<> // 删除这行 class wide_int_traits { ... }; // ✅ 修正后(正确) template<> class wide_int_traits<int> { // 明确指定特化类型 // 特化实现... }; ``` > **注意**:GCC 5.x 要求全特化必须显式指定类型参数[^1] --- #### 3. **添加编译器兼容指令** 在报错位置前添加版本兼容宏: ```cpp #if __GNUC__ == 5 && __GNUC_MINOR__ == 2 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wtemplate-param-list" #endif // 原始模板代码... #if __GNUC__ == 5 && __GNUC_MINOR__ == 2 #pragma GCC diagnostic pop #endif ``` --- #### 4. **强制指定 C++ 标准** 在编译命令中添加标准兼容选项: ```bash # 在 Makefile 或编译脚本中添加 arm-openwrt-linux-g++ -std=c++11 \ # 关键!GCC 5.2 默认可能用旧标准 -Wno-template-param-list \ -c your_file.cpp ``` --- #### 5. **完整修复案例** 假设错误出现在嵌套模板: ```cpp // 原始错误代码 (wide-int.h:370) template<int N> template<typename T> // ⚠️ 第370行报错 struct DataWrapper { ... }; ``` 修正为: ```cpp // ✅ 兼容 GCC 5.2.0 的写法 template<int N, typename T> // 合并模板参数列表 struct DataWrapper { // 实现... }; // 显式特化示例 template<> struct DataWrapper<8, int> { // 指定具体参数 // 特化实现... }; ``` --- #### 6. **工具链特定优化** 由于是 ARM Cortex-A7 交叉编译: 1. 确认头文件路径: ```bash find /path/to/toolchain -name wide-int.h ``` 2. 检查工具链补丁: ```bash grep -r "too many template-parameter-lists" /path/to/toolchain ``` 3. 若属第三方代码,尝试从上游仓库获取补丁: ```bash wget https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=7f0e7c7c patch -p1 < template_fix.patch ``` > **验证方法**:编译后检查对象文件符号: > ```bash > arm-openwrt-linux-nm -C your_object.o | grep wide_int > ``` --- ### 相关问题 1. 如何在 GCC 5.x 中正确实现模板偏特化? 2. ARM 交叉编译工具链常见的 C++ 兼容性问题有哪些? 3. 如何为旧版 GCC 编写跨版本兼容的模板代码? 4. musl libc 对 C++ 模板的支持有哪些限制?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NW嵌入式开发

感谢您的支持,让我们一起进步!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值