AnsweredAssumed Answered

STM32F427 UART DMA Receive Problem

Question asked by einarsson.hal on Aug 4, 2015
Latest reply on Aug 4, 2015 by einarsson.hal
Hello,

I am working with a design using STM32F427 where I have several UART devices (GPS, Wifi, Bluetooth, 3G, RS232) and am using the CubeF4 HAL drivers.  I am trying to use the DMA transfer on the RX side on few of the interfaces.  I have already gotten it to "almost" to work. For example then  am receiving the stream from the GPS (which is 9600bps, with regular messages every second) and am decoding the NMEA messages in the HAL_UART_RxCpltCallback() routine.

The problem that I have is that there seem to be always one or more byte missing at the start of each DMA cycle.  I use the CIRCULAR mode and I was not expecting to have any bytes missing when the DMA counter is automatically reloaded.  This does not matter much in the GPS because I get enough messages OK to get all the data that I need, but it is not good enough for anything else.  I have been doing tests with ST Wifi module (SPWF01SA) and it is very easy to detect that there are bytes missing when I listen to the standard +WIND: messages that are sent out automatically.  And when I check the RX buffer, I always get zero in the first byte of the buffer.  I am not sure what I am doing wrong, I have tried many combinations of setup for the DMA but have not solved why this happens.  I have not seen how to use the double buffer with the USART yet.  I did set up complete code to test the Wifi in one file and there is a copy of that code here below (I did move the Interrupt setup from stm32f4xx_it.c into the same c file to keep things together). 

It would be great if someone has experience with this and can give me some advice.

With thanks, Hal.

CODE:

#include <cmsis_os.h>                                           // CMSIS RTOS header file
#include <stdio.h>
#include <string.h>
#include "stm32f4xx_hal.h"
#include "main.h"

extern UART_HandleTypeDef WifiUartHandle;
extern UART_HandleTypeDef MdtUartHandle;

/*----------------------------------------------------------------------------
 *      WIFI UART setup and processing unit
 *---------------------------------------------------------------------------*/
 
/* External variables -------------------------------------------------------*/

// Wifi related buffers and variables
// Both WIFI_RX_BUFFER_SIZE and WIFI_COMMAND_BUFFER_SIZE are defined as 128
//
extern volatile uint8_t       wifiRxBuffer[WIFI_RX_BUFFER_SIZE];     
extern volatile uint8_t       wifiTxBuffer[WIFI_TX_BUFFER_SIZE];
extern volatile char        wifiCommandBuffer[WIFI_COMMAND_BUFFER_SIZE];
extern volatile int         wifiCommandBufferIndex;
extern volatile int         wifiRxCount;

/* Private defines -----------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/
DMA_HandleTypeDef WifiDMAHandle_rx;
DMA_HandleTypeDef WifiDMAHandle_tx;

/**
 * @brief  Configure the USART with DMA and Interrupt for Wifi (USART2)
 * @retval None
 */
void InitWifi(void)
{
  GPIO_InitTypeDef GPIO_InitStruct;
 
 /* The Wifi module is connected to USART2:                                  */
 /* TX pin: PD5                                                              */
 /* RX pin: PD6                                                              */
 /* DMA for USART2 is Channel 4 on DMA1, Stream 5 for RX and Stream 6 for TX */
 /*                                     */
 
  /*##-1- Enable peripherals and GPIO Clocks #################################*/
  /* Enable GPIO TX/RX clock */
  __GPIOD_CLK_ENABLE();
  /* Enable USART2 clock */
  __USART2_CLK_ENABLE();
  /* Enable DMA1 clock */
  __DMA1_CLK_ENABLE();
 
  /*##-2- Configure peripheral GPIO ##########################################*/
  /* UART TX GPIO pin configuration  */
  GPIO_InitStruct.Pin       = GPIO_PIN_5;
  GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull      = GPIO_NOPULL;
  GPIO_InitStruct.Speed     = GPIO_SPEED_FAST;
  GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
 
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
 
  /* UART RX GPIO pin configuration  */
  GPIO_InitStruct.Pin    = GPIO_PIN_6;
  GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
 
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
 
  /*##-3- Configure the UART peripheral ######################################*/
  /* Put the USART peripheral in the Asynchronous mode (UART Mode) */
 
  WifiUartHandle.Instance        = USART2;
  WifiUartHandle.Init.BaudRate   = 115200;
  WifiUartHandle.Init.WordLength = UART_WORDLENGTH_8B;
  WifiUartHandle.Init.StopBits   = UART_STOPBITS_1;
  WifiUartHandle.Init.Parity     = UART_PARITY_NONE;
  WifiUartHandle.Init.HwFlowCtl  = UART_HWCONTROL_NONE;
  WifiUartHandle.Init.Mode       = UART_MODE_TX_RX;
  WifiUartHandle.Init.OverSampling = UART_OVERSAMPLING_16;
 
  if(HAL_UART_Init(&WifiUartHandle) != HAL_OK)
  {
    //          Error_Handler();
    while(1);
  }
 
  /*##-4- Configure the UART TX DMA Transfer ######################################*/
 // *******************************************************************

  WifiDMAHandle_rx.Instance                 = DMA1_Stream5;
  WifiDMAHandle_rx.Init.Channel             = DMA_CHANNEL_4;
  WifiDMAHandle_rx.Init.Direction           = DMA_PERIPH_TO_MEMORY;
  WifiDMAHandle_rx.Init.PeriphInc           = DMA_PINC_DISABLE;
  WifiDMAHandle_rx.Init.MemInc              = DMA_MINC_ENABLE;
  WifiDMAHandle_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
  WifiDMAHandle_rx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
  WifiDMAHandle_rx.Init.Mode                = DMA_CIRCULAR;
  WifiDMAHandle_rx.Init.Priority            = DMA_PRIORITY_HIGH;
  WifiDMAHandle_rx.Init.FIFOMode            = DMA_FIFOMODE_ENABLE;
  WifiDMAHandle_rx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
  WifiDMAHandle_rx.Init.MemBurst            = DMA_MBURST_SINGLE;
  WifiDMAHandle_rx.Init.PeriphBurst         = DMA_PBURST_SINGLE;

  HAL_DMA_Init(&WifiDMAHandle_rx);
 
  __HAL_LINKDMA(&WifiUartHandle, hdmarx, WifiDMAHandle_rx);

  /*##-5- Configure the NVIC for DMA #########################################*/
  /* NVIC configuration for DMA transfer complete interrupt (WIFIUART_TX)     */
  //HAL_NVIC_SetPriority(WIFIUART_DMA_TX_IRQn, 0, 1);
  //HAL_NVIC_EnableIRQ(WIFIUART_DMA_TX_IRQn);
   
  /* NVIC configuration for DMA transfer complete interrupt (WIFIUART_RX)     */
  HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0);  
  HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
 
  /* NVIC configuration for USART TC interrupt */
  HAL_NVIC_SetPriority(USART2_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(USART2_IRQn);
 
  // *************************************************************************** 
 
  /* Starting Receiving on USART2 in DMA Circular Mode                             */
  HAL_UART_Receive_DMA(&WifiUartHandle, (uint8_t*)wifiRxBuffer, WIFI_RX_BUFFER_SIZE);
}

/**
  * @brief  This function handles DMA RX interrupt request. 
  * @param  None
  * @retval None  
  */
void DMA1_Stream5_IRQHandler(void)
{
  HAL_DMA_IRQHandler(WifiUartHandle.hdmarx);
}

/**
  * @brief  This function handles DMA TX interrupt request.
  * @param  None
  * @retval None  
  */
void DMA1_Stream6_IRQHandler(void)
{
  HAL_DMA_IRQHandler(WifiUartHandle.hdmatx);
}

/**
  * @brief  This function handles USART2 interrupt request.
  * @param  None
  * @retval None
  */
void USART2_IRQHandler(void)
{
  HAL_UART_IRQHandler(&WifiUartHandle);
}

/**
  * @brief  Rx Transfer completed callback
  * @param  UartHandle: UART handle
  * @note   This example shows a simple way to report end of DMA Rx transfer, and
  *         you can add your own implementation.
  * @retval None
  */
 
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
{
 int i,j;
 j = WIFI_RX_BUFFER_SIZE / 2;
 for (i=0; i < j; i++)
 {
  wifiCommandBuffer[i] = wifiRxBuffer[i+j];
  if ((wifiCommandBuffer[i] == 0) && (i != 0))
  {
   while(0);
  }
 }
 wifiCommandBuffer[j] = 124; // This is "|"
// HAL_UART_Transmit(&MdtUartHandle,(uint8_t *) wifiCommandBuffer, j+1, 1000);
}

/**
  * @brief  Rx Transfer Half completed callback
  * @param  UartHandle: UART handle
  * @note   This example shows a simple way to report end of DMA Rx transfer, and
  *         you can add your own implementation.
  * @retval None
  */
 
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *UartHandle)
{
 int i,j;
 j = WIFI_RX_BUFFER_SIZE / 2;
 for (i=0; i < j; i++)
 {
  wifiCommandBuffer[i] = wifiRxBuffer[i];
  if ((wifiCommandBuffer[i] == 0) && (i != 0))
  {
   while(0);
  }
 }
 wifiCommandBuffer[j] = 62; // This is ">"
 HAL_UART_Transmit(&MdtUartHandle,(uint8_t *) wifiCommandBuffer, j+1, 1000);
}
/**
  * @brief  UART error callbacks
  * @param  UartHandle: UART handle
  * @note   This example shows a simple way to report transfer error, and you can
  *         add your own implementation.
  * @retval None
  */
void HAL_UART_ErrorCallback(UART_HandleTypeDef *UartHandle)
{
 while(1)
 {
 }
}

 


Outcomes