十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

DSP2812外部中断XINT2配置与调试:从引脚到中断服务函数

DSP2812外部中断XINT2配置与调试:从引脚到中断服务函数 简介TMS320F2812 DSP外部中断扩展应用资源包面向开发者重点呈现XINT1、XINT2、XINT13可屏蔽中断与XNMI不可屏蔽中断的配置方法以及通过CPLD将按键信号扩展为EXINT5中断的实现思路对工业控制、电力电子等实时系统设计有直接参考价值。压缩包共80个文件、约235KB以17个C源码、17个头文件为主体并包含CCS工程文件.pjt/.cmd、编译输出.out/.map/.obj及调试日志等便于直接打开工程对照学习。已有268人学习适合熟悉基础外设但希望深入中断嵌套、外部触发与CPLD协同设计的入门及进阶开发者。通过阅读示例工程可掌握中断使能与优先级配置、中断服务程序编写以及CPLD外部扩展中断的完整处理流程能有效缩短相关项目的底层驱动开发时间。1. DSP2812 的 XINT2 外部中断入门先分清引脚和使能链从网上下到的 DSP2812-Ext_int 例程包解出来烧进 F2812 之后最常见的结局有三种灯完全不亮、只闪一次就再也不进、按一下按钮进好几次。前两种十有八九不是引脚接错而是 2812 外部中断这套中断链没走通——GPIO 复用、XINT2CR 的使能位、PIE 通道、CPU 的 IER 和 INTM任何一环断了XINT2 都进不了中断服务函数第三种则多半是触发极性和输入限定没设对。这篇文章把 TMS320F2812 的 XINT1/XINT2 外部中断从头捋到尾直接落到寄存器配置和可编译的 C 代码上适合刚把 2812 工程跑起来、正要接编码器 Z 相信号、霍尔传感器或者外部按键开关的工程师参考。2. 从 GPIOB0 到 PIEDSP2812 外部中断的硬管线与关键寄存器2.1 信号从 GPIOB0 到 CPU 中断线经过哪几道门TMS320F2812 上叫得上外部中断的输入有三路XINT1、XINT2 和 XINT13XNMI。绝大多数工程只用前两个XINT13 一般接 NMI 走不可屏蔽路径当普通外部事件触发用会给自己找麻烦。XINT2 的输入引脚在 GPIOB0数据手册里也叫 IOPB0它和 ADCSOC 输出共用同一个封装管脚所以软件第一件事是让 GPBMUX 的 bit0 选择外设功能而不是 GPIO。从引脚到 CPU 中断线信号依次穿过输入缓冲与两拍同步器、可选的采样限定逻辑、XINT2 边沿检测器、PIE 第 1 组第 4 通道、CPU 的 INT1 引脚最后被 INTM 位放行。这条链上有四个软件使能点GPBMUX 的复用选择、XINT2CR 的 EN 位、PIEIER1.INTx4、IER 的 M_INT1。任何一级没打开现象都一样——万用表能测到电平变化GPIO 读引脚也有反应但中断就是不进。提示281x 的 GPxMUX 位写 0 表示外设功能写 1 才是 GPIO。这个定义和 C2000 后来新系列的 GPIO 寄存器恰好相反从 28335 转过来的人最容易在这里翻车。2.2 XINT2CR、XINT2CTR、PIEACK三个决定中断行为的寄存器XINT2 相关的外设寄存器不多DSP281x 头文件里都集中在 XIntruptRegs 结构体中PIE 相关的则在 PieCtrlRegs 里。先看这张表后面代码就是对着这四样东西操作寄存器地址有效位作用XINT2CR0x0000 7076bit0 POLARITY、bit1 EN触发沿选择与总使能XINT2CTR0x0000 707816 位只读计数有效电平持续时间计数PIEIER1PIE 模块内bit INTx4第 1 组第 4 通道使能PIEACKPIE 模块内bit0第 1 组中断应答XINT2CR 只有两个有效位。bit0 是 POLARITY写 0 表示下降沿触发写 1 表示上升沿触发bit1 是 EN写 1 才把 XINT2 真正接入 PIE 仲裁。XINT2CTR 是 16 位只读计数器引脚处于有效电平期间每个 SYSCLKOUT 时钟加 1回到无效电平后自动清零。它不是普通定时器不能靠写寄存器清零它的价值集中在调试期读出这个值就能知道当前引脚是不是长时间停在有效电平上。PIEACK 是 PIE 第 1 组的应答位。任何一个第 1 组中断被 CPU 响应后的下一个周期硬件会把 PIEACK 的 bit0 置 1此后第 1 组里所有通道的中断请求全部被 PIE 挡住直到软件向 PIEACK 写入 1 清除。这个机制解释了中断只进一次的经典故障服务函数里忘了清 PIEACK第二脚永远进不来。XINT1、XINT2 都挂在第 1 组所以这两个中断互相也会被 PIEACK 影响。2.3 极性选错和电平型误触发怎么区分外部中断是边沿触发的2812 的 XINT 模块内部没有锁存整个电平的能力它根据 POLARITY 位检测跳变并向 PIE 发一个请求脉冲。如果按键一端接 GPIOB0、另一端接地平时引脚被上拉为高按下变低应该配下降沿反过来按键接电源、引脚靠下拉保持低那配上升沿。极性反了之后边沿检测只在错误的那半周跳变上动作表现出按下去没反应、松开反而触发。调试时把 XINT2CTR 读出来看如果它持续大于 0 并且在增长说明引脚正长时间停留在有效电平结合 POLARITY 反推信号逻辑基本可以认定是极性配反而不是脉冲问题。如果 XINT2CTR 始终是 0中断却进得来说明来的信号是窄脉冲宽度没有超过输入限定窗口这一类问题放到第四章展开。3. 最小可复现代码DSP2812 XINT2 外部中断三级使能一次配齐3.1 先搭好骨架头文件、PIE 初始化和向量声明常见做法是直接在 TI 官方 Example_281xExtInt 基础上改这类例程包的工程结构基本一致DSP281x_Device.h 定义外设寄存器结构体DSP281x_Examples.h 提供 InitPieCtrl、InitPieVectTable 等函数声明。PIE 向量表落在数据 RAM 的 0x000D00 起始区域由 DSP281x_GlobalVariableDefs.c 实例化链接脚本不动这部分不需要自己写。#include DSP281x_Device.h #include DSP281x_Examples.h // InitPieCtrl / InitPieVectTable 声明 interrupt void XINT2_ISR(void); // 中断服务函数声明 volatile Uint16 Int2Flag 0; // 置位给主循环ISR 里不做业务 volatile Uint32 Int2Count 0; // 中断次数统计 void main(void) { InitSysCtrl(); // 关看门狗、PLL 配到 150MHz 并等稳定 DINT; // 先关全局中断配置期间不允许进中断 InitPieCtrl(); // PIE 控制寄存器复位到默认态使能 PIE IER 0x0000; // 清 CPU 级中断使能 IFR 0x0000; // 清 CPU 级中断标志 InitPieVectTable(); // 把默认中断向量表装载到 RAM 0x000D00 ... }这段代码的逻辑顺序有讲究InitPieCtrl 会打开 PIE 模块的总开关并清空 PIEACKIER 和 IFR 清零保证没有旧的中断挂起InitPieVectTable 把复位默认的服务函数全部装进 RAM 向量表。如果跳过 InitPieCtrl 直接写自己的向量PIEIER 里那些残留值会让中断在一个无法预料的通道上乱跳。DINT 放在最前面的原因是PIE 已经使能后任何未初始化的中断源都可能触发先关全局中断才能保证配置过程不被中断打断。3.2 GPIOB0 复用成 XINT2 的完整写法引脚方向必须设成输入且把采样限定关掉。281x 的 GPxMUX 每一位对应一个引脚写 0 是外设功能写 1 是 GPIOGPxDIR 写 0 是输入、写 1 是输出。GPBQUAL 是对应引脚的输入限定开关外部中断建议直接用仅同步模式避免采样窗口滤掉短脉冲。EALLOW; // 受保护的寄存器写使能 GpioMuxRegs.GPBMUX.all 0xFFFE; // bit0 清 0GPIOB0 走 XINT2 GpioMuxRegs.GPBDIR.bit.GPIOB0 0; // 0 输入方向 GpioMuxRegs.GPBCTRL.bit.QUALPRD0 0; // 采样周期置 0窗口最窄 GpioMuxRegs.GPBQUAL.bit.QUAL0 0; // 0 仅同步不做 3 采样限定 EDIS;这里用而不是整体赋值是为了只改 bit0保留其它 GPIO 引脚已经配置好的状态很多例程包喜欢写GPBMUX.all 0x0000会把其它外设的复用位全部冲掉。GPBCTRL 的 QUALPRD0 管理 GPIOB0 到 GPIOB3 这一组设 0 表示采样周期最短GPBQUAL 的 QUAL0 才是针对单个引脚的开关主从配合才能把限定彻底关掉。如果只清 GPBQUAL 不清 QUALPRD采样窗口仍然存在只是变短而已。3.3 挂中断向量、开 PIE 和 IER 的正确顺序向量表在 RAM 里受 EALLOW 保护必须先挂好向量再开各级使能。顺序一旦反过来中断可能在向量还没指向你的函数时就到达执行的是默认 ISR表现为主循环看起来一切正常、但计数不动。EALLOW; PieVectTable.XINT2 XINT2_ISR; // 覆盖默认向量挂上自己的函数 EDIS; XIntruptRegs.XINT2CR.bit.POLARITY 1; // 1 上升沿触发0 为下降沿 XIntruptRegs.XINT2CR.bit.EN 1; // 使能 XINT2 到 PIE 的通路 PieCtrlRegs.PIEIER1.bit.INTx4 1; // PIE 第 1 组第 4 通道 XINT2 IER | M_INT1; // CPU 级使能 INT1即 PIE 第 1 组 EINT; // 打开全局中断开关等效 CLRC INTMPIEIER1 的 INTx4 对应 XINT2INTx3 才是 XINT1两个通道写错位是例程移植时的高频错误。IER 用M_INT1而不是M_INT2因为 XINT1/XINT2 都挂在 INT1 上也就是 PIE 第 1 组的 CPU 入口这正好解释了为什么这两个外中断会抢同一个 PIEACK。EINT 是宏展开成asm( CLRC INTM)它必须在 XINT2CR 和 PIEIER1 之后道理和 DINT 放最前一样先保证环境完整再放开总闸。3.4 服务函数里 PIEACK 不能忘ISR 内部第一原则是短。外部中断只负责置一个标志具体业务放在主循环的轮询里处理这样既减少中断时间也避免在 ISR 里做协议解析时被新中断重入。唯一必须做的额外动作是清 PIEACK。interrupt void XINT2_ISR(void) { Int2Flag 1; // 只置标志具体业务留给主循环 Int2Count; // 32 位自增稍后说明注意事项 PieCtrlRegs.PIEACK.all PIEACK_GROUP1;// 清第 1 组应答否则不再进中断 }PIEACK_GROUP1 的值是 0x0001写all而不是写bit是因为 PIEACK 各 bit 都是写 1 清除的语义整体赋值最稳妥。清 PIEACK 的位置建议放在 ISR 最后一条前面的操作是为了保证本次中断的处理不被打断。如果 ISR 里还有可能需要嵌套开启其它中断组也要先清 PIEACK 再开 EINT否则同组的后续中断会被封死。4. DSP2812 外部中断不进的排查限定、极性和共享变量4.1 短脉冲被输入限定滤掉是最隐蔽的丢中断原因把 2812 的外部中断接到一个输出宽度在 1 微秒量级的传感器上发现完全没反应但用示波器量引脚确实有跳变——这种情况九成是输入限定没关。281x 的 GPIO 输入路径默认允许做 3 采样限定只有当信号在连续多个采样周期内保持稳定内部逻辑才认为电平有效。脉冲宽度小于限定窗口时边沿检测器根本没见到有效跳变XINT2CR 的 EN 再开也没用。配置采样限定就三个寄存器位顺序很重要EALLOW; GpioMuxRegs.GPBCTRL.bit.QUALPRD0 0; // 采样周期最短按 SYSCLKOUT 数 GpioMuxRegs.GPBQUAL.bit.QUAL0 0; // 0 仅同步1 3 采样限定 EDIS;QUALPRD0 控制的是采样间隔QUAL0 控制是否启用限定。只改其中一个都会留下隐患QUAL0 保持 1 时即使 QUALPRD0 为 0信号依旧要走三采样逻辑脉冲宽度要覆盖至少两个采样间隔才能通过QUAL0 清 0 之后输入只经过两级同步器内部延迟大约 2 个 SYSCLKOUT在 150MHz 主频下约 13ns这个量级对外部事件来说基本可以忽略。4.2 中断标志和主循环共享变量的处理外部中断的 ISR 和主循环天然共享变量最常见的问题有三个忘记加 volatile、在 ISR 里做耗时操作、主循环读 32 位变量时被打断。volatile 的作用是让编译器每次访问都从内存读而不是缓存在寄存器里缺了它主循环可能永远看到旧值。volatile Uint16 Int2Flag 0; volatile Uint32 Int2Count 0; interrupt void XINT2_ISR(void) { Int2Flag 1; Int2Count; // 读取-自加-写回非原子操作 } Uint32 ReadInt2Count(void) { Uint32 tmp; DINT; // 临时关全局中断保证读完不被改写 tmp Int2Count; EINT; return tmp; }C28x 对 32 位变量的自增不是单指令中断执行到一半时主循环读到的高 16 位和低 16 位可能来自两次不同的自增结果。读 32 位计数时临时关一下全局中断代价是几十个时钟换来的是数据一致性。如果只是在主循环里查询 Int2Flag16 位读写是单指令的不用关中断但一定要记得读完后立刻给它清零否则会重复处理同一次触发。4.3 从 rar 例程包移植时最容易踩的向量表坑下载的 Ext_int 例程包解压后工程里通常带一份 DSP281x_PieVect.c 和一份原有的 main.c。直接往里面加代码时最常见的坑是重复调用 InitPieVectTable第一次调用已经把默认向量装进 RAM第二次调用会把你自己挂到 PieVectTable.XINT2 的地址重新覆盖回默认 ISR。另一个坑是工程里存在两份 DSP281x_GlobalVariableDefs.c链接器报重复符号还好办怕的是两份都编进去、PieVectTable 被分配到两个不同的 RAM 地址挂向量挂到了一份PIE 响应的是另一份。遇到烧进去没反应第一步不是在 main 里加打印而是确认链接器映射文件里 PieVectTable 的地址。在 CCS 的 map 文件里搜 PieVectTable地址应是 0x000D00。如果不是检查是否漏了--ram_model选项或者 cmd 文件里的 PIE_VECT 段被意外挪走。向量表地址不对后面所有的使能配置都是白做。4.4 用 XINT2CTR 做信号诊断的三步法XINT2CTR 是只读计数器引脚处于有效电平期间每个 SYSCLKOUT 加 1无效时自动清零。拿它做诊断可以在主循环里直接读寄存器不需要示波器也能定位问题现象计数器表现结论中断偶尔进计数器始终为 0脉冲太窄输入限定把边沿滤掉了中断完全不进计数器一直增长极性配反或引脚被电平钳在有效态按键按下有反应按下期间计数松开归零硬件和软件都正常问题在消抖策略Uint16 cnt XIntruptRegs.XINT2CTR; // 直接读任意时刻都安全 if (cnt 0) { // 引脚此刻处于有效电平且已经持续 cnt 个 SYSCLKOUT }这个寄存器不要尝试在 ISR 里写它清零它是只读的而且边沿触发模式下中断到达时电平往往已经翻回无效态计数器早就归零。正确的用法是放在主循环里轮询用来判断引脚电平状态和脉冲形状属于调试辅助手段不参与正常业务逻辑。5. 把 XINT2 外部中断延迟压到最小的寄存器技巧5.1 延迟由三段构成先知道能省哪段从引脚边沿到 ISR 第一条指令执行延迟分三段。第一段是输入路径仅同步模式约 2 个 SYSCLKOUT开了采样限定则是整个采样窗口这段由 GPBQUAL 和 GPBCTRL 决定是唯一能明显压缩的部分。第二段是 PIE 仲裁和 CPU 响应包括组内优先级判定、流水线清空、INTM 判定这部分是硬件行为只能通过把 XINT2 放到高优先级通道来间接优化在 281x 上 XINT1/XINT2 固定是 INT1.3 和 INT1.4没有重映射空间。第三段是现场保护编译器在进入 ISR 时压栈与该中断无关无法优化。5.2 ISR 最短化和 PIEACK 位置的影响ISR 里只做两件事置 flag、清 PIEACK。PIEACK 清得越早同组接下来的中断就能越早被响应但这个早不能以牺牲当前 ISR 的完整性为代价。实践里我一般把 PIEACK 放在 ISR 最后一条因为置 flag 是单周期操作早一个周期清毫无意义。真正影响延迟的是 ISR 里别调用延时函数、别做长除法、别访问慢速外设这些才是延迟和抖动的大头。5.3 示波器验证把中断延迟量出来用一个测试 GPIO 把中断延迟变成波形是验证上述配置是否生效的最终手段。选 GPIOA2 当测试口ISR 入口拉高、出口拉低示波器同时接 XINT2 输入和 GPIOA2直接读两个上升沿的时间差。EALLOW; GpioMuxRegs.GPAMUX.all 0xFFFB; // bit2 清 0GPIOA2 用 GPIO 功能 GpioMuxRegs.GPADIR.bit.GPIOA2 1; // 1 输出 EDIS; interrupt void XINT2_ISR(void) { GpioDataRegs.GPASET.bit.GPIOA2 1; // 入口拉高标记中断已进入 Int2Flag 1; PieCtrlRegs.PIEACK.all PIEACK_GROUP1; GpioDataRegs.GPACLEAR.bit.GPIOA2 1; // 出口拉低 }GPASET 和 GPACLEAR 是独立置位/清零寄存器比读改写 GPADAT 更安全不会破坏同端口其它引脚的电平。量出来的时间除以 6.67ns150MHz 时钟周期就能反推是几拍的开销。如果测出来的延迟明显大于理论值回去查 GPBCTRL 的 QUALPRD0 是不是被初始化库改成了非 0这是我在各种 2812 例程包里见过最多的隐藏配置项。本文还有配套的精品资源点击获取
返回列表