STM32学习笔记DMA代码理解

这篇博客介绍了STM32的DMA(直接存储器访问)技术,详细解析了如何配置DMA1通道4进行串口发送。内容包括DMA的时钟使能、通道参数初始化、传输启动、状态查询等步骤,并探讨了不同配置方法的优缺点。
摘要由CSDN通过智能技术生成

STM32学习笔记DMA代码理解

前言

  博主在学习如何在手机上实现电脑上位机波形效果的时候,发现采用DMA方式来传输数据能更为快速,准确,就花了半天的时间,整理总结了一下DMA传输相关的资料,前面大部分为正点原子的资料,后面是我的一些理解,不足之处还请指正。

正点原子官方手册资料

DMA了解

  DMA,全称为:Direct Memory Access,即直接存储器访问,DMA 传输将数据从一个地址空间复制到另外一个地址空间。当 CPU 初始化这个传输动作,传输动作本身是由DMA 控制器 来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的内存区。像是这样的操作并没有让处理器工作拖延,反而可以被重新排程去处理其他的工作。DMA 传输对于高效能嵌入式系统算法和网络是很重要的。DMA 传输方式无需 CPU 直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备开辟一条直接传送数据的通路,能使 CPU 的效率大为提高。STM32 最多有 2 个 DMA 控制器(DMA2 仅存在大容量产品中),DMA1 有 7 个通道。DMA2 有 5个通道。每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁起来协调各个 DMA 请求的优先权。


   具体请看正点原子库函数手册

具体配置

  用到串口 1 的发送,属于 DMA1 的通道 4,接下来我们就介绍库函数下 DMA1 通道 4 的配置步骤:

  1. 使能 DMA 时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能 DMA 时钟
  1. 初始化 DMA 通道 4 参数前面讲解过,DMA 通道配置参数种类比较繁多,包括内存地址,外设地址,传输数据长度,数据宽度,通道优先级等等。这些参数的配置在库函数中都是在函数 DMA_Init 中完成,下面我们看看函数定义:
void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx,DMA_InitTypeDef* DMA_InitStruct)

DMA_Init()函数在stm32f10x_dma.c里,在这里查询相关的参数

  函数的第一个参数是指定初始化的 DMA 通道号,这个很容易理解,下面我们主要看看第二个参数。跟其他外设一样,同样是通过初始化结构体成员变量值来达到初始化的目的,下面我们来看看 DMA_InitTypeDef 结构体的定义:

typedef struct
{
   
uint32_t DMA_PeripheralBaseAddr;
/*用来设置 DMA 传输的外设基地址,比如要进行串口DMA 传输,
那么外设基地址为串口接受发送数据存储器 USART1->DR 的地址,表示方法为&USART1->DR。*/
uint32_t DMA_MemoryBaseAddr;
/*内存基地址,也就是我们存放DMA传输数据的内存地址*/
uint32_t DMA_DIR;
/*设置数据传输方向,决定是从外设读取数据到内存还送从内存读取数*/
uint32_t DMA_BufferSize;
/*设置一次传输数据量的大小*/
uint32_t DMA_PeripheralInc;
/*设置传输数据的时候外设地址是不变还是递增。如果设置为递增,那么下一次传输的时候地址加 1,这里因为我们是一直往固定外设地址&USART1->DR
发送数据,所以地址不递增,值为 DMA_PeripheralInc_Disable;*/
uint32_t DMA_MemoryInc;
/*设置传输数据时候内存地址是否递增。这个参数和
DMA_PeripheralInc 意思接近,只不过针对的是内存。这里我们的场景是将内存中连续存储单
元的数据发送到串口,毫无疑问内存地址是需要递增的,所以值为 DMA_MemoryInc_Enable。*/
uint32_t DMA_PeripheralDataSize;
/*用来设置外设的数据长度是为字节传输(8bits),半
字传输(16bits)还是字传输 (32bits),这里我们是 8 位字节传输,所以 值设置为
DMA_PeripheralDataSize_Byte。*/
uint32_t DMA_MemoryDataSize;
/*是用来设置内存的数据长度,和第七个参数意思接近,这
里我们同样设置为字节传输 DMA_MemoryDataSize_Byte。*/
uint32_t DMA_Mode;
/*模式是否循环采集,也就是说,比如我们要从内存中采
集 64 个字节发送到串口,如果设置为重复采集,那么它会在 64 个字节采集完成之后继续从内
存的第一个地址采集,如此循环。这里我们设置为一次连续采集完成之后不循环。所以设置值
为 DMA_Mode_Normal。在我们下面的实验中,如果设置此参数为循环采集,那么你会看到串口
不停的打印数据,不会中断,大家在实验中可以修改这个参数测试一下。*/
uint32_t DMA_Priority;
/*通道的优先级,有低,中,高,超高三种模式,这个在前面讲解过,
这里我们设置优先级别为中级,所以值为 DMA_Priority_Medium。如果要开启多个通道,那么
这个值就非常有意义。*/
uint32_t DMA_M2M;
/*设置是否是存储器到存储器模式传输,这里我们选择
DMA_M2M_Disable。*/
}DMA_InitTypeDef;

这里我们给出上面场景的实例代码:

DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_PeripheralBaseAddr = &USART1->DR; //DMA 外设 ADC 基地址
DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //DMA 内存基地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //从内存读取发送到外设
DMA_InitStructure.DMA_BufferSize = 64; //DMA 通道的 DMA 缓存的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址不变
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //8 位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // 8 位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常缓存模式
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA 通道 x 拥有中优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值