2016-02-22 07:25 AM
Posted on February 22, 2016 at 16:25
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;
HAL_UART_Init(&huart2);
}
// 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;
HAL_UART_Init(&huart4);
}
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))
{
__HAL_UART_CLEAR_OREFLAG(&huart2);
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.
2016-02-22 08:45 AM
You shouldn't need to test both IT and status flags, pick one.
You don't have to clear RXNE or TXE, reading or writing USARTx->DR does this.Be careful your OS routines don't yieldDeal with the over-run and errors last.2016-02-22 10:40 AM
Thanks for your reply. I did as you suggested: moved the ORE check, only checked for the flag (only checking for IT did not work, the IT never appears to get reset after the first time through), removed flag resets, and I've verified my threads do not yield - but I am still receiving the byte loss...
An observation I've made (which seems to not make sense) is that if I replace the data to be written back through UART2 with static integer values instead of values received/processed from UART4, the byte loss goes away. It still goes away even if I read/write over the UART4 line but simply not use the data (by writing to an unused buffer to ensure it isn't being optimized out). This seems to suggest it is not an issue with the IRQ because the interrupts are still occurring but it contradicts my previous observation that the data makes it to the DR write line correctly...