1. 项目概述
如果你正在使用NXP的LPC2101/02/03系列ARM7微控制器开发产品,并且感觉程序跑起来有点“肉”,或者中断响应总是不尽如人意,那么这篇文章就是为你准备的。我花了相当长的时间,在多个工控和消费电子项目上深度调优过这几款经典芯片,今天就把关于其性能核心——内存加速模块(MAM)和向量中断控制器(VIC)——的配置心得和应用细节,掰开揉碎了讲清楚。
很多工程师拿到芯片后,可能只是简单启用一下MAM,或者照搬例程初始化一下VIC,就觉得万事大吉。但实际上,这两个模块的潜力远不止于此。MAM配置不当,轻则系统性能无法完全释放,重则出现偶发的、难以复现的程序跑飞;VIC配置不优,则会导致中断延迟不可控,在高实时性要求的场合(比如电机控制、高速通信)埋下隐患。它们的价值,正是在于通过硬件机制,将CPU从繁重的Flash等待和中断查询中解放出来,在有限的资源下榨取出每一分性能。无论是做实时数据采集、步进电机驱动,还是带复杂协议栈的通信设备,吃透这两个模块,都能让你的系统更稳健、更高效。
2. 内存加速模块(MAM)深度解析与配置实战
2.1 MAM是什么?为什么需要它?
LPC210x系列基于ARM7TDMI-S内核,其工作时钟(CCLK)可以跑到60MHz甚至更高。但是,它内部的Flash存储器访问速度是有限的。你可以把CPU想象成一个思维敏捷的工人,而Flash是一个反应较慢的仓库。工人每次需要原料(指令或数据)时,都得跑去仓库取。如果仓库出货慢,工人大部分时间都在等待,工作效率自然低下。
MAM的作用,就是在这个工人和仓库之间设立一个“智能中转站”(缓存和预取缓冲区)。它会预测工人下一步可能需要什么,提前从仓库取出来备好。当工人真的需要时,就能直接从中转站快速拿到,极大减少了等待时间。官方数据表明,正确配置MAM后,系统性能可提升至原来的300%以上,这对于提升整个应用的实时性和吞吐量至关重要。
2.2 MAM的三种工作模式与核心寄存器
MAM的行为完全由两个寄存器控制:MAM控制寄存器(MAMCR)和MAM时序寄存器(MAMTIM)。理解它们是精准配置的第一步。
MAMCR (0xE01F C000) - 模式选择开关这个寄存器只有最低2位(bit 1:0)有效,决定了MAM的基本工作模式:
- 00 - MAM功能关闭:这是复位后的默认状态。所有Flash访问都直接进行,无任何加速。功耗最低,但性能也最差。通常仅在初始化阶段或极低功耗休眠时使用。
- 01 - MAM部分使能:此模式下,MAM仅对指令预取生效。CPU取指时会利用预取缓冲,但数据访问依然直接进行。这是一种折中方案,在保证大部分性能提升的同时,简化了数据访问的时序一致性考量。适用于对数据访问实时性有特殊严格要求的场景(较少见)。
- 10 - MAM完全使能:这是绝大多数应用场景的推荐模式。MAM的指令预取和数据缓存功能全部开启,能最大化系统性能。
这里有一个非常重要的硬件特性需要注意:当你改变MAMCR的值(即切换模式)时,MAM内部所有的保持锁存器(holding latches)会被立即清空失效。这意味着,下一次取指或取数时,无论缓存里之前有什么,都会触发一次全新的Flash读取。在动态切换模式时,需要考虑这段“缓存失效期”对关键实时任务的影响。
MAMTIM (0xE01F C004) - 性能调谐旋钮这个寄存器的低3位(bit 2:0)用于设置Flash访存周期所需的CCLK时钟数,可选1到7个周期。这是平衡系统稳定性和性能的关键参数。
- 设置过小(如1个周期):如果Flash物理上无法在这个时间内完成数据读取,会导致CPU读到错误的数据或指令,造成系统崩溃。手册明确警告,不当设置可能导致设备错误操作。
- 设置过大:虽然绝对稳定,但浪费了性能潜力,MAM的加速效果大打折扣。
那么,这个值到底该设为多少?不能拍脑袋决定,必须根据你的**系统主频(CCLK)**来查表。官方手册给出了黄金参考:
| 系统时钟频率 (CCLK) | 推荐的MAMTIM值 (Flash访存周期) |
|---|---|
| < 20 MHz | 1 |
| 20 MHz 至 40 MHz | 2 |
| 40 MHz 至 60 MHz | 3 |
| > 60 MHz | 4 |
这个建议表是经过芯片电气特性验证的。例如,当CCLK=60MHz时,周期为16.67ns。设置MAMTIM=3,意味着给Flash的访问时间窗口是50ns。这必须大于Flash存储器本身在特定电压、温度下的最慢读取时间,才能保证稳定。在实际项目中,我强烈建议遵循这个表格,不要为了追求极限性能而冒险缩减周期。
2.3 MAM配置流程与代码实现
配置MAM不是一个简单的赋值操作,必须遵循严格的步骤,否则可能引发不可预知的行为。核心原则是:修改MAMTIM前,必须先关闭MAM(MAMCR=0)。
下面是一个标准的、健壮的MAM初始化函数,以Keil MDK环境为例,采用直接寄存器操作:
/** * @brief 配置MAM模块 * @param cclk_mhz: 系统核心时钟频率,单位MHz。用于自动选择最佳MAMTIM值。 * @retval 无 */ void MAM_Config(uint32_t cclk_mhz) { uint32_t mamtim_value; // 步骤1:根据核心时钟频率,确定MAMTIM值 if (cclk_mhz < 20) { mamtim_value = 1; } else if (cclk_mhz <= 40) { mamtim_value = 2; } else if (cclk_mhz <= 60) { mamtim_value = 3; } else { mamtim_value = 4; // 对于超频到60MHz以上的情况,需谨慎评估Flash性能 } // 步骤2:关闭MAM。这是修改MAMTIM的前提条件! MAMCR = 0x0; // 步骤3:配置Flash访问周期 MAMTIM = mamtim_value; // 步骤4:开启MAM完全加速模式 MAMCR = 0x2; // 完全使能模式 // 提示:为了代码可读性,MAMCR和MAMTIM应在头文件中定义为对应的寄存器地址。 // 例如:#define MAMCR (*((volatile unsigned long *) 0xE01FC000)) }关键操作解析与避坑指南:
- 顺序不可颠倒:必须先关(MAMCR=0),再设MAMTIM,最后再开MAM。如果顺序错乱,例如在MAM开启时直接修改MAMTIM,可能导致MAM内部状态混乱,引发零星的总线错误或取指错误。这种错误随机且难以调试。
- volatile关键字:在定义寄存器指针时,务必使用
volatile关键字。这告诉编译器不要对这个地址的读写做优化(比如合并写操作、缓存到寄存器),因为硬件寄存器的值可能被CPU以外的因素(即硬件本身)改变。省略volatile是嵌入式开发中一个经典的、会导致诡异问题的错误。 - 初始化时机:这段代码应该在系统时钟初始化(PLL配置)完成之后,但又在任何复杂的应用程序(尤其是需要高性能或中断)运行之前调用。通常放在
main()函数开头,紧跟着时钟配置之后。 - 动态频率切换:如果你的应用有动态调频功能(例如,运行模式与休眠模式切换),那么在提高频率前,需要按上述流程重新配置MAMTIM以适应更高的时钟;在降低频率后,虽然不强制,但为了最佳功耗性能比,也可以重新配置。记住,每次修改MAMTIM,都要遵循“关-改-开”的流程。
2.4 MAM使用中的高级技巧与疑难排查
性能评估:如何验证MAM确实在起作用?一个简单的方法是使用一个大的循环体(例如软件延时函数),用示波器或逻辑分析仪观察某个GPIO引脚翻转的频率。在相同CCLK下,分别关闭和开启MAM,翻转频率会有显著差异。开启MAM后,频率会大幅提高,直观证明取指效率的提升。
关于“部分使能”模式:这个模式在实际项目中用得很少。它的设计初衷可能是为了应对这样一种极端情况:某个极其关键的数据变量存储在Flash中,且要求每次访问都必须获取最新值,不能接受缓存带来的“旧数据”风险。但事实上,LPC210x的MAM数据缓存机制是透明的,且缓存行不大,这种风险极低。99%的情况下,直接使用“完全使能”模式即可。
异常问题排查:如果你的程序偶尔会跑飞,尤其是在高频下运行一段时间后,除了检查堆栈溢出、数组越界等常见问题外,请务必怀疑MAM配置。
- 第一步:检查CCLK计算是否正确。你是否使用了正确的晶体频率、PLL倍频/分频参数?用示波器测量一下主时钟输出引脚(如果使能了)来确认。
- 第二步:核对MAMTIM值是否与当前CCLK匹配。参照上面的推荐表,确保留有足够余量。在环境温度变化大的场合(如工业现场),可以考虑增加一个时钟周期的余量。
- 第三步:检查MAM配置代码的执行顺序。确保没有在其他中断服务程序或函数中意外修改了MAMCR或MAMTIM。
- 一个血的教训:我曾遇到一个产品,在高温老化测试中随机死机。最终定位到是MAMTIM设置在了临界值(CCLK=55MHz,却设置了MAMTIM=2)。在高温下Flash访问变慢,导致偶尔取指错误。将MAMTIM改为3后问题彻底消失。所以,在可靠性要求高的场合,不要贴着手册的极限值配置,适当增加余量是值得的。
3. 向量中断控制器(VIC)精讲与实战编程
3.1 VIC架构与核心概念
如果说MAM是提升CPU“干活”效率的利器,那么VIC就是确保CPU能“及时响应紧急事件”的大管家。传统的ARM7中断只有IRQ和FIQ两种,所有中断源挤在这两条线上,CPU收到中断后,还需要软件去遍历查询是哪个外设触发的,这无疑增加了响应延迟。
LPC210x的VIC将中断管理提升到了一个新的高度。它最大支持32个中断源,并可以可编程地将它们分为三类:
- FIQ(快速中断请求):优先级最高,用于处理最紧急、最需要快速响应的事件(如高速通信接收、关键故障信号)。VIC允许多个中断源被分配为FIQ,但最佳实践是只分配一个。因为如果有多个FIQ,服务程序仍需查询VICFIQStatus寄存器来区分是谁,这就丧失了FIQ“无需判断直接处理”的速度优势。
- Vectored IRQ(向量化IRQ):这是VIC的精华所在。你可以从32个中断源中,挑选出最多16个,分配到16个向量IRQ槽位(Slot 0-15)。Slot 0优先级最高,Slot 15最低。每个槽位都可以独立设置一个中断服务程序(ISR)的入口地址。当该中断发生时,CPU可以直接跳转到对应的地址执行,省去了软件查询的步骤,极大地缩短了中断响应时间。
- Non-Vectored IRQ(非向量化IRQ):优先级最低。所有未被分配到FIQ或向量IRQ槽位的中断源,或者虽然分配了但槽位被禁用的中断,都会归到这一类。它们共享一个默认的中断服务程序入口。CPU进入这个默认程序后,需要读取VICIRQStatus等寄存器来逐个判断是哪个中断触发的。
这种架构带来了极大的灵活性:你可以根据任务实时性要求,动态调整中断的类别和优先级。例如,在系统启动阶段,将UART中断设为向量IRQ以快速接收配置命令;在正常运行阶段,将其改为非向量IRQ,把宝贵的向量槽位让给更关键的定时器或ADC中断。
3.2 VIC寄存器全景图与功能详解
VIC的寄存器看起来很多,但按功能分组后脉络就很清晰了。下表是核心寄存器的功能速查:
| 寄存器名称 | 地址 | 读写 | 核心功能描述 |
|---|---|---|---|
| VICIntSelect | 0xFFFF F00C | R/W | 中断选择寄存器。32位对应32个中断源。写0表示该中断为IRQ,写1表示该中断为FIQ。复位后全为0(默认都是IRQ)。 |
| VICIntEnable | 0xFFFF F010 | R/W | 中断使能寄存器。某位写1,使能对应的中断源。使能是中断被响应的前提。 |
| VICIntEnClear | 0xFFFF F014 | WO | 中断使能清除寄存器。向某位写1,会清除VICIntEnable中的对应位(即禁用中断)。这是安全禁用中断的推荐方式,无需读-改-写。 |
| VICVectCntl0-15 | 0xFFFF F200-23C | R/W | 向量控制寄存器。共16个,对应16个向量IRQ槽。低5位指定分配给此槽的中断源编号(0-31);第5位(bit5)是此槽的使能位。 |
| VICVectAddr0-15 | 0xFFFF F100-13C | R/W | 向量地址寄存器。共16个,存放对应向量IRQ槽的中断服务程序(ISR)入口地址。 |
| VICDefVectAddr | 0xFFFF F034 | R/W | 默认向量地址寄存器。存放非向量IRQ共用服务程序的入口地址。 |
| VICVectAddr | 0xFFFF F030 | R/W | 向量地址寄存器(当前)。这是一个特殊的寄存器。读操作:当IRQ发生时,CPU读取此寄存器,会自动得到最高优先级已触发向量IRQ的入口地址,或非向量IRQ的默认地址。写操作:在ISR结束时,向此寄存器写入任何值(通常写0),用于通知VIC硬件本次中断处理完毕,可以更新优先级仲裁。 |
| VICIRQStatus | 0xFFFF F000 | RO | IRQ状态寄存器。只读。显示当前所有被使能且被分类为IRQ(包括向量和非向量)的中断源中,哪些正处于激活(请求)状态。 |
| VICFIQStatus | 0xFFFF F004 | RO | FIQ状态寄存器。只读。显示当前所有被使能且被分类为FIQ的中断源中,哪些正处于激活状态。 |
3.3 VIC配置实战:从零搭建中断系统
假设我们的系统需要配置以下中断:
- Timer0 匹配中断(中断号4):用于精确计时,实时性要求高,配置为向量IRQ, Slot 0(最高优先级)。
- UART0 接收中断(中断号6):用于接收命令,配置为向量IRQ, Slot 1。
- 外部中断0 (EINT0)(中断号14):用于紧急按键,配置为FIQ。
- SPI0 中断(中断号10):用于常规数据收发,配置为非向量IRQ。
以下是完整的配置代码示例:
// 1. 定义中断服务函数原型 void TIMER0_IRQHandler(void) __irq; void UART0_IRQHandler(void) __irq; void EINT0_FIQHandler(void) __fiq; void NonVectored_IRQHandler(void) __irq; // 2. VIC初始化函数 void VIC_Init(void) { // 步骤A:禁用所有中断(通过清除使能位) VICIntEnClr = 0xFFFFFFFF; // 写1清除,禁用所有中断源 // 步骤B:设置中断类别 (FIQ or IRQ) VICIntSelect = 0x00004000; // 仅将EINT0 (bit14) 设为FIQ,其余默认为IRQ // 步骤C:配置向量IRQ Slot 0 (Timer0) VICVectCntl0 = (0x20 | 4); // Bit5=1使能此槽,低5位=4 (Timer0中断号) VICVectAddr0 = (uint32_t)TIMER0_IRQHandler; // 设置入口地址 // 步骤D:配置向量IRQ Slot 1 (UART0) VICVectCntl1 = (0x20 | 6); // Bit5=1使能此槽,低5位=6 (UART0中断号) VICVectAddr1 = (uint32_t)UART0_IRQHandler; // 步骤E:设置非向量IRQ的默认入口地址 VICDefVectAddr = (uint32_t)NonVectored_IRQHandler; // 步骤F:使能我们关心的中断源 VICIntEnable = (1 << 14) | // 使能 EINT0 (FIQ) (1 << 4) | // 使能 Timer0 IRQ (1 << 6) | // 使能 UART0 IRQ (1 << 10); // 使能 SPI0 IRQ (非向量) // 提示:VICVectAddr寄存器在中断发生时由硬件自动管理,此处无需初始化。 } // 3. 中断服务函数示例 (以Timer0为例) void TIMER0_IRQHandler(void) __irq { // 清除Timer0模块自身的中断标志位(例如,访问T0IR寄存器) // ... 你的中断处理逻辑 ... // 关键步骤:通知VIC本次中断处理结束 VICVectAddr = 0; // 向VICVectAddr写任何值均可,通常写0 } // 4. 非向量IRQ服务函数 void NonVectored_IRQHandler(void) __irq { uint32_t irq_status = VICIRQStatus; // 读取当前激活的IRQ状态 if (irq_status & (1 << 10)) { // 检查是否是SPI0中断 // 处理SPI0中断 // ... 清除SPI0模块的中断标志 ... } // 可以继续检查其他非向量中断源... // 同样需要通知VIC VICVectAddr = 0; } // 5. FIQ服务函数 (EINT0) void EINT0_FIQHandler(void) __fiq { // FIQ处理要求尽可能快,通常用汇编编写核心部分 // ... 紧急处理逻辑,例如保存关键状态、触发安全机制 ... // 注意:FIQ模式下,编译器可能使用不同的寄存器组。 // 清除EXTINT寄存器中的EINT0标志位。 // FIQ处理结束时,不需要像IRQ那样操作VICVectAddr。 }配置要点与深度解析:
- 初始化顺序:先禁用所有中断(
VICIntEnClr),再进行分类、分配、使能等操作。这是一个良好的安全习惯,避免在配置过程中被意外中断打断。 __irq和__fiq关键字:这是ARM编译器(如Keil)的特殊函数修饰符。它们告诉编译器,该函数是中断服务程序,编译器会在函数入口和出口自动生成保存/恢复工作寄存器以及正确返回(如SUBS PC, LR, #4)的代码。务必加上,否则从中断返回时会导致程序错误。- 向量槽使能位:
VICVectCntlx寄存器的bit 5(值0x20)是槽使能位。如果你只设置了低5位的中断号而忘了置位bit 5,那么该中断将不会被映射到向量IRQ,而是会“降级”为非向量IRQ。 - 中断结束标志:在IRQ服务程序(无论是向量还是非向量)末尾,必须向
VICVectAddr寄存器执行一次写操作(通常写0)。这个操作有两个作用:一是告诉VIC硬件当前最高优先级的中断已处理完毕,它可以更新内部优先级逻辑,为响应下一个中断做准备;二是为某些可能的预取指错误提供清理。忘记这一步是导致中断只能响应一次的常见原因。 - FIQ的处理:FIQ服务程序末尾不需要操作
VICVectAddr。FIQ的设计是尽可能快,其优先级管理更简单。但需要记得清除触发FIQ的外设中断标志。
3.4 幽灵中断(Spurious Interrupt)问题与防御
这是使用VIC时一个非常重要且棘手的问题,手册第6章专门用大量篇幅进行了警告。所谓“幽灵中断”,是指CPU进入了中断,但VIC却无法识别出是哪个中断源触发的,最终CPU跳转到了默认向量地址(VICDefVectAddr)指向的程序。
产生原因:根本原因在于ARM7内核中断响应的异步性。简单来说,从VIC向CPU发出IRQ信号,到CPU实际读取VICVectAddr寄存器获取入口地址,中间存在几个时钟周期的延迟。如果在这极短的窗口期内,软件代码(例如在其他中断里或主程序中)修改了VIC的状态(比如禁用了刚才触发的中断),就会导致VIC在CPU来“问”的时候,找不到那个有效的中断了,于是返回默认地址。
解决方案:
- 设置健壮的默认中断服务程序:永远不要将
VICDefVectAddr留为0或指向一个空函数。应该将其指向一个特定的处理函数,该函数至少能记录错误、进行系统复位或安全恢复。这是最后一道防线。void Default_IRQHandler(void) __irq { // 1. 可以记录错误日志到非易失存储器 // 2. 进行看门狗复位或系统软复位 // 3. 或者尝试读取VICRawIntr等寄存器分析原因(在要求不高的场合) VICVectAddr = 0; // 仍然需要写回 // 触发系统复位 ... } - 规范编程,避免竞态条件:
- 避免在中断服务程序中动态开关或重新分配中断。ISR应专注于处理事务并快速退出。
- 如果必须在主程序中修改VIC配置(如切换工作模式),可以考虑暂时关闭总中断(操作ARM的CPSR寄存器),修改完成后再打开。但这需要非常小心,且会增大中断关闭时间。
- 对于电平触发的外部中断,要特别注意硬件消抖和信号质量,避免毛刺导致中断标志置位后又快速消失,从而引发幽灵中断。
一个真实案例:在一个多任务系统中,低优先级任务A禁用了某个中断,几乎同时该中断被触发。由于异步性,CPU可能已经锁定了这个中断并准备跳转,但VIC的状态已被任务A改变。最终CPU跳转到了默认处理程序,导致系统行为异常。解决方法是在修改VIC关键配置的代码段前后,进行更严格的中断保护。
4. MAM与VIC的协同优化策略
MAM和VIC不是孤立工作的,它们的配置会相互影响,共同决定系统的最终性能表现。
场景一:高频系统下的中断延迟当CCLK运行在较高频率(如60MHz)时,如果MAMTIM设置过小,Flash访问处于临界状态。此时若发生高优先级中断,CPU需要从Flash读取ISR的指令。不稳定的Flash访问可能导致取指错误或额外等待,直接增加中断响应时间的抖动(Jitter)。对于实时性要求严格的FIQ,这种抖动是不可接受的。因此,在高频下,务必保证MAMTIM设置留有充足余量,甚至可以考虑将最关键的FIQ服务程序拷贝到RAM中执行,以消除Flash访问的不确定性。
场景二:中断服务程序的位置与性能VIC的向量地址指向的是ISR函数的入口。如果这个ISR函数本身位于Flash中,那么它的执行速度就受到MAM的制约。对于执行时间非常短、调用频繁的中断(例如一个简单的定时器滴答),其大部分时间可能花在从Flash取指上。此时,MAM的加速效果就直接决定了中断服务的效率。你可以通过分析反汇编,查看ISR是否处于代码热区,确保MAM能有效缓存其指令。
配置流程建议:
- 系统初始化阶段:先配置系统时钟(PLL),得到稳定的CCLK。
- 紧接着配置MAM:根据CCLK频率,按照安全规范(关-改-开)设置MAMTIM和MAMCR。
- 然后初始化VIC:在MAM已优化、取指稳定的环境下,设置中断向量、优先级和使能。
- 最后初始化具体外设:配置Timer、UART等模块的中断源,并清除可能存在的残留中断标志。
这种顺序确保了当第一个中断到来时,整个系统的内存访问和中断响应机制都已处于最优状态。
5. 常见问题排查与调试技巧
在实际开发中,遇到与MAM或VIC相关的问题时,可以按照以下思路进行排查:
问题1:启用MAM后,程序运行不稳定,偶尔死机。
- 检查点:确认
MAMTIM值是否与当前CCLK严格匹配。使用示波器测量实际时钟频率。 - 检查点:确认MAM配置代码的执行顺序是否正确(先关MAM,设MAMTIM,再开MAM)。
- 检查点:检查电源电压是否稳定。Flash在电压偏低时访问速度会下降。
- 临时对策:将
MAMTIM增加1(如从3改为4),看问题是否消失。如果消失,说明原配置处于临界状态。
问题2:中断无法进入,或者只进入一次后就不再响应。
- 检查点:这是最高频的错误!确认在IRQ服务函数末尾是否执行了
VICVectAddr = 0。 - 检查点:确认外设模块本身的中断标志是否在ISR中被正确清除。VIC管理的是中断请求的传递,外设自身的标志需要手动清除。
- 检查点:使用调试器,在中断服务函数入口设置断点。观察是否能触发。如果不能,检查
VICIntEnable寄存器相应位是否置1,VICVectCntlx的槽使能位(bit5)是否置1。 - 检查点:检查
VICDefVectAddr是否指向了一个有效函数。如果幽灵中断发生且默认处理函数无效,程序可能跑飞。
问题3:中断响应速度慢,不符合预期。
- 检查点:确认高优先级中断(如FIQ、低序号向量IRQ)是否被正确分配给了最紧急的任务。
- 检查点:检查MAM是否已正确启用且配置合理。中断延迟包括“响应延迟”(从发生到进入ISR)和“执行延迟”(ISR本身运行时间)。Flash取指慢会影响两者。
- 检查点:如果可能,测量中断引脚到进入ISR第一条指令的实际时间。可以使用一个GPIO引脚在中断发生时拉高,在ISR入口处拉低,用示波器测量脉冲宽度。
问题4:多个中断同时发生时,低优先级中断被“饿死”。
- 分析:这是由VIC的优先级机制决定的。高优先级中断可以打断低优先级中断的服务。如果高优先级中断非常频繁,低优先级中断可能长期得不到执行。
- 解决策略:
- 优化ISR:确保所有ISR,尤其是高优先级的,执行时间尽可能短。只做最紧急的处理(如保存数据、清除标志),将非紧急任务(如数据处理)放到主循环中。
- 调整分类:考虑将一些对实时性要求不高的中断设置为非向量IRQ,或者分配更低的向量槽优先级。
- 使用软件优先级:在非向量IRQ的共享服务函数中,实现自己的简单优先级判断逻辑。
调试时,善用VICIRQStatus和VICFIQStatus寄存器。它们能告诉你当前已使能且已触发的中断有哪些。而VICRawIntr寄存器则能显示所有中断源的原始状态,无论是否使能,这在排查硬件连接问题时非常有用。