xQueueReceive() blocks endlessly

harlekin_666 wrote on Monday, December 03, 2007:

Hi!
I am new to FreeRTOS and try to make my first steps with version 4.6.1. I started with the demo application for Coldfire MCF5235 and ported it to my MCF52235. I am using the latest GCC distribution from codesourcery.com (since they have some good patches for coldfire GCC).
The demo application works good. Except if I start all tasks, but I think this is because the 52235 has only 16k RAM. I will find out later. More confusing is something else. I started an own task, which does

while (1) {
  signed portCHAR inchar;

  if ( xSerialGetChar( xSTDComPort0, &inchar, 10 ) == pdTRUE ) {
    xSerialPutChar( xSTDComPort0, inchar, 10 );
  }
}

Perhaps you all know the demo applications, but if not: the xSerialGetChar just calls an xQueueReceive() for the receive buffer. This buffer is filled from the UART interrupt. Using the timeouts like above (the 10), everything is fine and the application works and gives me an echo on the serial line. But with timeouts set to null - which should wait AFAIK really untill there is something in the buffer - I get only one character. That means the xQueueReceive() works for the first time, but starts blocking endlessly the second time.

Can anybody give me a hint what is wrong here? Can something be wrong with my port? Or is there a bug in the serial.c of the demo application or in FreeRTOS?

Thank you in advance,

Kay

davedoors wrote on Monday, December 03, 2007:

Are the other tasks still running ok?  Can you confirm that the tick interrupt is still running?  If the tick stops then you will not unblock.

By setting the time out to null do you mean setting it to zero?  This will prevent the task from blocking at all and in effect cause you to poll the queue.  If you want to block indefinitely then set the time out to portMAX_DELAY and set configINCLUDE_vTaskSuspend to 1 in FreeRTOSConfig.h.  If you do not set configINCLUDE_vTaskSuspend to 1 then you will block for portMAX_DELAY ticks which will be 0xffffffff ticks so a long time anyway.

harlekin_666 wrote on Monday, December 03, 2007:

Sorry, I was meaning portMAX_DELAY not null or zero. And the configINCLUDE_vTaskSuspend is set to 1. The other tasks are still running. I just checked it with a small additional task which lets some LEDs blink, with a vTaskDelay().
It is somehow strange. The first xQueueReceive() works. I mean I send a character to the board, the tasks sees the character which is put in a queue by the serial interrupt and echos it. And the second character does not let the task wake up any more. And the serial interrupt must also be working, since when I set the timeout to a small value it also works…

harlekin_666 wrote on Thursday, December 06, 2007:

I got another idea. Perhaps I just misunderstood the API. When I do

xQueueReceive( queue, &inchar, portMAX_DELAY );

(with configINCLUDE_vTaskSuspend set to 1), you said that it blocks indefinitely. Does this mean that it is meant not to wake up when the queue is filled?

Then it is not what I want but it would fit more to the actual behaviour.

jmr1972 wrote on Thursday, December 06, 2007:

Just check that in the ISR something along the lines of the following is present:

void vBufferISR( void )
{
portCHAR cIn;
portBASE_TYPE xTaskWokenByPost;

// We have not woken a task at the start of the ISR.
xTaskWokenByPost = pdFALSE;

  // Obtain a byte from the buffer.
  cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );

  // Post the byte.
  xTaskWokenByPost = xQueueSendFromISR( xRxQueue, &cIn, xTaskWokenByPost );

  // Now the buffer is empty we can switch context if necessary.
  if( xTaskWokenByPost )
  {
    // We should switch context so the ISR returns to a different task.
    // NOTE: How this is done depends on the port you are using. Check
    // the documentation and examples for your port.
    portYIELD_FROM_ISR();
  }
}

harlekin_666 wrote on Friday, December 07, 2007:

I finally found it. There was something similar to the portYIELD_FROM_ISR(). As I said before, my work is based on the MCF5235 port. And the serial interrupt is something like

{
portENTER_SWITCHING_ISR();

portEXIT_SWITCHING_ISR( ( xTaskWokenByTx || xTaskWokenByRx ) );
}

The actual mistake was the definition and use of xTaskWokenByTx and xTaskWokenByRx. They were defined as

static portBASE_TYPE xTaskWokenByTx = pdFALSE, xTaskWokenByRx = pdFALSE;

and therefore only initializied once. So I changed the definition to

static portBASE_TYPE xTaskWokenByTx, xTaskWokenByRx;

and added the

xTaskWokenByTx = pdFALSE; xTaskWokenByRx = pdFALSE;

after the portENTER_SWITCHING_ISR() and it finally works. Still I am not sure what exactly was going on, since the xTaskWokenByRx was really set to pdTRUE, so the portEXIT_SWITCHING_ISR() must have had worked. Is there probably a problem when vTaskSwitchContext() (which is called when the parameter to portEXIT_SWITCHING_ISR() is pdTRUE) without any reason?

I think the serial port of the MCF5235 port will also not work correctly. Shall I make a patch for this?