做电机控制或者数字电源的朋友,对 F28035 这颗芯片应该不陌生。它的 HRCAP 模块,全称 High-Resolution Capture,也就是高分辨率捕获模块,官方文档里写得很全,但说实话,自学门槛并不低。如果你只是像看小说一样把技术参考手册从头翻到尾,大概率会在 MEP、Time Stamp、Capture 通道这些概念里绕晕,最后除了记住几个寄存器名字,什么也没留下。
这篇文章是我自己啃 HRCAP 官方文档、在板子上反复调试总结出来的自学路线。我会告诉你先看哪份文档、后看哪份文档,HRCAP 到底在捕什么、精度从哪来,以及最关键的——寄存器该怎么配、代码该怎么写、坑在哪里。不管你是刚接触 C2000 系列的新手,还是已经调过普通 eCAP 但没碰过 HRCAP 的工程师,这篇文章应该都能帮你少走一大段弯路。
1. F28035 HRCAP 到底是个什么东西
1.1 HRCAP 解决了什么痛点
先说说这个模块存在的意义。普通捕获模块 eCAP,大家应该都熟:输入引脚上来了一个边沿,硬件就把当前计数器的值锁存到寄存器里,然后产生中断,软件去读这个时间戳。整个过程没有任何问题,但分辨率受限于系统时钟周期。
F28035 主频通常跑到 60MHz,一个系统时钟周期大约是 16.67ns。如果你捕获一个 100kHz 的 PWM 信号,周期是 10μs,16.67ns 的分辨率换算成频率误差大约是 0.17%,勉强能接受。但如果信号频率上到 1MHz,周期只有 1μs,同样 16.67ns 的分辨率带来的频率误差就超过 1.6%。在电机控制或者 LLC 电源里,这个精度远远不够。
HRCAP 的核心思路是在普通捕获的粗计数基础上,额外加了一个微边沿定位器,英文叫 MEP,Micro Edge Positioner。它能把一个系统时钟周期再细分出很多个小步进,这样一来,捕获时间戳的分辨率就从十几纳秒直接干到了皮秒级。F28035 的 MEP 步长虽然不同芯片有差异,但典型量级在 200ps 左右,相当于把一个 60MHz 的时钟周期切成了大约 80 份。
这才是 HRCAP 存在的真正理由:在高频信号面前,普通捕获模块的时钟计数分辨率不够用了,必须用硬件把边沿时间戳的位置“精修”到皮秒级。
1.2 HRCAP 与普通 eCAP 的差异在哪
了解差异之前,得先知道两者在硬件上有什么不同。普通 eCAP 的时间戳来源是系统时钟或者 Auxiliary Clock,单位就是一个个完整时钟周期。HRCAP 模块引入了一个 MEP 使能开关,打开之后,每次捕获事件发生时,硬件不仅锁存一个 24 位的粗计数,还会锁存一个 8 位的 MEP 分数值。这个 8 位分数值就代表捕获边沿落在当前时钟周期内部的精确位置。
用生活化的方式理解:普通 eCAP 相当于用一把厘米刻度的尺子量物体长度,量出来的结果总是整数厘米,误差最大能达到 1 厘米。HRCAP 相当于在同一把尺子上又加了一层毫米刻度,你能读出 10.3 厘米、10.7 厘米这种小数点后的精确值。对于高频信号测量来说,这层“毫米刻度”就是决定精度的关键。
另外,两者的配置思路也不同。普通 eCAP 只需要配置边沿极性、计数器分频、中断使能,基本就能工作。HRCAP 在进入正常工作之前,必须先完成 MEP 标定。这部分在官方文档里写得很细,但自学的时候很容易被忽略——如果不标定就开 HRCAP,读出来的时间戳连趋势都是不对的,更别提精度了。后面第 4 节我会专门讲标定的计算逻辑。
1.3 自学之前需要哪些前置知识
如果你是零基础直接上手 HRCAP,我建议先花点时间打底子。至少需要清楚时钟树的基本结构,知道 SYSCLK 是从哪来的、怎么分频;需要用过 GPIO 复用功能,不然你都不知道要把 HRCAP 的输入引脚切换到哪个复用编号;还要理解中断控制器 PIE 的工作流程,因为 HRCAP 捕获完成后要产生中断,你要在 PIE 里把对应的中断向量使能、挂接。
这些前置知识不需要精通,但至少要能看懂时钟图、能查复用表、能配 PIE。F28035 的官方技术参考手册里面都有对应章节,只是不像 HRCAP 章节这么难啃。我个人的建议是:先花一晚上把 GPIO、时钟、PIE 三块的入门内容过一遍,然后再正式进入 HRCAP 的自学。不然你配完 HRCAP 寄存器,中断却一直进不去,到时候根本分不清是 HRCAP 没配置对,还是 PIE 没配对。
2. 官方文档自学路径与资源地图
2.1 先看哪份文档、后看哪份文档
HRCAP 相关的官方资料主要有三份:芯片的数据手册、技术参考手册、以及 MEP 标定相关的应用笔记。三份文档的定位完全不同,学习顺序不能乱。
先看数据手册里的 HRCAP 部分。这个部分篇幅不长,主要是模块特性概览、电气参数、以及最重要的 MEP 分辨率参考值。数据手册的价值在于让你知道这个模块“能做到什么”:支持的输入通道数、时间戳位宽、MEP 步长的典型范围。有了这些数字打底,再去看技术参考手册会轻松很多。
第二步是技术参考手册的 HRCAP 章节。F28035 对应手册里这一章大概会占三四十页,内容包含模块框图、寄存器说明、操作模式、中断事件、以及 MEP 标定流程。这是整个自学过程中最核心的部分,但也最容易让人放弃。我的建议是不要逐字逐句读,先看模块框图搞清数据流,再看寄存器汇总表搞清控制位,最后回到操作模式章节看配置步骤。
第三步是应用笔记里关于 MEP 标定的内容。这份资料的重要性非常高。MEP 的步长受工艺、温度、电压影响,每颗芯片都不同,甚至同一颗芯片在不同温度下也会漂移。应用笔记会给出标定算法和参考代码,这部分必须吃透。
提示:读技术参考手册时,如果发现某个寄存器位描述读不懂,先跳过,回到模块框图里找这个信号流向。HRCAP 的寄存器位之间关联性很强,单独看一个位常常看不出所以然。
2.2 技术参考手册里 HRCAP 章节的精读顺序
技术参考手册的 HRCAP 章节,不要按页码顺序读,我建议按下面这个顺序精读。
第一,读模块功能概述和特性列表,也就是 Features 部分。这里通常会把“支持边沿时间戳”“支持绝对值/相对值捕获”“MEP 标定由硬件辅助完成”这些最关键的信息浓缩在几十行里。把这些话读懂,整个模块的骨架就有了。
第二,读功能框图。HRCAP 的框图会画清楚输入多路复用、边沿检测、时间戳锁存、MEP 校准、中断产生这一整条链路。你去看输入信号是怎么从 GPIO 引脚一路流到比较寄存器、再到时间戳缓冲区的,这个数据流搞清楚之后,后面的寄存器配置就顺理成章了。
第三,读操作模式。HRCAP 支持绝对时间戳捕获、相对时间戳捕获以及连续捕获。绝对模式适合测量信号从启动以来的时刻,相对模式适合测量周期和脉宽。这两种模式的差异在应用场景上是关键。量占空比用相对模式,算相位用绝对模式,搞混了的话数据完全没法用。
第四,读标定相关章节。MEP 标定会涉及一个专门的控制寄存器、一个状态标志,以及标定窗口的计数逻辑。这部分我会在第 4 节详细展开,精读的时候你重点抓住“标定窗口长度怎么定”和“标定结果怎么用”这两条主线就行。
2.3 数据手册里哪些参数和 HRCAP 强相关
数据手册里与 HRCAP 强相关的参数,主要集中在“电气特性”或者“外设特性”小节。重点关注三个东西。
第一个是 MEP 的步长范围,通常在数据手册里会给一个典型值和最大/最小值,单位是皮秒。这个参数决定了你最终时间戳的分辨率上限。
第二个是 HRCAP 输入引脚的施密特触发滞回电压、输入漏电流。如果输入信号边沿比较缓,或者幅值不干净,这些参数会影响捕获的稳定性。
第三个是 MEP 标定的窗口计数与误差模型。这部分内容不一定在数据手册里,可能只在应用笔记里。如果官方给了误差预算表,一定要截下来做成笔记,后面调试现场定位问题的时候对照着查非常有用。
实操心得:我在第一次做 HRCAP 时,就是只看技术参考手册没看数据手册,结果忽略了一个关键参数——不同封装下 MEP 步长的温度漂移范围。板子在高低温箱里跑的时候,测出来的频率一直往一个方向飘,查了半天才想起数据手册里有这组曲线。所以这两份文档一定要搭配着看,缺一不可。
3. HRCAP 工作原理拆解:从捕获事件到高分辨率时间戳
3.1 MEP 微边沿定位器的工作逻辑
MEP 是整个 HRCAP 的灵魂。它本质上是一条延迟链,输入信号边沿经过这条延迟链时,会以一个非常短的时间单位被逐步延迟。边沿在延迟链中传播到的位置,就是它在当前时钟周期内部“更精确”的时间位置。
F28035 的 MEP 是配合系统时钟工作的。当捕获事件触发时,系统时钟计数器已经锁存了一个整周期的粗计数,而 MEP 的延迟链则负责在亚时钟周期尺度上细分。打个比方:粗计数告诉你信号边沿发生在第 352 个时钟周期,MEP 告诉你这是在第 352 个周期的 45% 位置上。两者拼起来,才是一个完整的高分辨率时间戳。
理解这一点对后续配置很重要。MEP 不是独立于系统时钟的另一个时基,而是系统时钟内部的“游标卡尺”。它不能单独工作,必须先有粗计数作为整数部分,再叠加 MEP 分数作为小数部分,两个部分合起来才构成有效时间戳。
3.2 时间戳数据格式:24 位计数器加 MEP 分数位
HRCAP 的捕获时间戳寄存器位宽,官方文档会写得比较明确:高位部分对应粗计数值,一般为 24 位,低位部分对应 MEP 分数,共 8 位。粗计数值的时钟源通常是系统时钟,所以时间戳的实际时间值 = 粗计数值 × 系统时钟周期 + MEP 分数位对应的亚周期时间偏移。
MEP 分数位的含义不是普通二进制码,它表示当前时钟周期里 MEP 延迟链走了多少步。所以要把时间戳换算成物理时间,需要知道“一个系统时钟周期等于多少个 MEP 步”。这个比例关系正是标定要做的事。
需要特别提醒的是,MEP 分数位的 8 位数值,实际精度取决于 MEP 步长覆盖整个系统时钟周期所需的步数,这个步数通常远小于 256。也就是说,MEP 分数位的高几位有效,低几位基本是噪声,读取换算时不要傻乎乎地把 8 位全部当作等精度有效位数。官方应用笔记里会给出一个安全精度位数建议,按那个来就行。
3.3 SYNC 同步与时钟分频的配置逻辑
HRCAP 的粗计数时钟并不是只能直接用系统时钟,它支持一定的分频选择。这个分频位的配置逻辑,需要结合你要测量的信号频率来决定。
如果被测信号频率很低,比如几十赫兹,系统时钟周期才 16.67ns,粗计数器很快就会溢出。这时可以通过分频降低粗计数的时钟频率,让时间戳的范围覆盖更长的周期。如果被测信号频率很高,比如几兆赫兹,那应该尽量使用高频时钟作为粗计数时钟,否则整个时间戳的整数部分跳动幅度过大,MEP 的细分优势就被稀释了。
SYNC 同步信号的作用,是把 HRCAP 的时基和外部的某种参考事件对齐。比如你要测量多个通道之间的相位关系,如果不做同步,各通道的计数起点不同,测出的相位差就是错的。F28035 的 HRCAP 参数配置里通常会有一个同步源选择位,把这个配好,再配合 GPIO 的同步输入,就能保证多通道测量的相位基准一致。
这个模块我用下来的体会是:SYNC 和分频的配置,比设置边沿极性更值得花时间想清楚。很多人只记得“捕获上升沿、使能中断”,忽略了时基对齐问题,结果单通道测量没问题,一旦做多通道相位差就开始出现莫名其妙的固定偏置。
4. 手把手配置 HRCAP 寄存器的实操步骤
4.1 最简配置:捕获一个 PWM 上升沿
我们先从最简场景开始:捕获一个外部 PWM 信号的上升沿,读取绝对时间戳。所有代码基于寄存器操作,方便你对照官方手册理解。
第一步,配置 GPIO。HRCAP 输入引脚要先做复用切换,否则信号到达不了外设模块。以 F28035 的某个 HRCAP 输入通道为例,找到 GPIO 复用寄存器,把对应引脚切到 HRCAP 通道功能。
// GPIO 复用为 HRCAP 输入通道 GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 0; // 假设 GPIO0 复用为 HRCAP 输入 GpioCtrlRegs.GPADIR.bit.GPIO0 = 0; // 输入方向第二步,使能 HRCAP 时钟。F28035 外设模块默认时钟是关闭的,在哪打开你要去芯片系统控制寄存器里找。一般会有对应的 PCLKCR 寄存器,把 HRCAP 的位使能即可。
SysCtrlRegs.PCLKCR0.bit.HRCAPENCLK = 1; // 使能 HRCAP 外设时钟第三步,配置捕获通道和边沿极性。HRCAP 的捕获通道映射、上升沿还是下降沿,都在相应控制寄存器里配置。我这里给出一个基础配置,具体寄存器偏移地址以你的芯片手册为准。
// 配置 HRCAP 通道、极性、时间戳模式 HRcapRegs.HRCRD = 0; // 清状态寄存器 HRcapRegs.HRCNTH = 0; // 清粗计数器高位 HRcapRegs.HRCNTL = 0; // 清粗计数器低位 HRcapRegs.HRCCR = 0; HRcapRegs.HRCCR.bit.CHANSEL = 0; // 选择输入通道 HRcapRegs.HRCCR.bit.POL = 0; // 0:上升沿,1:下降沿 HRcapRegs.HRCCR.bit.MEPEN = 1; // 使能 MEP HRcapRegs.HRCCR.bit.CAPMODE = 0; // 0:绝对时间戳,1:相对时间戳第四步,启用捕获事件中断。F28035 的每个外设中断都会映射到 PIE 的特定分组,你要把 HRCAP 中断使能位打开,然后在 PIE 里把对应向量挂到中断服务函数。
HRcapRegs.HRCINTEN.bit.CAPIE = 1; // 捕获事件中断使能 PieCtrlRegs.PIEIER6.bit.INTx4 = 1; // 假设 HRCAP 中断映射到 PIE 第 6 组的第 4 个这些配置做完之后,HRCAP 就能在输入边沿到来时锁存时间戳并产生中断。但要想数据有意义,别忘了第 4.2 节的 MEP 标定。
4.2 标定 MEP 的流程与计算公式
MEP 标定是 HRCAP 使用中最绕不开的一步。官方手册和 GitHub 上一些开源代码会给出参考实现,但如果你只看代码不看原理,抄过来也不知道为什么这么写。
标定的核心逻辑是这样的:MEP 延迟链上每一步的时间长度,受工艺和温度影响,不是恒定值。为了知道一个系统时钟周期对应多少 MEP 步,硬件提供了一个辅助标定机制。你在某个配置位写 1 启动标定,硬件会在接下来的两个系统时钟上升沿之间记录 MEP 延迟链能走多少步。
这里遇到了一个矛盾:如果直接用外部信号边沿做标定基准,外部信号本身就有抖动;所以官方做法是利用两个相邻系统时钟边沿作为标定窗口,因为这两个边沿的时间差严格等于一个系统时钟周期。MEP 在这一个周期内走过的步数,就代表了一个周期的 MEP 步长当量。
公式很简单:
( MEP_STEPS_PER_CLK = MEP_CAL_COUNT )
每个 MEP 步的时间 = ( T_{SYSCLK} / MEP_STEPS_PER_CLK )。
时间戳总时间 = ( coarse_count \times T_{SYSCLK} + mep_frac / MEP_STEPS_PER_CLK \times T_{SYSCLK} )。
标定过程的典型实现,是定时刷新标定值。比如每隔一段时间重新标定一次,或者连续采样若干次求平均。具体怎么选,参考官方应用笔记的推荐即可,但一定要做这一点,否则精度无从谈起。
注意:不要在标定过程中关闭外设时钟,也不要在标定完成之前读取时间戳寄存器。我试过在标定未完成时就开中断读数据,读出来的 MEP 分数位乱成一团,而且每次复位后表现还不一样。
4.3 中断与数据读取的典型代码框架
中断服务函数里,第一步应该读取时间戳寄存器,第二步确认中断标志并清除,第三步才做业务处理。顺序不要搞反。
interrupt void hrcap_isr(void) { // 读取时间戳,注意高低位寄存器都要读 Uint16 coarseHigh = HRcapRegs.HRTSH; Uint16 coarseLow = HRcapRegs.HRTSL; Uint16 mepFrac = HRcapRegs.HRMFRAC; // 清除中断标志 HRcapRegs.HRCCLR.bit.CAPCLR = 1; // 业务处理:换算时间、算频率、算占空比 timestamp = ((Uint32)coarseHigh << 16) | coarseLow; time_ns = (timestamp / MEP_STEPS_PER_CLK) * CLK_PERIOD_NS; }中断函数里尽量只做数据提取和标志清除,剩余的换算运算放到主循环或者控制任务里。HRCAP 的中断频率可能很高,尤其连续捕获模式下,如果 ISR 里做太多浮点运算,CPU 开销会非常大,而且容易干扰其他实时任务。
数据读取时还有一个细节:时间戳寄存器的读取顺序。部分芯片要求在读取低位寄存器时,同时把高位值锁存,避免先读低、再读高过程中数据已经更新。具体以官方文档为准,但无论如何有个原则——一旦检测到中断标志,随即读取,不要在中断里翻来覆去地等待,这样最容易丢数据。
5. 常见问题与排查技巧实录
5.1 捕获时间戳一直为 0
这是我在社区里看到最多的问题。明明配置了 HRCAP,输入信号也接好了,中断偶尔进一下,但读出来的时间戳永远是 0。
排查思路分三步。第一步,检查 GPIO 复用是否生效。很多人只配了外设寄存器,忘了切 GPIO 复用,信号根本进不了 HRCAP 模块。第二步,检查 HRCAP 模块是否漏开了时钟,外设时钟没打开,寄存器写进去的配置读回来看是对的,但硬件完全不工作。第三步,检查标定状态位。如果 MEP 未完成标定,模块可能不会产生有效的时间戳。
如果以上三步都没问题,再用示波器确认输入信号是否符合电平规范。HRCAP 输入对信号边沿质量比较敏感,如果边沿太缓,无法触发捕获事件。
5.2 MEP 标定值异常导致精度反而变差
标定值偏移是一个隐蔽问题。比如你按默认配置标定,算出来一个系统时钟周期对应 72 个 MEP 步,但实际温度变化后发现对应关系已经变成 68 步。此时再用旧的 72 步去换算时间,误差会明显增大。
一个实用的做法是在连续标定模式中,每次读取标定结果时做有效性判断,如果标定值和上次相差超过某个阈值,就丢弃并重新标定。官方应用笔记里通常会给一个标定值合理范围,你可以根据经验校准这个阈值。
此外,标定窗口本身也有讲究。标定请求发出后,需要等待标定窗口结束。这个窗口长度不是固定的,受到系统时钟和 MEP 标定配置影响。如果你配置的分频系数太大,标定窗口内 MEP 走不到完整覆盖,得到的步数就不准。尽量让粗计数时钟频率保持在一个合理范围,确保标定窗口覆盖完整时钟周期。
5.3 中断频率过高导致 CPU 占用
HRCAP 用于高频 PWM 测量时,中断频率可能达到几百 kHz。此时如果每个边沿都进一次中断,CPU 开销非常惊人。
解决方案有两种思路。其一,尽量使用连续捕获缓冲区,让硬件连续捕获多个时间戳,软件定期批量搬走数据。这种模式减少中断次数,但需要注意缓冲区溢出问题。其二,只在上溢或特定条件下开中断,平时主循环直接查询 FIFO 状态。F28035 的 HRCAP 是否带 FIFO,需要查具体型号的参考手册,但查询方式的值状态寄存器始终存在。
我自己的做法是:在高速场景下,把 HRCAP 中断优先级降低,主控制任务通过轮询方式周期性地读取一批时间戳,再统一做换算。实测下来 CPU 占用率下降非常明显,而且高精度特性完全不受影响。
5.4 HRCAP 与 PWM 输出的配合时序问题
最后说一个联动场景。很多人用 HRCAP 测量由片内 PWM 模块产生的信号,比如测自己发出的 PWM 频率有没有漂移。这时候问题就来了:PWM 输出信号需要经过引脚、外部回环或者探针,再进入 HRCAP 输入,这段链路在高速切换时会产生传输延迟和信号抖动。
我在实测中发现,外部回环测量时,HRCAP 捕获到的频率总比 PWM 配置值偏大一点。原因是 PCB 布线和电平转换产生的延迟几乎可以忽略,但触发边沿的位置受 GPIO 输出驱动能力影响,低电平到高电平的过渡时间不一样,导致捕获点轻微偏移。应对办法是尽量使用施密特触发特性好的引脚,并在 HRCAP 输入端加一点滤波或者钳位电路,保证边沿位置稳定。
这类问题在官方文档里不会写,但它确实影响你最终测量结果的准确度。调试时如果发现频率测量值和理论值相差不大却稳定存在,优先怀疑边沿触发位置,而不是怀疑 HRCAP 模块本身。
6. 踩过几次坑之后,我对 HRCAP 自学的几点心得
关于 F28035 HRCAP 自学,我最想强调的其实不是寄存器怎么配,而是心态。技术参考手册的 HRCAP 章节是出了名的信息密集,你看第一遍几乎记不住任何东西。我当时的办法是:先看完功能框图,然后在板子上做一个最最简单的捕获实验,把时间戳读出来,对照手册里“时间戳数据格式”那一小节,一层层地把数据拆开看懂了,再回去读寄存器描述,忽然就顺畅了。
MEP 标定也是一个容易让人劝退的点。它不像 GPIO 那样翻到某个寄存器就能直接用,你需要建立“系统时钟周期 = MEP 步数 × MEP 步长”这个换算意识。我这个想法建立之后,再看那些标定代码和计算宏,逻辑就变得非常清晰。建议你也在自己的工程里把时间和步数的换算单独封装成函数,方便随时调试和校准。
最后一个小技巧:HRCAP 的时间戳寄存器不要只在中断里读,也可以把它做成一个环形缓冲区,定期导出到调试器里观察。这样能直观看到时间戳的连续性、抖动大小,以及是否有偶发的跳变值,定位问题比对着单次数据猜快得多。