新闻详情

新闻详情

首页 / 资讯中心 / 详情

STM32+DMA实现Dshot600协议波形生成与逆向解析

发布时间:2026/9/28 9:37:47来源:尧图网络
STM32+DMA实现Dshot600协议波形生成与逆向解析
一直玩惯了飞控直接接电调很少有人会认真想一下Dshot 的波形到底是什么样里面那 16 位数据是怎么编码的CRC 又是怎么算出来的我这次借着一块 STM32F103、一个 24MHz 的逻辑分析仪把 Dshot 协议从底层逆向拆了一遍。核心做法是用 CubeMX 配置定时器 PWM再通过 DMA 更新比较寄存器让硬件自己把帧“吐”出来最后用逻辑分析仪验证每一个位。这篇文章适合三种人想搞懂 Dshot 协议细节的、准备自己写电调驱动的、以及想在 STM32 上把 DMA 和定时器玩明白的。1. 项目背景与协议认知1.1 为什么是 Dshot而不是 PWM早期航模电调用的是标准 PWM 油门靠 1ms 到 2ms 的高电平脉宽来表示 0% 到 100% 油门。这种方案在接收机时代没毛病但放到飞控上就有点难受刷新率只有 50Hz 左右油门响应慢而且电调需要做“行程校准”否则最小值和最大值对不上。后来出了 Oneshot125、Oneshot42刷新率上去了但本质上还是模拟脉宽时序要求苛刻飞控和电调之间的兼容性问题很多。Dshot 完全换了个思路它把这 2048 级油门值直接编码成数字信号。接收端不再测脉宽对应的“模拟油门”而是解析一串由 0 和 1 组成的数字帧。这样飞控和电调之间不存在行程校准问题协议本身就是标准的电调只要按协议解帧就行。我在项目里需要自己生成 Dshot 波形第一步就是把协议结构彻底搞清楚不能靠猜。1.2 Dshot 帧结构与位编码规则Dshot 一帧总共 16 位按发送顺序依次是12 位油门值高位在前MSB First范围 0~20471 位遥测请求位置 1 时电调会在下个周期回传数据4 位 CRC 校验基于前 12 位数据计算。这 16 位不是用普通的 UART 电平发送的而是用“特定宽度的脉冲”来表示逻辑 0 和逻辑 1。以 Dshot600 为例每个位的周期是 1.667us逻辑 1 的高电平时间约 1250ns逻辑 0 的高电平时间约 625ns。也就是说一个位周期内先输出一段高电平然后拉低到周期结束高电平长短不同就区分了 0 和 1。不同速率下位宽不一样用表格看更直观速率位周期逻辑 1 脉宽逻辑 0 脉宽帧长16 位Dshot1506.667us5000ns2500ns106.7usDshot3003.333us2500ns1250ns53.3usDshot6001.667us1250ns625ns26.7us如果 STM32 的 PWM 正常工作DMA 每一次更新 CCR 寄存器就相当于“绘制”出一个位周期。逻辑分析仪看到的就是 16 个脉冲组成的一帧。1.3 方案选型STM32 CubeMX DMA 逻辑分析仪选择 STM32F103 纯粹是因为手头多72MHz 主频足够应付 Dshot600。CubeMX 用来做图形化配置定时器、DMA 中断都能直接生成初始化代码比手写寄存器高效得多。DMA 在这里的核心作用是把 CPU 从“每个位都要翻转一次电平”的重复劳动里解放出来。我只需要把一帧 16 位对应的 PWM 比较值填到一个数组里启动 DMA硬件会自动把这 16 个值陆续写入定时器的 CCR 寄存器PWM 输出就按预定的脉冲序列走完了。整个过程 CPU 基本不参与非常适合作为后续扩展的基础。逻辑分析仪则负责验证到底发出去的波形是不是符合 Dshot 协议。没有它我只能对着代码空想。2. 硬件准备与工具清单2.1 需要准备的硬件与接线项目硬件不复杂主要是三块STM32F103C8T6 最小系统板作为 Dshot 信号源支持 Dshot 的电调最好是 BLHeli_S 或者 BLHeli_32 固件逻辑分析仪24MHz 采样率8 通道足够。开发阶段的接线很简单STM32 的定时器 PWM 输出引脚接到电调信号线比如我用的是 TIM1 的 CH1对应 PA8。电调的电源和地线严格区分开信号地必须和 STM32 共地。这里特别提醒一句先不要接电机先把信号线单独空接只测 STM32 引脚上的波形等波形确认没问题再接电调安全第一。2.2 逻辑分析仪选型与采样率选择很多人以为逻辑分析仪越贵越好实际抓 Dshot 这种信号普通 24MHz 8 通道的型号就绰绰有余。Dshot600 下逻辑 1 脉宽是 1250ns逻辑 0 脉宽是 625ns24MHz 采样率下每个逻辑 0 也有大约 15 个采样点足够区分。我个人不建议用低于 8MHz 采样率的设备否则逻辑 0 可能只采到 3~5 个点脉宽测量误差会非常大肉眼判断 0/1 都会出问题。逻辑分析仪软件方面Saleae Logic 和 PulseView 都行Saleae 的界面更直观我记得它自带 Dshot 解码器扩展不过我们这次是逆向解析要自己从波形里读位所以不用依赖解码器。2.3 测试环境与安全准备调试 Dshot 波形时如果电机还带着桨那就是拿命在试。我个人的习惯是第一轮测试完全空载只量引脚信号第二轮接电调但不装桨第三轮才低速验证电机转向。另外STM32 和电调的供电顺序也有讲究最好是电调先上电再上逻辑板避免信号线处于不确定状态时电调误判。Dshot 虽然是数字协议但它的信号电平就是普通逻辑电平STM32 的 3.3V 输出直接接电调信号线一般没问题具体看电调说明。老式电调可能需要 5V 逻辑电平那就得加电平转换不能硬接。3. CubeMX 配置与代码实现3.1 定时器与 DMA 参数配置过程CubeMX 里的配置路径大致如下选择 STM32F103C8T6时钟树配到 72MHz然后找到 TIM1选择 Channel1 的 PWM Generation CH1。关键参数Prescaler 设置为 0不分频Counter Period 设置为 119也就是 ARR119Pulse 初始值随意后续 DMA 会持续改写。为什么 ARR 是 119因为 72MHz 下每个计数周期是 13.89ns定时器从 0 计数到 119一共 120 个计数周期恰好是 1.667us也就是 Dshot600 的一个位周期。这个计算可以写成公式位周期 (ARR 1) / 定时器时钟频率。反推就是 ARR 72MHz × 1.667us - 1 ≈ 119。然后配置 DMA请求源选 TIM1_UP方向是 Memory To Peripheral也就是内存写到外设。数据宽度是 Half Word因为 CCR 是 16 位寄存器。DMA 模式我最终选择的是 Normal这样一帧发完就停配合 DMA 传输完成中断做帧间隔控制。如果选 Circular 模式DMA 会一直重复发送同一个帧虽然信号是连续了但很容易导致帧与帧之间间隔太短电调反而不识别。生成代码后还要在 main 函数里确认初始化顺序DMA 初始化必须在定时器 PWM 启动之前完成。如果代码生成后手动改过初始化顺序DMA 可能触发不了我在后面排查章节会详细说。3.2 Dshot 帧编码与 CRC 算法实现帧编码是整个项目里最需要仔细的部分。先把油门值左移一位最低位放遥测请求位得到一个 12 位的 value。比如油门值是 500遥测位是 0那么 value (500 1) | 0 1000。然后是 CRC。Dshot 的 CRC 是 4 位多项式本质是个查表过程。我参考了常见的实现CRC 初始值为 0从第 11 位到第 0 位逐位处理每一位根据当前数据位是否为 1 选择查表更新。查表算法如下static const uint8_t dshot_crc_table[16] { 0, 5, 15, 10, 9, 12, 6, 3, 3, 6, 12, 9, 10, 15, 5, 0 }; uint8_t dshot_crc(uint16_t value) { uint8_t crc 0; for (int i 11; i 0; i--) { if (value (1 i)) { crc dshot_crc_table[crc ^ 1]; } else { crc dshot_crc_table[crc]; } } return crc; }注意 value 是 12 位数据而不是最终的 16 位帧。上面例子中 value1000二进制是 0b001111101000计算出来的 CRC 是 12也就是 0xC。最终的 16 位帧就是 value 左移 4 位再或上 CRC1000 4 | 12 16012二进制是 0b0011111010001100。这个 CRC 算法如果不查表手算会非常容易错我是直接用逻辑分析仪抓波形验证的后面对不上再回头查结果发现是我把查表索引搞错了不是协议问题。3.3 DMA 发送流程与油门更新逻辑发送端的核心是准备一个长度为 16 的数组每一位对应一个 PWM 比较值。我们需要根据这一位是 1 还是 0填入不同的 CCR 值。Dshot600 下位周期 120 个计数周期逻辑 1 的高电平 1250ns 对应 90 个计数周期逻辑 0 的高电平 625ns 对应 45 个计数周期。PWM 模式 1 下CCR 决定高电平持续时间所以数组里的值就是 90 或者 45。构造数组的代码大概长这样static uint16_t dshot_ccr_buf[16]; void dshot_prepare_frame(uint16_t throttle, uint8_t telemetry) { uint16_t value (throttle 1) | (telemetry 0x01); uint16_t frame (value 4) | dshot_crc(value); for (int i 15; i 0; i--) { if (frame (1 i)) { dshot_ccr_buf[15 - i] DSHOT_ONE_CCR; // 90 } else { dshot_ccr_buf[15 - i] DSHOT_ZERO_CCR; // 45 } } }发送时调用HAL_TIM_PWM_Start_DMA(htim1, TIM_CHANNEL_1, (uint32_t *)dshot_ccr_buf, 16);DMA 会把 16 个 CCR 值依次写入定时器比较寄存器PWM 输出对应的脉冲序列。一帧发完后DMA 会进入传输完成中断。我在中断里做了两件事停止 DMA同时手动把 CCR 设为 0让输出保持低电平作为帧间空闲状态。这样每个新的油门值由外部定时器中断周期性触发刷新率可以稳定控制在 500Hz 或者 1kHz。代码结构上主循环只负责更新油门目标值真正发送的节奏由定时器中断控制。4. 逻辑分析仪实测与逆向解析4.1 抓取波形的操作流程把逻辑分析仪的 CH0 接到 STM32 的 PA8也就是 TIM1_CH1地线接好共地。打开 Saleae Logic采样率设 24MHz触发方式选择 Rising Edge触发通道选 CH0采样时长设 20ms。然后让程序持续发送油门值 500 的 Dshot600 帧。如果一切正常软件里会看到一串密集的脉冲序列每 16 个脉冲构成一帧帧与帧之间有一段低电平间隔。展开其中一帧可以看到每个脉冲的高电平宽度明显有两种长度短的大约 625ns长的接近 1250ns。我曾经在低采样率下抓过波形高电平台阶被采得断断续续肉眼很难判断原始脉宽。换上 24MHz 采样率之后每个脉冲至少有十几个采样点测量精度完全够用。4.2 从波形还原 16 位帧数据逆向解析的核心就是逐位测量高电平脉宽然后归类为 0 或 1。方法是先统计一下当前帧里所有脉冲的宽度把明显偏短的一批记为 0偏长的一批记为 1。为了避免单次测量误差我通常会取多个脉冲的平均值再定阈值。Dshot600 下0 码实测约 625ns1 码约 1250ns阈值取 900ns 左右很稳定。按位顺序从第一个脉冲开始数第一个脉宽偏短记为 0第二个偏短记为 0第三个开始变长记为 1……一直数到第 16 个脉冲。以油门 500 为例理论上的帧位序列是0 0 1 1 1 1 1 0 1 0 0 0 1 1 0 0前 12 位 001111101000 就是 value其中前 11 位是油门值的主体第 12 位也就是 value 的最低位是遥测请求位。把 value 右移一位得到 500最低位是 0表示未请求遥测。后 4 位 1100 是 CRC。这一步最能体现“逆向解析”的意义你不是用飞控代码告诉你这帧是什么而是直接从波形上读出来再反推编码规则。4.3 实操验证解析结果与 CRC 校验把上面读出的 12 位 value 放进 CRC 算法重新算一遍得到的结果同样是 12二进制 0b1100跟波形上读到的后四位完全一致。这就说明两件事一是 Dshot 帧结构理解正确二是 DMA PWM 的发送时序没问题。为了确认不是巧合我再换几个油门值测比如 300、800、1000每次都用逻辑分析仪抓帧、读位、算 CRC最终结果都能对上。这个验证过程很重要因为只测一个值可能掩盖位序或者 CRC 的细节错误。如果抓到的帧和计算对不上优先检查三个地方位顺序是否读反0/1 脉宽阈值是否偏移以及 DMA 发送时数组下标和位序的对应关系。之前就遇到过数组倒序导致整个帧镜像翻转的情况逻辑分析仪读出来像是另一串数据但波形本身是完好的。5. 常见问题与排查经验5.1 高频问题速查表下面是我调试时遇到过的典型问题整理成速查表现象可能原因处理方式引脚无输出逻辑分析仪抓不到定时器 PWM 未启动或 DMA 未配置检查是否调用了 HAL_TIM_PWM_Start_DMA波形是一串均匀方波不是两种脉宽ARR 或 PSC 计算错误位周期不对重新计算 ARR 72MHz * 位周期 - 1帧之间间隔太短电调不识别DMA 使用 Circular 模式帧连续重复改用 Normal 模式发完停或加空闲间隔CRC 对不上位序读反、0/1 阈值偏移、CRC 算法错误从波形重新数位换多个油门值对比电调上电后电机不转信号正常油门值过小电调处于解锁保护状态发送怠速油门以上比如 500一帧发完后引脚电平不对DMA 完成后没有拉低空闲电平在 DMA 完成中断里设 CCR0其中“波形均匀方波”这个问题最坑。我第一次配 TIM1 时忘了把 Prescaler 设为 0结果每个位周期被拉长了 72 倍逻辑分析仪上看起来就像一片稳定的 PWM 方波完全不像是 Dshot 帧。后来用光标一量位周期才发现是 120us才反应过来定时器分频出了问题。5.2 我踩过的坑与心得第一个坑DMA 的 Normal 和 Circular 模式选择。标题里写了 DMA 版很多人包括我自己一开始都想着 Circular 模式多省心DMA 自动循环发。但实际上对于 Dshot 来说帧与帧之间必须有一定间隔电调才能正确判断新一帧的开始。Circular 模式会把同一帧 16 个位无缝重复整个线上看起来就是连续的 16 位脉冲串电调根本找不到帧边界自然也不响应。第二个坑HAL 库的 DMA 回调。我最初在HAL_TIM_PWM_PulseFinishedCallback里做帧结束处理但没仔细看回调参数导致中断一直进不来。排查了半天才发现 HAL 在 PWM_DMA 传输完成时走的是这个 PWM 脉冲完成回调不是普通的 DMA 中断回调。这个细节文档里写得很晦涩实际操作时很容易漏。第三个坑油门值 0 和电调解锁的关系。Dshot 电调通常以 0 作为怠速以下的“禁止启动”信号但你测试时发送 0电调不会转这不代表协议有问题。我当时为了安全起见一直发送很小的油门值结果电调纹丝不动我还以为是波形不对后来把油门提到 500电机立刻就有动静了。6. 从 Dshot600 扩展到更多玩法6.1 改速率只动一个参数如果想把 Dshot600 改成 Dshot300只需要修改 CubeMX 里定时器的 ARR。Dshot300 的位周期是 3.333us72MHz 下 ARR 239逻辑 1 和逻辑 0 的 CCR 值也相应变成 180 和 90。其他代码完全不用动。实测中改完 ARR 后逻辑分析仪抓到的位周期立刻变成 3.33us帧长也变成大约 53us。如果配合不同电调这招非常实用不了解对方支持哪种速率时一个个试过去就行。6.2 双向 Dshot 与遥测读取Dshot 协议还有一个进阶玩法双向 Dshot。电调在收到指令帧后会通过同一个引脚回传 eRPM、温度、电流等信息。飞控侧需要在发完帧后立刻把 GPIO 方向从输出切到输入然后测量电调回传的脉宽。这套链路和本文的逻辑分析仪逆向解析是一脉相承的。回传数据同样是用脉宽区分 0 和 1只是节奏更快。如果你把我上面 DMA 发送和逻辑分析仪解码的方法吃透了再去啃双向 Dshot 会轻松很多。6.3 配套硬件优化调试阶段我用的是逻辑分析仪后来发现如果想看真实的模拟波形细节还是得借个示波器。逻辑分析仪只有 0/1 概念看不出信号上升沿斜率、过冲和振铃。尤其是接线比较长的时候Dshot600 的 1.25us 高电平很容易被线缆寄生电容削掉一大截这时候逻辑分析仪可能仍然认为它是逻辑 1但电调端的识别余量已经被压缩了。如果要在实际机架上长线传输 Dshot建议信号线尽量短必要时加 33Ω 左右的串联电阻限制过冲。这一点我在调试时深有体会悬空测波形完全正常一接电调信号线就异常最后发现是飞线太长信号质量变差了。最后再分享一个小技巧把逻辑分析仪的采样率固定到 24MHz 以上采样时长不要贪长20ms 足够抓几十帧软件分析不卡光标测量也精准。逆向解析这种东西不是设备越贵越好而是抓到的波形越清楚越好。我这套 DMA 发送代码反复用的过程中感觉最值钱的经验就是先抓波形、再写逻辑波形对了协议自然就通了。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

快速搭建网站的工具怎么选?3个方案省下5万冤枉钱 2026/9/28 9:42:31

快速搭建网站的工具怎么选?3个方案省下5万冤枉钱

快速搭建网站的工具怎么选?3个方案省下5万冤枉钱 网站做好了没人访问,这是很多老板最头疼的事。你花大价钱做的官网,设计精美、功能齐全,但打开一看,流量为零,咨询为零。这时候你才意识到,问题不在“做没做”,而在“怎么快速做出来并推向市场”。面…

阅读更多 →
昇腾910B多机分布式推理:从HCCL到MindIE的DeepSeek部署实践 2026/9/28 9:42:24

昇腾910B多机分布式推理:从HCCL到MindIE的DeepSeek部署实践

昇腾910B上跑DeepSeek多机分布式推理,很多人卡在第一眼:MindIE、HCCL、ranktable、hccn_tool,每个词都眼熟,串起来就不是那么回事。实际踩过一圈之后你会发现,真正决定能不能跑起来的不是模型代码,而是通信…

阅读更多 →
从CANoe到TSMaster:车载总线测试工具链迁移实战指南 2026/9/28 9:42:24

从CANoe到TSMaster:车载总线测试工具链迁移实战指南

搞车载总线测试的工程师,电脑里大概率都装着一套CANoe。我最早接触CANoe是刚入行那会儿,跟着前辈在项目里做网络测试,从报文发送、DBC解析到UDS诊断,基本全是靠Vector这套工具撑起来的。说实话,CANoe确实是这个行业的标…

阅读更多 →
从刷榜到用榜:GitHub Trending 的增量逻辑、项目筛选与高效落地 2026/9/28 9:42:23

从刷榜到用榜:GitHub Trending 的增量逻辑、项目筛选与高效落地

1. 日榜的"热度"到底是怎么算出来的先别急着收藏仓库。每天打开 GitHub 的 Trending 页面,你看到的是过去 24 小时内 Star 增量最高的仓库,周榜和月榜则分别看一周、一个月内的增量。官方没有公开完整排序算法,但用久了会发现&…

阅读更多 →
【Java开发MCP】SSE模式开发并集成MCP:TaoToken统一Key接入与SpringAI WebFlux配置骨架 2026/9/28 9:42:23

【Java开发MCP】SSE模式开发并集成MCP:TaoToken统一Key接入与SpringAI WebFlux配置骨架

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
OpenCompass 高效评测:Partitioner 任务切分与 Runner 执行后端实战指南 2026/9/28 9:42:23

OpenCompass 高效评测:Partitioner 任务切分与 Runner 执行后端实战指南

模型评测人工智能大模型AI 评测 【免费下载链接】opencompass OpenCompass is an LLM evaluation platform, supporting a wide range of models from OpenAI, Anthropic, Gemini, Qwen, GLM, DeepSeek, etc, across 100 datasets covering knowledge, reasoning, coding, scie…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉