STM32F429 Discovery开发板应用:使用FreeRTOS队列+DMA双缓存实现串口数据接收
参考帖子:https://blog.csdn.net/freedompoi/article/details/122350866
目前想要实现STM32F4自带的DMA双缓冲区,尝试过一版,结果不能预期,就使用了RxHalfCplt和RxCplt去实现DMA双缓冲区的效果。
现在有时间了,又重新实现STM32F4自带的DMA双缓冲区,作为参考。
MCU:STM32F429ZIT6
开发环境:STM32CubeMX+MDK5
此时,双击完后会关闭此界面,然后打开一个新界面。
然后,我们开始基本配置。
现在我们选择一个LED作为系统LED,该步骤可以忽略,只是本人喜欢这样子。以硬件原理图的LD3为例子。
基本配置除了时钟树外,基本上已经配置好了。
现在配置时钟树
基本配置已经配置完,现在开始配置实验使用的内容。
配置USART1,打开USART中断。并打开DMA。
配置FreeRTOS
配置完成,完善工程,生成工程。
到此,STM32CubeMX工具的使用结束!可以发现在桌面已经生成了DMA_DoubleBuf工程。
使用MDK5打开SDCard_rw工程打开。点击魔法棒,勾选微库。选择对应的下载器,勾选下载完复位允许。
在usart.h文件中,加入内容。
1 /* USER CODE BEGIN Header */ 2 /** 3 ****************************************************************************** 4 * @file usart.h 5 * @brief This file contains all the function prototypes for 6 * the usart.c file 7 ****************************************************************************** 8 * @attention 9 * 10 * Copyright (c) 2023 STMicroelectronics. 11 * All rights reserved. 12 * 13 * This software is licensed under terms that can be found in the LICENSE file 14 * in the root directory of this software component. 15 * If no LICENSE file comes with this software, it is provided AS-IS. 16 * 17 ****************************************************************************** 18 */ 19 /* USER CODE END Header */ 20 /* Define to prevent recursive inclusion -------------------------------------*/ 21 #ifndef __USART_H__ 22 #define __USART_H__ 23 24 #ifdef __cplusplus 25 extern "C" { 26 #endif 27 28 /* Includes ------------------------------------------------------------------*/ 29 #include "main.h" 30 31 /* USER CODE BEGIN Includes */ 32 #include "cmsis_os.h" 33 #include <semphr.h> 34 /* USER CODE END Includes */ 35 36 extern UART_HandleTypeDef huart1; 37 38 /* USER CODE BEGIN Private defines */ 39 40 #define UART_BUFF_SIZE 30 41 42 #pragma pack(4) 43 typedef struct 44 { 45 uint16_t len; 46 uint8_t data[UART_BUFF_SIZE]; 47 }usart_multibuffer_data; 48 #pragma pack() 49 50 /* USER CODE END Private defines */ 51 52 void MX_USART1_UART_Init(void); 53 54 /* USER CODE BEGIN Prototypes */ 55 void UART_DMA_MultiBuffer(void); 56 /* USER CODE END Prototypes */ 57 58 #ifdef __cplusplus 59 } 60 #endif 61 62 #endif /* __USART_H__ */
在usart.c文件中,加入内容。
1 /* USER CODE BEGIN Header */ 2 /** 3 ****************************************************************************** 4 * @file usart.c 5 * @brief This file provides code for the configuration 6 * of the USART instances. 7 ****************************************************************************** 8 * @attention 9 * 10 * Copyright (c) 2023 STMicroelectronics. 11 * All rights reserved. 12 * 13 * This software is licensed under terms that can be found in the LICENSE file 14 * in the root directory of this software component. 15 * If no LICENSE file comes with this software, it is provided AS-IS. 16 * 17 ****************************************************************************** 18 */ 19 /* USER CODE END Header */ 20 /* Includes ------------------------------------------------------------------*/ 21 #include "usart.h" 22 23 /* USER CODE BEGIN 0 */ 24 QueueHandle_t queue_mes; 25 usart_multibuffer_data uart_buf[2]; 26 27 //DMA 缓存0 传输结束回调函数 28 void DMA_M0_RC_Callback(DMA_HandleTypeDef *hdma) 29 { 30 BaseType_t xHigherPriorityTaskWoken; 31 32 uart_buf[0].len = hdma->Instance->NDTR; 33 xQueueSendFromISR(queue_mes,&uart_buf[0],&xHigherPriorityTaskWoken); 34 portYIELD_FROM_ISR(xHigherPriorityTaskWoken); 35 } 36 37 //DMA 缓存1 传输结束回调函数 38 void DMA_M1_RC_Callback(DMA_HandleTypeDef *hdma) 39 { 40 BaseType_t xHigherPriorityTaskWoken; 41 42 uart_buf[1].len = hdma->Instance->NDTR; 43 xQueueSendFromISR(queue_mes,&uart_buf[1],&xHigherPriorityTaskWoken); 44 portYIELD_FROM_ISR(xHigherPriorityTaskWoken); 45 } 46 47 //DMA 传输错误回调函数 48 void DMA_Error_Callback(DMA_HandleTypeDef *hdma) 49 { 50 //里面做一些异常处理 51 } 52 /* USER CODE END 0 */ 53 54 UART_HandleTypeDef huart1; 55 DMA_HandleTypeDef hdma_usart1_rx; 56 57 /* USART1 init function */ 58 59 void MX_USART1_UART_Init(void) 60 { 61 62 /* USER CODE BEGIN USART1_Init 0 */ 63 64 /* USER CODE END USART1_Init 0 */ 65 66 /* USER CODE BEGIN USART1_Init 1 */ 67 68 /* USER CODE END USART1_Init 1 */ 69 huart1.Instance = USART1; 70 huart1.Init.BaudRate = 115200; 71 huart1.Init.WordLength = UART_WORDLENGTH_8B; 72 huart1.Init.StopBits = UART_STOPBITS_1; 73 huart1.Init.Parity = UART_PARITY_NONE; 74 huart1.Init.Mode = UART_MODE_TX_RX; 75 huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; 76 huart1.Init.OverSampling = UART_OVERSAMPLING_16; 77 if (HAL_UART_Init(&huart1) != HAL_OK) 78 { 79 Error_Handler(); 80 } 81 /* USER CODE BEGIN USART1_Init 2 */ 82 83 /* USER CODE END USART1_Init 2 */ 84 85 } 86 87 void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) 88 { 89 90 GPIO_InitTypeDef GPIO_InitStruct = {0}; 91 if(uartHandle->Instance==USART1) 92 { 93 /* USER CODE BEGIN USART1_MspInit 0 */ 94 95 /* USER CODE END USART1_MspInit 0 */ 96 /* USART1 clock enable */ 97 __HAL_RCC_USART1_CLK_ENABLE(); 98 99 __HAL_RCC_GPIOA_CLK_ENABLE(); 100 /**USART1 GPIO Configuration 101 PA9 ------> USART1_TX 102 PA10 ------> USART1_RX 103 */ 104 GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10; 105 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; 106 GPIO_InitStruct.Pull = GPIO_NOPULL; 107 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; 108 GPIO_InitStruct.Alternate = GPIO_AF7_USART1; 109 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); 110 111 /* USART1 DMA Init */ 112 /* USART1_RX Init */ 113 hdma_usart1_rx.Instance = DMA2_Stream2; 114 hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4; 115 hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; 116 hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE; 117 hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE; 118 hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; 119 hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; 120 hdma_usart1_rx.Init.Mode = DMA_CIRCULAR; 121 hdma_usart1_rx.Init.Priority = DMA_PRIORITY_MEDIUM; 122 hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; 123 hdma_usart1_rx.XferCpltCallback = DMA_M0_RC_Callback; 124 hdma_usart1_rx.XferM1CpltCallback = DMA_M1_RC_Callback; 125 hdma_usart1_rx.XferErrorCallback = DMA_Error_Callback; 126 if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK) 127 { 128 Error_Handler(); 129 } 130 131 __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart1_rx); 132 133 /* USART1 interrupt Init */ 134 HAL_NVIC_SetPriority(USART1_IRQn, 5, 0); 135 HAL_NVIC_EnableIRQ(USART1_IRQn); 136 /* USER CODE BEGIN USART1_MspInit 1 */ 137 138 /* USER CODE END USART1_MspInit 1 */ 139 } 140 } 141 142 void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle) 143 { 144 145 if(uartHandle->Instance==USART1) 146 { 147 /* USER CODE BEGIN USART1_MspDeInit 0 */ 148 149 /* USER CODE END USART1_MspDeInit 0 */ 150 /* Peripheral clock disable */ 151 __HAL_RCC_USART1_CLK_DISABLE(); 152 153 /**USART1 GPIO Configuration 154 PA9 ------> USART1_TX 155 PA10 ------> USART1_RX 156 */ 157 HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10); 158 159 /* USART1 DMA DeInit */ 160 HAL_DMA_DeInit(uartHandle->hdmarx); 161 162 /* USART1 interrupt Deinit */ 163 HAL_NVIC_DisableIRQ(USART1_IRQn); 164 /* USER CODE BEGIN USART1_MspDeInit 1 */ 165 166 /* USER CODE END USART1_MspDeInit 1 */ 167 } 168 } 169 170 /* USER CODE BEGIN 1 */ 171 //使能DMA 172 void UART_DMA_MultiBuffer(void) 173 { 174 uint32_t u32wk0; 175 176 SET_BIT(huart1.Instance->CR3,USART_CR3_DMAR); 177 HAL_DMAEx_MultiBufferStart_IT(&hdma_usart1_rx, 178 (uint32_t)(&huart1.Instance->DR), 179 (uint32_t)&uart_buf[0].data[0], 180 (uint32_t)&uart_buf[1].data[0], 181 UART_BUFF_SIZE); 182 183 //这里是解决DMA在启动时,如果接收到大量数据会出现死机的问题 184 u32wk0 = huart1.Instance->SR; 185 u32wk0 = huart1.Instance->DR; 186 UNUSED(u32wk0); 187 } 188 189 /* USER CODE END 1 */
在main函数中,加入内容。
1 /** 2 * @brief The application entry point. 3 * @retval int 4 */ 5 int main(void) 6 { 7 /* USER CODE BEGIN 1 */ 8 9 /* USER CODE END 1 */ 10 11 /* MCU Configuration--------------------------------------------------------*/ 12 13 /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ 14 HAL_Init(); 15 16 /* USER CODE BEGIN Init */ 17 18 /* USER CODE END Init */ 19 20 /* Configure the system clock */ 21 SystemClock_Config(); 22 23 /* USER CODE BEGIN SysInit */ 24 25 /* USER CODE END SysInit */ 26 27 /* Initialize all configured peripherals */ 28 MX_GPIO_Init(); 29 MX_DMA_Init(); 30 MX_USART1_UART_Init(); 31 /* USER CODE BEGIN 2 */ 32 queue_mes = xQueueCreate(10, sizeof(usart_multibuffer_data)); 33 UART_DMA_MultiBuffer(); 34 /* USER CODE END 2 */ 35 36 /* Init scheduler */ 37 osKernelInitialize(); /* Call init function for freertos objects (in freertos.c) */ 38 MX_FREERTOS_Init(); 39 /* Start scheduler */ 40 osKernelStart(); 41 42 /* We should never get here as control is now taken by the scheduler */ 43 /* Infinite loop */ 44 /* USER CODE BEGIN WHILE */ 45 while (1) 46 { 47 /* USER CODE END WHILE */ 48 49 /* USER CODE BEGIN 3 */ 50 } 51 /* USER CODE END 3 */ 52 }
在freertos.c文件中
1 extern usart_multibuffer_data uart_buf[2]; 2 extern QueueHandle_t queue_mes; 3 usart_multibuffer_data queue_data; 4 5 /* USER CODE BEGIN Header_StartDefaultTask */ 6 /** 7 * @brief Function implementing the defaultTask thread. 8 * @param argument: Not used 9 * @retval None 10 */ 11 /* USER CODE END Header_StartDefaultTask */ 12 void StartDefaultTask(void *argument) 13 { 14 /* USER CODE BEGIN StartDefaultTask */ 15 BaseType_t ret = pdFALSE; 16 /* Infinite loop */ 17 for(;;) 18 { 19 ret = xQueueReceive(queue_mes,&queue_data,portMAX_DELAY); 20 if(ret == pdTRUE) 21 { 22 HAL_UART_Transmit(&huart1,queue_data.data,queue_data.len,100); 23 } 24 } 25 /* USER CODE END StartDefaultTask */ 26 }
实验效果