AnsweredAssumed Answered

HAL UART DMA circular buffer TX/RX

Question asked by raggini.davide on Jun 8, 2017
Latest reply on Oct 19, 2017 by Jari Nippula

Hi everyone,

 

I'm trying to set up the UART1 peripheral of a STM32L072 to use DMA for TX / RX in circular buffer. While the setup for TX was straight-forward I cannot figure out what's wrong with the RX: it seems that nothing is received. I already have done it with SPL library for previous projects but I'm still struggling a little with HAL library!

Any one can see what's wrong with my code initialisation? 
Since RX DMA is in circular mode, once the steam is activated after the initialisation it should work "forever" as it was doing with SPL library?

What I can see is that the RxClptCallback never gets called, even if i never set up a TX transfer

 

Thank you,

hope this topic will help other that like me are trying to set up this kind of peripheral use: it would be great to show to the community a complete and working code snippet (from init to circular buffer management with HAL) !!

 

Davide

 

/* SEND String circular buffer SIZE */

#define BUFSIZE 512

/* SEND String temporary sprintf buffer SIZE */

#define BUFTEMPSIZE 64

/* RECEIVE String circular buffer SIZE */

#define BUFRECSIZE 64

 

/* SEND String circular buffer */

static char tx_buff[BUFSIZE] __attribute__ ((aligned (8)));

/* SEND String temporary sprintf buffer */

static char tempBuff[BUFTEMPSIZE] __attribute__ ((aligned (8)));

/* buffer write index for the SEND circular buffer */

static uint16_t tx_iw=0;

/* buffer read index for the SEND circular buffer */

static uint16_t tx_ir=0;

 

/* RECEIVE String circular buffer */

static char rx_buff[BUFRECSIZE] __attribute__ ((aligned (8)));

 

 

/* Uart Handle */

static UART_HandleTypeDef  UartHandle;

static DMA_HandleTypeDef   UsartDMAHandle_tx;

static DMA_HandleTypeDef   UsartDMAHandle_rx;

 

 

/**

* @brief  Records string on the circular Buffer

* @param  string

* @return None

*/

void usart1_Send( char *format, ... )

{

  va_list args;

  va_start(args, format);

  uint8_t len;

 

  // Convert into string at tempBuff[0] of length len

  len = vsprintf(&tempBuff[0], format, args);

 

  // Push characters into the send circular buffer

  uint8_t i = 0;

  for ( i=0; i<len; i++ ){

  tx_buff[tx_iw] = tempBuff[i];

  tx_iw = ( tx_iw + 1 ) % BUFSIZE;

  }

 

  // If not active, start the DMA transfer

  usart1_PollingSend();

 

  va_end(args);

}

 

/**

* @brief  Sends circular Buffer on com port

* @param  None

* @return None

*/

void usart1_PollingSend( void )

{

// Enter Critical Section.

// This function is protected since it get's called during the Idle and

// by the usart1_Send function in the application environment.

    BACKUP_PRIMASK();

    DISABLE_IRQ();

// If the previous DMA transfer is complete

if ( (HAL_DMA_GetState ( &UsartDMAHandle_tx ) == HAL_DMA_STATE_READY) ){

// Check for new data

if( tx_ir != tx_iw )

{

  //Get Buff Pointer

  uint8_t* BuffPointer;

  BuffPointer = (uint8_t*) &tx_buff[tx_ir];

  // Manage Buffer Overflow and ReadIndex pointer

  uint16_t size;

  if ( tx_iw > tx_ir){

  size = tx_iw - tx_ir;

  tx_ir += size;

  }

  else{

  size = BUFSIZE - tx_ir;

  tx_ir = 0;

  }

  // Send Data with the DMA

  HAL_UART_Transmit_DMA( &UartHandle, BuffPointer, size );

}

}

// Exit Critical Section

    RESTORE_PRIMASK();

}

 

 

/**

* @brief  Init the USART1.

* @param  None

* @return None

*/

void usart1_Init(void)

{

  /*## Enable peripherals Clock ###########################################*/

  __USART1_CLK_ENABLE();

  __DMA1_CLK_ENABLE();

 

  /*## Configure the USART peripheral ######################################*/

  /* Put the USART peripheral in the Asynchronous mode (USART Mode) */

  /* USART1 configured as follow:

      - Word Length = 8 Bits

      - Stop Bit = One Stop bit

      - Parity = NONE

      - BaudRate = 115200 baud

      - Hardware flow control disabled (RTS and CTS signals) */

  UartHandle.Instance         = USART1;

  UartHandle.Init.BaudRate   = 115200;

  UartHandle.Init.WordLength  = UART_WORDLENGTH_8B;

  UartHandle.Init.StopBits   = UART_STOPBITS_1;

  UartHandle.Init.Parity  = UART_PARITY_NONE;

  UartHandle.Init.Mode   = UART_MODE_TX_RX;

  UartHandle.Init.HwFlowCtl   = UART_HWCONTROL_NONE;

  UartHandle.Init.OverSampling   = UART_OVERSAMPLING_16;

  UartHandle.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;

  UartHandle.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;

 

  if(HAL_UART_Init( &UartHandle ) != HAL_OK)

  {

 

  while(1);

  }

 

  /*## Configure the UART DMA peripheral for TX transfers #################*/

  /* TX DMA is in Normal Mode */

  UsartDMAHandle_tx.Instance = DMA1_Channel2;

  UsartDMAHandle_tx.Init.Request = DMA_REQUEST_3;

  UsartDMAHandle_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;

  UsartDMAHandle_tx.Init.PeriphInc = DMA_PINC_DISABLE;

  UsartDMAHandle_tx.Init.MemInc = DMA_MINC_ENABLE;

  UsartDMAHandle_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

  UsartDMAHandle_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;

  UsartDMAHandle_tx.Init.Mode = DMA_NORMAL;

  UsartDMAHandle_tx.Init.Priority = DMA_PRIORITY_LOW;

  if (HAL_DMA_Init(&UsartDMAHandle_tx) != HAL_OK)

  {

  while(1);

  }

  // Link the DMA Channel to the USART1 Peripheral

  __HAL_LINKDMA( &UartHandle, hdmatx, UsartDMAHandle_tx);

 

  /*## Configure the UART DMA peripheral for RX transfers #################*/

  /* RX DMA is in Circular Mode */

  UsartDMAHandle_rx.Instance = DMA1_Channel3;

  UsartDMAHandle_rx.Init.Request = DMA_REQUEST_3;

  UsartDMAHandle_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;

  UsartDMAHandle_rx.Init.PeriphInc = DMA_PINC_DISABLE;

  UsartDMAHandle_rx.Init.MemInc = DMA_MINC_ENABLE;

  UsartDMAHandle_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

  UsartDMAHandle_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;

  UsartDMAHandle_rx.Init.Mode = DMA_CIRCULAR;

  UsartDMAHandle_rx.Init.Priority = DMA_PRIORITY_LOW;

  if (HAL_DMA_Init(&UsartDMAHandle_rx) != HAL_OK)

  {

  while(1);

  }

  // Link the DMA Channel to the USART1 Peripheral

  __HAL_LINKDMA( &UartHandle, hdmarx, UsartDMAHandle_rx);

 

  /*## Configure USART1 and DMA interrupts #################################*/

  HAL_NVIC_SetPriority(DMA1_Channel2_3_IRQn, USART1_IRQ_PRIORITY, 0);

  HAL_NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);

  HAL_NVIC_SetPriority(USART1_IRQn, USART1_IRQ_PRIORITY, 0);

  HAL_NVIC_EnableIRQ(USART1_IRQn);

 

  /*## Start the DMA RX Receive Service ###################################*/

  HAL_UART_Receive_DMA(&UartHandle, (uint8_t*) rx_buff, BUFRECSIZE);

 

  /*## Configure peripheral GPIO ##########################################*/

  usart1_IoInit();

}

 

/**

* @brief This function handles DMA1 channel 2 and channel 3 interrupts.

*/

void DMA1_Channel2_3_IRQHandler(void)

{

  HAL_DMA_IRQHandler( &UsartDMAHandle_tx );

  HAL_DMA_IRQHandler( &UsartDMAHandle_rx );

}

 

/**

* @brief This function handles DMA1 channel 2 and channel 3 USART Transfer Complete.

*/

void USART1_IRQHandler(USART_HandleTypeDef *husart){

  HAL_UART_IRQHandler( &UartHandle );

}

 

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart){

  asm("");

}

 

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){

  asm("");

}

 

 

/**

* @brief  Init the USART1 IOs.

* @param  None

* @return None

*/

void usart1_IoInit(void)

{

  GPIO_InitTypeDef  GPIO_InitStruct={0};

  /* Enable GPIO TX/RX clock */

  __GPIOA_CLK_ENABLE();

    /* UART TX GPIO pin configuration  */

  GPIO_InitStruct.Pin       = USART1_TX_PIN;

  GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;

  GPIO_InitStruct.Pull      = GPIO_PULLUP;

  GPIO_InitStruct.Speed     = GPIO_SPEED_HIGH;

  GPIO_InitStruct.Alternate = GPIO_AF4_USART1;

 

  HAL_GPIO_Init(USART1_TX_GPIO_PORT, &GPIO_InitStruct);

 

  /* UART RX GPIO pin configuration  */

  GPIO_InitStruct.Pin = USART1_RX_PIN;

  GPIO_InitStruct.Alternate = GPIO_AF4_USART1;

 

  HAL_GPIO_Init(USART1_RX_GPIO_PORT, &GPIO_InitStruct);

}

Outcomes