通过TIM+DMA Burst 实现STM32输出变频且不同脉冲数量的PWM波形

news2025/4/11 4:53:23

Burst介绍:

DMA控制器可以生成单次传输或增量突发传输,传输的节拍数为4、8或16。

为了确保数据一致性,构成突发传输的每组传输都是不可分割的:AHB传输被锁定,AHB总线矩阵的仲裁器在突发传输序列期间不会撤销DMA主设备的授权。

作用:

可以通过Burst进行多个寄存器的同时修改,在M2P时同时配置多个定时器。

burst会占用总线直到数据发完为止,此期间CPU打断不了,但是不连续的节拍之间CPU依然可以打断

问题剖析:

需要STM32输出变频且不同脉冲数量的PWM波形,具体要求如下:

交替输出两组参数:

参数组1:频率较高(ARR=1000),输出3个脉冲(RCR=2)。

参数组2:频率较低(ARR=5000),输出2个脉冲(RCR=1)。

实现方式:通过DMA Burst功能,在一次定时器事件中批量修改多个寄存器(ARR、RCR、CCR),无需CPU干预。

STM32的TIM模块支持DMA Burst功能,允许通过单次定时器事件触发多次DMA传输,从而批量更新多个寄存器。其核心硬件模块如下:

(1) 关键寄存器

TIMx_DCR(DMA控制寄存器):

DBSS (DMA Burst Source Selection):选择触发DMA Burst的事件源(如定时器更新事件)。

DBL (DMA Burst Length):设置一次DMA Burst传输的数据个数(例如3次传输,对应修改ARR、RCR、CCR)。

DBA (DMA Burst Address):设置DMA传输的起始寄存器地址偏移(例如ARR寄存器的地址偏移为0x2C)。

TIMx_DMAR(DMA地址寄存器):

DMA通过访问此寄存器,将数据写入目标寄存器(如ARR、RCR、CCR)。

(2) 工作原理

触发事件:定时器产生指定事件(如更新事件TIM_UPDATE)。

DMA请求:事件触发DMA Burst传输,DMA控制器根据TIMx_DCR配置的传输次数(DBL)和起始地址(DBA),将内存中的数据连续写入多个寄存器。

自动更新参数:寄存器值被修改后,定时器立即使用新参数生成PWM波形。

理解关键参数:

Burst Size与传输次数的关系

在STM32的DMA Burst模式中,Burst Size 表示 单次突发传输(Burst)中连续传输的数据单元个数,而 传输总次数 由以下两个参数共同决定:

Burst Size(突发传输单元数):例如设置为4,表示一次突发传输4个数据单元。

Data Width(数据宽度):每个数据单元的大小(字节、半字或字)。

NDTR(Number of Data):DMA传输的总数据单元数(需在代码中动态设置)。

公式:

总传输次数 = NDTR / Burst Size

例如:若NDTR=12,Burst Size=4,则总传输次数为3次(每次突发传输4个单元)。

这里我们让DMA Burst输出一次,一次传四个数据单元的值(实际上只用三个,但是mx中只可以配4increment,第四个数据传0即可),输出的脉冲个数通过传入的四个单元值中RCR 的值决定;

PWM参数定义

ARR (Auto-Reload Register):决定PWM频率。

频率公式:PWM频率 = 定时器时钟 / (ARR + 1)

示例:

pulse1[0] = 1000 → 频率 = 100MHz / 1001 ≈ 99.9 kHz

pulse2[0] = 5000 → 频率 = 100MHz / 5001 ≈ 20 kHz

RCR (Repetition Counter Register):控制脉冲个数。

脉冲个数公式:脉冲数 = RCR + 1

示例:

pulse1[1] = 2 → 输出3个脉冲

pulse2[1] = 1 → 输出2个脉冲

CCR (Capture/Compare Register):决定占空比。

占空比公式:占空比 = CCR / (ARR + 1)

示例:

pulse1[2] = 500 → 占空比 ≈ 50%

pulse2[2] = 2500 → 占空比 ≈ 50%

参数结构:

uint32_t pulse1[3] = {1000, 2, 500};  // ARR=1000, RCR=2, CCR=500
uint32_t pulse2[3] = {5000, 1, 2500}; // ARR=5000, RCR=1, CCR=2500

CubeMX设置:

在CubeMX中配置Burst Size

打开DMA Settings标签页,选择对应的DMA通道。

设置 Burst Size 为 4 Increment(根据需求选择1/4/8/16)。

设置 Data Width 为 Word(32位,与TIM寄存器位宽一致)。

勾选 Increment Address(内存地址递增)。

选择 Mode 为 Normal 或 Circular。(若需持续传输,选择Circular模式并且设置足够大的NDTR)

每次DMA Burst需传输3个寄存器值(ARR、RCR、CCR)。

每个寄存器为32位(4字节),共需传输12字节。

Burst Size = 4 Increment(每次传输4个数据单元,但实际仅用3个,最后一个填充0)。

Data Width = Word(32位)。

NDTR = 3(传输3个数据单元)。

HAL_DMA_Start_IT()函数原型:

HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)

 代码实现:

uint32_t pulse_data[4] = {1000, 2, 500, 0}; // 第4个数据填充0
HAL_DMA_Start_IT(&hdma_tim1, (uint32_t)pulse_data, (uint32_t)&TIM1->DMAR, 3);// NDTR=3

交替输出的实现

(1) 中断切换模式

第一次传输:DMA传输pulse1到TIM寄存器。

传输完成中断:在中断回调函数中重新配置DMA,传输pulse2。

循环触发:重复上述过程,实现交替输出。

(2) 双缓冲模式

配置双缓冲:使能DMA双缓冲,设置两组内存地址(pulse1和pulse2)。

自动切换:DMA传输完当前缓冲区后,自动切换到下一组参数,无需CPU干预。

关键代码片段(基于HAL库)

// 1. DMA传输完成中断回调函数
void HAL_TIM_DMADelayPulseCplt(DMA_HandleTypeDef *hdma) {
  // 切换参数组
  static uint8_t is_pulse1 = 0;
  if (is_pulse1) {
    HAL_DMA_Start_IT(&hdma_tim1, (uint32_t)pulse1, (uint32_t)&TIM1->DMAR, 3);
  } else {
    HAL_DMA_Start_IT(&hdma_tim1, (uint32_t)pulse2, (uint32_t)&TIM1->DMAR, 3);
  }
  is_pulse1 = !is_pulse1;
}

// 2. 主函数初始化
int main(void) {
  // 初始化定时器和DMA
  HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
  HAL_DMA_Start_IT(&hdma_tim1, (uint32_t)pulse1, (uint32_t)&TIM1->DMAR, 3);
  while (1) {
    // 其他任务
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2326390.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[Effective C++]条款26:尽可能延后变量定义的出现时间

. 在C中,尽可能延后变量定义的出现时间,主要原因是为了提供代码的可读性,减少不必要的开销以及避免潜在的错误。 1、代码执行过程中抛出异常 如果在代码开头定义了变量,但在后续代码中抛出了异常,可能导致变量在未被使…

如何在k8s中对接s3存储

github地址: https://github.com/majst01/csi-driver-s3 1.CSI for S3 这是用于 S3(或兼容 S3)存储的容器存储接口 (CSI)。它可以动态分配存储桶并通过Fuse mount将它们安装到任何容器中 2.状态 这仍处于试验阶段,不应在任何…

FPGA实现LED流水灯

一、在VsCode中写代码 1、建立工程项目文件water_led.v文件 2、打开项目文件,创建三个目录 3、打开文件trl,创建water_led.v文件 4、打开文件tb,创建water_led_tb.v文件 5、用VsCode打开water_led.v文件,编写源代码 module water…

百度文库免费下载器

01 引言 在国内的环境下,Greasy Fork网站是彻底打不开了,导致好多小伙伴想要用脚本都没办法。 特别是需要某Wen库下载的小伙伴,之前还说实在没办法,去Greasy Fork网站上安个脚本就可下载,但是现在网站被墙了&#xf…

[NCTF2019]True XML cookbook[XXE] [内网探测] [网络ip相关知识]

一模一样的登录界面 我直接故伎重演但是并卵 &#xff08;话说XXE注入之前好像其他博客都加上了<?xml version"1.0" encoding"utf-8"?>&#xff0c;但是不加好像也没有什么问题&#x1f914;&#xff09; <?php /** * autor: c0ny1 * date: …

Linux驱动的基本概念

一 交叉开发编译 概念&#xff1a;交叉开发编译(Cross Compilation)是指在一个平台上生成能在另一个不同平台上执行的代码的编译过程。这是嵌入式系统开发和跨平台软件开发中的常见技术。 二 系统启动流程 在Linux源码下&#xff0c;通过网口利用tftp协议把u-bantu下的uImage…

win server2022 限制共享文件夹d

点击配额管理中的配额 然后创建配额 导入要配额的文件即可 然后确定即可

Ansible(3)——主机清单与配置文件

目录 一、创建 Ansible 清单&#xff1a; 1、清单定义&#xff1a; 2、使用静态清单指定受管主机&#xff1a; &#xff08;1&#xff09;主机名称指定&#xff1a; &#xff08;2&#xff09;IP 地址指定&#xff1a; 3、验证清单&#xff1a; &#xff08;1&#xff0…

C语言 【初始指针】【指针一】

引言 思绪很久&#xff0c;还是决定写一写指针&#xff0c;指针这块内容很多&#xff0c;也不是那么容易说清楚&#xff0c;这里尽可能写地详细&#xff0c;让大家理解指针。&#xff08;未完序&#xff09; 一、内存和地址 在讲指针前&#xff0c;需要有一个对内存和地址的认…

IP 地址规划中的子网划分:/18 网络容纳 64 个 C 段(/24)的原理与应用解析

整体表格说明 这是某市教育城域网中某县教育相关机构的IP地址规划表&#xff0c;明确了某县一中和某县教育局的IP地址范围&#xff0c;包括终端使用地址段、业务互访地址段。 概念解析 64个C段终端及互联地址 C段地址&#xff1a;一个C段是IP地址中的一个/24网络&#xff08;…

linux下Tomcat配置提示权限不够解决办法

文章目录 前言解决方案 前言 往linux服务器上部署Java后端&#xff0c;但是在服务器上安装好的tomcat&#xff0c;却因为权限不够无法进入 这就导致后端war包项目及前端页面无法部署 解决方案 sudo chmod -R 777 /opt/tomcat/webapps修改tomcat目录下的权限即可&#xff0c;对…

您使用的开源软件许可证是否存在冲突呢?

开源软件代码使用现状 根据最新发布的《第三次自由和开源软件普查报告》&#xff0c;96%的代码库中使用了开源组件&#xff0c;这表明开源技术在现代软件开发中占据了核心地位。在国内企业软件项目中&#xff0c;开源软件的使用率达到了100%&#xff0c;平均每个项目使用了166…

leetcode刷题日记——接雨水

[ 题目描述 ]&#xff1a; [ 思路 ]&#xff1a; 题目要求求凹进去的部分能接多少雨水&#xff0c;即有多少个格子可以从第一个高度快出发去寻找下一个高于或者等于他的格子&#xff0c;然后计算其中的差值 有高于或等于他的格子&#xff0c;计算他俩中间能装的雨水当后续没有…

阿里巴巴暑期实习Java面经,灵犀互娱一面

哈希表熟悉吗&#xff0c;可以如何实现&#xff1f; 开散列版本什么时候需要扩容 高并发服务器内的主从reactor模型是如何实现的&#xff1f; 进程 线程 协程 的区别&#xff1f; 如何保证线程安全 &#xff1f; 了解读写锁吗&#xff1f; 单例模式有了解吗&#xff1f; 可以怎…

AI知识补全(十四):零样本学习与少样本学习是什么?

名人说&#xff1a;一笑出门去&#xff0c;千里落花风。——辛弃疾《水调歌头我饮不须劝》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 上一篇&#xff1a;AI知识补全&#xff08;十三&#xff09;&#xff1a;注意力…

如何用Postman实现自动化测试?

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 这里简单演示在postman中怎样实现自动化测试&#xff08;不涉及到用户登录的token认证&#xff09; 导入测试用例文件&#xff0c;测试web接口 postman使用流程…

LeetCode Hot100 刷题笔记(9)—— 二分查找、技巧

目录 前言 一、二分查找 1. 搜索插入位置 2. 搜索二维矩阵 3. 在排序数组中查找元素的第一个和最后一个位置 4. 搜索旋转排序数组 5. 寻找旋转排序数组中的最小值 6. 寻找两个正序数组的中位数 二、技巧 1. 只出现一次的数字 2. 多数元素 3. 颜色分类 4. 下一个排列 5. 寻找重复…

Ubuntu 系统上完全卸载 Docker

以下是在 Ubuntu 系统上完全卸载 Docker 的分步指南 一.卸载验证 二.卸载步骤 1.停止 Docker 服务 sudo systemctl stop docker.socket sudo systemctl stop docker.service2.卸载 Docker 软件包 # 移除 Docker 核心组件 sudo apt-get purge -y \docker-ce \docker-ce-cli …

Python----计算机视觉处理(Opencv:道路检测之道路透视变换)

一、透视变换 对于道路检测来说&#xff0c;为了方便车辆进行行驶&#xff0c;道路上都有车道线&#xff0c;为了更加方便对道路线进行检测&#xff0c;首先我们要把到路线平视图转变为俯视图&#xff0c;以便后期处理更加方便&#xff0c;如下图所示&#xff0c;该为虚拟场景的…

为什么 ThreadLocalMap 的 key 是弱引用 value是强引用

问题一&#xff1a;为什么 ThreadLocalMap 的 key 是弱引用&#xff1f; 【假设 Entry 的 key 是对 ThreadLocal 对象的强引用】&#xff1a;这个 Entry 又持有 ThreadLocal 对象和 value 对象的强引用。如果在其他地方都没有对这个 ThreadLocla 对象的引用了、然后在使用 Thr…