Hello fellow electronics engineers!

I'm having a bit of a problem with setting up the STM32F072-Nucleo board as a small shell (I want to send commands via UART and set/get various settings of the application I'm making.) using the UART with DMA in interrupt mode.

The code is based on BrinirController. The problem is that while I can receive the first character and echo it back, after that first interrupt the MCU does not do another interrupt if I try to write another character. The HAL I'm using is 1.2.1 (together with the STM32CubeMX) and it does not have the macro __HAL_UART_FLUSH_DRREGISTER(&huart2) for flushing the UART's RX data buffer.

Does the function __HAL_UART_SEND_REQ(&huart2, UART_RXDATA_FLUSH_REQUEST) do the same thing as the macro __HAL_UART_FLUSH_DRREGISTER(&huart2) in the previous version of HAL?

Could this be the problem: the RX data buffer is full so it just won't start another interrupt while it's not cleared/read from?

The RxCpltCallback callback function is called only the first time I enter something in the serial terminal... It just won't interrupt the second time... I've tried everything, it seems! :D What could be the solution? I'm using the STM32F072RBT6 (STM32F072-Nucleo board)

The code goes like this:

UART_HandleTypeDef huart2;
DMA_HandleTypeDef hdma_usart2_rx;
DMA_HandleTypeDef hdma_usart2_tx;

/* USART2 init function */

void MX_USART2_UART_Init(void)

  huart2.Instance = USART2;
  huart2.Init.BaudRate = 9600;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  huart2.Init.OneBitSampling = UART_ONEBIT_SAMPLING_DISABLED ;
  huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;


void HAL_UART_MspInit(UART_HandleTypeDef* huart)

  GPIO_InitTypeDef GPIO_InitStruct;
  /* USER CODE BEGIN USART2_MspInit 0 */

  /* USER CODE END USART2_MspInit 0 */
    /* Peripheral clock enable */

    /**USART2 GPIO Configuration    
    PA2     ------> USART2_TX
    PA3     ------> USART2_RX 
    GPIO_InitStruct.Pin = GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF1_USART2;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF1_USART2;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* Peripheral DMA init*/

    hdma_usart2_rx.Instance = DMA1_Channel5;
    hdma_usart2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_usart2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart2_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart2_rx.Init.Mode = DMA_NORMAL;
    hdma_usart2_rx.Init.Priority = DMA_PRIORITY_MEDIUM;


    hdma_usart2_tx.Instance = DMA1_Channel4;
    hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart2_tx.Init.Mode = DMA_NORMAL;
    hdma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW;


  /* USER CODE BEGIN USART2_MspInit 1 */

  /* USER CODE END USART2_MspInit 1 */

and the interrupt callback function:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
  __HAL_UART_SEND_REQ(&huart2, UART_RXDATA_FLUSH_REQUEST); // Clear the buffer to prevent overrun
  int i = 0;
  HAL_UART_Transmit_DMA(&huart2, (uint8_t *)&rxBuffer, 1);

  if (rxBuffer == 8 || rxBuffer == 127) // If Backspace or del
      printf(" \b"); // "\b space \b" clears the terminal character. Remember we just echoced a \b so don't need another one here, just space and \b
      if (rxindex < 0) rxindex = 0;

  else if (rxBuffer == '\n' || rxBuffer == '\r') // If Enter
      rxString[rxindex] = 0;
      rxindex = 0;
      for (i = 0; i < MAXSTRING; i++) rxString[i] = 0; // Clear the string buffer

      rxString[rxindex] = rxBuffer; // Add that character to the string
      if (rxindex > MAXSTRING) // User typing too much, we can't have commands that big
      rxindex = 0;
      for (i = 0; i < MAXSTRING; i++) rxString[i] = 0; // Clear the string buffer
      printf("\r\nKonsole> ");

Of course, I'm calling the HAL_UART_Receive_DMA(&huart2, &rxBuffer, 1) in the main routine before the infinite loop and have defined these variables as buffers:

uint8_t rxBuffer = '\000';
uint8_t rxString[MAXSTRING];
int rxindex = 0;

1 Answer 1


Switch the RX DMA mode to DMA_CIRCULAR. Normal DMA mode executes once and you have to configure it again. Circular mode allows you to do the same operation until you explicitly stop it.

  • \$\begingroup\$ I had similar case, and switching the USART RX DMA Mode (within Cube's DMA configuration window) from to NORMAL to CIRCULAR has helped -> now ISRs for characters/data being received are being called regularly and do not require re-enabling them (which just means they work more stable). Thank you for the hint ! :-) \$\endgroup\$
    – user126563
    Commented Oct 13, 2016 at 15:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.