1. 项目概述与核心价值
在嵌入式系统开发,尤其是汽车电子和工业控制这类对实时性、可靠性要求严苛的领域,系统的心跳和脉搏是如何精准控制的?答案往往藏在那些看似不起眼的硬件定时器模块里。今天要深入探讨的实时中断(RTI)模块,就是这样一个核心角色。它远不止是一个简单的“闹钟”,而是整个系统时间基准的基石,是任务调度、性能测量乃至系统自愈能力的源头。
想象一下,一个复杂的实时操作系统(RTOS)需要同时管理数十个任务,有的要求每1毫秒执行一次,有的需要等待外部事件触发,还有的需要在特定时间点精确控制一个电机。如果没有一个稳定、精确且可编程的硬件定时器来产生这些“节拍”,整个系统的时序就会乱套,轻则功能失常,重则引发安全事故。RTI模块正是为此而生,它通过可编程的计数器,生成多个独立的时间基准,驱动整个系统的有序运行。
更关键的是,一个健壮的系统必须具备“跌倒后自己爬起来”的能力。这就是看门狗定时器(WDT)的价值所在。它像一个沉默的守护者,时刻监视着CPU是否在正常执行预设的“喂狗”程序。一旦程序跑飞或陷入死循环,看门狗就会在超时后强制系统复位或触发最高优先级的中断,将系统从崩溃边缘拉回。而现代的高安全性系统,如符合ISO 26262标准的汽车电子控制单元(ECU),往往要求更严格的监控,于是窗口看门狗(DWWD)应运而生,它要求程序必须在特定的时间窗口内“喂狗”,进一步防止了因程序局部紊乱导致的误判。
本文将以德州仪器(TI)某些微控制器中的RTI模块为蓝本,但所阐述的原理和设计思想具有普适性。我们将从模块的双计数器架构讲起,拆解其如何生成高精度时间基准;然后深入比较单元与中断/DMA请求机制,看它如何成为RTOS的调度引擎;接着剖析捕获功能在性能分析和事件时间戳记录中的应用;最后,重点解读数字看门狗与窗口看门狗的工作原理、配置要点及其在构建高可靠系统时的实战技巧。无论你是正在评估芯片选型的系统架构师,还是埋头调试定时器驱动的嵌入式软件工程师,理解RTI模块的“内功心法”,都将让你在设计和调试中更加游刃有余。
2. RTI模块核心架构与设计哲学
要理解RTI模块的强大之处,必须先吃透其核心架构。它不是一个简单的单一定时器,而是一个为复杂、多任务、高可靠场景设计的定时器子系统。其设计哲学围绕着三个核心:灵活性(提供多个独立时间基准)、精确性(硬件计数,不受软件延迟影响)和安全性(集成看门狗)。
2.1 双计数器块:构建时间基准的基石
RTI模块的核心是两个完全独立的64位计数器块:Counter Block 0 和 Counter Block 1。这种双核设计是灵活性的关键。你可以让一个计数器块以1ms为周期产生系统滴答(Tick),用于任务调度;同时让另一个计数器块以10μs为周期,用于高精度的延时或PWM生成,两者互不干扰。
每个计数器块内部又由两级计数器组成,构成了一个可编程预分频的64位向上计数器:
- 32位向上计数器(RTIUCx):这是第一级,直接由模块时钟
RTICLK驱动。它从0开始向上计数,直到达到一个我们预设的比较值(RTICPUCx)。一旦匹配,就会触发两个动作:第一,它自己复位到0;第二,它会让第二级计数器加1。 - 32位自由运行计数器(RTIFRCx):这是第二级,构成了64位计数器的高32位。每当RTIUCx完成一轮计数(达到RTICPUCx),RTIFRCx就加1。RTIFRCx会一直累加,直到溢出(从0xFFFFFFFF翻转到0),此时可以产生一个溢出中断,通常用于超长周期的计时或作为系统运行时间的“年表”。
为什么需要两级设计?这其实是一种经典的预分频器思路。RTICLK的频率可能很高(比如200MHz),如果直接用这个频率去驱动一个64位计数器,虽然精度极高,但计数器值变化太快,不方便软件读取和比较,而且对于毫秒级的定时需求也显得浪费。通过设置RTICPUCx,我们可以将RTICLK分频。
- 公式:自由运行计数器
RTIFRCx的更新频率f_FRCx = f_RTICLK / (RTICPUCx + 1)。 - 举例:若
RTICLK = 100 MHz,我们希望系统滴答为1ms(即f_FRC0 = 1 kHz)。那么代入公式:1 kHz = 100,000,000 Hz / (RTICPUC0 + 1),解得RTICPUC0 = 99,999。这样,RTIUC0每计数100,000个RTICLK周期(即1ms),RTIFRC0才加1。此时,读取RTIFRC0的值,其单位就是1ms。软件操作的对象是一个变化较慢的“粗粒度”计数器,但底层的时间基准依然是高精度的硬件时钟。
注意:技术文档中提到,不建议将
RTICPUCx设置为0。因为当它为0时,公式退化为f_FRCx = f_RTICLK / (2^32 + 1),这是一个极低且不直观的频率。更关键的是,硬件实现上,向上计数器在从0xFFFFFFFF溢出到0后,会保持在0状态长达2个RTICLK周期,这会引入非预期的计时误差。在实践中,我们应始终设置一个合理的、非零的预分频值。
2.2 比较单元:中断与DMA事件的发动机
有了稳定递增的时间基准(RTIFRC0/1),如何让它触发具体的行为呢?这就是比较单元的工作。RTI模块提供了4个独立的比较寄存器(RTICOMP0-3)。
每个比较寄存器都可以独立配置,选择与Counter Block 0或Counter Block 1的自由运行计数器(RTIFRC0/1)进行比较。当计数器的值等于比较寄存器中设定的值时,硬件就会产生一个匹配事件。这个事件可以映射为两种输出:
- 中断请求(IRQ):发送给向量中断管理器(VIM),通知CPU处理。这是实现RTOS周期性任务调度的核心机制。
- DMA请求:直接触发DMA控制器进行数据传输,无需CPU介入。这对于需要高带宽、确定性数据搬运的应用(如ADC定期采样数据搬运到内存)至关重要,能极大减轻CPU负担。
如何实现周期性中断?这是通过更新比较寄存器(RTIUDCPy)实现的。在每次比较匹配事件发生后,硬件会自动将RTIUDCPy的值累加到当前的RTICOMPy值上,从而生成下一个比较点。假设RTIUDCP0 = 1000,初始RTICOMP0 = 1000。第一次匹配发生在计数器到1000时,之后RTICOMP0自动变为2000,下一次匹配就在计数器到2000时发生,如此循环,实现了周期为RTIUDCPy个计数器周期的精确中断。
中断周期计算公式:t_COMPx = t_RTICLK × (RTICPUCy + 1) × RTIUDCPy其中,y是对应的计数器块(0或1)。这个公式结合了预分频和比较更新值,让你可以灵活配置从纳秒级到秒级甚至更长的各种定时周期。
2.3 捕获功能:为事件贴上精确的时间戳
除了“定时产生事件”,RTI模块还能“记录事件发生的时间”,这就是捕获功能。每个计数器块都配备了一套捕获寄存器(RTICAFRCx和RTICAUCx)。
你可以配置某个外部事件(通常是一个特定的外设中断信号,通过VIM路由过来)作为捕获触发源。当该事件发生时,硬件会瞬间将此刻的RTIUCx和RTIFRCx值“冻结”并存入对应的捕获寄存器中。
这个功能有什么用?
- 性能剖析(Profiling):在你想测量的一段代码起点和终点,分别触发捕获事件。读取两次捕获的时间戳并相减,就能得到这段代码执行的精确时钟周期数,这是优化代码性能的黄金标准。
- 事件间时序分析:例如,在电机控制中,你可以捕获霍尔传感器跳变和ADC采样完成这两个事件的时间戳,从而精确分析它们之间的相位关系。
- 脉冲宽度测量:利用两个边沿触发捕获,可以高精度测量输入信号的脉冲宽度或频率。
重要实操细节:读取顺序一致性由于捕获(或直接读取)的是64位值(RTIFRCx + RTIUCx),而CPU总线通常是32位,需要分两次读取。为了保证读取的这两个32位值属于同一个“时间快照”,必须遵循严格的顺序:
- 读取计数器时:必须先读RTIFRCx(高32位),再读RTIUCx(低32位)。硬件会在你读RTIFRCx的瞬间,将当前的RTIUCx值锁存到影子寄存器中,随后读取RTIUCx得到的就是匹配的值。
- 读取捕获值时:必须先读RTICAFRCx,再读RTICAUCx。 违反这个顺序,读出的高低32位可能来自不同的时间点,导致计算出错。这是一个非常经典的硬件同步机制,在编写底层驱动时必须严格遵守。
3. 看门狗定时器:系统的终极守护者
如果说RTI的比较单元是系统的“节拍器”,那么看门狗定时器就是系统的“急救员”。它的唯一职责就是在系统“生病”(程序跑飞、死循环)时,采取强制措施使其恢复。
3.1 数字看门狗(DWD)基础原理
DWD本质上是一个递减计数器。上电后默认是关闭的,需要通过配置RTIDWDCTRL寄存器来使能。一旦使能,就无法通过软件关闭,只有系统复位才能重置,这防止了软件意外禁用看门狗。
使能后,一个25位的下行计数器(RTIDWDCNTR)会以RTICLK的频率从初始值开始递减。这个初始值来源于一个12位的预加载寄存器(RTIDWDPRLD),但硬件会将其左移13位后加载。因此,超时时间计算公式为:t_exp = (DWDPRLD + 1) × 2^13 / f_RTICLK
如何“喂狗”(服务看门狗)?CPU必须在一个固定的、短于t_exp的时间间隔内,向RTIWDKEY寄存器写入一个特定的密钥序列:先写0xE51A,再写0xA35C。当硬件检测到这个正确的序列后,就会将下行计数器重新加载为初始值,从头开始递减。如果程序正常运行,这个“喂狗”动作会周期性地发生,计数器永远减不到0。
如果出错了呢?两种可能:
- 程序跑飞/死循环,无法执行到“喂狗”代码。计数器递减到0,触发看门狗动作。
- 程序错乱,向
RTIWDKEY写入了错误的密钥。硬件会立即触发看门狗动作。
看门狗动作可以是系统复位或不可屏蔽中断(NMI)。复位是最彻底的方式,让整个系统重启。NMI则提供了一个“临终抢救”的机会,可以在系统复位前,执行一些紧急日志保存或状态记录的操作,但NMI服务程序本身也必须尽快“喂狗”,否则仍会引发复位。
3.2 数字窗口看门狗(DWWD):更严格的安全卫士
标准的DWD只规定了一个“最后期限”(超时时间)。但想象一个场景:一个任务本应在第5ms到第10ms之间“喂狗”,但它由于某种错误,在第1ms就提前“喂狗”了。对于标准DWD,这是允许的,系统不会复位。但这可能掩盖了错误——任务虽然还在运行,但时序已经乱了。
窗口看门狗(DWWD)就是为了解决这个问题。它定义了一个时间窗口,要求“喂狗”动作必须发生在这个窗口内,既不能太早,也不能太晚。
- 窗口起点:由窗口大小配置寄存器(
RTIWWDSIZECTRL)决定。它定义了在超时期限结束前的多长时间窗口打开。例如,超时时间设为100ms,窗口大小设为25%,那么窗口就在超时前的最后25ms(即第75ms到第100ms)打开。 - 窗口终点:就是DWD的超时时间点(由
RTIDWDPRLD设定)。
DWWD的行为规则:
- 在窗口打开之前“喂狗” →视为错误,触发动作(复位/NMI)。
- 在窗口之内“喂狗” →正确,计数器重置。
- 在窗口之后(即超时)仍未“喂狗” →视为错误,触发动作。
这种机制能有效检测出任务执行过快(提前完成但可能逻辑错误)或过慢(未在规定时限内完成)的故障,符合汽车功能安全标准(如ISO 26262)中对时序监控的要求。
窗口大小配置:通常可选100%(即退化为普通DWD)、50%、25%、12.5%、6.25%、3.125%。选择更小的窗口意味着对任务执行时间的约束更严格,但也对软件设计的确定性提出了更高要求。
3.3 看门狗配置的实战经验与陷阱
配置和使用看门狗时,有几个坑一旦踩中,调试起来会非常痛苦:
- 时钟源确认:
RTICLK的频率是多少?它可能来源于系统时钟分频,也可能是独立的低速时钟。错误估计RTICLK会导致计算的超时时间完全不对。务必查阅芯片数据手册,确认RTICLK的准确频率。 - 预加载值计算:根据需要的超时时间
t_desired和f_RTICLK,反推DWDPRLD值。公式变形为:DWDPRLD = (t_desired × f_RTICLK) / 2^13 - 1。计算结果必须取整,且确保在0-4095范围内。例如,要求超时时间为1秒,f_RTICLK = 10MHz,则DWDPRLD = (1 × 10,000,000) / 8192 - 1 ≈ 1220 - 1 = 1219。 - “喂狗”时序与延迟:你的“喂狗”代码执行路径必须是确定性的。不能放在一个执行时间不确定的任务中,或者被可能被长时间关闭的中断所阻塞。通常,“喂狗”任务应具有最高优先级之一。同时,注意CPU写入看门狗密钥寄存器到硬件实际响应之间存在传播延迟。虽然很短,但在极限配置(超时窗口非常小)时需要考虑。确保“喂狗”操作在窗口早期完成。
- 调试模式(Halting Debug)下的行为:当连接调试器进行单步调试时,CPU会暂停,但看门狗计数器可能不会。这会导致你在调试时看门狗意外复位。RTI模块的COS(Continue on Suspend)位可以控制调试挂起时计数器是否停止。在开发阶段,你可能需要根据调试需求合理配置此位,或使用调试器命令在断点处自动“喂狗”。
- 窗口看门狗的动态配置:
RTIWWDSIZECTRL(窗口大小)和RTIWWDRXNCTRL(违规反应)可以在看门狗使能后修改,但新配置只在下次成功“喂狗”后才生效。这个特性可以被巧妙利用,实现不同运行模式下不同的监控强度。
4. RTI模块的寄存器级编程与驱动设计
理解了原理,最终要落到代码上。RTI模块的编程本质上是配置一系列寄存器。下面我们以一个典型的应用场景为例,讲解如何初始化RTI模块,并为其编写稳健的驱动程序。
场景:我们需要使用Counter Block 0产生一个1ms的系统滴答中断,同时启用一个超时时间为1秒的窗口看门狗(窗口大小25%)。
4.1 初始化流程与关键寄存器配置
全局控制寄存器(RTIGCTRL):
CNT0EN位:置1,使能Counter Block 0。COS位:根据调试需求设置。若希望在调试时定时器暂停,则清0;否则置1。NTUSEL:选择外部时间基准源,若无特殊需求,通常使用内部时钟,此字段保持默认。
配置Counter Block 0的预分频:
- 假设
RTICLK = 200 MHz,我们需要f_FRC0 = 1 kHz。 - 计算
RTICPUC0:RTICPUC0 = f_RTICLK / f_FRC0 - 1 = 200,000,000 / 1,000 - 1 = 199,999。 - 将199,999写入
RTICPUC0寄存器。
- 假设
配置比较单元0产生1ms中断:
- 我们希望RTIFRC0每增加1(即每1ms)产生一次中断。因此,
RTIUDCP0应设置为1。 - 初始
RTICOMP0值需要设置为一个大于当前RTIFRC0值的数。通常,我们先读取当前的RTIFRC0值,然后加上RTIUDCP0作为初始比较值。例如:uint32_t current_frc0 = HWREG(RTI_BASE + RTI_O_FRC0); HWREG(RTI_BASE + RTI_O_COMP0) = current_frc0 + 1; // 设置首次比较点 HWREG(RTI_BASE + RTI_O_UDCP0) = 1; // 设置更新值,周期为1ms - 在
RTICOMPCTRL寄存器中,确保COMPSEL0位为0,表示RTICOMP0与RTIFRC0比较。
- 我们希望RTIFRC0每增加1(即每1ms)产生一次中断。因此,
启用中断:
- 向
RTISETINTENA寄存器的对应位(例如bit 0对应Event0)写1,使能比较匹配0中断。 - 在向量中断管理器(VIM)中配置RTI中断的入口函数。
- 在中断服务程序(ISR)中,必须读取
RTIINTFLAG寄存器以清除中断标志位。
- 向
配置并启用数字窗口看门狗(DWWD):
- 计算预加载值:要求超时时间
t_exp = 1s,f_RTICLK = 200MHz。DWDPRLD = (t_exp * f_RTICLK) / 8192 - 1 = (1 * 200,000,000) / 8192 - 1 ≈ 24414 - 1 = 24413。检查是否在0-4095范围内?不在!计算值远大于4095。这说明在200MHz下,无法直接用DWWD实现1秒超时,因为最大超时时间t_max = (4095+1)*8192 / 200,000,000 ≈ 0.167秒。 - 调整方案:要么降低
RTICLK频率(如果支持),要么接受更短的超时时间(如100ms),要么使用RTI的溢出中断配合软件计数器来实现更长周期的看门狗。这里我们调整目标为100ms。DWDPRLD = (0.1 * 200,000,000) / 8192 - 1 ≈ 2441.4 - 1 = 2440。 - 配置窗口:窗口大小25%,即超时前25%的时间窗口打开。对于100ms超时,窗口在最后25ms(即75ms到100ms之间)打开。
- 编写代码:
// 1. 禁用看门狗(如果之前使能了,只能通过复位禁用) // 2. 配置预加载值 (假设RTICLK已正确配置) HWREG(RTI_BASE + RTI_O_DWDPRLD) = 2440; // 3. 配置窗口大小为25% (寄存器字段值需查手册,例如0x2代表25%) HWREG(RTI_BASE + RTI_O_WWDSIZECTRL) = 0x2; // 4. 配置违规动作为产生复位 HWREG(RTI_BASE + RTI_O_WWDRXNCTRL) = 0x1; // 假设0x1代表复位 // 5. 使能数字窗口看门狗 HWREG(RTI_BASE + RTI_O_DWDCTRL) = 0xA98559DA; // 使能密钥,具体值查手册 // 注意:一旦使能,无法通过软件禁用!
- 计算预加载值:要求超时时间
4.2 驱动层设计要点与封装
一个好的RTI驱动应该提供清晰、安全的API,并处理好底层硬件细节。
// rti_driver.h typedef struct { uint32_t baseAddr; // RTI模块基地址 uint32_t rtiClkFreq; // RTICLK频率 (Hz) bool isCounter0Enabled; bool isCounter1Enabled; bool isDwdEnabled; } RTI_Config; typedef enum { RTI_COUNTER_BLOCK_0, RTI_COUNTER_BLOCK_1 } RTI_CounterBlock; typedef enum { RTI_EVENT_0, RTI_EVENT_1, RTI_EVENT_2, RTI_EVENT_3 } RTI_CompareEvent; RTI_Handle RTI_init(const RTI_Config *config); void RTI_deinit(RTI_Handle handle); bool RTI_startCounter(RTI_Handle handle, RTI_CounterBlock block, uint32_t prescale); bool RTI_setupPeriodicInterrupt(RTI_Handle handle, RTI_CompareEvent event, RTI_CounterBlock sourceBlock, uint32_t periodCount); bool RTI_enableDigitalWatchdog(RTI_Handle handle, uint32_t timeoutMs, uint32_t windowSizePercent, bool generateReset); void RTI_feedWatchdog(RTI_Handle handle); uint64_t RTI_getTimeStamp(RTI_Handle handle, RTI_CounterBlock block);在驱动实现中,要特别注意:
- 寄存器访问保护:对关键寄存器的写操作可能需要特权模式或特定的密钥。
- 状态管理:驱动内部应维护模块状态(如哪个计数器已启动、看门狗是否使能),防止重复初始化或非法操作。
- 中断清理:在中断服务程序中,必须清除正确的中断标志位。对于比较匹配中断,除了清除RTI模块自身的
RTIINTFLAG,有时还需要操作RTICOMPxCLR寄存器来清除比较事件。 - 64位时间戳获取:封装一个安全的函数来按正确顺序读取RTIFRCx和RTIUCx,并组合成64位值。
5. 常见问题排查与调试技巧实录
在实际项目中,RTI模块相关的问题可能非常隐蔽。下面是我在多年调试中总结的一些典型问题和排查思路。
5.1 中断不触发或触发异常
- 症状:配置了周期性中断,但一次都没触发,或者触发的频率不对。
- 排查清单:
- 时钟源:确认
RTICLK是否真的在运行?测量相关引脚或通过其他外设间接验证。检查系统时钟配置,确保RTI模块的时钟使能位被置位。 - 计数器使能:
RTIGCTRL中的CNTxEN位是否置1?这是最容易被忽略的一步。 - 预分频值
RTICPUCx:计算是否正确?写入的值是否超出了32位范围?切记不要设为0。 - 比较值与更新值:
RTICOMPx的初始值是否大于当前的RTIFRCx?如果小于当前值,可能需要等待计数器溢出(约49天)才会匹配。RTIUDCPx是否设置正确?如果设为0,则只会触发一次比较。 - 中断使能与路由:
- RTI模块内部中断使能位(
RTISETINTENA)是否设置? - 中断是否在中断控制器(如VIM)中使能?
- 中断服务程序(ISR)向量表配置是否正确?
- CPU全局中断是否开启?
- RTI模块内部中断使能位(
- 中断标志:在ISR中是否清除了
RTIINTFLAG标志?如果未清除,中断只会触发一次。 - 优先级与嵌套:中断是否被更高优先级的中断长时间阻塞?检查中断优先级配置。
- 时钟源:确认
5.2 看门狗意外复位
- 症状:系统运行时偶尔或频繁地无故复位。
- 排查清单:
- “喂狗”时序:这是最常见的原因。用逻辑分析仪或高端调试器的追踪功能,抓取“喂狗”密钥(
0xE51A,0xA35C)的写入序列和时间间隔。- 间隔是否大于超时时间?→ 延长超时时间或优化“喂狗”代码路径。
- 对于DWWD:“喂狗”是否发生在窗口之外?特别是是否在窗口打开前就提前“喂狗”了?这需要精确测量第一个“喂狗”操作相对于看门狗使能时刻的时间。
- 密钥序列错误:检查写入
RTIWDKEY寄存器的两个16位值顺序和数值是否正确。是否有其他代码误写了该寄存器? - 寄存器访问延迟:在高速时钟下,从CPU发出写命令到寄存器生效可能有几个周期的延迟。如果“喂狗”操作卡在超时的临界点,可能因为延迟导致实际生效时已超时。解决方案是提前“喂狗”,留出足够余量。
- 调试器干扰:在调试时,断点会暂停CPU,但看门狗可能仍在计数。确保调试器配置正确(如使用“调试时冻结看门狗”功能),或临时增大超时时间。
- 低功耗模式:系统进入低功耗模式后,
RTICLK可能被关闭或分频,导致看门狗计数变慢或停止。需要根据低功耗模式调整看门狗配置,或确保在进入低功耗模式前禁用看门狗(如果允许)。
- “喂狗”时序:这是最常见的原因。用逻辑分析仪或高端调试器的追踪功能,抓取“喂狗”密钥(
5.3 时间测量或捕获不准
- 症状:用捕获功能测量的代码执行时间或事件间隔,与预期有偏差。
- 排查清单:
- 读取顺序:绝对要检查读取64位捕获值或计数器值的顺序!必须先读高32位(RTICAFRCx/RTIFRCx),再读低32位(RTICAUCx/RTIUCx)。编写一个专用的
RTI_getCapture64()函数来固化这个操作。 - 中断延迟:如果捕获触发源是一个中断,从中断发生到CPU响应、进入ISR、再执行捕获操作,存在中断延迟。这个延迟会引入误差。对于需要极高精度的测量,应考虑使用DMA或硬件直接触发捕获,完全绕过CPU。
- 时钟精度:
RTICLK的精度决定了计时精度。它是来自晶振还是内部RC振荡器?内部RC的精度可能较差(±1%到±5%),不适合高精度计时。对于要求高的应用,应使用外部晶振作为时钟源。 - 计数器溢出:如果你的测量间隔很长,超过了RTIFRCx的溢出周期(
(RTICPUCx+1)*2^32 / f_RTICLK),简单的差值计算会出错。软件需要处理溢出情况,通常通过维护一个软件扩展的高位计数器或在中断中处理溢出标志来实现。
- 读取顺序:绝对要检查读取64位捕获值或计数器值的顺序!必须先读高32位(RTICAFRCx/RTIFRCx),再读低32位(RTICAUCx/RTIUCx)。编写一个专用的
5.4 多计数器同步问题
- 症状:使用两个计数器块分别计时,发现它们之间存在微小的偏移或漂移。
- 分析与解决:Counter Block 0和Counter Block 1虽然是独立的,但它们通常由同一个
RTICLK驱动,理论上应该是同步的。出现偏移可能是因为:- 使能时机不同:两个计数器不是在同一时刻使能的。确保在初始化完成后,再同时置位
CNT0EN和CNT1EN。 - 预分频值不同:不同的
RTICPUCx值导致计数器递增的粒度不同,但这属于正常功能差异。 - 如果要求绝对同步,可以考虑使用Counter Block 0作为主基准,而Counter Block 1通过外部模式(如果支持)或软件同步的方式与其对齐。
- 使能时机不同:两个计数器不是在同一时刻使能的。确保在初始化完成后,再同时置位
调试RTI模块,示波器和逻辑分析仪是你的最佳伙伴。可以直接测量RTI模块输出的中断信号或触发信号,直观地观察定时是否准确、是否如期发生。芯片的寄存器视图和实时变量监控功能也必不可少,可以动态查看计数器、比较寄存器的值,帮助定位配置错误。