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的协议 的相关文章

  • FIFO与DMA

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

    在STM32F4系列中DMA增加了个FIFO 这个FIFO的作用是什么 xff1f 当我使能这个FIFO时 xff08 DMA InitStructure DMA FIFOMode 61 DMA FIFOMode Enable xff09
  • HAL_DMA_IRQHandler()代码详细分析

    这里使用ADC1联动DMA1 xff0c 开启半传输中断 传输中断 debug时 xff0c dma也一直在工作 xff0c 所以半传输中断 传输中断会同时生效 1 adc1使用了DMA1 Stream0 xff0c Instance表示如
  • 怎么把PWM信号转为模拟量

    有一个测量位置变化的位置传感器 xff0c 用万用表电压档测量传感器的输出信号 xff0c 结果显示的是模拟量信号 xff0c 即位置和信号输出大小呈线性关系 但是 xff0c 用示波器 xff08 Picoscope 4227 xff09
  • STM32 DMA正常模式等待传输完成和开始下一次传输

    选择DMA的正常模式 xff0c 即DMA只传输一次 如果当传输完一次后 xff0c 还想再传输一次 xff0c 就需要重启DMA xff1a DMA Cmd DMA1 Channel6 DISABLE 重新设置源地址 重新设置目的地址 重
  • STM32 HAL 串口收发(无DMA,中断接收)

    STM32CUBE配置 一 使用printf发送数据 xff0c 在usart c中添加代码串口重定向 USER CODE BEGIN 0 include lt stdio h gt ifdef GNUC define PUTCHAR PR
  • 在EBAZ4205 zynq7010上运行AXI_DMA中断回环测试

    在EBAZ4205 zynq7010上运行AXI DMA loop interrupt 整体的布局图 这是上面的一张接口图 下面对每个模块附上截图 AXI DMA的输出mm2s introut s2mm introut接到PS系统的中断触发
  • 16. GD32F103C8T6入门教程-adc 使用教程2-dma+连续扫描方式采集数据

    adc 使用教程2 dma 连续扫描方式采集数据 adc 的扫描模式就是把配置了规则或注入通道按照配置的顺序采集一轮 adc 的连续转换模式就是把配置了规则或注入通道按照配置的顺序采集N轮 注意 dma使用时存在一个外设映射到一个dam外设
  • 电机控制基础——定时器基础知识与PWM输出原理

    单片机开发中 电机的控制与定时器有着密不可分的关系 无论是直流电机 步进电机还是舵机 都会用到定时器 比如最常用的有刷直流电机 会使用定时器产生PWM波来调节转速 通过定时器的正交编码器接口来测量转速等 本篇先介绍定时器的基础知识 然后对照
  • 基于32单片机的16通道ADC的数据采集

    基于32单片机的16通道ADC的数据采集 这个部分的内容 是作为外部模拟量部分的采集工作 按照任务要求 所设计的方案 需要完成以下指标 ADC必须能采集16通道的模拟量 ADC的分辨率是16bit 采样率不小于20khz 由此分析可以得出
  • STM32通用定时器(原理、结构体、库函数、定时器中断每秒闪烁一次灯) —— 时钟源、分频值、重装载值

    参考 stm32定时器与定时器中断 作者 打酱油的 发布时间 2021 04 11 01 04 09 网址 https blog csdn net weixin 46098612 article details 115493737 参考 s
  • X2000 Linux PWM

    一 硬件设计 PC04 PWM4 二 通过shell开启PWM 配置参数 cmd pwm config pc04 freq 1000 max level 100 active level 1 accuracy priority freq 启
  • STM32通用定时器使用详解

    1 通用定时器基本介绍 通用定时器包括TIM2 TIM3 TIM4和TIM5 STM32通用定时器是一个通过可编程预分频器驱动的16位自动装载计数器构成 每个定时器都是完全独立的 没有互相共享任何资源 它们可以一起同步操作 定时器可以进行定
  • BeagleBone Black (v4.14) 上的 PWM 芯片到引脚映射

    关于如何在较新版本的内核上配置 Beaglebone 进行 PWM 的信息非常少 我按照以下指示进行操作BeagleBone Black v4 14 上的 PWM https stackoverflow com questions 5020
  • 启用 DMA 的 UART Tx 模式

    我已经为 UART 在传输模式下编写了一个简单的设备驱动程序 并启用了 DMA 和中断 我使用的硬件是 omap 4460 pandaboard 其中加载了 Linux 3 4 下面我分享一下相关部分的代码 在开放阶段 dma map io
  • 从哪里开始学习 Linux DMA/设备驱动/内存分配

    我正在移植 调试设备驱动程序 由另一个内核模块使用 并面临死胡同 因为 dma sync single for device 因内核错误而失败 我不知道这个函数应该做什么 而且谷歌搜索也没有什么帮助 所以我可能需要了解更多关于这个东西的知识
  • Linux内核设备驱动程序以DMA方式进入内核空间

    LDD3 p 453 演示dma map single使用作为参数传入的缓冲区 bus addr dma map single dev gt pci dev gt dev buffer count dev gt dma dir Q1 这个缓
  • Linux 内核中的 DMA 映射和 DMA 引擎是什么?

    Linux 内核中的 DMA 映射和 DMA 引擎是什么 DMA映射API和DMA引擎API何时可以在Linux设备驱动程序中使用 任何真正的 Linux 设备驱动程序示例作为参考都会很棒 Linux 内核中的 DMA 映射和 DMA 引擎
  • 环形缓冲区和 DMA

    我试图了解从数据包到达网卡到目标应用程序收到数据包之间发生的所有事情 假设 缓冲区足够大 可以容纳整个数据包 我知道情况并非总是如此 但我不想介绍太多技术细节 一种选择是 1 Packet reaches the NIC 2 Interru
  • 当端点和 PMA 地址均更改时,CubeMX 生成的 USB HID 设备发送错误数据

    我正在调试我正在创建的复合设备的问题 并在新生成的仅 CubeMX 代码中重新创建了该问题 以使其更容易解决 我添加了少量代码main 让我发送 USB HID 鼠标点击 并在按下蓝色按钮时使 LED 闪烁 uint8 t click re

随机推荐

  • 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