STM32 DMA传输笔记(HAL库版)

DMA,全称为:Direct Memory Access,即直接存储器访问。DMA传输方式无需CPU 直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为RAM 与I/O设备开辟一条直接传送数据的通路,能使CPU 的效率大为提高。

一、DMA请求映像

  STM32F10x有两个DMA控制器,使用DMA控制器可使数据从存储器到存储器、存储器到外设、外设到存储器。每个控制器有若干通道,参考《STM32参考手册》,各通道请求一览如下图:

二、DMA初始化

  1、使能DMA时钟

__HAL_RCC_DMA1_CLK_ENABLE();            //DMA1时钟使能 

  2、关联DMA与UART1

DMA_HandleTypeDef  UART1TxDMA_Handler;      //DMA句柄
__HAL_LINKDMA(&UART1_Handler,hdmatx,UART1TxDMA_Handler);            //将DMA与USART1联系起来(发送DMA)

 

  3、配置DMA句柄

//Tx DMA配置
UART1TxDMA_Handler.Instance=chx;                                    //通道选择 通道4指的是UART1Tx
UART1TxDMA_Handler.Init.Direction=DMA_MEMORY_TO_PERIPH;             //存储器到外设
    /*由于是从存储器读数据给外设,所以存储器设置为增量模式,这样的话,它地址可以自动增加;而外设因为是固定的地址,所以设为非增量模式。*/
UART1TxDMA_Handler.Init.PeriphInc=DMA_PINC_DISABLE;                 //外设非增量模式
UART1TxDMA_Handler.Init.MemInc=DMA_MINC_ENABLE;                     //存储器增量模式
    /*外设数据长度和存储器数据长度要设置一样的位数,其可以定义一次传输数据量的大小*/
UART1TxDMA_Handler.Init.PeriphDataAlignment=DMA_PDATAALIGN_BYTE;    //外设数据长度:8位
UART1TxDMA_Handler.Init.MemDataAlignment=DMA_MDATAALIGN_BYTE;       //存储器数据长度:8位
UART1TxDMA_Handler.Init.Mode=DMA_NORMAL;                            //外设普通模式
UART1TxDMA_Handler.Init.Priority=DMA_PRIORITY_MEDIUM;               //中等优先级
HAL_DMA_DeInit(&UART1TxDMA_Handler);   
HAL_DMA_Init(&UART1TxDMA_Handler);

  其中 Instance 参数根据请求映像表需要用到哪个设备就选择相应通道; Init.Direction 可选择“存储器到外设”、“外设到存储器”、“存储器到存储器”,决定数据传输方向; Init.PeriphInc 参数选择外设是否增量模式,本例中使用外设串口1的发送端,所以地址是固定的,要使用非增量模式;Init.MemInc 参数选择存储器是否为增量模式,由于存储器地址是连续的,本例中要读取连续的地址区域,所以要使用增量模式;Init.PeriphDataAlignment和Init.MemDataAlignment 分别表示外设和存储器长度,两个长度要相同,否则可能读取不完全;其余参数lue。

  4、开启DMA传输

//开启一次DMA传输
//huart:串口句柄
//pData:传输的数据指针
//Size:传输的数据量
void MYDMA_USART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
    HAL_DMA_Start(huart->hdmatx, (u32)pData, (uint32_t)&huart->Instance->DR, Size);//开启DMA传输
    
    huart->Instance->CR3 |= USART_CR3_DMAT;//使能串口DMA发送
}      

 

  我中使用到了寄存器编程使能DMA发送。开启DMA传输时直接调用该函数即可。

  5、其他API

__HAL_DMA_GET_FLAG(&UART1TxDMA_Handler,DMA_FLAG_TC4) //传输完成返回1,否则返回0

 

__HAL_DMA_CLEAR_FLAG(&UART1TxDMA_Handler,DMA_FLAG_TC4);//清除DMA1通道4传输完成标志
HAL_UART_DMAStop(&UART1_Handler);      //传输完成以后关闭串口DMA
__HAL_DMA_GET_COUNTER(&UART1TxDMA_Handler);//得到当前还剩余多少个数据

  6、(补充)DMA的接收 

在用cubemx配置DMA的时候,要注意配置一下RX的mode,配置为Circular,意思是DMA接收处于循环接受状态,否则DMA只能接收一次。

在使用DMA接收的时候,使用函数

HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

  

注意:如果在cubemx设置为循环接收模式,该函数可以不放在while循环里;如果没有设置为循环接收模式(即设置为normal模式),需要放在while里循环是能DMA接收中断。

DMA接收中断使用回调函数

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)

实测使用回掉函数void UART_DMAReceiveCplt(DMA_HandleTypeDef *hdma)的话不知道为什么进入不了中断(即进入不了这个回掉函数),不知道为什么,希望有大神来解答一下,谢谢。

 

三、总结

使用DMA传输可以使大量的数据传输交给DMA控制器执行,CPU空闲出来做其他的事,提高了运行效率。

 

posted @ 2018-06-04 21:21  sovagxa&静默  阅读(32951)  评论(0编辑  收藏  举报