STM32F429 Discovery开发板应用:使用FreeRTOS队列+DMA双缓存实现串口数据接收

发布时间 2023-06-13 11:41:46作者: Couvrir洪荒猛兽

 

参考帖子: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 }

 

实验效果