davebryan wrote on Saturday, March 15, 2008:
Hi,
I’ve implemented a queued UART Tx/Rx scheme based on the code in Demo\CORTEX_STM32F103_IAR\serial.c file.
I’m having intermittent problems with the Tx queue where the call to xQueueReceiveFromISR in the UART interrupt handler returns the incorrect data from the Tx queue. When incorrect data is returned I’ve found that the Tx queue ‘pcReadFrom’ pointer equals the Tx queue ‘pcWriteTo’ pointer. For correct operation the pcReadFrom pointer should be 1 or more bytes behind the pcWriteTo pointer.
I only have a single task accessing the Tx/Rx queues. The fact that this behaviour happens intermittantly suggests some sort of timing issue but looking at the FreeRTOS queue.c code I can’t see how this can happen.
Has anyone come across this or have any clues ?
Thanks
Dave
Code is as follows:
void Uart_init()
{
/* create the receive & transmit queues */
hostRxQ = xQueueCreate( 128, 1);
hostTxQ = xQueueCreate( 128, 1);
}
portBASE_TYPE Uart_Tx( unsigned char byte, portTickType timeout)
{
/* try to queue the byte */
portBASE_TYPE txResult = xQueueSend( hostTxQ, &byte, timeout);
if (txResult == pdTRUE)
{
/* enable transmitter empty interrupts */
USART_ITConfig(USART2, USART_IT_TXE, ENABLE);
}
return txResult;
}
void UART_Interrupt_Handler()
{
unsigned char ch;
portBASE_TYPE taskWokenByRxQAdd = pdFALSE;
portBASE_TYPE taskWokenByTxQRemove = pdFALSE;
if (USART_GetITStatus(USART2, USART_IT_TXE) == SET)
{
/* transmitter is ready for the next byte so see if there is more to transmit */
if (xQueueReceiveFromISR( hostTxQ, &ch, &taskWokenByTxQRemove) == pdTRUE)
{
/* send the byte */
USART_SendData(USART2, ch);
}
else
{
/* disable further USART2 Transmit interrupts */
USART_ITConfig(USART2, USART_IT_TXE, DISABLE);
}
/* Clear the USART2 transmit interrupt pending flag */
USART_ClearITPendingBit(USART2, USART_IT_TXE);
}
if (USART_GetITStatus(USART2, USART_IT_RXNE) == SET)
{
/* read the received byte from the receive data register */
ch = USART_ReceiveData(USART2);
taskWokenByRxQAdd = xQueueSendFromISR( hostRxQ, &ch, taskWokenByRxQAdd);
/* Clear the USART2 Receive interrupt */
USART_ClearITPendingBit(USART2, USART_IT_RXNE);
}
/* see if we need to switch tasks */
portEND_SWITCHING_ISR( taskWokenByRxQAdd || taskWokenByTxQRemove);
}