单向 DSHOT 输出实现概要设计
目录
- DSHOT 协议概述
- 总体设计思路
- 方案一:GPTMR + DMA
- 方案二:I2S 移位输出
- 方案三:PWM + DMA + HRAM(双比较 + 影子寄存器)
- 方案四:PWMV2 + DMAV2(FIX_BURST,1 路 DMA 服务 4 路 PWM)
- 方案对比与选型建议
- 共性关键设计点
1. DSHOT 协议概述
DSHOT(Digital Shot)是无刷电调(ESC)的数字油门协议。每帧固定 16 bit,MSB 先发,无起始/停止位,靠帧间空闲(低电平)分帧:

每个 bit 采用脉宽编码,以固定的位周期 T 为时间基准:
- 位周期 T:每一个 DSHOT bit(不论 0 还是 1)都占用同一个完整的位周期 T,由所选速率等级决定(见下表),bit 之间连续发送、无间隔;
- 数据靠高电平宽度判决:在一个位周期 T 之内,高电平持续时间决定该 bit 的值 —— bit1 高电平 ≈ 75% T(低电平补足剩余 ≈25% T),bit0 高电平 ≈ 37.5% T(低电平补足剩余 ≈62.5% T)。
注意:“bit 0 的 T”指的就是这个完整的位周期 T,并非只有 37.5% T;37.5% T 只是 bit0 的高电平宽度,其余时间均为低电平,二者共同凑满一个 T。电调(ESC)判决阈值约 50%,实际实现有较大容差,例程中 2/3、5/8 等占空比均可被正确识别。

| 速率等级 | 位速率 | 位周期 T | 一帧时长(16 bit) |
|---|---|---|---|
| DSHOT150 | 150 kbps | 6.67 μs | 106.7 μs |
| DSHOT300 | 300 kbps | 3.33 μs | 53.3 μs |
| DSHOT600 | 600 kbps | 1.67 μs | 26.7 μs |
| DSHOT1200 | 1200 kbps | 0.83 μs | 13.3 μs |
2. 总体设计思路
单向 DSHOT 的本质是:以固定位周期连续输出 16 个宽度可变的脉冲。软件位翻转(bit-bang)无法满足 μs 级精度且占用 CPU,因此所有方案都遵循同一个模式:

四种实现方式的差异只在于"波形发生器"与"供数方式"的组合:
| 方案 | 波形发生器 | 供数方式 | 可变量 |
|---|---|---|---|
| ① GPTMR + DMA | GPTMR 输出比较 | DMA 逐周期更新 CMP | 比较值(脉宽) |
| ② I2S | I2S 移位寄存器 | FIFO(CPU 或 DMA 填充) | 位图(1 个 DSHOT 位 = 16 个 BCLK 位) |
| ③ PWM + DMA | PWM 输出比较(4 通道) | 4 路 DMA 各自更新 1 路 CMP | 比较值(脉宽) |
| ④ PWMV2 + DMAV2 | PWMV2 输出比较(8 通道) | 1 路 DMAV2 FIX_BURST 更新 8 路 CMP | 比较值(脉宽) |
3. 方案一:GPTMR + DMA
3.1 原理
将 GPTMR 通道配置为输出比较模式,计数器 RELOAD 为 1 个位周期 T。GPTMR 比较器有两个关键特性:① 计数器计数到任一个比较值 CMP,通道输出即翻转一次;② 当 CMP0 = 32'hFFFFFFFF 时,通道输出强制保持为逻辑 0(初始极性)——空闲(IDLE)即利用此特性:此时即使 CMP1 每周期仍匹配一次,输出也被锁定为 0,不会产生有效脉冲。初始极性为低(cmp_initial_polarity_high = 0),故每周期先到 CMP1 = T/3 翻为高、再到 CMP0 翻回低。
正是这两个特性决定了比较器分工:把 CMP1 固定为 T/3 作为每个位的边界(每周期必翻转一次、产生位起点),而只改变 CMP0 来调节脉宽——发送 bit 时 CMP0 取 T−1 或 2T/3 产生"翻回低"的数据沿;空闲时 CMP0 取 0xFFFFFFFF,数据沿永不产生,输出恒为逻辑 0(空闲电平)。由于 GPTMR 没有影子寄存器(见下方约束),单个 DSHOT 位必须跨两个定时器周期实现——详见图 3-2。
- 以计数时钟 100 MHz 为例:
RELOAD = 83≈ DSHOT1200,RELOAD = 166≈ DSHOT600; - 固定比较点
CMP1 = T/3每周期把输出翻为高(即每个位的起点 / 位边界);CMP0由 DMA 在每个重载事件刷新,决定输出翻回低的时刻(脉宽结束沿),从而决定高电平宽度:bit"1" →CMP0 = T−1(结束沿推到接近位尾,高电平最长 ≈ 2/3T),bit"0" →CMP0 = 2T/3(结束沿靠前,高电平最短 ≈ 1/3T);电调(ESC)只需测量高电平持续时间(从 CMP1 翻高到 CMP0 翻低)即可判决:≈2/3T 判为 1、≈1/3T 判为 0。 - DMA 请求源选择
gptmr_dma_request_on_reload,即每个位周期开始瞬间把下一位的比较值写入 CMP0 寄存器(目的地址固定、源地址递增、handshake 模式); - 缓冲区共 18 个字:
[0]与[17]填0xFFFFFFFF(CMP0 = 32'hFFFFFFFF→ 比较器永不命中,输出被强制为逻辑 0,即空闲电平),中间 16 个字对应 16 个数据位;缓冲区放在 AHB SRAM(ATTR_PLACE_AT(".ahb_sram"))以保证 DMA 零等待访问。
⚠ 关键约束:GPTMR 无影子寄存器 → 必须跨周期实现
GPTMR 的比较器没有影子寄存器:软件 / DMA 写入
CMP0后立即生效,无法像 PWM 那样等到周期边界再统一加载。若试图在单个定时器周期内同时表达"位起点电平 + 位中数据沿",中途改写 CMP 会当拍影响当前位、产生毛刺。解决方式:把 1 个 DSHOT 位拆到"跨两个定时器周期"。以固定比较点
CMP1 = T/3作为位边界(每周期必触发一次),数据沿由CMP0产生;于是"本周期 T/3 → 下一周期 T/3" 恰好等于一个完整 DSHOT 位周期(宽度 = 1 个定时器周期 T,但相对重载点偏移了 T/3)。DMA 在每次重载点写入的CMP0作用于当前周期内的数据沿,与位窗口天然对齐,全程无需中途改写。该方案采用等效脉宽编码:电调(ESC)只需测量高电平持续时间(位边界 CMP1 翻高 → 数据沿 CMP0 翻低)即可判决 0/1,与标准 DSHOT 兼容。


3.2 发送流程
- 停止计数器并复位计数值(
gptmr_stop_counter/gptmr_channel_reset_count); - 按 MSB first 将 16 bit 帧展开为比较值数组,首尾填空闲值;
- 重设 DMA 源地址与传输长度(18 字),使能 DMA 通道;
- 启动计数器,硬件自动逐位发送;DMA 完成中断可用作"帧发送完成"标志。
3.3 资源占用与评价
| 项目 | 每路电机占用 |
|---|---|
| 定时器 | 1 个 GPTMR 通道(1 个 GPTMR 外设含 4 通道) |
| DMA | 1 个 DMA 通道 + 1 个 DMAMUX 通道 |
| CPU | 仅帧编码(每帧一次,约数十条指令) |
✅ 优点: 实现最简单、任意 GPTMR 引脚可用、单路资源少。
⚠ 局限: 多路电机之间无硬件同步(各通道独立启动);4 路电机需 4 个 GPTMR 通道 + 4 个 DMA 通道。
4. 方案二:I2S 移位输出
4.1 原理
把 DSHOT 波形当作"数字音频流":1 个 DSHOT 位展开成 16 个 BCLK 位的位图,由 I2S 移位寄存器按位时钟恒速移出。占空比由位图中 1 的个数决定:
- bit"1" →
0xFFC0(前 10 位高、后 6 位低,高电平 62.5% T); - bit"0" →
0xFC00(前 6 位高、后 10 位低,高电平 37.5% T); - BCLK = 16 × DSHOT 位速率。例:DSHOT2400 → BCLK = 38.4 MHz,由音频 PLL 精确产生(614.4 MHz ÷ 16);配置上采样率 = 位速率 ÷ 每帧通道数,通道长度/位深均为 16 bit,
MSB_JUSTIFIED协议、主机模式; - I2S 外设具有 4 条 TX 数据线(TXD0~3),共用同一 BCLK/FCLK,天然支持 4 路严格同步输出;
- 一帧 DSHOT = 16 位 × 16 bit 位图 = 256 BCLK = 每线 8 个 32 bit FIFO 字,一次性写入 FIFO 即可。

4.2 发送流程
- 配置音频 PLL 与 I2S 分频,使 BCLK 精确等于 16 × 位速率;
- 帧编码后按"U32 传输字序"把 16 个位图交织写入缓冲(例程中偶/奇半字对调以匹配 FIFO 字序);
i2s_stop→ 向 4 条线各写 8 个字 →i2s_start,移位输出;- 等待 FIFO 水位下降后,各线补写一个
0,保证发送完成后数据线保持空闲低电平(I2S 下溢时会重复最后数据,必须用 0 兜底)。
4.3 资源占用与评价
| 项目 | 4 路电机占用 |
|---|---|
| 外设 | 1 个 I2S(4 条 TX 数据线) |
| DMA | 0(FIFO 深度足够容纳一整帧,CPU 直接填充;也可选配 DMA) |
| CPU | 帧编码 + FIFO 填充(每帧 32 次寄存器写) |
✅ 优点: 1 个外设带 4 路且严格同步;时钟来自音频 PLL,频率精度最高;不占 DMA。
⚠ 局限: 引脚固定为 I2S TXD,灵活性差;空闲电平需软件兜底(补 0);内存放大 16 倍(每 DSHOT 位 16 bit)。
5. 方案三:PWM + DMA(双比较 + 影子寄存器)
5.1 原理
使用 1 个 PWM 外设输出 4 路 DSHOT。PWM 计数器 RELOAD = 1 个位周期 T。每路输出采用两个比较器——概念上与 GPTMR 的 CMP0/CMP1 一对完全对等:一个决定上升沿、一个决定下降沿;只是 PWM 的每个比较器都带有硬件影子寄存器,因此一个 DSHOT 位干净地落在一个周期 T 内,无需像 GPTMR 那样跨两个周期。
这 2 个比较器是 PWM 中 2 个独立的 CMP[n] 比较器通道(例如第 k 路 CMP[k] 与第 k+1 路 CMP[k+1]),每个只使用其 CMP[n] 寄存器的 CMP 位域——该寄存器虽也包含 XCMP 位域,但本方案并不使用。分工如下:
- 固定比较器
CMP[k].CMP = 0:在每周期计数起点(count 0,即周期边界)强制输出为高(上升沿),它定义了每个 DSHOT 位高脉冲的起点,固定在周期边界; - 可变比较器
CMP[k+1].CMP由 DMA 逐位更新:决定输出翻回低的时刻(下降沿 / 数据沿),即高脉冲的终点; - 输出非反转(
invert_output = false),重装载点把输出复位为初始低电平。
与 GPTMR 同一对比较器的差异:二者都是「固定上升沿 + 可变下降沿」的双比较结构(GPTMR 用
CMP1固定上升、CMP0可变下降;本方案用CMP[k]固定上升、CMP[k+1]可变下降);唯一差别在于:GPTMR 无影子寄存器,上升沿只能固定在T/3并跨两个周期拼接 1 个位;PWM 有影子寄存器,上升沿可固定在周期起点0、单个 bit 干净落在一个周期 T 内(无需跨周期)。
bit 取值由可变比较器 CMP[k+1].CMP 决定高电平宽度(高电平从周期起点 0 开始、到该比较值处结束):
| bit | 可变比较器 CMP[k+1].CMP |
高电平区间 | 高电平宽度 |
|---|---|---|---|
| 1 | 2T/3 |
[0, 2T/3] |
≈ 2/3 T |
| 0 | T/3 |
[0, T/3] |
≈ 1/3 T |
电调(ESC)只需测量高电平持续时间即可判决 0/1。
✅ idle 天然为低、无需反转:空闲时把可变比较器
CMP[k+1].CMP也置 0,使上升沿(count 0)与下降沿(count 0)重合、高脉冲宽度坍缩为 0,配合重装载点复位,输出始终停在低电平——与 DSHOT 空闲低电平要求一致。这与 GPTMR 用CMP0 = 0xFFFFFFFF(比较值永不可达)锁低异曲同工:都是"空闲时无有效高脉冲",只是实现手段不同,都不需要invert_output。
其余要点:
- 影子寄存器 + 周期边界锁存事件:DMA 在每个重装载点写入的可变比较值
CMP[k+1],经影子寄存器缓存在周期边界由 shadow-lock 事件原子加载到活动比较器,保证一个 bit 的比较值整周期生效、不中途改写、无毛刺。对应驱动pwm_load_cmp_shadow_on_match(锁存点比较值 =RELOAD)、pwm_issue_shadow_register_lock_event,以及比较器的update_trigger = pwm_shadow_register_update_on_hw_event; - 一路 PWM 输出对应一路 DMA 通道:每路由 1 个专用触发比较器(CMP8~11)产生 DMA 请求,4 路请求时刻在 1 个位周期内错峰(见 §5.1.1);请求经
TRGM → DMAMUX → HDMA(通道 1~4)送到该路可变比较器CMP[k+1]的影子寄存器(目的地址固定、源地址递增、handshake);每个位周期各搬 1 个字(字的PWM_CMP_CMP_SET字段即CMP[k+1]的比较值),固定比较器CMP[k].CMP = 0仅在初始化时配置一次、不随 DMA 变化; - HRAM(AHB SRAM):缓冲放在与 HDMA 同总线域、零等待的内存(示例用 noncacheable 段;设计上推荐
.ahb_sram,见 §8.1),确保 DSHOT1200 下 4 路 DMA 并发不超时; - 缓冲 = 18 字/路:帧首 1 字空闲(上升沿 = 0 → idle 低)+ 16 个数据位 + 帧尾 1 字空闲(上升沿 = 0 → idle 低),首尾空闲字保证帧边界清晰、电调(ESC)可稳定分帧。
5.1.1 触发比较器与 DMA 请求错峰
每路输出各配 1 个专用触发比较器(CMP8~11),其比较值错开设置,使 4 路 DMA 请求在 1 个位周期内分散到达,避免 4 路同时请求 HDMA 造成总线争抢、比较值晚于重载点加载而出现坏位:
| 通道 | 触发比较器 | 比较值(计数器取值) | DMA 请求时刻 |
|---|---|---|---|
| ch0 | CMP8 | 2 |
位起点 + 2 ticks |
| ch1 | CMP9 | 4 |
位起点 + 4 ticks |
| ch2 | CMP10 | 6 |
位起点 + 6 ticks |
| ch3 | CMP11 | 8 |
位起点 + 8 ticks |
表中比较值为计数器取数(从 0 起算):相邻通道错开 2 个 tick,4 路请求在 1 个位周期前段(0~8 ticks)均匀分布,避开重载边界、分散总线峰值压力,又远早于周期边界发生,保证比较值在周期边界的 shadow-lock 事件前已全部就位、原子锁存、无毛刺。
每个触发比较器命中后产生一次 DMA 请求,经 TRGM → DMAMUX → HDMA 三级路由到对应 HDMA 通道(handshake 模式、目的地址固定为 CMP[k+1] 影子、源地址递增):
#if TEST_CH0
trgm_dma_request_config(HPM_TRGM0, TRGM_DMACFG_1, HPM_TRGM0_DMA_SRC_PWM0_CMP8);
dmamux_config(BOARD_APP_DMAMUX, DMA_SOC_CHN_TO_DMAMUX_CHN(HPM_HDMA, 1), HPM_DMA_SRC_MOT0_1, true);
pwm_enable_dma_request(PWM, PWM_DMAEN_CMPENX_SET(1<<8));
#endif
#if TEST_CH1
trgm_dma_request_config(HPM_TRGM0, TRGM_DMACFG_0, HPM_TRGM0_DMA_SRC_PWM0_CMP9);
dmamux_config(BOARD_APP_DMAMUX, DMA_SOC_CHN_TO_DMAMUX_CHN(HPM_HDMA, 2), HPM_DMA_SRC_MOT0_0, true);
pwm_enable_dma_request(PWM, PWM_DMAEN_CMPENX_SET(1<<9));
#endif
#if TEST_CH2
trgm_dma_request_config(HPM_TRGM0, TRGM_DMACFG_2, HPM_TRGM0_DMA_SRC_PWM0_CMP10);
dmamux_config(BOARD_APP_DMAMUX, DMA_SOC_CHN_TO_DMAMUX_CHN(HPM_HDMA, 3), HPM_DMA_SRC_MOT0_2, true);
pwm_enable_dma_request(PWM, PWM_DMAEN_CMPENX_SET(1<<10));
#endif
#if TEST_CH3
trgm_dma_request_config(HPM_TRGM0, TRGM_DMACFG_3, HPM_TRGM0_DMA_SRC_PWM0_CMP11);
dmamux_config(BOARD_APP_DMAMUX, DMA_SOC_CHN_TO_DMAMUX_CHN(HPM_HDMA, 4), HPM_DMA_SRC_MOT0_3, true);
pwm_enable_dma_request(PWM, PWM_DMAEN_CMPENX_SET(1<<11));
#endif
pwm_enable_dma_request(PWM, PWM_DMAEN_CMPENX_SET(1 << n)):使能第 n 个触发比较器(CMP8~11 对应 bit8~11)的 DMA 请求;trgm_dma_request_config(...):把 PWM 的CMPnDMA 源(HPM_TRGM0_DMA_SRC_PWM0_CMP8~11)绑定到某个 TRGM 输出(TRGM_DMACFG_0~3,例程中MOT0_x对应的 DMACFG 索引);dmamux_config(...):把该 TRGM 输出路由到 DMAMUX 的HPM_DMA_SRC_MOT0_0~3,最终送达HPM_HDMA通道 1~4。
4 路 HDMA 通道各自 handshake 搬运 1 个字到对应 CMP[k+1] 影子寄存器后,由周期边界的 shadow-lock 事件统一加载,形成"错峰供数 → 统一锁存"的时序:既分散了总线峰值压力,又保证所有通道的比较值在周期边界原子生效、无毛刺。
5.2 发送流程
- 初始化:配置 4 路输出波形(可变比较器
CMP[k+1]update_trigger = on_hw_event、固定比较器CMP[k].CMP = 0一次写定)与影子锁存点;配置每路专用触发比较器与 TRGM/DMAMUX 路由,使能 PWM DMA 请求; - 每帧:编码 → 填 4 份 18 字缓冲(首字 / 末字 = 0 → idle 低)→ 重配并使能 4 个 HDMA 通道 → 发出 shadow-lock 事件后启动计数器;
- 4 个 HDMA 均产生 TC(传输完成)中断后本帧结束,输出停在空闲电平。
5.3 资源占用与评价
| 项目 | 4 路电机占用 |
|---|---|
| PWM | 1 个 PWM 外设:8 个比较器(4 路 × 2:固定 CMP[k]=0 + 可变 CMP[k+1]=DMA)+ 4 个触发比较器(+ 1 个共享的影子锁存比较点) |
| DMA | 4 个 HDMA 通道 + 4 个 DMAMUX 通道 + 4 个 TRGM DMA 路由 |
| 内存 | 4 × 18 字 @ HRAM |
⚠ 主要痛点: DMA 通道消耗大——每 4 路电机需 4 个 DMA 通道;4 路请求在同一位周期密集到达,依赖 HRAM 零等待与 DMA 优先级配置保证时序余量。这正是方案四要解决的问题。
6. 方案四:PWMV2 + DMAV2(DST_FIXBURST,1 路 DMA 服务 8 路 PWM)
6.1 原理
波形生成部分与方案三同构:PWMV2 计数器 RELOAD 为 位周期 T,每路输出各用双比较点(固定比较点 = 0,上升沿落在周期起点 count 0;可变比较点 = DMA 写入的数据值,下降沿为数据沿),比较值在周期边界(shadow-lock / reload 事件)原子加载,非反转、idle 低,一个 DSHOT 位干净落在一个周期 T 内(无需跨周期)。差异全部在供数通路上:
- PWMV2 原生 DMA 请求选择:通过
DMA_EN寄存器直接选择"哪个比较点或重载点"产生 DMA 请求(pwmv2_enable_dma_at_reload_point选重载点;例程选cmp0 == 0,即每个位周期起点 count 0)。与方案三不同,这里只需 1 个请求源、每个位周期 1 次请求,即可驱动全部 8 路; - DMAV2 的 DST_FIXBURST:置位
DST_FIXBURST(dma_set_dst_fixed_burst)后,每次 DMA 请求搬运一个 burst = 通道数 字的突发——burst 内目的地址递增(依次写入 CMP[0]、CMP[1]、…、CMP[7] 这 8 个连续比较寄存器),burst 结束后目的地址回卷到 CMP[0],等待下一次请求。例程取burst = 8(= 8 路); - 源缓冲按位交织排布:例程把 16 个 bit × 8 路共 128 字排在 HRAM,布局为
HRAM[bit_k * 0x20 + ch_i * 4]——即以 bit 为主序、路为次序([bit15_ch0, bit15_ch1, …, bit15_ch7, bit14_ch0, …])。每个 burst(8 字)正好是一"位"的 8 路数据; - 帧边界由计数器 BURST 模式界定:例程不靠缓冲区里的空闲字,而是把每个 PWM 计数器配置为
CNT_BURST = 16——计数器发出 16 个位周期后自动停止。因此缓冲只需 16 个数据位(无需方案三的 2 字空闲填充),发完 16 个 burst 后计数器停在 idle 低电平; - 结果:1 路 HDMA 通道即可为全部 8 路 PWM 通道供数,即"用 1 路 DMA 通道 + 1 次 FIX_BURST 把全部路的同 bit 数据一次性搬入 CMP[0..7]"。


6.2 关键配置点(以 8 路为例)
| 配置项 | 取值 / 接口 | 说明 |
|---|---|---|
| DMA 请求源 | pwmv2_enable_dma_at_reload_point() 或选 cmp0 == 0 |
每个位周期起点 1 次请求 |
| 请求路由 | DMAMUX(例程经 MOT_GPR 触发矩阵 → DMAMUX → HDMA ch0) | PWMV2 请求线仍需路由到 HDMA |
| burst 长度 | = 通道数(例程 8,对应 src_burst_size 8 beats) |
一次请求写完全部路的同 bit CMP |
| DST_FIXBURST | dma_set_dst_fixed_burst(ptr, ch, true) |
burst 内 dst++ 写 CMP[0..7],burst 间 dst 回卷 |
| 目的地址 | CMP[0] 比较寄存器基址(8 个连续) | 要求被服务比较器地址连续 |
| 源地址 | HRAM,递增,位交织 128 字 | [bit_k * 8 + ch_i],16 bit × 8 路 |
| 计数器 BURST | pwmv2_set_counter_burst(cnt, 16) |
发满 16 位后自动停,界定帧边界 |
| 影子加载 | 周期边界(reload / shadow-lock)统一加载 | 保证 8 路脉宽同周期原子更新 |
6.3 资源占用与评价(8 路)
| 项目 | 8 路电机占用 |
|---|---|
| PWMV2 | 1 个外设:8 路输出,每路 2 比较点(固定=0 上升沿 + 可变=DMA 下降沿)+ 1 个 DMA 请求线 |
| DMA | 1 个 HDMA 通道(即 DMAV2 实例,对比方案三节省 3 个) |
| 内存 | 128 字交织缓冲 @ HRAM(16 bit × 8 路;无空闲填充,靠计数器 BURST 界定帧) |
✅ 优点: 资源效率最高的 PWM 类方案——8 路同步(同一组计数器 + 同点加载),仅 1 个 DMA 通道即服务全部 8 路(burst = 8),请求链路最短;FIX_BURST 把"1 次请求 → N 路同 bit"打包,总线峰值远低于方案三的 4 路错峰。
⚠ 局限: 仅支持带 DMAV2 的新系列(如 HPM6E00/HPM5E00 等);要求被服务的比较器(CMP[0..N-1])地址连续。
7. 方案对比与选型建议
| 维度(按 4 路电机) | ① GPTMR+DMA | ② I2S | ③ PWM+DMA+HRAM | ④ PWMV2+DMAV2+HRAM |
|---|---|---|---|---|
| 波形外设 | 4 个 GPTMR 通道 | 1 个 I2S(4 线) | 1 个 PWM(4 输出·各 2 个独立 CMP + 影子寄存器) | 1 个 PWMV2(4 输出·各 2 个独立 CMP + 影子寄存器) |
| DMA 通道 | 4 | 0 | 4 | 1 |
| 多路同步性 | 无硬件同步 | 严格同步(同移位时钟) | 同步(同计数器) | 同步(同计数器) |
| 引脚灵活性 | 高(任意 GPTMR 引脚) | 低(固定 I2S TXD) | 中(PWM 引脚) | 中(PWM 引脚) |
| 每帧 CPU 开销 | 低 | 中(填 FIFO 32 次写) | 低 | 低 |
| 内存开销 | 18 字/路 | 8 字/路(位图放大 16×) | 18 字/路 | 64 字(4 路交织,16 字/路;8 路例程 128 字) |
| 频率精度 | 受总线时钟整除限制 | 最高(音频 PLL 可微调) | 受总线时钟整除限制 | 受总线时钟整除限制 |
| 芯片依赖 | 全系列 | 带多线 I2S 的系列 | 带 PWM(v1) 系列(HPM6700/6300 等) | 带 PWMV2/DMAV2 系列(HPM6E00 等,HPM6E00 上 DMAV2 即 HDMA) |
| 典型场景 | 单路/散点电机、引脚受限 | 四轴飞控、DMA 紧张、要求极致同步 | PWM(v1) 平台的四电机方案 | 新平台四/八电机,资源最优 |
8. 共性关键设计点
8.1 缓冲区放置(HRAM)
- DMA 源缓冲统一放 AHB SRAM(
ATTR_PLACE_AT(".ahb_sram")):与 HDMA 同总线域、零等待,避免高位速率下因总线争抢导致比较值更新晚于重载点而出现坏位; - 若使用带 cache 的内存,需保证 DMA 一致性(clean cache 或使用 noncacheable 段)。
✅ 首选 HRAM(HDMA + AHB SRAM): HDMA 与 AHB SRAM 属于同一总线域,DMA 读写缓冲零等待、带宽最足,存取效率最高,是 DSHOT 高位速率(DSHOT1200+)下最稳妥的放置方式。
⚠ 不要用 XDMA 或 AXI-SRAM: XDMA 或挂在 AXI-SRAM(AXI 总线域)上的缓冲,相对 HDMA + HRAM 组合效率明显更低——跨总线域访问有额外延迟、且易与 CPU/其它主设备争抢 AXI 带宽。在 DSHOT 位周期很短(微秒级)的约束下,这类放置可能因一次 DMA 搬运耗时过长、来不及在周期边界的 shadow-lock 事件前把 CMP 比较值更新就位,导致输出坏位甚至整帧错乱。因此源缓冲务必放在 HRAM,使"错峰供数 → 统一锁存"的时序始终有余量。
8.2 DMA 的选择
四类方案的差异最终都收敛到"由谁、用什么 DMA、在何时把比较值搬进 CMP 影子寄存器",选型要点:
- DMA 控制器选型:PWM 类方案(方案③④)优先选与 HRAM 同总线域、零等待的 HDMA;PWMV2 方案进一步利用 DMAV2 的
FIX_BURST特性(见 §6),在一个 burst 内连续写 4 个 CMP 影子寄存器,使通道数与请求次数都降到 1/4; - DMA 请求源:统一在"位周期起点附近"产生——方案①③用定时器重载点(
gptmr_dma_request_on_reload/ PWM 重载事件),方案③的 4 路还通过在 1 个位周期内错峰(CMP8~11 比较值取 2/4/6/8)分散请求,避免 4 路同时抢占 HDMA 总线; - 传输参数:均为 handshake 模式,目的地址 = 对应 CMP 影子寄存器(固定)、源地址递增;每个位周期搬运 1 个字(方案③)或 1 个 burst 含 4 个字(方案④);
- 通道数权衡:方案③「1 路输出对应 1 路 DMA 通道」实现简单、各路独立,但 4 路电机吃 4 个通道;方案④ 用 DMAV2
FIX_BURST「1 路 DMA 通道服务 4 路 PWM」,显著省通道。DMA 控制器的能力(是否支持 FIX_BURST / 多比较器请求)直接决定方案的可扩展性——这也是方案四相对方案三的核心改进点。