TI微控制器RTI模块深度解析:从定时器原理到DMA触发与窗口看门狗实战
1. RTI模块核心架构与设计思路拆解
在嵌入式实时系统中,定时器模块是系统的心跳和节拍器,而TI微控制器中的实时中断(RTI)模块,则是一个功能远超基础定时器的精密时序引擎。它不仅仅是一个简单的计数器,更是一个集成了多路独立比较、自动重载、DMA触发和高级看门狗保护的综合事件发生器。理解其设计思路,是进行精准配置的前提。
RTI模块的核心思想是“比较匹配触发事件”。它内置了两个自由运行计数器(RTIFRC0和RTIFRC1),这两个计数器在RTICLK时钟驱动下不断递增。模块提供了多达4组独立的“比较-更新”寄存器对(RTICOMPx/RTIUDCPx)。你可以将RTICOMPx寄存器想象成一个“闹钟时间点”,当自由运行计数器的值走到这个时间点时,就会产生一个“闹钟响”的事件。这个事件可以映射为三种动作:触发一个CPU中断、发起一次DMA传输请求,或者两者同时进行。
更巧妙的是RTIUDCPx寄存器,它实现了“自动重设闹钟”的功能。当一次比较匹配发生后,RTICOMPx寄存器的值会自动加上RTIUDCPx中设定的增量值,从而生成下一个匹配点。这就实现了完全由硬件驱动的周期性事件生成,无需软件反复干预写寄存器,极大地减轻了CPU负担,并保证了周期性的绝对精确。这种设计特别适合产生PWM波形、精确的ADC采样触发或者通信协议的位定时。
除了核心的定时比较功能,RTI模块还深度集成了两级看门狗系统:基础的数字看门狗(DWD)和更先进的窗口看门狗(WWWD)。DWD是一个传统的倒计时器,超时即触发复位,防止程序跑飞。而WWWD则引入了“喂狗时间窗口”的概念,你不仅要在超时前喂狗,还不能喂得太早。这能有效检测程序是否在错误的时序点(例如卡在某个循环的初期)执行了喂狗操作,是对程序逻辑流健康度的更严格监控。
模块的中断管理也体现了硬件便利性的设计。RTISETINTENA和RTICLEARINTENA寄存器采用了“置位使能”和“清零使能”的机制。这意味着,如果你想单独使能比较通道2的中断,无需先读取整个中断使能寄存器、用软件进行位操作(读-改-写),再写回。你只需要直接向RTISETINTENA寄存器的对应位写1即可。这种设计消除了在多任务或中断环境中,对同一寄存器进行读-改-写操作可能引发的竞态条件风险,提高了代码的可靠性和执行效率。
2. 核心寄存器功能深度解析与配置要点
面对数十个寄存器,初学者容易感到无从下手。我们可以将其分为几个功能集群来理解:核心定时器、中断控制、看门狗以及高级辅助功能。下面我们挑出最关键的几个寄存器,深入解析其每一位的含义和配置时的“坑”。
2.1 比较与更新寄存器:精准周期的基石
RTICOMPx (x=0,1,2,3) 与 RTIUDCPx 寄存器对是RTI的发动机。每个RTICOMPx寄存器都是32位可读写(特权模式)寄存器,存储着与自由运行计数器比较的目标值。
关键点:比较的基准是哪个计数器(RTIFRC0还是RTIFRC1)?这并非由COMPx寄存器本身决定,而是由另一个寄存器——RTICOMPCTRL(比较控制寄存器,资料中未详细列出但至关重要)来配置的。你需要在RTICOMPCTRL中为每个比较通道x选择对应的计数器源。配置错误会导致比较事件永不发生或发生在错误的时钟域。
RTIUDCPx寄存器是自动化的关键。它存储的是一个“增量值”,而非下一个绝对时间点。工作流程如下:
- 系统初始化时,你设置
RTICOMPx = 初始匹配值A,RTIUDCPx = 周期增量值P。 - 当计数器值等于A时,发生比较匹配,触发中断/DMA。
- 硬件自动执行:
RTICOMPx = A + P。 - 计数器继续运行,当值等于
A+P时,再次触发事件,然后RTICOMPx被更新为A+2P,如此循环。
实操心得:计算初始值A和增量值P时,必须考虑计数器的位数和时钟频率。例如,RTICLK = 100MHz,想要产生10ms的周期中断。10ms = 0.01s, 需要的计数周期数 N = 0.01s * 100e6 Hz = 1,000,000。由于计数器是32位(最大约42.9亿),1,000,000完全在范围内。那么,你可以设置
RTIUDCPx = 1,000,000。初始值RTICOMPx可以设置为RTIFRCx的当前值 + 1,000,000,这样第一个中断将在10ms后到来。务必注意溢出:如果A + P > 0xFFFFFFFF,加法会回绕,这可能导致下一个中断间隔异常。软件上需要处理这种边界情况,或者通过合理配置周期值来避免。
2.2 中断使能管理寄存器:安全便捷的开关
RTISETINTENA和RTICLEARINTENA寄存器是一对“镜像”寄存器,它们本身并不存储中断使能的状态,而是作为“动作寄存器”来修改真正的RTIINTENA(中断使能寄存器)的状态。
- RTISETINTENA:向其中的某个位写1,会将RTIINTENA中对应的位置1(使能中断/DMA)。读操作返回的是RTIINTENA对应位的状态。
- RTICLEARINTENA:向其中的某个位写1,会将RTIINTENA中对应的位清0(禁用中断/DMA)。读操作返回的是RTIINTENA对应位的状态。
这种设计的精妙之处在于“原子性”操作。假设在多线程或高优先级中断环境中,你想使能COMP1中断。传统做法是:
temp = read_reg(RTIINTENA); // 步骤1:读取 temp |= (1 << INT1_BIT_POS); // 步骤2:修改 write_reg(RTIINTENA, temp); // 步骤3:写回如果在步骤1和步骤3之间,发生了中断,并且中断服务程序也修改了RTIINTENA,那么你的修改可能会被覆盖或产生冲突。
而使用SET/CLEAR寄存器,只需要一步原子操作:
write_reg(RTISETINTENA, (1 << SETINT1)); // 一步到位,安全使能硬件保证这个“置位”操作是不可分割的,彻底避免了竞态条件。这对于可靠性要求极高的汽车或工业控制软件至关重要。
2.3 数字看门狗控制寄存器:一次使能,终身守护
RTIDWDCTRL寄存器的行为非常特殊,是嵌入式安全设计的一个典型。它不是一个简单的“使能/禁用”开关。
- 使能:只有当向该寄存器写入特定的“魔法数字”0xA98559DA时,数字看门狗(DWD)计数器才会被使能。
- 禁用:一旦使能,无法通过软件禁用。唯一的禁用方式是系统复位或掉电复位。向寄存器写入其他任何值(包括“禁用值”0x5312ACED),都不会改变DWD的运行状态。
- 状态读取:读取该寄存器,如果返回0xA98559DA,表示DWD已使能;如果返回0x5312ACED,表示DWD未使能。
严重警告:这是一个“单行道”配置。在产品的启动代码中,你必须非常明确何时以及为何要使能看门狗。一旦使能,你的应用程序就必须在整个生命周期内定期服务它(喂狗),否则系统会被复位。切勿在调试初期或程序不稳定时随意使能它,否则会导致设备不断重启,增加调试难度。通常,看门狗使能是产品软件启动流程的最后一步。
RTIDWDPRLD寄存器用于设置看门狗超时时间。计算公式为:超时时间 texp = (DWDPRLD + 1) × 2^13 / RTICLK1其中RTICLK1是驱动DWD的时钟频率(可能与RTICLK同源,但需查具体芯片手册)。DWDPRLD是一个12位值(0-4095)。关键限制:此寄存器只能在DWD禁用时配置。也就是说,你必须在使能RTIDWDCTRL之前,就计算好超时时间并配置好RTIDWDPRLD。
2.4 窗口看门狗高级控制:时间窗口约束
窗口看门狗在基础DWD之上增���了“开始时间”的概念。你不能在窗口打开前喂狗,也不能在窗口关闭后喂狗,必须在“窗口期”内喂狗。
- RTIWWDSIZECTRL:定义窗口大小。它不是一个绝对时间值,而是一个相对于整个超时周期的百分比。例如,设置值为0x00000005代表100%窗口(即退化为普通看门狗,整个超时周期内都可以喂狗)。值为0x00050000则代表窗口大小为超时周期的6.25%。这意味着喂狗操作必须在超时周期结束前的最后6.25%时间段内进行,喂早了(在窗口打开前)或喂晚了(超时)都会触发违规。
- RTIWWDRXNCTRL:定义违规反应。可以配置为触发系统复位(0x5)或产生一个不可屏蔽中断NMI(0xA)。NMI为调试提供了可能:你可以在NMI服务程序中记录错误状态到非易失存储器,然后再触发软复位,有助于分析死机原因。
注意:这两个寄存器的配置有一个重要的“生效时机”规则。如果修改发生在看门狗服务窗口打开之前,新配置立即生效。如果修改发生在窗口已经打开之后,则新配置要等到下一次成功喂狗之后才会生效。这防止了在窗口期内动态改变规则可能导致的不可预测行为。
3. 从零构建RTI驱动:配置流程与代码实现
理解了寄存器原理后,我们通过一个具体的场景来串联配置流程:我们需要使用RTI产生一个周期为1ms的中断,并启用一个超时为2秒的窗口看门狗,窗口期为超时周期的25%。
3.1 系统时钟与模块初始化
首先,必须确认RTI模块的时钟源RTICLK的频率。假设通过系统时钟配置,RTICLK = 200MHz。同时,我们需要初始化RTI模块的基本计数器。这部分通常涉及RTIGCTRL(全局控制)、RTITBCTRL(时基控制)等寄存器,用于使能模块、选择计数器时钟源和预分频等。假设我们使用RTIFRC0作为计数器。
// 伪代码,寄存器地址需参考具体芯片手册 #define RTI_BASE_ADDR 0xFFFFFC00 #define RTIGCTRL (*(volatile uint32_t *)(RTI_BASE_ADDR + 0x00)) #define RTITBCTRL (*(volatile uint32_t *)(RTI_BASE_ADDR + 0x04)) #define RTIFRC0 (*(volatile uint32_t *)(RTI_BASE_ADDR + 0x10)) void RTI_ModuleInit(void) { // 1. 使能RTI模块(如果存在使能位) RTIGCTRL |= 0x1; // 2. 配置时基控制:选择RTICLK作为计数器时钟,不分频 // 假设RTITBCTRL[CLK_SRC]位域为0表示RTICLK,预分频为1 RTITBCTRL = 0x0; // 3. (可选)复位或初始化自由运行计数器 // 有些实现可能需要通过特定序列启动计数器,这里假设上电后从0开始计数 // RTIFRC0 = 0; // 直接写可能无效,需查手册 }3.2 配置1ms周期性中断
目标是利用比较通道0(COMP0)产生1ms中断。计算周期计数值: 周期 T = 1ms = 0.001s RTICLK 频率 F = 200MHz = 200e6 Hz 所需计数值 P = T × F = 0.001 × 200e6 = 200,000
我们设置RTIUDCP0 = 200,000。初始匹配值RTICOMP0需要设置为当前计数器值加上一个周期,以确保第一个中断在1ms后发生。
#define RTICOMP0 (*(volatile uint32_t *)(RTI_BASE_ADDR + 0x20)) #define RTIUDCP0 (*(volatile uint32_t *)(RTI_BASE_ADDR + 0x30)) #define RTICOMPCTRL (*(volatile uint32_t *)(RTI_BASE_ADDR + 0x08)) // 假设地址 void RTI_Config1msPeriodicInt(void) { uint32_t current_counter; // 1. 停止计数器更新(如果需要安全配置,取决于具体芯片) // 2. 配置比较通道0使用RTIFRC0作为源 // 假设COMPCTRL寄存器每2位控制一个通道:00=FRC0, 01=FRC1... RTICOMPCTRL &= ~(0x3 << 0); // 清零通道0源选择位 // RTICOMPCTRL |= (0x0 << 0); // 选择FRC0 (已经是0,可不写) // 3. 设置更新值(周期) RTIUDCP0 = 200000; // 1ms 周期 // 4. 设置初始比较值:当前计数值 + 一个周期 current_counter = RTIFRC0; // 处理可能的计数器溢出风险 if ((UINT32_MAX - current_counter) > 200000) { RTICOMP0 = current_counter + 200000; } else { // 如果接近溢出,从0附近开始计算 RTICOMP0 = 200000 - (UINT32_MAX - current_counter); } // 5. 使能比较通道0的中断(使用SET寄存器进行原子操作) #define RTISETINTENA (*(volatile uint32_t *)(RTI_BASE_ADDR + 0x80)) RTISETINTENA = (1 << 0); // 设置SETINT0位为1,使能COMP0中断 // 6. 在系统中断控制器(如VIM)中使能RTI中断线,并注册中断服务函数 // Enable_IRQ(RTI_INT_NUM); // Register_ISR(RTI_INT_NUM, RTI_1ms_ISR); // 7. 恢复计数器运行(如果之前停止了) }中断服务程序(ISR)中,必须清除中断标志位,否则会持续进入中断。
#define RTIINTFLAG (*(volatile uint32_t *)(RTI_BASE_ADDR + 0x88)) void RTI_1ms_ISR(void) { // 1. 清除中断标志位(写1清除) RTIINTFLAG = (1 << 0); // 清除INT0标志 // 2. 执行1ms周期任务,例如更新系统时钟、检查任务队列等 // SystemTick_1ms_Increment(); // Task_Scheduler(); }3.3 配置并启用窗口看门狗
我们要配置一个超时时间为2秒,窗口期为25%的窗口看门狗,违规时触发NMI。
第一步:计算并配置超时时间。假设DWD时钟RTICLK1 = 100MHz(可能与RTICLK不同)。 超时时间 texp = 2秒。 根据公式:texp = (DWDPRLD + 1) × 2^13 / RTICLK1 推导出:DWDPRLD = (texp × RTICLK1) / 2^13 - 1 代入:DWDPRLD = (2 × 100e6) / 8192 - 1 ≈ 24414 - 1 = 24413 (0x5F5D) 检查范围:0x5F5D (24413) < 4095 (0xFFF)?不,它超出了12位DWDPRLD的范围(0-4095)!
这说明2秒的超时时间对于100MHz时钟和此预分频因子(2^13)来说太长了。我们需要重新计算可行的超时时间,或者查手册是否有其他预分频配置位。最大超时时间对应于DWDPRLD=4095: 最大 texp_max = (4095+1)×8192 / 100e6 ≈ 0.335秒。 因此,我们需要选择一个更短的超时时间,例如300ms,或者寻找改变时钟分频的配置位(可能在RTIDWDCTRL或其他相关控制寄存器中)。假设我们调整需求,设置超时为300ms。 计算:DWDPRLD = (0.3 × 100e6) / 8192 - 1 ≈ 3662 - 1 = 3661 (0xE4D)。这在范围内。
第二步:配置窗口大小。我们需要25%的窗口。查RTIWWDSIZECTRL寄存器描述,值0x00000500对应25%窗口。
第三步:配置违规反应。我们选择触发NMI,对应RTIWWDRXNCTRL寄存器的值应为0xA。
第四步:编写配置代码。注意顺序:必须先配置窗口大小、反应和预加载值,最后再使能看门狗。
#define RTIDWDPRLD (*(volatile uint32_t *)(RTI_BASE_ADDR + 0x94)) #define RTIWWDSIZECTRL (*(volatile uint32_t *)(RTI_BASE_ADDR + 0xA8)) #define RTIWWDRXNCTRL (*(volatile uint32_t *)(RTI_BASE_ADDR + 0xA4)) #define RTIDWDCTRL (*(volatile uint32_t *)(RTI_BASE_ADDR + 0x90)) void RTI_ConfigWindowedWatchdog(void) { uint32_t timeout_ticks; // 0. 确保DWD当前是禁用状态(读取RTIDWDCTRL,应返回0x5312ACED) // 如果已使能,则无法配置,此函数应返回错误。 // 1. 配置窗口大小:25% RTIWWDSIZECTRL = 0x00000500; // 2. 配置违规反应:产生NMI (0xA) RTIWWDRXNCTRL = 0xA; // 3. 配置超时预加载值 (300ms @ RTICLK1=100MHz) // 计算 DWDPRLD = (0.3 * 100e6) / 8192 - 1 = 3661 timeout_ticks = 3661; // 注意:寄存器只有[11:0]位有效,需确保值在0-0xFFF之间 RTIDWDPRLD = (timeout_ticks & 0xFFF); // 4. 使能数字看门狗(单行道操作,谨慎!) // 写入魔法数字 0xA98559DA RTIDWDCTRL = 0xA98559DA; // 此后,看门狗计��器开始递减。必须在300ms * 25% = 75ms之后, // 且在300ms到期之前,完成第一次喂狗。 }第五步:实现喂狗服务程序。喂狗必须按照严格的密钥序列:先写0xE51A,再写0xA35C。必须在窗口期内完成。
#define RTIWDKEY (*(volatile uint32_t *)(RTI_BASE_ADDR + 0x9C)) void RTI_ServiceWatchdog(void) { // 正确的喂狗序列 RTIWDKEY = 0xE51A; RTIWDKEY = 0xA35C; // 此操作将重载看门狗计数器 }重要提醒:喂狗函数
RTI_ServiceWatchdog()必须被放置在系统主循环或一个确定会在窗口期内被定期调用的地方。绝对不能在中断服务程序中随意调用,除非你能严格保证该中断的发生时间落在看门狗窗口内。错误的喂狗时机是窗口看门狗触发的最常见原因。
4. 高级功能与联动应用:DMA触发与自动清中断
RTI模块的强大之处在于其与DMA控制器的无缝联动,可以实现“定时触发-数据搬运”的纯硬件流水线,极大解放CPU。
4.1 配置RTI比较事件触发DMA
假设我们需要每隔50us通过DMA将ADC结果缓冲区的一个数据搬运到串口发送缓冲区。我们可以使用RTI比较通道1来触发DMA。
首先,配置RTI产生50us周期事件(假设RTICLK=200MHz,周期计数值=0.00005 * 200e6 = 10,000)。
#define RTICOMP1 (*(volatile uint32_t *)(RTI_BASE_ADDR + 0x24)) #define RTIUDCP1 (*(volatile uint32_t *)(RTI_BASE_ADDR + 0x34)) #define RTICOMPCTRL (*(volatile uint32_t *)(RTI_BASE_ADDR + 0x08)) void RTI_ConfigDMATrigger(void) { uint32_t current_cnt = RTIFRC0; uint32_t period_ticks = 10000; // 50us // 1. 配置比较通道1使用RTIFRC0,并设置周期 // 假设COMPCTRL[3:2]位控制通道1源 RTICOMPCTRL &= ~(0x3 << 2); RTICOMPCTRL |= (0x0 << 2); // 选择FRC0 RTIUDCP1 = period_ticks; RTICOMP1 = current_cnt + period_ticks; // 2. 使能比较通道1的DMA请求(而非中断) // 使用SET寄存器原子操作,设置SETDMA1位 #define RTISETINTENA (*(volatile uint32_t *)(RTI_BASE_ADDR + 0x80)) RTISETINTENA = (1 << 9); // SETDMA1位在bit9 // 注意:此时对应的中断(SETINT1)可能未被使能,我们只用了DMA功能。 }然后,需要在DMA控制器中配置一个通道,将其触发源设置为“RTI比较匹配1”事件。这样,每次RTI比较事件发生,硬件会自动发起一次DMA传输,无需CPU介入。
4.2 使用自动清中断功能实现高频率无延迟响应
在某些极高频率的中断应用中,进入中断服务程序、保存上下文、清除标志、恢复上下文这一系列软件操作本身的开销可能无法忽略,甚至成为瓶颈。RTI的“比较中断自动清除”功能(RTIINTCLRENABLE和RTICMPxCLR寄存器)就是为了解决这个问题。
原理:为某个比较通道(例如COMP0)再设置一个“清除比较值”(CMP0CLR)。当自由运行计数器第一次匹配COMP0值时,触发中断。但同时,硬件开始等待计数器第二次匹配CMP0CLR值。当第二次匹配发生时,硬件会自动清除该通道的中断标志位(INT0),而无需软件在ISR中操作。
配置步骤:
- 使能自动清除功能:向
RTIINTCLRENABLE寄存器的INTCLRENABLE0字段写入非0x5的值(例如0x0)。 - 设置
RTICOMP0为第一次触发值(T1)。 - 设置
RTICMP0CLR为第二次触发值(T2),且T2 > T1,并确保(T2 - T1)的时间大于你的中断服务程序最坏执行时间,但小于中断周期。这样,在下一个中断到来前,标志位已被硬件清除。
#define RTIINTCLRENABLE (*(volatile uint32_t *)(RTI_BASE_ADDR + 0xAC)) #define RTICMP0CLR (*(volatile uint32_t *)(RTI_BASE_ADDR + 0xB0)) void RTI_ConfigAutoClearInt(void) { uint32_t trigger_val, clear_val; uint32_t period = 200000; // 1ms周期 uint32_t isr_max_time_ticks = 1000; // 假设ISR最长执行时间对应1000个RTICLK trigger_val = RTIFRC0 + period; clear_val = trigger_val + isr_max_time_ticks + 10; // 留一点余量 // 1. 使能COMP0的自动清除功能 // INTCLRENABLE0字段在bits[3:0],写入非5值使能,例如0xA RTIINTCLRENABLE &= ~(0xF << 0); // 先清零 RTIINTCLRENABLE |= (0xA << 0); // 使能自动清除 // 2. 配置比较值和清除值 RTICOMP0 = trigger_val; RTICMP0CLR = clear_val; // 必须大于COMP0值 RTIUDCP0 = period; // 更新值,用于COMP0下次触发 // 3. 使能COMP0中断 RTISETINTENA = (1 << 0); }这样配置后,在COMP0的ISR中,你甚至可以不进行清除标志位的操作(当然,安全的做法是依然读取一下RTIINTFLAG以确保)。这个功能对于需要极低中断延迟和确定性响应的应用非常有用。
5. 调试技巧与常见问题排查实录
在实际开发中,RTI模块配置不当会导致中断不触发、周期不准、看门狗误复位等问题。以下是一些实战中总结的排查清单和技巧。
5.1 中断不触发或触发一次后停止
这是最常见的问题。
- 检查时钟源:确认RTICLK是否确实存在且频率符合预期。使用示波器或通过翻转GPIO在RTI中断里输出脉冲来验证。
- 验证计数器是否运行:读取RTIFRC0和RTIFRC1的值,在调试器中连续观察它们是否在递增。如果不递增,检查RTIGCTRL和RTITBCTRL的配置,确认模块和计数器已使能。
- 检查比较值与更新值:
- 确保
RTICOMPx的初始值大于当前计数器值,否则第一次匹配可能已经过去。 - 确保
RTIUDCPx不为0。如果为0,则比较值永远不会更新,只会触发一次中断。 - 计算
RTICOMPx + RTIUDCPx是否溢出。如果溢出,下一个比较点会变成一个很小的数,导致中断间隔混乱。需要在ISR或初始化时处理溢出逻辑。
- 确保
- 确认中断使能与标志位:
- 使用
RTISETINTENA正确使能了中断吗?读取RTIINTENA(如果可读)或RTISETINTENA本身(读回的是状态)来确认位已被置1。 - 中断触发后,标志位
RTIINTFLAG的对应位会置1。必须在ISR中写1清除该位。如果忘记清除,中断标志会一直存在,但可能不会再次进入中断(取决于中断控制器的边沿/电平触发模式)。最稳妥的做法是在ISR入口立即清除标志。 - 检查芯片的系统级中断控制器(如VIM、NVIC),是否已映射并开启了RTI的中断线。
- 使用
5.2 看门狗意外复位系统
- 检查使能时机:确认不是在调试初期或程序不稳定阶段误写了
RTIDWDCTRL=0xA98559DA。可以在使能前加一个长延时,或通过一个未使用的GPIO输出状态,用逻辑分析仪观察复位与使能指令的顺序。 - 验证喂狗时序(窗口看门狗):
- 喂早了:在窗口打开前(即超时周期开始后的前75%时间)喂狗,会立即触发违规。确保你的喂狗函数第一次调用时间在初始化并使能看门狗之后的
(超时时间 × (1-窗口比例))之后。例如,300ms超时,25%窗口,则首次喂狗必须在225ms之后,300ms之前。 - 喂晚了:超过300ms未喂狗,超时复位。
- 密钥序列错误:必须是先写
0xE51A,再写0xA35C。写错值、顺序颠倒、只写一次都会触发复位。检查代码,确保两次写操作之间没有被其他中断或高优先级任务打断。特别注意:手册提到写RTIWDKEY寄存器需要3个VCLK周期,在两次写操作之间插入少量空操作(__nop())是良好的实践。
- 喂早了:在窗口打开前(即超时周期开始后的前75%时间)喂狗,会立即触发违规。确保你的喂狗函数第一次调用时间在初始化并使能看门狗之后的
- 检查RTIWDSTATUS寄存器:发生复位后,在启动代码中尽早读取
RTIWDSTATUS寄存器的值。DWWD_ST、END_TIME_VIOL、START_TIME_VIOL、KEY_ST等位会指示具体的违规原因,是调试窗口看门狗问题的金钥匙。 - 时钟源失效:如果RTICLK时钟源丢��,看门狗也会失效(等同于禁用)。检查你的时钟配置。
5.3 DMA触发不工作
- 源端配置:确认RTI侧的DMA请求已使能(通过
RTISETINTENA设置SETDMAx位)。 - 目的端配置:在DMA控制器中,必须将对应通道的触发源(Trigger Source)正确设置为“RTI Compare x Match”。
- DMA通道使能:配置好DMA的源地址、目的地址、传输量后,需要使能DMA通道。有些DMA控制器需要等待触发事件才启动,有些则配置后立即启动单次传输并等待下次触发。请仔细查阅DMA控制器的文档。
- 事件与请求类型:确认DMA控制器配置的是“单次请求”还是“连续请求”。对于RTI周期性触发,通常配置为“单次请求”,每个比较事件触发一次传输。
5.4 周期性出现时间漂移
如果发现中断间隔有微小的、累积的误差:
- 时钟精度:检查RTICLK的时钟源(通常是PLL输出或外部晶振)的精度。
- 软件开销:中断服务程序执行时间过长,挤占了主循环或其他中断,可能间接影响下一次中断的准时性。优化ISR,只做最必要的操作。
- 更新值计算误差:确保
RTIUDCPx的值是整数。如果计算出的周期计数值是小数,取整会带来误差。例如,期望周期1ms,RTICLK=199.999MHz,计数值=199999,实际周期约为1.000005ms,每天累积误差可达0.432秒。对于高精度应用,需要选择能产生整数计数值的时钟频率。 - 使用时间基准计数器:对于需要绝对时间戳的应用,不要依赖中断次数*固定周期来计时。应该在ISR中读取自由运行计数器
RTIFRCx的值作为精确的时间戳。因为中断响应本身可能有微小的抖动,但硬件计数器的值是连续且精确的。
通过系统性地理解寄存器功能、遵循正确的配置流程、并利用好状态寄存器和调试工具,可以高效地驾驭RTI模块,构建出稳定、实时、可靠的嵌入式系统时序基石。