1. 从寄存器手册到实战代码:GPTM定时器的深度解析与应用
在嵌入式开发领域,尤其是基于ARM Cortex-M内核的Tiva TM4C系列微控制器,通用定时器模块(GPTM)是工程师手中最核心、最灵活的工具之一。无论是实现一个简单的毫秒级延时,还是驱动复杂的无刷电机,亦或是为实时操作系统提供精准的滴答时钟,其底层都离不开对GPTM寄存器的精准操控。很多开发者拿到数据手册,看到GPTMTBPMR、GPTMTAPR、GPTMTAV等一连串寄存器名称和密密麻麻的位域描述时,往往会感到无从下手。这些寄存器不仅仅是内存中的几个地址,它们共同构成了一个精密的数字时钟系统。理解它们之间的协同关系,就如同理解一个机械钟表的齿轮如何啮合。今天,我们就抛开枯燥的文档翻译,从一个实际开发者的视角,深入拆解GPTM的核心寄存器组,并结合真实的代码场景,让你不仅知道每个寄存器“是什么”,更明白“为什么”要这么配置,以及在实际项目中“怎么用”。
2. GPTM定时器架构与寄存器地图总览
在深入每个寄存器之前,我们必须先建立对GPTM模块的整体认知。Tiva TM4C的GPTM并非一个单一的定时器,而是一个高度可配置的定时器“综合体”。它包含多个定时器单元(如Timer0到Timer5),每个单元又由两个可独立或联合工作的子定时器(Timer A和Timer B)构成。这种设计带来了极大的灵活性:你可以将它们用作两个独立的16位定时器,也可以将它们级联成一个32位甚至64位的“大”定时器,以满足不同精度和范围的需求。
整个模块的寄存器访问基于一个“基地址+偏移量”的内存映射模型。你提供的资料中已经列出了各个定时器模块的基地址,例如16/32位Timer 0的基址是0x4003.0000。这是一个非常重要的起点。所有针对该定时器的配置、控制和状态读取,都是通过在这个基地址上加上一个固定的偏移量来完成的。例如,GPTM控制寄存器(GPTMCTL)的偏移量是0x00C,那么要访问Timer0的控制寄存器,实际地址就是0x4003.0000 + 0x00C = 0x4003.000C。这种设计使得我们可以用一套统一的代码逻辑,通过改变基地址来操作不同的定时器实例,极大地提高了代码的复用性。
GPTM的寄存器大致可以分为几类:配置类(如GPTMCFG, GPTMTnMR)、控制类(如GPTMCTL)、计数与匹配类(如GPTMTnR, GPTMTnMATCHR, GPTMTnPMR)、状态与快照类(如GPTMRIS, GPTMIS, GPTMTnPS, GPTMTnV)。你提供的资料主要聚焦在计数、匹配和快照相关的寄存器上,这些正是实现定时功能的核心。理解这些寄存器,关键在于理解两个核心概念:计数器和预分频器。计数器是核心的计时单元,每个时钟周期加1或减1;预分频器则是一个前置的“减速齿轮”,它可以将系统时钟进行分频后再提供给计数器,从而扩展定时周期。例如,一个16位的计数器最大计数值为65535,如果直接接在80MHz的系统时钟上,最多只能计时约0.8毫秒。但配合一个8位的预分频器(分频值0-255),就可以将定时范围扩展256倍,达到约200毫秒。你资料中反复出现的“预分频匹配寄存器”,正是为了与这种扩展后的定时逻辑相匹配而设计的。
3. 核心寄存器深度解析与实战关联
3.1 GPTM Timer B 预分频匹配寄存器 (GPTMTBPMR)
这个寄存器是理解GPTM扩展定时能力的关键。根据资料,它的偏移地址是0x044。它的作用很明确:当定时器使用了预分频器时,用于扩展GPTMTBMATCHR(Timer B匹配寄存器)的匹配范围。
为什么需要它?我们以最常见的16位定时器模式为例。在16位模式下,GPTMTBMATCHR本身是一个16位寄存器,它决定了计数器计到哪个数值时产生匹配事件。如果没有使用预分频器,那么匹配值就是0到65535之间的一个数。但如果使能了预分频器(通过GPTMTnMR寄存器的TnMR字段配置),定时器的实际“长度”就变成了“预分频器值 * 计数器值”。此时,仅靠一个16位的GPTMTBMATCHR就无法指定完整的匹配点了,因为它只能覆盖计数器的低16位。
GPTMTBPMR就是为了解决这个问题而生的。在16/32位GPTM的16位模式下,GPTMTBPMR的TBPSMR域(低8位)保存了匹配值的第23到16位。这样,完整的24位匹配值就由GPTMTBPMR.TBPSMR(高8位)和GPTMTBMATCHR(低16位)共同组成。计算实际匹配时间T_match的公式就变成了:T_match = (GPTMTBPMR.TBPSMR * 65536 + GPTMTBMATCHR) * T_clock * (Prescale + 1)其中,T_clock是系统时钟周期,Prescale是预分频器加载值(存在GPTMTnPR寄存器中)。
实操心得:在编程时,最容易出错的地方就是忽略了这两个寄存器的联合作用。假设你需要Timer B在使能了预分频器(分频值设为255)的情况下,产生一个1秒的定时中断(系统时钟80MHz)。你的计算步骤应该是:
- 计算所需的总计数周期数:
Total_Ticks = 1秒 / (1/80MHz) = 80,000,000。- 考虑预分频器(+1):
Effective_Ticks = Total_Ticks / (255 + 1) = 80,000,000 / 256 ≈ 312,500。- 这个
Effective_Ticks(312,500)就是需要由GPTMTBPMR和GPTMTBMATCHR联合表示的值。- 分解这个值:
GPTMTBPMR.TBPSMR = Effective_Ticks >> 16 = 312,500 >> 16 = 4(高8位)。GPTMTBMATCHR = Effective_Ticks & 0xFFFF = 312,500 & 0xFFFF = 0x8C34(低16位)。- 在代码中,你需要分别对这两个寄存器进行赋值。顺序很重要:通常先写匹配值寄存器(GPTMTBMATCHR),再写预分频匹配寄存器(GPTMTBPMR),最后再使能定时器,以避免在配置过程中产生意外的匹配事件。
对于32/64位宽GPTM的32位模式,逻辑类似,但位数扩展了。此时GPTMTBPMR的TBPSMRH和TBPSMR两个域共同组成一个16位的值,作为匹配值的高16位(第47到32位),与GPTMTBMATCHR的32位(低32位)共同构成一个48位的匹配值。这为超长定时(例如以小时甚至天为单位)提供了可能。
3.2 GPTM Timer A/B 寄存器 (GPTMTAPR/GPTMTBPR)
这两个寄存器(偏移量0x048和0x04C)是只读的,它们是观察定时器“心跳”的窗口。资料中描述:“在任何情况下该寄存器显示当前Timer A/B计数器的值,输入边沿计数模式的情况除外”。这句话点出了它们的核心功能——实时计数器值读取。
在绝大多数定时模式下(如周期性定时、PWM生成),你读取GPTMTAR或GPTMTBR,得到的就是计数器当前是递增到了哪个数,或是递减到了哪个数。这对于实现非阻塞式的延时检查、计算PWM占空比的实际输出时间等场景非常有用。
但有两个特殊的模式需要特别注意,这也是资料中特别强调的例外情况:
- 输入边沿计数模式:在此模式下,GPTMTnR不再表示时间,而是变成了一个事件计数器。它记录的是在对应输入引脚上捕获到的上升沿或下降沿的个数。这在旋转编码器测速、脉冲流量计等应用中非常关键。
- 输入边沿计时模式:在此模式下,GPTMTnR记录的是上一次边沿事件发生时,计数器的值。这用于测量两个脉冲之间的时间间隔,即计算脉冲周期或频率。
注意事项:读取这些寄存器时,尤其是在32位或64位模式下,需要警惕“原子性”问题。当定时器运行速度很快时,如果你先读取低16位,再读取高16位,在这两次读取之间,计数器可能已经进位,导致你读到一个“撕裂”的错误值(��如低16位是0xFFFF,高16位是0x0001,实际值可能是0x0001FFFF或0x0000FFFF)。对于Tiva的GPTM,在32位模式下,读取GPTMTAR会自动锁存GPTMTBR的值到影子寄存器,保证你读取的32位值是同一时刻的。但在软件层面,对于更宽的数据或需要极高精度的场合,有时需要采取关中断再读取的策略。
3.3 GPTM Timer A/B 值寄存器 (GPTMTAV/GPTMTBV)
这两个寄存器(偏移量0x050和0x054)可能是最容易被误解,但也最具实用价值的寄存器之一。它们是可读可写的。资料指出:“在所有模式下,读取该寄存器返回Timer A/B自由运行的值”。
“自由运行的值”是理解的关键。GPTMTnR寄存器在某些模式下(如单次触发或PWM的匹配点)会复位或重新加载。而GPTMTnV寄存器则不同,它背后连接着一个自由运行的计数器,这个计数器不受匹配事件的影响,会一直不停地计数(在定时器使能的情况下)。这就好比你有两块表,一块(GPTMTnR)是倒计时闹钟,响铃后会重置;另一块(GPTMTnV)是普通的电子表,一直走时不停。
这个特性有什么用?资料里给了非常重要的提示:“在周期操作模式下配合使用快照特性时,软件可以根据该值来判断从发生中断到进入ISR(中断服务程序)之间所用时间。” 这就是中断延迟测量的经典方法。
具体操作流程如下:
- 使能定时器的周期模式并开启中断。
- 在中断服务程序(ISR)中,立即读取GPTMTnV的值。
- 将这个值与预期的匹配值(即你设置的GPTMTnMATCHR等)进行比较。
- 两者的差值,再乘以时钟周期,就是从中断事件发生到CPU实际开始执行ISR第一条指令所经过的时间,即中断响应延迟。
这个值对于评估系统的实时性、优化中断服务程序长度至关重要。此外,向GPTMTAV/GPTMTBV写入值,会在下一个时钟周期加载到GPTMTAR/GPTMTBR中,这为软件同步或强制设置计数器初始值提供了一种手段。
3.4 GPTM RTC预分频寄存器 (GPTMRTCPD) 与预分频快照/值寄存器
这一组寄存器(GPTMRTCPD, GPTMTnPS, GPTMTnPV)揭示了GPTM模块更深层次的工作机制,主要服务于实时时钟(RTC)模式和调试诊断。
GPTMRTCPD(偏移量0x058)仅在定时器配置为RTC模式时有效。RTC模式通常使用一个独立的、更低频率的精确时钟源(如32.768kHz晶振)。GPTMRTCPD就是这个低频时钟源对应的预分频器的当前值。由于RTC用于长时间的日历计时,其计数器(GPTMTAR/GPTMTBR)和预分频器(GPTMRTCPD)都在持续运行。为了原子性地读取一个完整的、不会“撕裂”的时间戳,必须按照特定顺序连续读取这三个寄存器。数据手册中提到的“原子访问”和“参见图11-2”正是这个意思。通常的顺序是:先读GPTMTBR(高位),再读GPTMTAR(低位),最后读GPTMRTCPD(预分频)。有些架构会要求在读取过程中禁止中断,或者硬件有自动锁存机制。
GPTMTnPS(Timer n预分频快照寄存器,偏移量0x05C和0x060)和GPTMTnPV(Timer n预分频值寄存器,偏移量0x064和0x068)则与“快照”功能相关。当定时器配置为某种“快照”模式时(例如在输入边沿捕获模式中),在触发事件(如边沿到来)发生的瞬间,硬件会自动将当前计数器的值锁存到GPTMTnR,同时将当前预分频器的值锁存到GPTMTnPS。而GPTMTnPV则类似于GPTMTnV,它提供预分频器自由运行的值。这些寄存器为高精度时间间隔测量(捕获模式)和系统调试提供了底层数据。
排查技巧:当你发现定时器中断的时间似乎“不准”或者有微小抖动时,除了检查系统时钟配置,一个高级的排查手段就是利用GPTMTAV和GPTMTAPV(或B系列)。在中断服务程序中记录下这两个值,与理论值对比。如果GPTMTAV的偏差是固定的几个时钟周期,那很可能是中断响应延迟;如果偏差是随机的、且与预分频器值(GPTMTAPV)相关,那可能需要检查总线竞争或预分频器时钟是否稳定。
3.5 GPTM外设属性寄存器 (GPTMPP)
这个位于偏移地址0xFC0的寄存器看似简单,却是一个运行时进行硬件识别的关键。它只有一个有效的位域SIZE(位[3:0])。读取这个寄存器,你可以知道当前这个GPTM模块的硬件属性:SIZE=0表示这是一个16/32位的定时器(Timer A和B是16位,带8位预分频);SIZE=1则表示这是一个32/64位的宽定时器(Timer A和B是32位,带16位预分频)。
为什么这很重要?在编写可移植的驱动库或者Bootloader时,你的代码可能需要运行在不同型号的TM4C芯片上,这些芯片的定时器资源可能不同。通过读取GPTMPP寄存器,你的软件可以动态地识别硬件能力,从而决定是使用16位模式还是32位模式,是使用8位预分频还是16位预分频,实现“一次编写,到处运行”。
4. 实战演练:从寄存器配置到功能实现
理解了寄存器原理,我们通过两个典型场景,将知识转化为代码。我们将使用C语言和TI提供的TivaWare固件库进行说明,但会同时揭示库函数背后的寄存器操作,让你知其然更知其所以然。
4.1 场景一:实现一个高精度微秒延时函数
我们通常用SysTick做毫秒延时,但对于几微秒到几十微秒的延时,SysTick粒度太粗,用GPTM则非常合适。假设我们使用Timer0的16位单次触发递减模式。
步骤1:模块使能与时钟配置首先,必须启用Timer0模块的时钟。这是所有外设操作的前提。
// TivaWare库函数方式 SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); // 等待外设就绪(良好习惯) while(!SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER0));库函数SysCtlPeripheralEnable的本质是设置系统控制模块中对应的RCGCx寄存器位,向该位写1,时钟门控打开,Timer0模块获得时钟信号。
步骤2:定时器配置与模式选择接下来配置定时器为16位单次触发递减模式。这涉及到GPTMCFG和GPTMTnMR寄存器。
// 先配置为16位模式(GPTMCFG寄存器写0x00) TimerConfigure(TIMER0_BASE, TIMER_CFG_16_BIT); // 更底层的寄存器操作视角: // HWREG(TIMER0_BASE + GPTM_O_CFG) = 0x0; // GPTMCFG = 0x00 // 配置Timer A为单次触发递减模式(设置GPTMTAMR寄存器) // TIMER_TAMR_TAMSEL_SINGLE | TIMER_TAMR_TAMR_ONE_SHOT TimerLoadSet(TIMER0_BASE, TIMER_A, 0xFFFF); // 初始加载值 TimerMatchSet(TIMER0_BASE, TIMER_A, 0); // 匹配值,递减到0触发 // 底层操作涉及GPTMTnILR和GPTMTnMATCHR寄存器TimerConfigure函数帮我们打包了GPTMCFG和GPTMTAMR的配置。在16位单次触发递减模式下,计数器从加载值(GPTMTnILR)开始递减,减到匹配值(GPTMTnMATCHR)时产生中断(如果使能)并停止。
步骤3:计算并设置加载值(实现延时)延时函数的核心是计算需要的计数值。假设系统时钟是80MHz,我们需要延时us微秒。
void Timer0_DelayUs(uint32_t us) { // 1. 停止定时器,确保配置安全 TimerDisable(TIMER0_BASE, TIMER_A); // HWREG(TIMER0_BASE + GPTM_O_CTL) &= ~TIMER_CTL_TAEN; // 2. 计算计数值。80MHz时钟,每个周期12.5ns。 // 需要的时钟周期数 = 延时时间(us) * 1000 (ns) / 12.5 (ns) // 简化:周期数 = us * 80 uint32_t ticks = us * 80; // 80MHz时钟下,1us对应80个周期 // 3. 检查是否超出16位计数器范围(0-65535) if(ticks > 0xFFFF) { // 如果延时过长,需要启用预分频器,这里为简化假设ticks在范围内 // 实际应用中,应计算预分频值Prescaler = (ticks / 65536) - 1 // 然后设置GPTMTnPR寄存器,并将ticks调整为 ticks = ticks / (Prescaler+1) return; // 或处理错误 } // 4. 设置加载值和匹配值(递减模式,从ticks减到0) TimerLoadSet(TIMER0_BASE, TIMER_A, ticks); TimerMatchSet(TIMER0_BASE, TIMER_A, 0); // 底层:HWREG(TIMER0_BASE + GPTM_O_TAILR) = ticks; // HWREG(TIMER0_BASE + GPTM_O_TAMATCHR) = 0; // 5. 清除可能存在的旧中断标志,并重新使能定时器(单次触发) TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT); TimerEnable(TIMER0_BASE, TIMER_A); // 底层:HWREG(TIMER0_BASE + GPTM_O_ICR) = TIMER_TIMA_TIMEOUT; // HWREG(TIMER0_BASE + GPTM_O_CTL) |= TIMER_CTL_TAEN; // 6. 等待超时标志置位(阻塞式延时) while(!TimerIntStatus(TIMER0_BASE, false) & TIMER_TIMA_TIMEOUT) { // 空循环等待 } // 7. 延时结束,清除标志位 TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT); }这个函数展示了如何将抽象的“延时”需求,转化为对GPTMTnILR(加载值)、GPTMTnMATCHR(匹配值)和GPTMCTL(控制使能)寄存器的具体操作。阻塞式等待TimerIntStatus就是不断查询GPTMRIS(原始中断状态)寄存器的相应位。
4.2 场景二:生成一路PWM信号
使用GPTM生成PWM是另一个核心应用。我们使用Timer1的16位周期模式,并启用PWM输出功能。
步骤1:初始化与模式配置
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); // 假设PWM从PF2引脚输出 while(!SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER1)); while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOF)); // 配置GPIOF2引脚为Timer1的PWM输出功能 GPIOPinConfigure(GPIO_PF2_T1CCP0); GPIOPinTypeTimer(GPIO_PORTF_BASE, GPIO_PIN_2); // 配置Timer1为16位周期PWM模式 // TIMER_CFG_16_BIT_PAIR 和 TIMER_CFG_A_PWM 是库提供的便捷宏 TimerConfigure(TIMER1_BASE, TIMER_CFG_16_BIT_PAIR | TIMER_CFG_A_PWM); // 底层操作:设置GPTMCFG=0x4,GPTMTAMR=0xA(周期模式,PWM使能)这里的关键是TIMER_CFG_A_PWM,它告诉定时器硬件,将匹配事件与引脚输出控制逻辑关联起来。
步骤2:设置PWM周期与占空比PWM周期由定时器的加载值决定,占空比由匹配值决定。在递减计数PWM模式下,输出在计数器等于匹配值时由高变低,在计数器重载时由低变高。
// 假设系统时钟80MHz,期望PWM频率为1kHz uint32_t sysClock = SysCtlClockGet(); // 获取系统时钟频率,假设80,000,000 uint32_t periodTicks = sysClock / 1000; // 1kHz对应的周期计数值 = 80,000 // 由于periodTicks=80000 > 65535,必须使用预分频器 // 计算预分频值:Prescaler = (periodTicks / 65536) - 1 uint32_t prescaler = (periodTicks >> 16); // 等价于除以65536 TimerPrescaleSet(TIMER1_BASE, TIMER_A, prescaler); // 底层:设置GPTMTAPR寄存器 // 重新计算计数器加载值(预分频后) uint32_t timerLoad = periodTicks / (prescaler + 1); // 80000 / (1+1) = 40000 TimerLoadSet(TIMER1_BASE, TIMER_A, timerLoad); // 设置周期 // 设置占空比为50%,即匹配值为周期的一半 uint32_t matchValue = timerLoad / 2; TimerMatchSet(TIMER1_BASE, TIMER_A, matchValue); // 设置占空比 // 注意:在PWM模式下,GPTMTnMATCHR寄存器决定了输出反转点步骤3:使能PWM输出并启动定时器
// 使能Timer A的PWM输出功能(在GPTMCTL寄存器中设置TnPWML位) TimerControlLevel(TIMER1_BASE, TIMER_A, true); // 设置输出为高电平有效 // 底层:HWREG(TIMER1_BASE + GPTM_O_CTL) |= TIMER_CTL_TAPWML; // 最后,使能定时器开始运行 TimerEnable(TIMER1_BASE, TIMER_A);在这个例子中,我们遇到了和GPTMTBPMR类似的情况:因为需要的计数值超过了16位计数器的范围,我们启用了预分频器(通过TimerPrescaleSet设置GPTMTAPR)。此时,PWM的实际周期由(GPTMTAPR + 1) * GPTMTnILR共同决定。而占空比则由GPTMTnMATCHR决定。这里我们不需要使用GPTMTnPMR,因为PWM模式下的匹配逻辑通常只关心计数器本身的值,预分频器被视为时钟源的一部分。但如果你需要产生一个周期和占空比都极其精确,且数值非常大的PWM,理解预分频匹配寄存器的机制仍然是必要的。
5. 调试技巧与常见问题排查实录
即使理解了所有寄存器,实际调试中依然会遇到各种问题。下面是我在多年项目中总结的一些典型问题和排查思路。
问题1:定时器中断根本不触发。
- 检查清单:
- 时钟门控:是否调用了
SysCtlPeripheralEnable?用SysCtlPeripheralReady检查是否真的就绪了。 - 中断使能:是否在NVIC(嵌套向量中断控制器)中使能了定时器中断?
TimerIntEnable只是打开了定时器模块内部的中断源,还需要IntEnable和IntMasterEnable(通常由Startup代码完成)。 - 全局中断:是否开启了全局中断(
__enable_irq()或等效操作)? - 模式与匹配值:定时器模式(GPTMTnMR)配置是否正确?是单次触发还是周期模式?匹配值(GPTMTnMATCHR)设置是否合理?在递减模式下,匹配值必须小于加载值,否则永远不会匹配。
- 控制寄存器:GPTMCTL寄存器中的
TnEN位(定时器使能位)是否置1?
- 时钟门控:是否调用了
问题2:中断触发的时间间隔与预期不符。
- 排查步骤:
- 计算复核:首先用计算器或代码仔细复核计数值的计算过程。考虑预分频器是“+1”的(即分频值N,实际分频比为N+1)。
- 系统时钟:确认
SysCtlClockGet()返回的系统时钟频率是否与你的预期一致。如果使用了PLL,配置是否正确? - 寄存器查看:在调试器中,直接查看GPTM相关的寄存器:GPTMCFG, GPTMTnMR, GPTMTnILR, GPTMTnMATCHR, GPTMTnPR。确认它们的值是否与你的软件设置一致。特别注意GPTMTnPR(预分频寄存器),它默认是0,如果你计算时考虑了预分频但忘记设置它,定时会快很多倍。
- 中断延迟:使用前面提到的GPTMTnV寄存器测量中断响应时间。如果延迟较大且不稳定,可能是中断优先级太低,被其他高优先级中断或临界区代码阻塞。
问题3:PWM输出频率或占空比不准。
- 排查方向:
- 引脚复用:确认GPIO引脚是否正确配置为定时器外设功能(
GPIOPinConfigure)。 - PWM模式:确认GPTMTnMR寄存器中是否正确配置了PWM模式。在PWM模式下,输出行为由硬件自动管理,与普通定时器中断模式不同。
- 电平极性:检查GPTMCTL寄存器的
TnPWML位。它控制PWM输出是高电平有效还是低电平有效。设置错误会导致占空比意义相反。 - 加载值与匹配值关系:在递减PWM模式下,输出在计数器等于匹配值时翻转。确保你的占空比计算逻辑与模式匹配。例如,50%占空比时,匹配值应设置为加载值的一半。
- 引脚复用:确认GPIO引脚是否正确配置为定时器外设功能(
问题4:在输入捕获模式下,捕获的值跳动很大。
- 可能原因与解决:
- 边沿去抖:被测量的信号可能存在抖动。需要在外部硬件或软件上增加滤波电路,或者使用定时器的输入边沿去抖功能(如果支持)。
- 中断处理延迟:在高速信号捕获时,中断响应和处理的延迟可能导致丢失脉冲或计时不准。考虑使用DMA直接将捕获寄存器的值搬运到内存,或者使用定时器的“连续捕获”模式(一个事件触发后自动准备下一次捕获,无需软件立即干预)。
- 原子性读取:在32位捕获模式下,读取捕获到的计时值(可能存放在GPTMTnR和GPTMTnPS中)时,必须确保读取的完整性,防止在读取高低位之间发生进位。
终极调试工具:寄存器视图与数据手册。当遇到任何无法解释的现象时,最有效的办法就是打开调试器的寄存器查看窗口,对照芯片的数据手册(Technical Reference Manual, TRM),逐位核对所有相关寄存器的值。数据手册中的寄存器描述、时序图和操作流程,是解决一切疑难杂症的最终依据。你提供的这份寄存器资料,正是数据手册的核心片段。养成“遇事不决查手册”的习惯,是嵌入式工程师成长的必经之路。