TPWM — PWM 测量模式(TIM PWM Measurement Mode)

TIM_MODE = 0b000,依赖 CLK_SEL。手册 13.4.2.1。

1. 一句话说明

测量输入 PWM 信号的脉宽(占空比)周期,结果存入 GPR0(脉宽)与 GPR1(周期)。


2. 时钟来源与选择

项目 来源 说明
计数时钟 CMU 时钟 CNTCCM[i]_CLK_RES[CLK_SEL] 递增,直到检测到下降沿(DSL=1 时)
时钟选择 CTRL.CLK_SEL [26:24] 从 CCMi_CLK_RES0..7 中选一路
时间戳 TBU 通过 GPR0_SEL/GPR1_SEL 可选 TS0/TS1/TS2 打时间戳

计数分辨率 = 所选 CMU 时钟周期。例如 CLK_SEL 选 50ns 分辨率,则 CNT 每 50ns +1。


3. 计数模式

  • CNT 递增计数:在有效电平期间按 CMU 时钟递增;
  • 下降沿(DSL=1):把 CNT 值存入影子寄存器 CNTS(脉宽),CNT 继续计数直到下一个上升沿(周期);
  • 上升沿(DSL=1):CNTS 值 → GPR0(脉宽),CNT 值 → GPR1(周期),随后 CNT 清零并触发 NEWVAL;
  • 之后每个离开 DSL 定义电平的边沿都会更新 CNTS。

起始条件

  • IMM_START=0:等首个 DSL 定义的边沿(DSL=1 时等上升沿)才开始;

  • IMM_START=1:通道使能(TIM_EN=1)后立即开始。

DSL 极性

  • DSL=1:测高电平脉宽 + 周期(高电平占空比);

  • DSL=0:测低电平脉宽 + 周期(低电平占空比),等下降沿开始。

ECNT_RESET

  • =0:CNT 在 DSL 定义的有效边沿 清零;

  • =1:CNT 在每个输入边沿都清零。

SWAP_CAPTURE:交换 GPR1 与 CNTS 的捕获边沿(见手册 Table 17 详细动作表)。


4. 外部读取的内容

寄存器 默认内容(EGPRx_SEL=0, GPRx_SEL=11) 读取方式
GPR0 脉宽长度(脉宽计数值) 先读 GPR1,再读 GPR0(读 GPR0 即 ACK)
GPR1 周期长度(周期计数值)
CNTS 脉宽影子值 可选读出

通过 GPR0_SEL/GPR1_SEL 可改为读 TBU 时间戳等。

数据一致性 :可用 ECNT[7:1] 校验 GPR0/GPR1 是否一致(防止读取瞬间被更新)。


5. 对应中断

中断 触发
NEWVAL 一个完整 PWM 周期测量完成(GPR0/GPR1 更新)
CNTOFL CNT 溢出(0xFFFFFF→0)
ECNTOFL ECNT 溢出
GPROFL 上次数据未消费即被覆盖

5a. 周期与占空比测量方法(重点)

TPWM 是 GTM 里**测单周期脉宽+周期(占空比/频率)**的唯一正选模式。完整步骤:

复制代码
配置:
  CTRL.TIM_MODE  = 0b000        // TPWM
  CTRL.DSL       = 1            // 测高电平脉宽(=0 则测低电平脉宽)
  CTRL.CLK_SEL   = 选 CMU 分辨率 // 如 CLK0=20MHz → 50ns/bit
  CTRL.GPR0_SEL  = 0b11, EGPR0_SEL=0   // GPR0 ← CNTS(脉宽)
  CTRL.GPR1_SEL  = 0b11, EGPR1_SEL=0   // GPR1 ← CNT(周期)
  ECTRL.IMM_START= 0            // 等首个 DSL 边沿开始
  CTRL.TIM_EN    = 1

测量时序(DSL=1):
   ┌────────┐          ┌────────┐
 ──┘        └──────────┘        └──
   ↑上升沿: CNT=0 开始计数
         ↓下降沿: CNT 值 → CNTS(脉宽),CNT 继续
              ↑下一上升沿: CNTS→GPR0(脉宽), CNT→GPR1(周期), CNT=0, 触发 NEWVAL

换算(T_CLK = 所选 CLK_SEL 分辨率周期):
  脉宽 t_on  = GPR0 × T_CLK
  周期 T     = GPR1 × T_CLK
  占空比 D   = GPR0 / GPR1
  频率 f     = 1 / (GPR1 × T_CLK)

⚠️ TPIM(0b001)不能做周期/占空比测量------它是"脉冲时间累加积分",CNT 跨周期持续累计,无单周期概念。单周期占空比用 TPWM,多周期能量/平均占空比才用 TPIM。

5b. ECNT7:1 数据一致性校验(polling 怎么防读到一半被更新)

原理(硬件快照) :ECNT 每收到一个滤波后边沿 +1。GPR0GPR1CNTS 三个寄存器里,每个都自带一个只读的 ECNT 字段 在 bit31:24GPR0.ECNT / GPR1.ECNT / CNTS.ECNT,Access Type = R),其值"refers to ECNT.ECNT[7:0]"------即这 8 位随时反映此刻 ECNT 计数器的低 8 位。

关键澄清------它并不是"捕获那一刻的冻结快照" :从寄存器定义看,GPR0.ECNT[31:24] 是"活的"(Volatile=True、R 只读),读到的就是读取当下 ECNT 的值,而不是 GPR023:0 被捕获那瞬间的值。因此它的正确用法是读两次、比较两次读到的 ECNT 是否相同,来判断"读取期间是否又来了新边沿/新测量",而不是直接拿 GPR0.ECNT 和 GPR1.ECNT 比(这两个是不同时刻读的,ECNT 一直在涨,天然不等)。

polling 读取 + 校验流程(先 GPR1 再 GPR0,读 GPR0 即 ACK)

复制代码
uint32_t v1a, v1b, v0;
do {
    v1a = READ(GPR1);      // 第 1 次读 GPR1(低 24 位=周期,高 8 位=本次 ECNT)
    v0  = READ(GPR0);      // 读 GPR0(低 24 位=脉宽,读这一下即向硬件 ACK)
    v1b = READ(GPR1);      // 第 2 次读 GPR1
} while ( ((v1a >> 24) & 0xFE) != ((v1b >> 24) & 0xFE) );
// 两次读 GPR1 的 ECNT[7:1] 一致 → 读取期间无新边沿插入 → v0/v1a 可信
uint32_t pulse  = v0  & 0xFFFFFF;
uint32_t period = v1a & 0xFFFFFF;

关键点:

  1. 为什么先 GPR1 后 GPR0 :手册 13.4 规定 ARU_EN=0(CPU 消费)时,读 GPR0 这一下就是 ACK,硬件据此解除 GPROFL、才允许下一次测量覆盖 GPR0/GPR1。所以顺序固定:先读 GPR1、再读 GPR0 收尾。
  2. 为什么校验用 7:1 而非 7:0:ECNT0 被复用为当前输入电平 F_OUT(上升沿=奇、下降沿=偶),是电平不是序号,校验只看 bit7:1 的边沿序号。
  3. 为什么能防止"读到一半被写" :GPR0/GPR1 的更新发生在同一 NEWVAL 事件(一次完整 PWM 周期结束),且 ACK 之后才会发生下一次更新。若两次读 GPR1 的 ECNT7:1 相同,说明这中间没有新增边沿、也就没有触发新一轮捕获,读到的 v0/v1a 是同一周期的一致数据;若不同,说明读取窗口内来了新边沿,丢弃重读。
  4. 若需更严谨,可对 GPR0 也做同样的"读两次比 ECNT"操作。注意不同 TIM 模式寄存器更新策略不同,校验方式要按各模式动作表调整。

6. 应用场景

  • ICU 输入捕获:发动机转速(曲轴/凸轮轴传感器)、轮速等 PWM/占空比型信号测量;
  • PWM 占空比监测:配合 TDU 做 0%/100% 占空比异常检测(见之前 TDU 文档);
  • 频率测量:由周期 GPR1 反推频率。

7. 关键寄存器配置

复制代码
CTRL.TIM_MODE   = 0b000   // TPWM
CTRL.DSL        = 1       // 高电平脉宽测量(或 0=低电平)
CTRL.CLK_SEL    = 选择 CMU 分辨率
CTRL.GPR0_SEL   = 0b11, EGPR0_SEL=0  // GPR0 = CNTS(脉宽)
CTRL.GPR1_SEL   = 0b11, EGPR1_SEL=0  // GPR1 = CNT(周期)
CTRL.OSM        = 0       // 连续模式(或 1 单次)
ECTRL.IMM_START = 0       // 等首边沿(或 1 立即)
CTRL.TIM_EN     = 1       // 使能

8. 信号路径框图

复制代码
DSL=1(高电平脉宽测量)示例
                                    ┌──────────────┐
 TIM_IN[x] ─►INPUTSRC─►FLT─►F_OUT──►│ 边沿检测      │
                                    │ (REDGE/FEDGE) │
                                    └──────┬───────┘
                    CMU_CLK_RES[CLK_SEL]──► CNT (递增计数)
                                           │  上升沿: CNT=0 开始
                                           │  下降沿: CNT值→CNTS(脉宽)
                                           │  下一上升沿: CNTS→GPR0, CNT→GPR1
                                           ▼
                                    ┌──────────────┐
                                    │ GPR0=脉宽     │──► CPU(AEI) / ARU
                                    │ GPR1=周期     │──► NEWVAL_IRQ
                                    └──────────────┘

   时序示意(DSL=1):
         ┌────────┐          ┌────────┐
   ──────┘        └──────────┘        └─────
      ↑    ↑      ↑
      │    └下降沿: CNT→CNTS(脉宽)
      └上升沿: CNT=0 开始计数
                      ↑上升沿: CNTS→GPR0, CNT→GPR1, CNT=0, NEWVAL
相关推荐
叶子野格2 小时前
《Verilog学习:前置知识》
学习·fpga开发
周洲083011 小时前
STM32 最简工程搭建|标准库/HAL库规范化模板,零冗余可直接落地
stm32·单片机·嵌入式硬件
ACP广源盛1392462567312 小时前
M6/M5 Pro Mac mini 端侧 AI 落地@ACP#YLB3116 中端多盘存储扩展在 AI 服务中的机会与应用场景
大数据·网络·数据库·人工智能·嵌入式硬件·macos
ACP广源盛1392462567313 小时前
M6/M5 Pro Mac mini 端侧 AI 新形态@ACP#GSV5800 Serdes 长距离视频传输在 AI 服务中的机会与落地场景
大数据·网络·数据库·人工智能·嵌入式硬件·macos·音视频
OIDCAT14 小时前
国产USB转千兆网卡芯片CH398-RTL8153国产替代实测与选型
网络·嵌入式硬件·智能硬件·国产芯片·usb转千兆网卡
HRTOS15 小时前
HRTOS 4.0 驱动库:06_Storage 存储设备驱动——24C02 EEPROM与I²C驱动开发
c语言·驱动开发·嵌入式硬件·51单片机
周洲083015 小时前
STM32 串口不定长接收|空闲中断 IDLE 方案,无固定帧长限制,项目实战
stm32·单片机·嵌入式硬件
科恒盛远15 小时前
RFSoC XCZU47DR 100G UDP高速数据传输的实现与调试(PCIE908 板卡技术系列三)
fpga开发
我和头发拼了17 小时前
STM32--10硬件读写MPU6050
stm32·单片机·嵌入式硬件