AnsweredAssumed Answered

UART Byte Loss

Question asked by banchy.mark on Feb 22, 2016
Latest reply on Feb 22, 2016 by banchy.mark
I have two UARTs configured as follows (code generated by CubeMX).

UART_HandleTypeDef huart2;
UART_HandleTypeDef huart4;

// Pins (Rx/Tx): PA3 / PA2 - Asynchronous (UART)
void MX_USART2_UART_Init(void)
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  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;

// Pins (Rx/Tx): PA1 / PC10 - Asynchronous (UART)
void MX_UART4_UART_Init(void)
  huart4.Instance = UART4;
  huart4.Init.BaudRate = 115200;
  huart4.Init.WordLength = UART_WORDLENGTH_8B;
  huart4.Init.StopBits = UART_STOPBITS_1;
  huart4.Init.Parity = UART_PARITY_NONE;
  huart4.Init.Mode = UART_MODE_TX_RX;
  huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart4.Init.OverSampling = UART_OVERSAMPLING_16;

A command is sent over UART2, the software parses the command, and sends bytes over UART4 (a servo controller). Bytes are then received over UART4, packaged, and sent over UART2. The process is asynchronous and the interrupts are are setup as follows. The USART4_IRQHandler is set up identical with separate RX/TX buffers.

void USART2_IRQHandler(void)
     /* UART Over-Run interrupt occurred ----------------------------------------*/
     if((__HAL_UART_GET_FLAG(&huart2, UART_FLAG_ORE)    != RESET) &&
        (__HAL_UART_GET_IT_SOURCE(&huart2, UART_IT_ERR) != RESET))
       huart2.ErrorCode |= HAL_UART_ERROR_ORE;

     if((__HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE)    != RESET) &&
        (__HAL_UART_GET_IT_SOURCE(&huart2, UART_IT_RXNE) != RESET))
          osMessagePut(RxQueueHandle, (uint8_t)(huart2.Instance->DR & (uint8_t)0x00FF), 0);
          __HAL_UART_CLEAR_FLAG(&huart2, UART_FLAG_RXNE);

     if((__HAL_UART_GET_FLAG(&huart2, UART_FLAG_TXE)    != RESET) &&
        (__HAL_UART_GET_IT_SOURCE(&huart2, UART_IT_TXE) != RESET))
          osEvent e = osMessageGet(TxQueueHandle, 0);

          if(e.status == osOK)
               __HAL_UART_DISABLE_IT(&huart2, UART_IT_TXE);
          else if(e.status == osEventMessage)
               huart2.Instance->DR = (e.value.v & (uint16_t)0x00FF);
               __HAL_UART_CLEAR_FLAG(&huart2, UART_FLAG_TXE);

The problem is that there is a byte lost (~5% of the time) on the receive portion of UART2. I've confirmed that the software reaches the UART2 interrupt (by pushing to a debugging queue) with the correct data in hand - but it is not received by the peripheral (XBEE radio) attached to UART2. Is the flag checking/handling correct? Could the DR register not be writing over the UART2 TX line due to a flag being reset by the RX portion of the IRQ?

I will say I decided to write my own IRQ instead of using the HAL - I was having trouble getting it to work correctly.

Thanks in advance, any insight is helpful.