0 参考材料
基于普中DSP28335开发攻略.pdf 第十四章
资料链接:PZ-DSP28335-L开发板资料
1 背景
在学习DSP中断时候发现看不懂,有太多东西不理解,尝试用大白话翻译和理解。
2 理解14.1.2F28335 中断概述
F28335的中断源可分为片内外设中断源,比如PWM、CAP、QEP、定时器等,片外中断源,外部中断输入引脚XINT1、XINT2引入的外部中断源。这些中断源将中断请求信号传递给内核就需要中断线,F28335的中断线是有限的。
F28335 内部有16个中断线,其中包括2个不可屏蔽中断(RESET和NMI)与14 个可屏蔽中断。
可屏蔽中断通过相应的中断使能寄存器使用或者禁止产生的中断,在这14个可屏蔽中断中,其中TIM1和TIM2产生的中断请求通INT13、INT14
中断线到达CPU,这两个中断已经预留给了实时操作系统,因此剩下的12个可屏蔽中断可供外部中断和处理器内部单元使用。
这段话是在解释 DSP中断系统的分配规则。
什么是可屏蔽中断?
- 可屏蔽中断 = 可以通过软件设置来允许 或禁止的中断
- 与之相对的是不可屏蔽中断(如硬件复位、NMI),无法禁止
中断使能寄存器的作用
c
// 类似这样的寄存器控制中断是否被允许
PieCtrlRegs.PIEIER1.bit.INTx1 = 1; // 使能某个中断
PieCtrlRegs.PIEIER1.bit.INTx1 = 0; // 禁止某个中断
"这两个中断已经预留给了实时操作系统"
意思 :TIM1和TIM2的中断被占用了,不建议用户使用
为什么预留:
- 实时操作系统(RTOS,如uC/OS、FreeRTOS)需要周期性时钟节拍来切换任务
- 通常用TIM1或TIM2产生这个节拍(比如每1ms中断一次)
- 如果用户也使用这两个中断,会与RTOS冲突
实际影响:
- 如果跑RTOS → 不要碰TIM1/TIM2的中断
- 如果不跑RTOS → 仍然可以用,但要注意代码示例中通常避开它们
"剩下的12个可屏蔽中断可供外部中断和处理器内部单元使用"
意思 :INT1~INT12 这12个中断线是留给用户的
分配给谁:
| 中断线 | 典型用途 |
|---|---|
| INT1 | PIE分组1(ADC、SPI等) |
| INT2 | PIE分组2(ePWM、eCAP等) |
| INT3~INT12 | 其他外设中断 |
c
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // 应答INT1
PieCtrlRegs.PIEACK.all = PIEACK_GROUP3; // 应答INT3
用的就是INT1和INT3,属于12个可用中断。
F28335的外设中断源远远不止12个,共用58个。那么如何将这58个外设中断源分配给这12个中断线呢,这就需要F28335的PIE外设中断扩展模块来完成。F28335的中断源及连接如下图所示:

F28335 中断源及IO复用结构图如下图所示:


3 理解 14.1.3 F28335 中断机制
F28335的中断采用的是3级中断机制,分别是外设级中断、PIE级中断和CPU级中断,最内核部分为CPU级中断,即CPU只能响应从CPU中断线上过来的中断请求,但F28335中断源很多,CPU没有那么多中断线,在有限中断线的情况下,只能安排中断线进行复用,其复用管理就有了中间层的PIE级中断,外设要能够成功产生中断响应,就要首先经外设级中断允许,然后经PIE允许,最终CPU做出响应。
这是 F28335 的 PIE 中断响应流程示意图,整个过程分为上下两部分:
- 下半部分 :外设/外部中断信号,如何通过 PIE 模块 传递到 CPU 的 12 条中断线(INT1~INT12);
- 上半部分:CPU 如何接收这 12 条中断线的请求,最终响应中断。
1. 下半部分:PIE 模块(外设中断分组管理)
这部分负责把 96 个外设中断,按 8 个一组,汇总成 12 条 CPU 中断线。
| 缩写 | 全称 | 作用 |
|---|---|---|
From Peripherals or External Interrupts |
外设或外部中断源 | 比如串口、ADC、GPIO外部中断 |
INTx.1 ~ INTx.8 |
第x组的第1~8个中断 | 比如 INT1.1~INT1.8 都属于第1组 |
PIEIFRx(8:1) |
PIE Interrupt Flag Register(PIE 中断标志寄存器) | 外设触发中断后,对应位会自动置1 |
PIEIERx(8:1) |
PIE Interrupt Enable Register(PIE 中断使能寄存器) | 快递柜的"柜门开关",只有对应位设为1,这个中断的"柜门才会打开,快递才能继续往CPU送" |
MUX |
多路选择器 | 同一组的8个中断,通过优先级逻辑,选出最高优先级的那个,汇总成1条信号 |
INTx |
PIE 输出到CPU的中断信号 | 送到CPU的INTx线(比如第1组汇总后是INT1) |
PIEACKx |
PIE Acknowledge(PIE 中断应答) | CPU响应中断后,必须写这个寄存器来清除中断请求,不然CPU会一直收到同一个中断 |
2. 上半部分:CPU 中断响应流程
这部分是CPU怎么处理PIE送上来的12条中断请求。
| 缩写 | 全称 | 作用 |
|---|---|---|
INT1 ~ INT12 |
CPU 12 条中断线 | - |
IFR(12:1) |
CPU Interrupt Flag Register(CPU 中断标志寄存器) | 对应中断线有请求时,对应位会置1 |
IER(12:1) |
CPU Interrupt Enable Register(CPU 中断使能寄存器) | 只有对应位设为1,CPU才会接收这条线上的中断 |
MUX |
多路选择器(优先级仲裁) | 按固定优先级,选出当前最高优先级的中断请求 |
INTM |
Global Interrupt Mask(全局中断屏蔽位) | CPU的"家门总开关",只有IN=0(开关打开),CPU才会响应所有使能了的中断;如果IN=1(开关关闭),就算有中断也不会响应 |
CPU |
中央处理器 | 最终的"收件人",收到中断请求后,暂停当前程序,跳转到中断服务程序执行 |
下面我们就来详细介绍下这 3 级中断。
(1) 外设级中断 CPU
正常处理程序过程中,外设产生了中断事件(比如定时器定时时间到,串口接收数据完成),那么该外设对应中断标志寄存器(IF)响应的位将被自动置位,如果该外设对应中断使能寄存器(IE)中响应的使能位正好置位(需要软件控制),则外设产生的中断将向
PIE 控制器发出中断申请。如果对应外设级中没有被使能,就相当于该中断被屏蔽,不会想 PIE 提出中断申请,更不会产生 CPU中断响应,但此时中断标志位寄存器的标志位将保持不变,一直处在中断置位状态,要使该中断信号消失,中断标志寄存器复位,就需要软件编程清楚,如果没有被清楚,中断产生以后,一旦中断使能位被使能,同样会向
PIE 申请中断。进入中断服务后,有部分硬件外设会自动复位中断标志寄存器,多数外设需要在中断服务中手动复位中断标志寄存器。
(2) PIE 级中断 F28335 处理器内部集成了多种外设,每个外设都会产生一个或者多个外设级中断。由于 CPU 没有能力处理所有外设级的中断请求,因此 F28335 的 CPU 让出了 12 个中断线交给 PIE 模块进行复用管理。PIE 模块内部结构图如下图所示:
从图中可以看出,PIE 将外设中断分成了 12 个组,分别对应着 CPU 的 12 个可屏蔽中断线,每 1 组由 8
个外设级中断组成,这 8 个外设中断分别对应相应外设接口的中断引脚,PIE 通过一个 8 选 1 的多路选择器将这 8 个外设中断组成 1组。具体连接关系如下图所示:
每 1 组由 8 个外设级中断组成,这 8 个外设中断分别对应相应外设接口的中断引脚
意思:
它定义了一个 固定的、不可更改的硬件映射关系。就像快递柜的每个格子只能由特定快递公司的快递员打开一样,每个外设的中断请求,在芯片内部就被物理线连接到了PIE模块中一个唯一且固定的位置(特定的组和特定的通道)
"对应"这个词在硬件上是非常实在的,它是通过电路连接实现的:
芯片内部布线:在DSP芯片制造时,工程师就用内部电路把 ADC模块的中断请求输出引脚 和 PIE模块的 (Group1, INTx.1) 这个输入通道 物理连接在了一起。
固定路径:这条路径是固定的,无法通过软件更改。ADC的中断请求,只能从它自己的引脚发出,然后只能被送到属于它的那个PIE通道。
这张表是 F28335 芯片的 PIE 中断向量分配表 ,简单说就是:告诉你每个外设中断,最终被分到了哪一组(INTx)、哪一号(INTx.y)通道里。
| 位置 | 含义 |
|---|---|
第一列 INTx |
代表 CPU 的 12 条中断线,也就是我们常说的 INT1~INT12 |
第一行 INTx.1 ~ INTx.8 |
代表 PIE 模块里,每一组(INTx)下面分的 8 个中断子通道,优先级是 INTx.1 > INTx.2 > ... > INTx.8 |
| 单元格里的内容 | 对应"第几组、第几号"通道,分配给了哪个外设的中断 |
举个例子:
表格第一行 INTx=1,INTx.7 列写着 TIMER0,意思就是:
CPU 定时器0的中断,被分配到了 INT1.7 通道,它属于INT1组,组内优先级第7位。
1. INT1 组(最常用的基础中断组)
| 通道 | 外设 | 说明 |
|---|---|---|
| INT1.1 | SEQ1 | ADC 序列1的中断(ADC 转换完成触发) |
| INT1.2 | SEQ2 | ADC 序列2的中断 |
| INT1.4 | XINT1 | 外部中断1(GPIO 引脚触发) |
| INT1.5 | XINT2 | 外部中断2(GPIO 引脚触发) |
| INT1.6 | ADC | ADC 全局中断 |
| INT1.7 | TIMER0 | CPU 定时器0中断(最常用的系统定时) |
| INT1.8 | WAKE | 看门狗/低功耗唤醒中断(就是之前说的 WDINT/LPMINT 合并后的 WAKEINT) |
2. INT2/3 组(ePWM 相关中断)
这两组都是给 PWM 模块用的,是电机控制里最核心的中断:
- INT2.x :
EPWMx_TZINT,是 ePWM 的错误保护中断(比如过流、过压触发的跳闸保护) - INT3.x :
EPWMx_INT,是 ePWM 的周期中断(PWM 计数到0或周期值时触发,用来更新占空比)
例子:INT3.1 是 EPWM1_INT,也就是 ePWM1 的周期中断。
3. INT4 组(eCAP 模块中断)
全是 ECAPx_INT,也就是增强型捕获模块的中断,用来捕获外部脉冲的边沿、测量频率/占空比,比如 INT4.1 是 ECAP1_INT。
4. INT5 组(eQEP 模块中断)
给正交编码器模块用的中断,用来读取电机编码器的位置、速度,比如 INT5.1/INT5.2 都是 EQEP1_INT。
5. INT6 组(SPI 串口中断)
给 SPI 模块用的中断:
INT6.1:SPIRXINTA(SPI-A 接收中断)INT6.2:SPITXINTA(SPI-A 发送中断)
6. INT8 组(SCI/I2C 串口中断)
INT8.1:I2CINT1A(I2C 模块A的中断)INT8.3/4:SCIRXINTC/SCITXINTC(SCI-C 串口的接收/发送中断)
7. INT9 组(CAN/SCI 中断)
INT9.1~4:SCIRXINTA/SCITXINTA/SCIRXINTB/SCITXINTB(SCI-A/B 串口中断)INT9.5~8:ECAN0/1 INTA/INTB(CAN 总线模块的中断)
8. INT12 组(外部中断扩展)
给额外的外部中断用的:
INT12.1~5:XINT3~XINT7(扩展的外部中断)INT12.7/8:LVF/LUF(低电压/低频率故障中断)
- 优先级顺序 :
- 组间优先级:
INT1 > INT2 > ... > INT12 - 组内优先级:
INTx.1 > INTx.2 > ... > INTx.8
比如INT1.8的优先级,比INT2.1还要高。
- 组间优先级:
- 保留位:表里写着"保留"的通道,是芯片预留的功能,没有对应的外设中断,一般不用。
和外设级中断类似,在 PIE 模块内每组中断有相应的中断标志位(PIEIFRx)和使能位(PIEIERx.y)。除此之外,每组 PIE 中断(INT1~INT12)有一个响应标志位(PIEACK)。下图给出了 PIEIFR 和 PIEIER 不同设置时的 PIE硬件的操作流程。
一旦 PIE 控制器有中断产生,相应的中断标志位(PIEIFRx.y)将置 1。如果相应的 PIE 中断使能位(PIEIERx.y)也置1,则 PIE 将检查相应的 PIEACKx 以确定 CPU 是否准备响应该中断。如果相应的 PIEACKx 位清零,PIE 向 CPU申请中断;如果 PIEACKx置 1,PIE 将等待到相应的 PIEACKx 清零才向 CPU 申请中断。PIE 通过对PIEACKx的位控制来控制每 1 组中只有 1 个中断能被响应,一旦响应后,就需要将 PIEACKX相应位清零,以让它能够响应该组中后边过来的中断。
(3) CPU 级中断 一旦 CPU 申请中断,CPU 级中断标志位(IFR)将置 1。中断标志位锁存到标志寄存器后,只有 CPU中断使能寄存器(IER)或中断调试使能寄存器(DBGIER)相应的使能位和全局中断屏蔽位(INTM)被使能时才会响应中断申请。 CPU 级使能可屏蔽中断采用 CPU 中断使能寄存器(IER)还是中断调试使能寄存器(DBGIER)与中断处理方式有关。标准处理模下,不使用中断调试使能寄存器(DBGIER)。只有当F28335 使用实时调试(Real-time Debug)且 CPU 被停止(Halt)时,才使用中断试使能寄存器(DBGIER),此时 INTM 不起作用。如果 F28335 使用实时调试而 CPU 仍然工作运行,则采用标准的中断处理。
这段解释了 DBGIER 这个特殊寄存器的唯一用途。
核心前提:两个概念
在理解这段话之前,需要先明白两个东西:
- IER (Interrupt Enable Register) :标准中断使能寄存器。在正常程序运行时,用它来允许/禁止中断。
- DBGIER (Debug Interrupt Enable Register) :调试中断使能寄存器。这是一个特殊的、只在 Debug 模式下才可能用到的"备用开关"。
第一句
CPU 级使能可屏蔽中断采用 CPU 中断使能寄存器(IER)还是中断调试使能寄存器(DBGIER)与中断处理方式有关。
- 解读 :
- 这句话问的是:CPU 到底听谁的指挥?是听 IER 的,还是听 DBGIER 的?
- 答案 :这取决于当前芯片处于什么"处理方式"(也就是下面要说的标准模式 vs 实时调试暂停模式)。不同模式下,发号施令的寄存器不同。
第二句
标准处理模式下,不使用中断调试使能寄存器(DBGIER)。
- 解读 :
- "标准处理模式" :指程序正常运行 ,或者虽然正在调试(比如单步执行),但 CPU 内核没有被暂停。
- 在这种绝大多数情况下,DBGIER 是不起作用的。
- 结论 :平时写代码,只需要配置 IER 就够了,可以完全忘记 DBGIER 的存在。
第三句
只有当 F28335 使用实时调试(Real-time Debug)且 CPU 被停止(Halt)时,才使用中断调试使能寄存器(DBGIER),此时 INTM 不起作用。
这里有两个关键的前提条件 ,必须同时满足:
- 条件1:正在使用实时调试。硬件仿真器连着,且开启了实时调试模式(Real-time Mode)。
- 条件2:CPU 被停止了 。因为程序遇到了断点 (Breakpoint),你手动点击了暂停 (Halt),CPU 内核不再 fetching 指令。
只有在上面这种特定状态下,才会发生以下两件事:
- 启用 DBGIER :CPU 不再看 IER ,而是改看 DBGIER。只有 DBGIER 里允许的中断,才能在这个暂停的间隙被响应。
- INTM 不起作用 :INTM 是 CPU 的总中断开关(
EINT/DINT控制的那个位)。在标准模式下,如果INTM=1,所有中断都被屏蔽。但在这种暂停模式下,INTM 被忽略了。即使关了总中断,只要 DBGIER 里开了,中断依然能响应。
为什么 TI 要设计这么复杂的机制?
- 场景 :在调试电机控制程序,在某个地方设了断点。程序跑到断点处,CPU 停了。
- 危险:如果 CPU 停了,它无法执行代码去关 PWM,但功率管 IGBT 可能还通着大电流。几毫秒内就会过流烧毁。
- 解决方案 :通过 DBGIER,强制使能 TZ (Trip Zone) 过流中断 。即使 CPU 卡在断点,过流信号一来,CPU 依然能立刻跳去执行
HardWareErrorDeal()封锁 PWM,保护硬件。
第四句
如果 F28335 使用实时调试而 CPU 仍然工作运行,则采用标准的中断处理。
- 解读 :
- 这也是一种场景:虽然连接了仿真器,也在调试,但 CPU 是在全速运行 的(比如点了"Run")。
- 此时,虽然处于调试状态,但因为 CPU 没有暂停 ,所以依然按照标准模式处理。
- 结论 :看 IER ,INTM 生效,不看 DBGIER。
4 理解 14.1.4 F28335 中断向量
CPU响应中断,就是 CPU 要去执行相应的中断服务程序,其响应过程是 CPU将现执行程序的指令地址压入堆栈,跳转到中断服务程序入口地址,中断服务程序的入口地址就是中断向量,这个中断向量用 2 个 16 位寄存器存放。入口地址是 22 位的,地址的低 16 位保存在该向量的低 16 位;地址的高 16 位则保存在它的高 6 位,更高的 10 位保留。
(1) 中断向量分配 PIE 最多可支持 96 个中断,每个中断都有自己对应的中断向量,即每个中断源都对应着自己的中断服务程序的入口地址,这些中断向量均连续存放在 RAM中,这就构成了整个系统的中断向量表,用户可以根据需要适当的对中断向量表进行调整,在响应中断时,CPU 将自动的从中断向量表中获取响应的中断向量。 CPU 获取中断向量和保存重要的寄存器所需要 9 个 CPU 时钟周期,因此 CPU 能够快速响应中断。CPU 响应中断是通过中断线的,而且只能 1 次响应其中 1 条中断线,每条中断线连接的中断向量都在中断向量表中占 32 位地址空间,用来存放中断服务程序的入口地址。有可能这 16 条中断线上的中断请求同时到达 CPU,这时就要对各个中断请求进行优先级定义。 每条中断线对应的不是唯一中断,每组 PIE 对应的也不是唯一中断,中断服务程序要处理所有输入的中断请求,这就要求编程人员在服务程序的入口处采用软件方法将这些中断线复用的中断分开,以便能够正确响应中断。但是软件分离的方法会影响中断的响应速度,在实时性要求高的应用中不能使用。这就涉及如何加快中断服务程序的问题。
理解:这段话是在解释 PIE中断向量表的组织结构、CPU响应机制,以及一个关键的设计矛盾:硬件复用带来的"中断识别"问题。
一、基础概念:中断向量表 = 函数的"地址簿"
"每个中断都有自己对应的中断向量(即中断服务程序的入口地址),这些中断向量均连续存放在RAM中,这就构成了整个系统的中断向量表。"
- 含义 :中断向量表就是一张跳转地址列表 。
- 比如:
地址A处存放着ADC中断服务函数的入口。 - 当ADC中断发生时,CPU会自动去
地址A取地址,然后跳转过去。
- 比如:
- 优点:硬件自动完成,非常快。
二、硬件结构:CPU只能"看到"12根线
"CPU 响应中断是通过中断线的,而且只能 1 次响应其中 1 条中断线... 每条中断线连接的中断向量都在中断向量表中占 32 位地址空间。"
- 含义 :CPU 有 12 根中断线(INT1-INT12),一次只能处理一根线上来的信号。
- 关键点 :每条中断线,在中断向量表中只对应一个 32位 的存储空间。
- 也就是说,硬件只给 INT1 这一根线预留了 1个 存放函数地址的位置。
三、核心矛盾:一根线上挂了8个中断
"每条中断线对应的不是唯一中断... 中断服务程序要处理所有输入的中断请求。"
- 问题所在 :
- 硬件安排 :PIE把8个外设中断(如ADC、SPI、Timer0)都挂在了 同一根 CPU中断线(比如INT1)上。
- 硬件限制 :CPU接到INT1的请求后,只能从INT1对应的那 1个 地址里取出函数。
- 矛盾 :8个中断源共用1个入口,CPU跳进去后,根本不知道 到底是谁触发了这次中断
四、常规解法:软件查询(但影响速度)
"这就要求编程人员在服务程序的入口处采用软件方法将这些中断线复用的中断分开... 但是软件分离的方法会影响中断的响应速度。"
- 什么意思 :
- 软件分离法:既然硬件分不清,那就在软件里分。ISR(中断服务程序)一进来,就去"询问"(读取PIE标志位)到底是ADC、SPI还是Timer0触发的。
- 流程图 :
- 触发INT1。
- CPU跳转到INT1对应的唯一ISR。
- 【软件查询】 检查
PIEIFR1.bit.INTx1(ADC标志) 是否为1?是 -> 执行ADC_Handler()。 - 【软件查询】 检查
PIEIFR1.bit.INTx2(SPI标志) 是否为1?是 -> 执行SPI_Handler()。
- 为什么影响速度 :
- 这种"一问一答"的软件查询过程浪费了宝贵的CPU时间。
- 尤其是在电机控制这类实时性要求极高的应用中,每一个时钟周期都很珍贵。因此,这段内容说这种方法**"在实时性要求高的应用中不能使用"**。
(2) 中断向量表
在 F28335 中采用 PIE 中断向量表来解决上述问题,通过 PIE 中断向量表使得 96 个可能产生的中断都有各自独立的 32 位入口地址。PIE 向量表由 256X16B的 SRAM 内连续存放,如果这部分空间不用作 PIE 模块时,可用作数据 RAM。复位时, PIE 向量表内容没有定义。CPU 的中断优先级有高到低依次是从 INT1-INT12。每组 PIE 控制的 8 个中断优先级依次是从 INTx.1-INTx.8。
这段话是在纠正或细化 上一个概念可能带来的误解,并揭示了F28335实现高性能实时中断响应的核心硬件机制。
一、核心概念:从"共用入口"到"独享入口"
- 上一段的问题:CPU只有12根中断线,每根线只对应1个入口地址。导致8个共享一根线的中断,必须挤在同一个入口里,靠软件慢速区分。
- 这段话的解决方案 :引入PIE向量表 ,这是一个硬件加速器。它为96个中断,每个都分配了一个独立的32位入口地址。
二、逐句解读
"在 F28335 中采用 PIE 中断向量表来解决上述问题,通过 PIE 中断向量表使得 96 个可能产生的中断都有各自独立的 32 位入口地址。"
- 含义 :这是最核心的一句。F28335在硬件上为 每一个 外设中断(ADC、EPWM1、EPWM2...)都分配了一个专属的、32位宽的存储空间,用来存放这个中断自己的服务函数地址。
- 结果 :ADC的中断触发时,CPU会自动从"ADC的专属入口"取地址;EPWM1触发时,从"EPWM1的专属入口"取地址。彻底解决了"多个中断挤在一个入口"的问题。
"PIE 向量表由 256X16B的 SRAM 内连续存放,如果这部分空间不用作 PIE 模块时,可用作数据 RAM。"
- 含义 :
- 位置与大小 :PIE向量表实际上是芯片内部一块256字 × 16位的SRAM内存区域。
- 双重用途 :这块内存很灵活。
- 用作PIE:当使能PIE模块时,这块内存被硬件用作中断向量表,存放96个中断函数的地址。
- 用作普通RAM:如果不需要这么多中断(比如跑非常简单的程序),可以把这块内存关掉,当作普通的变量存储空间来用,节约内存。
"复位时,PIE 向量表内容没有定义。"
- 含义 :芯片上电或复位时,这块存放函数地址的内存里的数据是随机的、无效的。
- 行动要求 :这是开发者最重要的工作! 必须在程序初始化阶段,主动把这96个中断函数的地址,挨个填到对应的位置上。否则中断一来,CPU拿到一个无效地址,程序就会跑飞。
- 代码体现 :
InitPieVectTable()函数就是干这个活的。
"CPU 的中断优先级有高到低依次是从 INT1-INT12。"
- 含义:在CPU层面,中断线INT1的优先级最高,INT12最低。如果INT1和INT3同时触发,CPU会先处理INT1。
- 注意:这只是CPU层面的接收优先级。具体到代码,把ADC中断挂在INT1上,它天然就比挂在INT3上的PWM中断优先级高。
"每组 PIE 控制的 8 个中断优先级依次是从 INTx.1-INTx.8。"
- 含义 :在每个PIE分组内部,也有优先级顺序。比如ADC挂在
INT1.1,SPI挂在INT1.2,那么ADC的优先级就高于SPI。
5 理解 14.1.5 中断向量映射方式
在 F28335 中,中断向量表可以被映射到 4 个不同的存储区域,在实际应用中,F28335 只能使用 PIE 中断向量表映射区域。中断向量表映射主要由以下型号控制。
①VMAP:该位在状态寄存器 1(ST1)的第 3 位,复位后值为 1。可以通过改变 ST1 值或使用 SETC/CLRC VMAP 指令改变 VMAP 的值,正常操作时该位置 1。
②MOM1MAP:该位在状态寄存器 1(ST1)的第 11 位,复位后该位置 1.可以通过改变 ST1 的值或使用 SETC/CLRC M0M1MAP 指令改变 M0M1MAP 的值,正常操作该位置 1。M0M1MAP=0 是厂家测试时使用。
③ENPIE:该位在 PIECTRL 寄存器的第 0 位,复位的默认值为 0(PIE 被屏蔽)。器件复位后,可以通过调整 PIECTRL 寄存器的值进行修改。
第一句
"在F28335中,中断向量表可以被映射到4个不同的存储区域,在实际应用中,F28335只能使用PIE中断向量表映射区域。"
- 含义 :
- F28335的CPU有4个可能的"抽屉"(存储区域)可以用来存放中断向量表。
- 但是 :在正常的、非测试的应用(比如你的汇川电机控制程序)中,只能使用其中1个 ,即 PIE中断向量表映射区域。
- 原因:PIE向量表提供了96个独立的中断入口,是F28335实现高性能中断响应的核心。其他3个区域是用于兼容旧代码或厂家测试的,功能受限(比如可能只支持32个中断)。
第二句
"中断向量表映射主要由以下型号控制。" (注:原文"型号"应为"信号"或"位")
- 含义 :中断向量表到底映射到哪个存储区域,由CPU内部几个控制位的状态来决定。通过软件设置这几个位的值,就可以"拨动开关",切换向量表的位置。
第三句(VMAP位)
"①VMAP:该位在状态寄存器1(ST1)的第3位,复位后值为1。可以通过改变ST1值或使用SETC/CLRC VMAP指令改变VMAP的值,正常操作时该位置1。"
- 含义 :
- VMAP :一个1bit的开关,位于CPU的ST1寄存器的第3位。
- 复位值=1:芯片上电后,这个开关默认是"开"的状态(值为1)。
- 如何修改 :可以直接改写ST1寄存器,或者使用专门的
SETC VMAP(置1)和CLRC VMAP(清零)指令。 - 正常操作要求 :在正常的应用程序中(如电机控制),这个位必须设置为1。
- 作用:VMAP=1时,告诉CPU:"请使用高位的向量表(包括PIE向量表所在的区域)"。如果VMAP=0,CPU会去寻址一个低位的、旧的向量表(用于兼容老式DSP,如F240x),但这在F28335上是不推荐的。
第四句(M0M1MAP位)
"②MOM1MAP:该位在状态寄存器1(ST1)的第11位,复位后该位置1.可以通过改变ST1的值或使用SETC/CLRC M0M1MAP指令改变M0M1MAP的值,正常操作该位置1。M0M1MAP=0是厂家测试时使用。"
- 含义 :
- M0M1MAP :另一个1bit开关,也在ST1寄存器里(第11位)。注意原文"MOM1MAP"应为"M0M1MAP"。
- 复位值=1:上电后默认也是"开"的状态。
- 如何修改 :同样可以通过改写ST1或使用专用指令
SETC/CLRC M0M1MAP。 - 正常操作要求 :正常应用中,这个位也必须设置为1。
- M0M1MAP=0的特殊性 :这个状态是厂家测试时使用 的。如果清零,会改变芯片内部两块小内存(M0和M1)的映射方式,可能导致程序崩溃。开发者永远不要将其清零。
- 作用:这个位和VMAP配合,决定中断向量表是放在"正常"的PIE区域,还是放在"测试"或"兼容"区域。为了保证使用PIE向量表,它必须为1。
第五句(ENPIE位)
"③ENPIE:该位在PIECTRL寄存器的第0位,复位的默认值为0(PIE被屏蔽)。器件复位后,可以通过调整PIECTRL寄存器的值进行修改。"
- 含义 :
- ENPIE :这是PIE模块的总开关 ,位于
PIECTRL寄存器的第0位。 - 复位值=0 :上电后,PIE模块默认是关闭的("PIE被屏蔽")。
- 如何修改 :软件直接操作
PIECTRL寄存器来修改。
- ENPIE :这是PIE模块的总开关 ,位于
- 关键作用 :
- ENPIE = 0 :PIE模块完全不工作。此时CPU只能看到12个传统的中断,F28335强大的96个中断支持被禁用。
- ENPIE = 1 :PIE模块使能! 96个中断的独立入口生效,中断向量表使用PIE向量表区域。
如何使用PIE向量表(三步设置)
必须同时满足以下三个条件:
- VMAP = 1 (正常操作时,这默认就是1)
- M0M1MAP = 1 (正常操作时,这默认也是1)
- ENPIE = 1 (这是你必须在代码中设置的! 通常在
InitPieCtrl()函数中完成)
6 理解14.2.1 复位中断操作过程
PIE 模块 8 个中断分成一组与外部中断一起共用一个 CPU 中断,总共有 12组中断(INT1-INT12)。每组中断有相应的中断标志(PIEIFR)和使能寄存器(PIEIER),这些寄存器控制 PIE 向 CPU 申请中断。同时 CPU 还根据 PIEIFR 和 PIEIER 寄存器确定执行哪个中断服务程序。在清除 PIEIFR 和 PIEIER 的位时,要遵循以下 3 个规则。
①不要用软件编程清除 PIEIFR 的位:清除 PIEIFR 寄存器的位时,有可能会使产生的中断丢失。要清除 PIEIFR 位时,还未被执行的中断必须被执行,如果用户希望在执行正常的服务程序之前就要清除 PIEIFR 位时,需要遵循以下步骤:
1,设置 EALLOW 位为 1,允许修改 PIE 向量表。
2,修改 PIE 向量表,使外设服务程序指针向量指向一个临时的 ISR,这个临时的 ISR 只执行一个中断返回(IRET)操作。
3,使能中断,使中断执行临时中断服务程序。
4,在执行完中断服务程序之后,PIEIFR 位将被清除。
5,修改 PIE 向量表,重新映射外设服务程序到正确的中断服务程序。
6,清除 EALLOW 位。
CPU 中断标志寄存器 IFR 在 CPU 内部,这样操作将不会影响任何向 CPU 申请的中断。
②软件设置中断优先级。使用 CPU IER 寄存器控制全部中断的优先级,PIEIER寄存器控制每组中断的优先级,只有与被服务的中断在同一组时,修改 PIEIFR寄存器的值才有意义,当 PIEACK 位保持来自 CPU 中断时,修改操作才被最终执行。当来自无关本组的中断被执行时,禁止本组的 PIEIER 位没有意义。
③使用 PIEIER 禁止中断。如果 PIEIFR 寄存器用来使能一个中断,同样可以禁止该中断,具体设置在后面会介绍。
这段话是F28335中断编程的核心操作手册,解释了如何安全、正确地管理PIE模块的中断标志(PIEIFR)和使能(PIEIER)寄存器。它重点强调了三个容易出错的地方。
我们直接切入核心,看看它说的三个规则到底是什么意思。
核心矛盾:为什么PIEIFR这么"娇贵"?
PIEIFR(PIE中断标志寄存器)是硬件自动置1的。如果用软件强行清除它,可能刚好在清除的瞬间,对应的那个外设又来了一次中断请求,导致硬件刚把标志位置1,就被你的软件清0了,这个中断就永远丢失了。
规则一:禁止用软件直接清除PIEIFR位(除非遵守严格的"5步替换法")
这段话指出"不要用软件编程清除PIEIFR的位",并给出了一种极端情况下的安全操作流程。
核心目的 :当一个中断已经被挂起(PIEIFR=1),但你希望在不执行它正常的服务程序(ISR)的前提下清除它时使用。
为什么需要? 比如系统初始化时,可能由于硬件状态不确定,意外触发了某个中断。你不想响应它,但直接软件清零又可能导致中断丢失,甚至系统错误。
"5步替换法"解读:
它提供了一个绕开直接清零的"曲线救国"方案,核心思路是:用一个"空"的ISR,替换掉原来的ISR,让硬件自己去清除标志位。
- 设置EALLOW:允许修改受保护的中断向量表。
- 修改向量表 :把想清除的那个中断的入口地址,临时指向一个空ISR (函数里只有一条
IRET指令,马上返回)。 - 使能中断 :让CPU去执行这个空ISR。
- 硬件清除:当CPU执行完这个空ISR时,硬件本身会自动清除PIEIFR的标志位。这是关键!你绕开了软件直接清除。
- 恢复向量表 :再把向量表的入口地址改回正确的、正常的ISR。
- 关闭EALLOW。
这个过程有些复杂,甚至在实际应用中很少用,但它清楚地指明了关键点:不要自己去碰PIEIFR,让硬件自己去清除它。
规则二:中断优先级与屏蔽
"只有与被服务的中断在同一组时,修改 PIEIFR 寄存器的值才有意义"
- 含义 :你想修改 PIEIFR(比如清除某个中断的标志位),只有当你修改的是当前正在被 CPU 处理的那个组的 PIEIFR 时,这个操作才有意义。
- 举例 :
- 当前 CPU 正在执行 INT3 组的中断服务程序(比如 PWM 中断)。
- 此时你去修改 PIEIFR1 (INT1 组的标志寄存器),这个操作没有意义。因为 INT1 组根本没有被激活,它的标志位可能不会生效,或者会产生意想不到的后果。
- 只有修改 PIEIFR3(INT3 组的标志寄存器),才是合理的操作。
原因:每个 PIE 分组是独立的。硬件在设计时,只在当前激活的组上下文中处理标志位的修改。修改非激活组的标志位可能被忽略或导致不确定行为。
"当 PIEACK 位保持来自 CPU 中断时,修改操作才被最终执行"
-
含义 :即使你修改的是本组 的 PIEIFR,这个修改也不是立即生效的。它必须等到 PIEACK 位被置 1(也就是 CPU 已经响应该组的中断,并且还没有清除 PIEACK)时,才会被执行。
-
更直白的解释:
PIEACK = 1:表示 CPU 正在处理本组的中断,PIE 模块处于"应答状态"。- 在这个状态下,你对 PIEIFR 的修改操作才被认为是有效的,PIE 模块才会真正去执行这个修改。
- 如果
PIEACK = 0(本组没有中断被响应),你修改 PIEIFR 可能无效,或者只是写入了缓存,没有被真正执行。
所以,修改 PIEIFR 的操作虽然被你写入了,但真正的执行时机是"在 PIEACK 保持为 1 的情况下"被硬件捕捉并延迟到 PIEACK 清零时才最终生效。
"使用 CPU IER 寄存器控制全部中断的优先级,PIEIER寄存器控制每组中断的优先级...当来自无关本组的中断被执行时,禁止本组的 PIEIER 位没有意义。"
-
CPU级 vs PIE级:
IER(CPU级):决定第几组(INT1-INT12)能被响应,相当于控制哪个"大楼"(组)能进入。PIEIER(PIE级):决定组内第几个(INTx.1-INTx.8)能被响应,相当于控制"大楼"里哪个"房间"能接待。- 最终优先级是这两级优先级的组合。
-
"禁止本组的PIEIER位没有意义"解读:
- 翻译:假设当前CPU正在执行 INT2组 的中断服务程序。
- 此时,INT2组的PIEACK(中断应答标志)被硬件置1,表示"我正在处理这一组"。
- 在这个期间,整个INT2组的中断请求都被PIE硬件暂时扣住了,不会发给CPU。
- 所以,如果你在INT2的中断服务程序里,去修改 PIEIER2(本组的使能寄存器),想关掉本组的某个中断------这个操作没有任何效果,因为PIE硬件本来就不会把本组的新中断送出去。
在某个组的ISR执行期间,禁止本组的其他中断是没有意义的,因为硬件已经帮你屏蔽了整个组。
规则三:用PIEIER禁止中断
"使用PIEIER禁止中断。"
- 含义 :虽然不鼓励用软件清除PIEIFR标志,但如果你想关闭 一个中断(让它不再触发),推荐的做法是通过PIEIER寄存器来操作。
- 正确操作 :
PieCtrlRegs.PIEIERx.bit.INTxX = 0;(x组,X号)。然后为了确保效果,需要再读一下该寄存器的值,强制完成写操作(有些DSP有写缓冲)。 - 恢复:需要时再重新设为1即可。
| 规则 | 核心要点 | 误操作后果 |
|---|---|---|
| ① 清除标志 | 别碰PIEIFR,让硬件自己清。 | 中断丢失 |
| ② 优先级/屏蔽 | 执行ISR时,整个组都被挂起,改PIEIER无用。 | 操作无效,浪费时间 |
| ③ 禁止中断 | 想关中断,改PIEIER(清零),别改PIEIFR。 | 无法彻底关闭,可能误触发 |
7 理解14.2.2 使能/禁止复用外设中断的处理
应用外设中断的使能/禁止标志位使能/禁止外设中断,PIEIER 和 CPU IER寄存器主要是在同一组中断内设置中断优先级。如果要修改 PIEIER 寄存器的设置,有两种方法。第一种方法是保护相应的 PIE 标志寄存器标志位,防止中断丢失。第二种方法是清除相应的 PIE 寄存器的标志位。
方法 1:利用 PIEIERx 寄存器禁止中断保护相应的 PIEIERx 相关的标志位,需要采取以下步骤:1,屏蔽全局中断(INTM=1)。
2,清除 PIEIERx.y 位,屏蔽给定的外设中断。这样可以屏蔽同一组中断的一个或多个外设中断。
3,等待 5 个周期,这个延时是为了保证在 CPU IFR 寄存器中产生的任何中断都能向 CPU 发出申请。
4,清除 CPU IFRx 内相应外设中断组的标志位,在 CPU IFR 寄存器上采用这样的操作是比较安全的。
5,清除相应外设中断组的 PIEACKx 寄存器位。
6,使能全局中断(INTM=0)。
方法 2:使用 PIEIFRx 寄存器屏蔽中断并清除相应的 PIEIFRx 的标志位。为了完成外设中断的软件复位和清除 PIEIFRx 和 CPI IFR 内相应的标志位,需要采取以下的处理步骤:1,屏蔽全局中断(INTM=1)。
2,设置 EALLOW 位为 1。
3,修改 PIE 向量表,使外设服务程序指针向量指向一个临时的 ISR,这个临时的 ISR 只执行一个中断返回(IRET)操作,这种方法能够清楚单个中断标志位 PIEIFRx.y,而且保证不会丢失同一组内其他外设产生的中断。
4,屏蔽外设寄存器中的外设中断。
5,使能全局中断(INTM=0)。
6,等待所有挂起外设中断由空的中断服务程序处理。
7,屏蔽全局中断(INTM=1)。
8,调整 PIE 向量表,将外设中断向量映射到原来的中断服务程序。
9,清除 EALLOW 位。
10,屏蔽给定的 PIEIER 位。
11,清除给定外设中断组的标志位 IFR(对 CPU IFR 寄存器操作比较安全)。
12,清除 PIE 组的 PIEACK 位。
13,使能全局中断。
方法一和方法二的核心区别
两种方法的目标都是安全地关闭一个中断,但策略完全不同:
一、核心思路区别
| 对比项 | 方法一 | 方法二 |
|---|---|---|
| 核心思路 | 直接关门 + 清理残留 | 派个空哨兵去"消耗"掉可能的中断,再关门 |
| 比喻 | 你想关店,先挂"暂停营业"牌,再把门口排队的人劝走。 | 你想关店,先让一个空店员去把门打开,让可能存在的顾客进来、服务完、送走,确保没人排队了,再关门。 |
| 是否执行中断服务程序 | 否 | 是(执行一个空ISR) |
| 是否清除PIEIFR | 否(绕过) | 是(硬件自动清除) |
二、操作流程对比
方法一(直接关门法):
关全局中断 → 清PIEIER(关门) → 等待5周期 → 清CPU IFR → 清PIEACK → 开全局中断
↑ ↑
关掉使能位 清理CPU里的残留请求
方法二(空ISR消耗法):
关全局中断 → 改向量表(指向空ISR) → 开中断 → 等待空ISR执行(硬件自动清PIEIFR)
→ 关中断 → 恢复向量表 → 清PIEIER(关门) → 清CPU IFR → 清PIEACK → 开中断
↑ ↑
在确认干净后才关门 最后清理
8 了解14.2.3 外设复用中断向 CPU 申请中断的流程
1,任何一个 PIE 中断组的外设或外部中断产生中断。如果外设模块内的中断被使能,中断请求将被送到 PIE 模块。
2,PIE 模块将识别出 PIE 中断组 x 内的 y 中断(INTx.y)申请,然后相应的 PIE 中断标志位被锁存:PIEIFRx.y=1。
3,PIE 的中断如要送到 CPU 需满足下面两个条件:
①相应的使能位必须被设置(PIEIFRx.y=1)。
②相应的 PIEACKx 位必须被清除。
4,如果满足步骤 3 中的两个条件,中断请求将被送到 CPU 并且相应的相应寄存器位被设置 1(PIEACKx=1)。PIEACKx 位将保持不变,除非为了使本组中的其他中断向 CPU 发出申请而清除该位。
5,CPU 中断标志位被置位(CPU IFRx=1),表明产生一个 CPU 级的挂起中断。
6,如果 CPU 中断被使能(CPU IERx=1 或者 DBGIERx=1),并且全局中断使能(INTM=0),CPU 将处理中断 INTx。
7,CPU 识别到中断并自动保存相关的中断信息,清除使能寄存器(IER)位,设置 INTM,清除 EALLOW。CPU 完成这些任务准备执行中断服务程序。
8,CPU 从 PIE 中获取响应的中断向量。
9,对于复用中断,PIE 模块用 PIEIERx 和 PIEIFRx 寄存器中的值确定响应中断的向量地址。有以下两种情况:
①在步骤 4 中若有更高优先级的中断产生,并使能了 PIEIERx 寄存器,且 PIEIERx 的相应位处于挂起状态,则首先响应优先级高的中断。
②如果在本组内没有挂起的中断被使能,PIE 将响应组内优先级最高的中断,调转地址使用 INTx.1。这种操作相当于处理器的 TRAP 或 INT 指令。
CPU 进入中断服务程序后,将清除 PIEIFRx.y 位。需要说明的是,PIEIFRx寄存器用来确定中断向量,在清除 PIEIFRx 寄存器时必须注意。
9 理解 14.2.4 可屏蔽中断处理
按照是否可以被屏蔽,可将中断分为两大类:不可屏蔽中断(又叫非屏蔽中断,NMI)和可屏蔽中断。不可屏蔽中断源一旦提出中断请求,CPU 必须无条件响应;而对可屏蔽中断源的请求,CPU 可以响应,也可以不响应。对于可屏蔽中断,除了受本身的屏蔽位控制外,还都要受一个总的控制,即 CPI 标志寄存器中的中断允许标志位 IF 的控制。IF 位为 1,可以得到 CPU 响应,否则得不到响应。 IF 位可以由用户控制。
可屏蔽中断的响应过程实质上就是中断的产生、使能到处理过程,其结构如下图所示。包括两个部分设置:CPU 级中断设置(INT1-INT4)和 PIE 级中断设置(INTx.1-INTx.8)。
(1) CPU 级中断
①CPU 级中断标志设置。除了系统初始化,一般不建议改变标志寄存器的状态,否则可能清除某些有用的中断信息或者产生意外中断。但有时也可能希望通过软件方式使某些中断标志位置位或者清零,在这种情况下可以通过以下 2 条指令完成。
c
IFR|=0X0008;//INT4 位置位
IFR|=0XFFF7;//INT4 位清零
如果在清除中断标志寄存器中的某些状态位时刚好有中断产生,则此时中断有更高的优先级,相应的标志位仍然为 1.在系统复位和 CPU 相应中断后,中断标志位将自动清零。
②CPU 级中断使能。CPU 级中断使能寄存器的 16 位分别控制每个中断的使能状态。当相应的位置 1 时,使能中断,写 0 禁止中断。在 C 语言中可采用下面代码实现中断的控制,系统复位禁止所有中断。
c
IER|=0X0008;//使能中断 INT4
IER|=0XFFF7;//禁止中断 INT4
③全局中断使能。状态寄存器 ST1 的位 0(INTM)为全局中断使能控制位,当该位等于 0 时全局中断使能,当该位等于 1 时禁止所有中断。CPU 要实现中断处理必须在产生中断的前提下,相应的 IER 寄存器位使能并且需要全局使能位使
能。可以采用以下代码实现全局中断使能控制。
c
asm(" clrc INTM");
asm(" setc INTM");
(2) PIE 级中断
当系统有中断请求到 PIE 模块时,相应的 PIE 中断标志寄存器(PIEIFRx.y)置 1,如果相应的 PIE 中断使能寄存器(PIEIFRx.y)也已经置 1,则 PIE 开始检查相应的中断响应寄存器(PIEACKx)来决定 CPU 是准备相应该组的中断。如果该组的 PIEACKx 已经清零,PIE 送该中断请求到 CPU 级,否则 PIE 等待,直到 PIEACKx 已经清零,才送中断请求到 CPU 级。
10 理解 14.2.5 不可屏蔽中断处理
不可屏蔽中断设置简单得多,以 XNMI_XINT13 引脚外部中断设置为列,只要配置好相应的引脚配置寄存器就可以,因为 NMI 优先级最高,CPU 必须响应,无需配置 CPU。
核心概念:NMI 是什么?
- 全称 :Non-Maskable Interrupt,即不可屏蔽中断。
- 特点 :就像它的名字一样,它无法被软件屏蔽或禁止。一旦发生,CPU 必须立刻、无条件地放下手头所有工作去响应它。
- 用途 :通常用于检测最严重的硬件故障,比如 电源即将断电、电压剧烈跌落、硬件致命错误 等。系统必须用最快的速度去保存关键数据或执行紧急停机,防止设备损坏。
引脚功能:XNMI_XINT13 是什么?
这是一个 多功能引脚 (引脚名中的 X 通常表示复用)。可以通过软件把它配置成两种功能之一:
- XNMI 功能 :作为 外部不可屏蔽中断 的输入引脚。这是它最常用的功能。
- XINT13 功能 :作为一个普通的 外部可屏蔽中断(XINT13)的输入引脚。
关键点 :图片中的代码正是通过配置,把这个引脚复用为 XNMI 功能。
代码逐行解析
现在,我们对照你提供的图片,看看如何配置这个"紧急按钮"。
c
// 1. 允许修改受保护的寄存器(必须步骤)
EALLOW;
// 2. 配置引脚复用功能:将这个引脚设置为 XNMI_XINT13 功能
// 代码中将它配置为 XNMI 功能,使其成为不可屏蔽中断引脚
GpioMuxRegs.GPEMUX.bit.XNMI_XINT13_GPIOE2 = 1;
// 3. 配置 XNMI 中断的触发方式
XINTRUPT_REG.S.XINT2CR.bit.ENABLE = 1; // 使能 XNMI 中断
XINTRUPT_REG.S.XINT2CR.bit.POLARITY = 0; // 设置下降沿触发
// 4. 设置中断服务函数:告诉 CPU,当 NMI 发生时,去执行 NMI_ISR 这个函数
PieVectTable.XINT13 = &NMI_ISR;
// 5. 结束修改保护
EDIS;
对比"简单得多"在哪里?
这段代码特意提到 NMI 设置"简单得多",是因为它对比的是普通中断的设置流程。
- 普通中断 (INTx):需要配置 PIE 模块的使能寄存器(PIEIER)、CPU 的中断使能寄存器(IER),还要设置全局中断开关(INTM),流程繁琐。
- NMI 中断 :无需配置任何使能寄存器 。只要在引脚上检测到有效的信号(下降沿),CPU 无论如何都会响应。你只需要告诉它"谁来处理"(
PieVectTable.XINT13 = &NMI_ISR;)即可,所以更简单。
11 关于14.3 中断相关寄存器
14.3.1 PIE 控制寄存器(PIECTRL)
PIE 控制寄存器(PIECTRL)各位信息如下图所示:


14.3.2 PIE 中断应答寄存器(PIEACK)
PIE 中断应答寄存器(PIEACK)各位信息如下图所示:

14.3.3 PIE 中断标志寄存器(PIEIFRx)
PIE 中断标志寄存器 PIEIFRx(x=1-12)各位信息如下图所示:

14.3.4 PIE 中断使能寄存器(PIEIERx)
PIE 中断使能寄存器 PIEIERx(x=1-12)各位信息如下图所示:

14.3.5 CPU 中断标志寄存器(IFR)
CPU 中断标志寄存器(IFR)是一个 16 位的 CPU 寄存器,用于标志和清除被执行的中断。CPU 中断寄存器(IFR)包含 CPU 级可屏蔽中断(INT1-INT14、DLOGINT和 RTOSINT)的标志位。当 PIE 模块被使能,PIE 模块为中断组 INT1-INT12 提供复用中断源。
当一个可屏蔽请求发生时,相应外设控制寄存器的标志位置 1,如果相应的屏蔽位也是 1,则该中断请求被送到 CPU,并在 IFR 中相应的标志位置 1,这表示中断未被执行或等待应答。
为识别未执行的中断,可利用 PUSH IFR 指令以测试堆栈的值,利用 OR IFR指令去置位 IFR 位,利用 AND IFR 指令手动清除未被执行的指令。所有未执行的中断用 ADN IFR #0 指令或硬件复位清除。
CPU 的应答中断和硬件复位也可以清除 IFR 标志。CPU 中断标志寄存器(IFR)各位信息如下图所示:

14.3.6 CPU 中断使能寄存器(IER)
CPU 中断标志寄存器(IFR)是一个 16 位的 CPU 寄存器,包含 CPU 级可屏蔽中断(INT1-INT14、DLOGINT 和 RTOSINT)的使能位。IER 中既不包含 NMI 也不包含 XRS,这样 IER 不受这些中断的影响。
用户可以通过读 IER 来定义使能中断或设置中断的级别,也可以通过写 IER来激活中断。利用 OR IER 指令将相应的 IER 位置 1 可以使能中断,利用 AND IER指令将相应的 IER 位置 0 可以禁止一个中断。当一个中断被禁止,不管 INTM 位的值是多少,它都不会应答,当一个中断被使能,如果相应的 IFR 位为 1,且 INTM位是 0,那么中断就被响应了。
CPU 使能中断寄存器的各位信息如下图所示:

14.3.7 CPU 调试中断使能寄存器(DBGIER)
CPU 在实时仿真模式下暂停中需要中断的时候就要用到 CPU 调试中断使能寄存器 DBGIER,其中各位如下图所示:

CPU 在实时暂停模式时,中断服务也需要 IER 寄存器使能。在实时仿真模式中,采用的是标准的中断服务进程,忽略 DBGIER。同 IER 一样,可以通过读 DBGIER寄存器的值,使能或者禁止中断,采用 PUSH DBGIER 指令从 DBGIER 读取数据,采用 POP DBGIER 将值写入 DBGIER,复位时,所有的 DBGIER 位均为 0。
14.3.8 外部中断控制寄存器(XINTnCR)
F28335 共支持 7 个外部中断 XINT1-XINT7,XINT13 还有一个不可屏蔽的外部中断 XNMI 共用中断源。每一个外部中断可以被选择为正边沿或负边沿触发,也可以被使能或者禁止(包括 XNMI)。可屏蔽中断单元包括一个 16 位增计数器,该计数器在检测到有效中断边沿时复位为 0,同时用来准确记录中断发生的时间。
外部中断控制寄存器(XINTnCR n=1-7)各位信息如下图所示:

14.3.9 外部 NMI 中断控制寄存器(XNMICR)
外部 NMI 中断控制寄存器(XNMICR)各位信息如下图所示:

14.3.10 外部中断 x 计数器(XINTxCTR)
外部中断 x 计数器(XINTxCTR)各位信息如下图所示:

12 理解 14.4 中断配置
前面讲解了那么多中断知识,如果大家不理解也没有关系,只要会应用即可,等到后面 F28335 熟练了,再回过头深入了解自然就会明白。要使用中断我们就需要先配置它,通常都需经过这几步:
(1) 使能外设对应的 PIE 中断,由于外设中断较多,它们是由 PIE 统一管理,所以要根据你所使用的外设中断选择对应的组,比如外部中断 1,它是由 PIE组 1 的第 4 线连接,这个在前面中断介绍时讲解过。因此可由 PIE 控制寄存器中相应中断使能位来控制。其实现代码如下所示:
c
PieCtrlRegs.PIEIER1.bit.INTx4 = 1; // 使能 PIE 组 1 的 INT4
(2) 使能外设中断,这个具体是由外设相关中断使能位来控制,比如外部中断 1,这个可由外部中断 1 的控制寄存器中相应中断使能位来控制。其实现代码如下:
c
XIntruptRegs.XINT1CR.bit.ENABLE= 1; // 使能 XINT1
(3) 指定中断向量表中断服务函数地址,这个通过对 PIE 中断向量表寄存器的相应位进行设置,中断服务函数名可自定义,但是要符合 C 语言标识符命名规则,在中断函数名前需加上地址符"&"。在对 PIE 中断向量表寄存器设置时要先声明 EALLOW,修改完成后还要声明 EDIS。比如外部中断 1,其设置如下:
c
EALLOW; // 修改被保护的寄存器,修改前应添加 EALLOW 语句
PieVectTable.XINT1 = &EXTI1_IRQn;
EDIS; // EDIS 的意思是不允许修改被保护的寄存器
(4) 使能 CPU 中断及全局中断,这个通过对 IER 和 EINT 寄存器相应位设置进行使能或者失能。比如外部中断 1,其代码如下:
c
IER |= M_INT1; // 使能 CPU 中断 1(INT1)
EINT; // 开全局中断
(5) 编写中断服务函数
配置好中断后如果有触发,即会进入中断服务函数,中断服务函数名在前面已定义好,所以要保证一致,否则将不会进入中断服务函数内执行。在 DSP28335软件开发中,要在中断服务函数名前加上关键字 interrupt。例如外部中断 1 的中断服务函数:
c
interrupt void EXTI1_IRQn(void)
{
...功能程序
}
在上面提到的 PieCtrlRegs、PIEIER1、PieVectTable、M_INT1 等,这些都是 TI 公司为我们封装好的寄存器或者宏定义值,我们直接使用即可。中断相关的 寄 存 器 及 函 数 可 在 DSP2833x_PieCtrl.c 、 DSP2833x_PieVect.c 、 DSP2833x_GlobalVariableDefs.c 文件及其对应的头文件内查找到,这里就不列举出来。
一、五步分别使能了什么
| 步骤 | 操作 | 使能的对象 | 寄存器/操作 |
|---|---|---|---|
| (1) | 使能PIE中断 | PIE级中断(组内的第y个中断) | PIEIERx.bit.INTxY = 1 |
| (2) | 使能外设中断 | 外设模块本身的中断 | 外设控制寄存器(如XINT1CR.bit.ENABLE) |
| (3) | 指定中断向量 | 告诉CPU中断服务函数的入口地址 | PieVectTable.XINT1 = &函数名 |
| (4) | 使能CPU中断+全局中断 | CPU级中断线 + 总开关 | IER + EINT |
| (5) | 编写中断服务函数 | 中断发生时要执行的代码 | interrupt void 函数名(void) |
二、它们的关系(从上到下的层级)
这5步是按从具体到通用的顺序配置的:
外设模块(步骤2)
↓ 产生中断请求
PIE级(步骤1) ← 控制这个具体中断是否被PIE转发
↓
CPU级(步骤4中的IER) ← 控制整个INTx组是否被CPU接收
↓
总开关(步骤4中的EINT) ← 控制CPU是否响应任何可屏蔽中断
↓
CPU取向量(步骤3) ← 找到函数入口
↓
执行中断服务函数(步骤5)
三、区别(为什么需要分别配置)
| 步骤 | 控制的是什么 | 如果不使能会怎样 |
|---|---|---|
| (2) 外设中断 | 外设模块是否产生中断信号 | 外设根本不会向PIE发送中断请求 |
| (1) PIE使能 | PIE是否将这个中断转发给CPU | 外设发了请求,但PIE挡掉了 |
| (4) IER | CPU是否接收这个INTx组的所有中断 | PIE转了,但CPU不收 |
| (4) EINT | CPU总开关 | CPU收了,但总闸关着,不处理 |
| (3) 向量表 | CPU响应时跳转到哪里 | 响应了但跳错地址,程序跑飞 |
简单说 :这5步缺一不可,它们是一个串联通道。任何一个环节没开或配错,中断都无法正常执行。
四、以外部中断1为例的完整流程
c
// 步骤2:外设模块自己产生中断的能力
XIntruptRegs.XINT1CR.bit.ENABLE = 1;
// 步骤1:PIE允许这个中断转发给CPU
PieCtrlRegs.PIEIER1.bit.INTx4 = 1;
// 步骤3:告诉CPU跳转到哪个函数
EALLOW;
PieVectTable.XINT1 = &EXTI1_IRQn;
EDIS;
// 步骤4:CPU级使能
IER |= M_INT1; // INT1组
EINT; // 总开关
// 步骤5:函数体
interrupt void EXTI1_IRQn(void)
{
// 用户代码
}





