CubeMX 配置PWM使用DMA,生成Dshot600的协议

2023-05-16

看到电调支持Dshot125-600的协议,想自己做一个支持Dshot协议的驱动,所以研究了一下,如何利用精确的PWM产生Dshot协议。

先看结果!图中为油门值为1500的时候的输出的Dshot600的一个协议帧

长的代表1   短的代表0,一共18个数据,包括最后连个低电平表示的帧间隔。

=============================分隔符================================

【Dshot协议】

主要用于飞控和电调之间的通讯,根据通讯速录不同可以分为Dshot150,Dshot300,...等等
•DShot600 – 1200k bits/Sec
•DShot600 – 600k bits/Sec
•DShot300 – 300k bits/Sec
•DShot150 – 150k bits/Sec


DSHOT协议一帧信号由16位组成:
1、油门值:
前11位二级制数表示油门的大小,其范围为0-2047。
2、回传标志位:
第12位,由0和1表示,0为不回传数据,1位回传数据,相交于传统的电调这种电调多了回传信息,更有利于开发者进行开发。
3、校验位:
第13-16位组成, 其数值为是将前12位分成3组,每组4位,将三组数据进行亦或计算得出的数值即为校验位。
每一位的数值均由0和1组成,由PWM波的占空比进行数值的表示。

 

拿Dshot600协议来说:每600k b/s ,每包数据有18个bit ,所以每包数据要30us。每个bit大概要1.67us。       上图表示bit1时的脉宽为1.22us 周期1.66us。 表示bit0时的脉宽为610ns。

其实我也不确定表示1和0时,高电平的时间是怎么分割的,感觉是单个bit周期的70%和30%左右即可,等我电调回来了实验一下。

 

所以这个图中表示的就是101  1101  1100     0  100  0 - - 

前11位就是1500的二进制表示,下一个0代表不需要回传,100  0代表CRC校验。 - -代表两个低电平 帧分割 。

 =============================分隔符================================

首先进行CubeMX的配置:我使用的是F103VET6开发板

Time2的配置,注意合适的分频系数以及重装载值。

 

DMA的配置主要注意数据宽度,以及方向,还有内存地址递增。要和程序进行结合

实际函数使用 HAL_TIM_PWM_Start_DMA进行发送

HAL_TIM_PWM_Start_DMA(&htim2,TIM_CHANNEL_3,(uint32_t *)esc_cmd,ESC_CMD_BUF_LEN);

CubeMX中配置外设的数据宽度位16位(半字),因为PWM对应的存放定时值的寄存器长度是16。

初始化数组的时候也要uint16的数组,从这个地址每次取16bit。

uint16_t ESC_CMD[18]={0};

HAL_TIM_PWM_Start_DMA的第三个参数是一个地址,不用理会(uint32_t)。只要你设置了两个数据宽度为Half Word, DMA就会从这个地址开始每次拿16位数据,然后地址递增,拿够你设置的个数。

这样就可以输出希望个数的 占空比不同的 PWM波了(不要忘记在DMA输出完后 ,回调中关闭DMA)。

其他的CubeMX配置都是比较简单的了,时钟也贴出来了。最后调用pwmWriteDigital函数就可以输出希望的Dshot协议了。

  =============================分隔符================================

【程序部分】【程序参考bf开源固件中的部分】



//定时器 4分频72/4=18mhz ;分频不固定,可自行调整
//pwm波周期 1.67us ;对应的pwm分辨率 1.67us /(1/18)= 30;
// 0.625us/(1/18) = 11; 0的占空比11/30
// 1.250us/(1/18) = 22; 1的占空比22/30
 
#define ESC_BIT_0     11
#define ESC_BIT_1     22  
#define ESC_CMD_BUF_LEN 18 
uint16_t ESC_CMD[ESC_CMD_BUF_LEN]={0};


//定时器 1分频32/1=32mhz ;分频不固定,可自行调整  记一次数就是1/32 us
//pwm波周期 1.67us ;对应的pwm分辨率 1.67us /(1/32)= 53.44;
// 0.625us/(1/32) = 20; 0的占空比20/53
// 1.250us/(1/32) = 40; 1的占空比40/53

// #define ESC_BIT_0     20
// #define ESC_BIT_1     40  

/*************************************************************
** Function name:       prepareDshotPacket
** Descriptions:        CRC校验以及要不要回传信息
** Input parameters:    value: 油门大小 注意取值范围, requestTelemetry 是否请求回传数据
** Output parameters:   None
** Returned value:      None
** Remarks:             None
*************************************************************/
static uint16_t prepareDshotPacket(const uint16_t value, bool requestTelemetry)
{
    // 油门大小为11位  所以这里先左移一位 添加上请求回传标志共12位
    uint16_t packet = (value << 1) | (requestTelemetry ? 1 : 0);

    // 将12位数据分为3组 每组4位, 进行异或
    // compute checksum
    int csum = 0;
    int csum_data = packet;
    for (int i = 0; i < 3; i++) {
        csum ^=  csum_data;   // xor data by nibbles
        csum_data >>= 4;
    }
    //取最后四位 其他的不要 
    csum &= 0xf;
    // append checksum 将CRC添加到后四位
    packet = (packet << 4) | csum;
    return packet;
}


/*************************************************************
** Function name:       pwmWriteDigital
** Descriptions:        根据输入 填充esc_cmd,填充的数值代表每一位的高低电平
** Input parameters:    None
** Output parameters:   None
** Returned value:      None
** Remarks:             None
*************************************************************/
static void pwmWriteDigital(uint16_t *esc_cmd, uint16_t value)
{
	value = ( (value > 2047) ? 2047 : value );
	value = prepareDshotPacket(value, 0);
    esc_cmd[0]  = (value & 0x8000) ? ESC_BIT_1 : ESC_BIT_0;
    esc_cmd[1]  = (value & 0x4000) ? ESC_BIT_1 : ESC_BIT_0;
    esc_cmd[2]  = (value & 0x2000) ? ESC_BIT_1 : ESC_BIT_0;
    esc_cmd[3]  = (value & 0x1000) ? ESC_BIT_1 : ESC_BIT_0;
    esc_cmd[4]  = (value & 0x0800) ? ESC_BIT_1 : ESC_BIT_0;
    esc_cmd[5]  = (value & 0x0400) ? ESC_BIT_1 : ESC_BIT_0;
    esc_cmd[6]  = (value & 0x0200) ? ESC_BIT_1 : ESC_BIT_0;
    esc_cmd[7]  = (value & 0x0100) ? ESC_BIT_1 : ESC_BIT_0;
    esc_cmd[8]  = (value & 0x0080) ? ESC_BIT_1 : ESC_BIT_0;
    esc_cmd[9]  = (value & 0x0040) ? ESC_BIT_1 : ESC_BIT_0;
    esc_cmd[10] = (value & 0x0020) ? ESC_BIT_1 : ESC_BIT_0;
    esc_cmd[11] = (value & 0x0010) ? ESC_BIT_1 : ESC_BIT_0; 	
    esc_cmd[12] = (value & 0x8) ? ESC_BIT_1 : ESC_BIT_0;
    esc_cmd[13] = (value & 0x4) ? ESC_BIT_1 : ESC_BIT_0;
    esc_cmd[14] = (value & 0x2) ? ESC_BIT_1 : ESC_BIT_0;
    esc_cmd[15] = (value & 0x1) ? ESC_BIT_1 : ESC_BIT_0;

    HAL_TIM_PWM_Start_DMA(&htim2,TIM_CHANNEL_3,(uint32_t *)esc_cmd,ESC_CMD_BUF_LEN);
}


/*************************************************************
** Function name:       HAL_TIM_PWM_PulseFinishedCallback
** Descriptions:        每次DMA发送完后会进这个回调函数,可以做标记。要记得关闭DMA
** Input parameters:    None
** Output parameters:   None
** Returned value:      None
** Remarks:             None
*************************************************************/
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
	HAL_TIM_PWM_Stop_DMA(&htim2, TIM_CHANNEL_3);
}

参考文章:

https://blog.csdn.net/qq_43650722/article/details/116402588?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162728504716780261987921%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=162728504716780261987921&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v29-5-116402588.first_rank_v2_pc_rank_v29&utm_term=DSHOT&spm=1018.2226.3001.4187

https://blog.csdn.net/qq_35081072/article/details/107747996?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162728504716780265454079%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=162728504716780265454079&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-4-107747996.first_rank_v2_pc_rank_v29&utm_term=DSHOT&spm=1018.2226.3001.4187

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CubeMX 配置PWM使用DMA,生成Dshot600的协议 的相关文章

  • stm32串口DMA方式发送数据

    该文档介绍stm32 uart1通过DMA方式发送和接收数据 xff0c 代码示例基于ucos ii操作系统 该文档参考https wenku baidu com view d44ef1380975f46526d3e1b5 html 中内容
  • FIFO与DMA

    FIFO存储器是一个先入先出的双口缓冲器 xff0c 即第一个进入其内的数据第一个被移出 xff0c 其中一个存储器的输入口 xff0c 另一个口是存储器的输出口 主要有三个方面的作用 xff1a 1 xff09 对连续的数据流进行缓存 x
  • FIFO和DMA

    FIFO SPI端口增加了FIFO xff0c 使得传输数据有了缓冲区间 FIFO存储器是一个先入先出的双口缓冲器 xff0c 即第一个进入其内的数据第一个被移出 xff0c 其中一个存储器的输入口 xff0c 另一个口是存储器的输出口 主
  • stm32串口DMA方式向上位机连续发送数据

    目录 一 认识DMA1 DMA框图2 什么是DMA xff1f 3 DMA传输方式4 DMA传输参数5 DMA数据传输的四个要素6 DMA的应用场景 二 串口DMA方式向上位机发送数据1 实验要求2 通过STMCube配置项目 1 设置RC
  • 怎么把PWM信号转为模拟量

    有一个测量位置变化的位置传感器 xff0c 用万用表电压档测量传感器的输出信号 xff0c 结果显示的是模拟量信号 xff0c 即位置和信号输出大小呈线性关系 但是 xff0c 用示波器 xff08 Picoscope 4227 xff09
  • STM32】 DMA原理,步骤超细详解,一文看懂DMA

    如需转载请注明地址 xff1a https blog csdn net as480133937 article details 104927922 DMA的基本介绍 什么是DMA DMA的基本定义 DMA xff0c 全称Direct Me
  • 2.14 STM32 串口传输最佳处理方式 FreeRTOS+队列+DMA+IDLE (二)

    紧接着上一篇文章 如何合理处理多个串口接收大量数据 此种方法 很厉害 很NB 首先 利用DMA 可节省大量CUP资源 其次 利用IDLE空闲中断来接收位置个数的数据 最后利用串口DMA环形数据的偏移量 长度 入队 出队处理数据 保证了任务的
  • AXI DMA总结、内核axidmatest.c测试程序分析、SG mode

    AXI DMA 概述 xff1a XILINX提供的AXI DMA支持Scatter Gather mode和Direct Register mode 数据位宽支持32 64 128 256 512 1024bits xff0c strea
  • 用PWM控制舵机(以是stm32为例)

    因为做校创需要用到舵机 xff0c 以前知道大致的理论 xff0c 因此看了一些帖子 xff0c 总结一下被以后查看 什么是PWM波 PWM就是脉冲宽度调制 xff0c 也就是占空比可变的脉冲波形 pwm的占空比 xff0c 就是指高电平保
  • Arduino接收航模遥控器RC接收机的PWM数据

    本文将介绍如何使用Arduino读取RC接收机的PWM数据 1 硬件部分 我的设备 xff1a 接收机 遥控器发射机 将Arduino Nano的引脚 D8 D11 接到接收机的1 4通道 xff0c 接收机上的电源正极和负极连接到Ardu
  • 魔方机器人之下位机编程---------舵机控制

    1 春天180 舵机 SR 403P 信号线和控制线颜色对应关系 两黑一白 白色信号线 中间电源 另一黑色电源 以上MC9S12XS128单片机通道三产生的周期为20ms 高电平为1 5ms的舵机控制信号 void PWM Init voi
  • mega328p-ADC,PWM,UART驱动

    ADC驱动 函 数 名 Ai Init 函数功能 Ai端口初始化 输入参数 void 输出参数 void 返 回 值 void 参考文档 void 创 件 人 程强刚 创建日期 2016 02 09 修改历史 void Ai Init vo
  • PMIC驱动之—PMIC硬件相关知识

    PMIC 电源管理集成电路 Power Management IC 在之前项目中 驱动最小系统 对于PMIC这块儿很懵懂 故抽时间查看一些优秀博文及资料 加强对电源管理的理解 本文介绍 PMIC 硬件电路相关的一些知识 在此作一些阶段性的学
  • STM32F031串口(RS485)中断+DMA发送(预备知识)

    STM32F031串口 RS485 中断 DMA发送 前言 GPIO移植过程 与F1系列的一些区别 串口 DMA 前言 最近在搞STM32F031的项目 F0系列与常用的F1系列有一定区别 在开发过程中遇到一些问题 而且花了好长花间在搜寻解
  • 快速学习Stm32舵机控制板控制多个舵机运动以及调速

    本次分享stm32对多个舵机的控制 之前讲解过单个舵机的控制 以及控制原理 定时器的使用和pwm的输出来控制一个舵机的角度转向 这次就和大家分享一下多个舵机的控制以及调速 利用单片机实现对 8 个舵机的同时控制 掌握多个舵机控制程序实现方法
  • GD32F4xx MCU ADC+DMA 多通道采样

    1 GD32F4xx ADC GD32F4xx 的12位ADC是一种采用逐次逼近方式的模拟数字转换器 1 1 主要特征 可配置12位 10位 8位 6位分辨率 ADC采样率 12位分辨率为2 6MSPs 10位分辨率为3 0 MSPs 分辨
  • 一起学nRF51xx 9 -  pwm

    前言 上一讲我们学习了nrf51822定的器的使用 那行如何用定时器实现PWM输出呢 NRF51的time模块不支持 PWM 功能 不可我们可以通过定时器 PPI GPIOTE模块一起工作的方式在NRF51XX上产生 PWM 信号 下面以使
  • 数据缓存如何路由本例中的对象?

    考虑图示的数据缓存架构 ASCII 艺术如下 CPU core A CPU core B Devices Cache A1 Cache B1 with DMA Cache 2 RAM
  • arm64 上的 Linux:从 mmapped 相干 DMA 缓冲区发送数据时,sendto 导致“未处理的故障:对齐故障 (0x96000021)”

    我正在构建一个基于配备arm64 CPU的UltraScale FPGA的数据采集系统 数据通过DMA传输到RAM 驱动程序中的 DMA 缓冲区保留如下 virt buf i dma zalloc coherent pdev gt dev
  • 环形缓冲区和 DMA

    我试图了解从数据包到达网卡到目标应用程序收到数据包之间发生的所有事情 假设 缓冲区足够大 可以容纳整个数据包 我知道情况并非总是如此 但我不想介绍太多技术细节 一种选择是 1 Packet reaches the NIC 2 Interru

随机推荐

  • Shell学习--基本运算符与test命令

    原生bash不支持简单的数学运算 xff0c 但是可以通过其他命令来实现 xff0c 例如 awk 和 expr xff0c expr 最常用 expr 是一款表达式计算工具 xff0c 使用它能完成表达式的求值操作 例如 xff0c 两个
  • Shell学习--echo命令

    echo 用于字符串的输出 xff0c 命令格式如下 xff1a echo string 1 显示普通字符串 echo 34 It is a test 34 二者效果一致 echo It is a test 2 显示转义字符 xff0c 双
  • Shell学习--printf命令

    printf 命令模仿 C 程序库 xff08 library xff09 里的 printf 程序 xff0c 使用 printf 的脚本比使用 echo 移植性好 printf 使用引用文本或空格分隔的参数 xff0c 外面可以在 pr
  • Shell学习--流程控制

    一 if else 1 if 语法格式 if condition then command1 command2 commandN fi 也可以写成一行 if ps ef grep c 34 ssh 34 gt 1 then echo 34
  • Shell学习--Shell函数

    linux shell 可以用户定义函数 xff0c 然后在shell脚本中可以随便调用 一 简单的函数定义 1 shell中函数的定义格式如下 xff1a function funname action return int 说明 xff
  • Shell学习--Shell 输入/输出重定向

    大多数 UNIX 系统命令从你的终端接受输入并将所产生的输出发送回 到您的终端 一个命令通常从一个叫标准输入的地方读取输入 xff0c 默认情况下 xff0c 这恰好是你的终端 同样 xff0c 一个命令通常将其输出写入到标准输出 xff0
  • Shell学习--Shell 文件包含

    和其他语言一样 xff0c Shell 也可以包含外部脚本 这样可以很方便的封装一些公用的代码作为一个独立的文件 Shell 文件包含的语法格式如下 xff1a filename 注意点号 和文件名中间有一空格 或 source filen
  • 向Github上传文件或项目

    准备工作 xff1a 具有 Github 账号 xff0c 电脑已安装 Git Bash 一 在 Github 上创建新的仓库 1 登录到 Github 主页创建一个新的仓库 xff08 两种方法都可以 xff09 2 配置新建仓库的属性
  • Github分支创建、管理、下载与上传

    当我们想进行文件备份 文件分类 版本更新 分工合作等工作时 xff0c 对github仓库进行分支就变得非常重要 一 创建分支 在Github仓库创建时会生成默认的主分支 xff0c 一般名称为 main xff0c 我们可以以主分支为基础
  • 删除Github仓库中的指定的文件或文件夹

    在Github 仓库中是无法通过鼠标操作直接删除文件和文件夹的 xff0c 那只能通过 git 命令来执行删除操作 xff0c 当我们想删除 First 分支中的 folder 文件夹及其内部的文件 和 file c 文件 时 一 获取当前
  • 如何判断栈、堆的增长方向?

    如何判断栈的增长方向 xff1f 对于一个用惯了i386系列机器的人来说 xff0c 这似乎是一个无聊的问题 xff0c 因为栈就是从高地址向低地址增长 不过 xff0c 显然这不是这个问题的目的 xff0c 既然把这个问题拿出来 xff0
  • 向文件最后一行添加字符串

    当我们想向某个文件中添加指定的字符串时 xff0c 可以使用相关的指令 一 echo指令 使用echo追加重定向可以直接向文件中添加一行字符串 echo 34 add string 34 gt gt test txt 可以看到echo会在文
  • KernelShark分析内核任务执行过程

    一 KernelShark简介 KernelShark是一个非常实用的工具 xff0c 其可以搭配 trace cmd 使用 xff0c 将内核的任务执行过程以直观的形式展现出来 下面的文档中详细的介绍了KernelShark的使用方法和功
  • 关于Linux中断的相关查询

    1 linux 内核 proc interrupts 在 proc interrupts 文件中记录了 Linux 内核的中断信息 xff0c 我们可以通过命令查看 sudo cat proc interrupts 文件中以表格的形式列举出
  • Latex中编译IEEE sensors journal 模板中遇到的种种问题

    总的来说 xff0c 这个期刊的模板跟之前那个TIE的模板不太一样 xff0c 因为目前只接触了这两个 xff08 本人水平比较菜 xff09 1 编译左上角的Logo xff0c 一直在报错 xff0c 并没有显示成功 xff0c 一直显
  • python笔记:argparse模块

    用途 python用于解析命令行参数和选项的标准模块 xff0c 内置于python xff0c 不需要安装 使用步骤 引入模块 span class token keyword import span argparse 创建一个解析器 使
  • Hadoop伪分布部署

    Hadoop伪分布部署 一 任务描述二 任务目标三 任务环境四 任务分析五 任务实施步骤1 解压Hadoop压缩包步骤2 配置Hadoop文件 六 任务测试 原创申明 xff1a 未经许可 xff0c 禁止以任何形式转载 xff0c 若要引
  • ubuntu下共存多个python版本,切换python版本

    ubuntu下切换默认python版本 知乎 zhihu com 1 以 root 身份登录 xff0c 首先罗列出所有可用的python 替代版本信息 update alternatives list python 这一步可能会报错upd
  • Deformable DETR进行目标检测,解决size mismatch问题

    问题描述 xff1a strict 61 False 但还是size mismatch for copying a param with shape from checkpoint the shape in cur 接着 6条消息 Defo
  • CubeMX 配置PWM使用DMA,生成Dshot600的协议

    看到电调支持Dshot125 600的协议 xff0c 想自己做一个支持Dshot协议的驱动 xff0c 所以研究了一下 xff0c 如何利用精确的PWM产生Dshot协议 先看结果 xff01 图中为油门值为1500的时候的输出的Dsho