STM32 HAL UART DMA приём пакетов переменной длины

STM32 HAL UART Приём данных переменной длины с помощью DMA.

Добавляем определение обработчика для IDLE.

diff --git a/Drivers/STM32F1xx_HAL_Driver/Inc/stm32f1xx_hal_uart.h b/Drivers/STM32F1xx_HAL_Driver/Inc/stm32f1xx_hal_uart.h
--- a/Drivers/STM32F1xx_HAL_Driver/Inc/stm32f1xx_hal_uart.h
+++ b/Drivers/STM32F1xx_HAL_Driver/Inc/stm32f1xx_hal_uart.h
@@ -693,6 +693,7 @@ void HAL_UART_IRQHandler(UART_HandleTypeDef *huart);
 void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);
 void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart);
 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
+void HAL_UART_RxIdleCallback(UART_HandleTypeDef *huart);
 void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);
 void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart);

Добавляем обработку прерывания IDLE в обработчик прерываний UART.

diff --git a/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_uart.c b/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_uart.c
--- a/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_uart.c
+++ b/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_uart.c
@@ -1238,6 +1238,15 @@ void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
     UART_EndTransmit_IT(huart);
   }  

+  tmp_flag = __HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE);
+  tmp_it_source = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_IDLE);
+  /* UART in mode Transmitter end --------------------------------------------*/
+  if((tmp_flag != RESET) && (tmp_it_source != RESET))
+  {
+    __HAL_UART_CLEAR_IDLEFLAG(huart);
+    HAL_UART_RxIdleCallback(huart);
+  }
+
   if(huart->ErrorCode != HAL_UART_ERROR_NONE)
   {
     /* Set the UART state ready to be able to start again the process */
@@ -1248,6 +1257,19 @@ void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
 }

 /**
+  * @brief  Rx Idle callbacks.
+  * @param  huart: Pointer to a UART_HandleTypeDef structure that contains
+  *                the configuration information for the specified UART module.
+  * @retval None
+  */
+__weak void HAL_UART_RxIdleCallback(UART_HandleTypeDef *huart)
+{
+ /* NOTE: This function should not be modified, when the callback is needed,
+          the HAL_UART_RxIdleCallback can be implemented in the user file
+  */
+}
+
+/**
   * @brief  Tx Transfer completed callbacks.
   * @param  huart: Pointer to a UART_HandleTypeDef structure that contains
   *                the configuration information for the specified UART module.

Доработка задачи приёма.
Настраивается приём через DMA для пакета размером в весь доступный буфер.
Затем идёт ожидание семафора. Семафор устанавливается в обработчике IDLE.
После, вычисляется количество принятых данных, как разница между ожидаемым количеством (размером буфера) и оставшимся (ещё не принятым) CNDTR.

diff --git a/Src/freertos.c b/Src/freertos.c
index a7db5b3..5ffd4df 100644
--- a/Src/freertos.c
+++ b/Src/freertos.c
@@ -38,13 +38,15 @@

 /* USER CODE BEGIN Includes */     
 #include "stm32f1xx_hal.h"
+#include <string.h>
 /* USER CODE END Includes */

 /* Variables -----------------------------------------------------------------*/
 osThreadId taskTestHandle;
 osThreadId taskSerialCommHandle;
 osThreadId taskDisplayHandle;
-osSemaphoreId semSerialCommReceivedHandle;
+osSemaphoreId semSerialCommRxIdleHandle;
+osSemaphoreId semSerialCommTxCompletedHandle;

 /* USER CODE BEGIN Variables */
 extern UART_HandleTypeDef huart1;
@@ -75,9 +77,13 @@ void MX_FREERTOS_Init(void) {
   /* USER CODE END RTOS_MUTEX */

   /* Create the semaphores(s) */
-  /* definition and creation of semSerialCommReceived */
-  osSemaphoreDef(semSerialCommReceived);
-  semSerialCommReceivedHandle = osSemaphoreCreate(osSemaphore(semSerialCommReceived), 1);
+  /* definition and creation of semSerialCommRxIdle */
+  osSemaphoreDef(semSerialCommRxIdle);
+  semSerialCommRxIdleHandle = osSemaphoreCreate(osSemaphore(semSerialCommRxIdle), 1);
+
+  /* definition and creation of semSerialCommTxCompleted */
+  osSemaphoreDef(semSerialCommTxCompleted);
+  semSerialCommTxCompletedHandle = osSemaphoreCreate(osSemaphore(semSerialCommTxCompleted), 1);

   /* USER CODE BEGIN RTOS_SEMAPHORES */
   /* add semaphores, ... */
@@ -126,10 +132,29 @@ void TaskTestStart(void const * argument)
 void TaskSerialCommStart(void const * argument)
 {
   /* USER CODE BEGIN TaskSerialCommStart */
+  int i, retval, rcvdCount;
+  /* Set semaphores to default state */
+  osSemaphoreWait(semSerialCommRxIdleHandle, osWaitForever);
+  osSemaphoreWait(semSerialCommTxCompletedHandle, osWaitForever);
   /* Infinite loop */
   for(;;)
   {
-    osDelay(1000);
+    uint8_t buffer[32];
+    memset(buffer, 0, sizeof(buffer));
+
+    __HAL_UART_CLEAR_IDLEFLAG(&huart1);
+    __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
+    if (HAL_UART_Receive_DMA(&huart1, buffer, sizeof(buffer)) != HAL_OK) {
+      // error
+    }
+
+    retval = osSemaphoreWait(semSerialCommRxIdleHandle, osWaitForever);
+    rcvdCount = sizeof(buffer) - huart1.hdmarx->Instance->CNDTR;
+    HAL_UART_DMAStop(&huart1);
+
+    HAL_UART_Transmit_DMA(&huart1, buffer, rcvdCount);
+    retval = osSemaphoreWait(semSerialCommTxCompletedHandle, osWaitForever);
+    HAL_UART_DMAStop(&huart1);
   }
   /* USER CODE END TaskSerialCommStart */
 }
@@ -147,6 +172,21 @@ void TaslDisplayStart(void const * argument)
 }

 /* USER CODE BEGIN Application */
+void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
+{
+  osSemaphoreRelease(semSerialCommTxCompletedHandle);
+}
+
+void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
+{
+  osSemaphoreRelease(semSerialCommRxIdleHandle);
+}
+
+void HAL_UART_RxIdleCallback(UART_HandleTypeDef *huart)
+{
+  __HAL_UART_DISABLE_IT(huart, UART_IT_IDLE);
+  osSemaphoreRelease(semSerialCommRxIdleHandle);
+}
 /* USER CODE END Application */