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空閑出來做其他的事,提高了運行效率。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM