×
单片机 > 单片机程序设计 > 详情

STM32之DMA讲解及配置过程,附带代码说明

发布时间:2020-08-31 发布时间:
|

DMA涉及概念讲解: 


①:DMA即Direct Memory Access(直接存储器存取),是STM32特有的外设。大容量STM32产品集成了两个DMA,分别是DMA1和DMA2,。其中DMA1有7个通道,DMA2有5个通道,具体每个通道连接的外设可以参考STM32芯片的数据手册。


②:通过DMA可以将数据在两个不同的地址之间进行传递,如存储器到外设寄存器,外设寄存器到存储器,也可以从存储器到存储器之间。


③:当两个数据在不同的地址之间传递时,需要在程序配置中确定每次传输的字节数,确定是字节、半字还是字。


④:DMA的每个通道优先级是可变的。以DMA1为例,它有7个通道,可以配置每个通道的优先级为很高、高、中,低四种中的一种。若两个通道的优先级一样,当两个通道同时有DMA请求时,通道号小的优先级则高。


⑤:DMA每次传输的数据量是可变的,DMA中有一个专门的寄存器用于存储这个数据量值。这个寄存器是32位的,但高16位全部保留为0,实际上起作用的是低16位,所以每次传输的最大数据量值是65536。


⑥:⑤中所示,比如设置数据量值为100,若DMA传输设置为循环模式,则100个数据传输完成后,将自动进行下一轮传输。若设置成非循环模式,则需要先关闭DMA,再设置数据量值,再开启DMA,才能进行下一轮传输。


⑦:DMA在传输过程中,常用的有3种标志位--传输完成一半、传输全部完成,传输过程发生错误。可以在程序中设置开启对应标志位的中断,当标志位到来时,会执行中断服务程序。也可不开启相应标志位的中断。


⑧:确定好要传输的外设和存储器地址之后,需要在程序中设置传输方向,即传输方向是从外设到寄存器,还是从寄存器到外设。


⑨:DMA一般用来在外设和存储器之间进行数据传输,所以还要设置外设地址及存储器地址是否递增。例如定义一个数组,char data[100],外设地址为&UART->TX,若将数组中的100个数据传输到UART->TX中,则存储器地址需要每次递增,而外设地址不需要递增。


DMA配置过程:


①:确定传输数据的外设和寄存器地址


②:确定传输方向


③:确定每次传输的数据量值


④:确定传输数据的字节数


⑤:配置通道优先级


⑥:确定传输是循环模式还是非循环模式


⑦:如若需要开启中断,则开启响应位中断




注意:DMA也可以从存储器到存储器,但存储器到存储器过程只能为非循环模式。




程序讲解:


例:程序实现功能是将存储器中的数据传输到串口的发送寄存器TX,每次传输的数据量是100,非循环模式传输。


void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx, u32 cpar, u32 cmar, u16 cndtr)


{


RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //开启时钟


DMA_DeInit(DMA_CHx); //初始化通道,设置为默认配置


DMA1_MEM_LEN=cndtr;


DMA_InitStructure.DMA_PeripheralBaseAddr = cpar;//外设地址


DMA_InitStructure.DMA_MemoryBaseAddr = cmar;//存储器地址


DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//传输方向,从内存到外设


DMA_InitStructure.DMA_BufferSize = cndtr;//每次循环传输的数据量值


DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址不变


DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存地址每次加1


DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//字节传输


DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//字节传输


DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//非循环模式


DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//设置优先级--中


DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//不是内存到内存


DMA_Init(DMA_CHx, &DMA_InitStructure);//初始化DMA配置过程


}


//开启一次传输

void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)

DMA_Cmd(DMA_CHx, DISABLE );  //关闭DMA     

  DMA_SetCurrDataCounter(DMA_CHx,DMA1_MEM_LEN);//重新确定每次循环要传输的数据量值

  DMA_Cmd(DMA_CHx, ENABLE);  //再次开启DMA

}


int main()


{


u8 SendBuff[100]; //存储器数据


MYDMA_Config(DMA1_Channel4, (u32)&USART1->DR, (u32)SendBuff, 100);//调用函数


MYDMA_Enable(DMA1_Channel4);  //开启一次传输


}



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
Keil(MDK-ARM)系列教程(七)_菜单