串口通信-DMA方式
1 DMA概述
直接存儲器訪問 (DMA) : 用于在外設與存儲器之間以及存儲器與存儲器之間進行高速數據傳輸。DMA傳輸過程的初始化和啟動由CPU完成,傳輸過程由DMA控制器來執行,無需CPU參與,從而節省CPU資源,提高利用率。
DMA數據傳輸的四個要素:
- 傳輸源 :DMA數據傳輸的來源
- 傳輸目標:DMA數據傳輸的目的
- 傳輸數量:DMA傳輸數據的數量
- 觸發信號:啟動一次DMA數據傳輸的動作
STM32的DMA控制器特點
- 每個DMA控制器有8個數據流,每個數據流可以映射到8個通道(或請求);
- 每一個DMA控制器用于管理一個或多個外設的存儲器訪問請求,并通過總線仲裁器來協調各個DMA請求的優先級;
- 數據流(stream)是用于連接傳輸源和傳輸目標的數據通路,每個數據流可以配置為不同的傳輸源和傳輸目標,這些傳輸源和傳輸目標稱為通道(Channel);
- 具備16字節的FIFO。使能FIFO功能后,源數據先送入FIFO,達到FIFO的觸發閾值后,再傳送到目標地址。
DMA數據傳輸方式
- 普通模式:傳輸結束后(即要傳輸數據的數量達到零),將不再產生DMA操作。若 開始新的DMA傳輸,需在關閉DMA通道情況下,重新啟動DMA傳輸。
- 循環模式:可用于處理環形緩沖區和連續數據流(例如ADC掃描模式)。當激活循 環模式后,每輪傳輸結束時,要傳輸的數據數量將自動用設置的初始值進行加載,并繼續響應DMA請求。
2 DMA方式的接口函數
串口DMA方式發送函數:
HAL_UART_Transmit_DMA
函數原型 HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_Handle TypeDef *huart, uint 8_t *pData, uint 16_t Size)
功能描述 在DMA方式下發送一定數量的數據 入口參數1 huart:串口句柄的地址 入口參數 pData:待發送數據的首地址 入口參數3 Size:待發送數據的個數 返回值 HAL狀態值:HAL_OK表示發送成功;HAL_ERROR表示參數錯誤;HAL_BUSY表示串口被占用; 注意事項 1. 該函數將啟動DMA方式的串口數據發送2. 完成指定數量的數據發送后,可以觸發DMA中斷,在中斷中將調用發送中斷回調函數HAL_UART_TxCpltCallback進行后續處理3. 該函數由用戶調用戶調用 串口DMA方式接收函數:
HAL_UART_Receive_DMA
函數原型 HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_Handle TypeDef *huart, uint 8_t *pData, uint 16_t Size)
功能描述 在DMA方式下接收一定數量的數據 入口參數1 huart:串口句柄的地址 入口參數 pData:待接收數據的首地址 入口參數3 Size:待接收數據的個數 返回值 HAL狀態值:HAL_OK表示發送成功;HAL_ERROR表示參數錯誤;HAL_BUSY表示串口被占用; 注意事項 1. 該函數將啟動DMA方式的串口數據接收2. 完成指定數量的數據接收后,可以觸發DMA中斷,在中斷中將調用接收中斷回調函數HAL_UART_ExCpltCallback進行后續處理3. 該函數由用戶調用戶調用 獲取未傳輸數據個數函數:
__HAL_DMA_GET_COUNTER
函數原型 __HAL_DMA_GET_COUNTER
功能描述 獲取DMA數據流中未傳輸數據的個數 參數 HANDLE :串口句柄的地址 返回值 NDTR寄存器的內容,即DMA數據流中無傳輸數據的個數 注意事項 1. 該函數是宏函數,進行宏替換,不發生函數調用2. 該函數需要由用戶調用,用于獲取未傳輸數據的個數 關閉DMA數據流:
__HAL_DMA_DISABLE
函數原型 __HAL_DMA_DISABLE(__HANDLE__)
功能描述 關閉指定的DMA數據流 參數 HANDLE :串口句柄的地址 返回值 無 注意事項 1. 該函數是宏函數,進行宏替換,不發生函數調用2. 該函數需要由用戶調用,用于關閉指定的DMA數據流3. 關閉DMA數據流后觸發DMA中斷,最終調用串口收發的回調函數
任務實踐4
不定長數據的收發:利用串口調試助手,從PC上發送任意長度的字符到開發板,開發板收到后原樣發回到PC。
空閑中斷的特點:
- 在一幀數據傳輸結束后,通信線路將會維持高電平,這個狀態稱為空閑狀態;
- 當CPU檢測到通信線路處于空閑狀態時,且空閑狀態持續時間大于一個字節傳輸時間時,空閑狀態標志IDLE將由硬件置1。如果串口控制寄存器CR1中的IDLEIE位為1,將會觸發空閑中斷( IDLE中斷);
- 由于空閑標志是在一幀數據傳輸完成后才置位,在有效數據傳輸過程中不會置位,因此借助空閑中斷,可以實現不定長數據的收發。
設計思路:
使能IDLE中斷,在串口2的中斷服務程序USART2_IRQHandler中添加對IDLE中斷的判斷,該函數位于stm32f4xx_it.c文件;
設置傳輸模式為普通模式,啟動DMA傳輸。串口一旦接收到數據,則觸發DMA操作,將數據存放到用戶定義的接收緩沖區;
當一幀數據發送完成后,線路處于IDLE狀態,將觸發IDLE中斷,調用IDLE中斷回調函數,設置數據接收完成標志;
主程序檢測到接收完成標志置位后,將接收的一幀數據原樣發回到PC,并禁能DMA,以觸發DMA中斷。DMA中斷將調用接收中斷回調函數,在回調函數中重新啟動DMA傳輸。
串口1的DMA配置
DMA數據流的中斷使能由CubeMX自動勾選,手動使能串口2中斷編寫程序
在stm32f1xx_it.c
中添加空閑中斷的處理/** * @brief This function handles USART1 global interrupt. */ void USART1_IRQHandler(void) { /* USER CODE BEGIN USART1_IRQn 0 */ /* USER CODE END USART1_IRQn 0 */ HAL_UART_IRQHandler(&huart1); /* USER CODE BEGIN USART1_IRQn 1 */ // Add handling of idle interrupts if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE != RESET)) { __HAL_UART_CLEAR_IDLEFLAG(&huart1); // Clear the IDLE interrupt flag HAL_UART_IdleCpltCallback(&huart1); // User-written IDLE interrupt callback function } /* USER CODE END USART1_IRQn 1 */ }
在
main.c
中添加用戶宏變量、變量定義
/* USER CODE BEGIN PM */ #define LENGTH 100 // Receive buffer size /* USER CODE END PM */ /* USER CODE BEGIN PV */ uint8_t RxBuffer[LENGTH]; uint8_t RecCount = 0; uint8_t RxFlag = 0; /* USER CODE END PV */
聲明和定義空閑中斷回調函數,定義DMA接收中斷回調函數
/* USER CODE BEGIN PFP */ void HAL_UART_IdleCpltCallback(UART_HandleTypeDef *huart) /* USER CODE END PFP */ /* USER CODE BEGIN 4 */ int fputc (int ch, FILE *f) { HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY); return ch; } int fgetc(FILE *f) { uint8_t ch = 0; HAL_UART_Receive(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY); return ch; } void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart- >Instance == USART1) { HAL_UART_Receive_DMA(&huart1, (uint8_t*)RxBuffer, LENGTH); } } void HAL_UART_IdleCpltCallback(UART_HandleTypeDef *huart) { RxFlag = 1; } /* USER CODE END 4 */
編寫用戶應用代碼
/* USER CODE BEGIN 2 */ printf("*** UART coummunication using IDLE IT + DMAn"); pringf("PLease enter arbitrary length characters:n"); __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); HAL_UART_Receive_DMA(&huart1, (uint8_t*)RxBuffer, LENGTH); /* USER CODE END 2 */ /* USER CODE BEGIN 3 */ if (RxFlag == 1) { RxFlag = 0; RecCount = LENGTH - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx); HAL_UART_Transmit_DMA(&huart1, (uint8_t*)RxBuffer, RecCount); RecCount = 0; __HAL_DMA_DISABLE(&hdma_uasrt1_rx); } } /* USER CODE END 3 */
-
存儲器
+關注
關注
38文章
7637瀏覽量
166483 -
cpu
+關注
關注
68文章
11044瀏覽量
216076 -
STM32
+關注
關注
2290文章
11017瀏覽量
362519 -
串口通信
+關注
關注
34文章
1636瀏覽量
56574 -
dma
+關注
關注
3文章
572瀏覽量
102377
發布評論請先 登錄
STM32 串口使用IDLE中斷+DMA接收(HAL庫函數)

【STM32】使用DMA方式實現串口數據轉發

STM32中斷與串口DMA通信

STM32 HAL CubeMX 串口IDLE接收空閑中斷+DMA

STM32采用串口DMA方式的USART串口通訊

STM32串口中斷之DMA通信

評論