FreeRTOS Support Archive
The FreeRTOS support forum is used to obtain active support directly from Real
Time Engineers Ltd. In return for using our top quality software and services for
free, we request you play fair and do your bit to help others too! Sign up
to receive notifications of new support topics then help where you can.
This is a read only archive of threads posted to the FreeRTOS support forum.
The archive is updated every week, so will not always contain the very latest posts.
Use these archive pages to search previous posts. Use the Live FreeRTOS Forum
link to reply to a post, or start a new support thread.
[FreeRTOS Home] [Live FreeRTOS Forum] [FAQ] [Archive Top] [April 2007 Threads] Problem with blocking a taskPosted by Ricky on April 23, 2007 I have a project I'm developing that currently has only one task, a command processor that reads commands from the serial port, acts on them, and sends a response back out the serial port.
I've been having problems with transmitting the response back. It appeared that the transmit FIFO was overflowing and I was losing characters, even though I was blocking when the transmit FIFO became full (I used the STR912F demo for IAR as the template). Debugging showed that the task would correctly block when taking a semaphore when the FIFO filled and then wait for the semaphore to be given back by the UART ISR when the FIFO became free. But when running full bore, the FIFO overflowed as if the semaphore weren't there.
I then had an idea that maybe the task was blocking on the semaphore and then immediately awakening again because it was the only task in the system and the scheduler had to wake somebody after the lone task went to sleep. This occurred to me once before with the uCOS RTOS, and I was wondering if it was happening in FreeRTOS as well.
Here's the code in the Send Character function I use to block on, which doesn't work:
___if (UART_GetFlagStatus (mkapsUARTBase [ziUART], UART_FLAG_TxFIFOFull)) { ______xSemaphoreTake (mapsTxSemaphore [ziUART], portMAX_DELAY); ___}
But when I make it a loop to force it to go back to sleep if the FIFO is still full, it works very well:
while (UART_GetFlagStatus (mkapsUARTBase [ziUART], UART_FLAG_TxFIFOFull)) { xSemaphoreTake (mapsTxSemaphore [ziUART], portMAX_DELAY); }
Is this what could be happening? Why doesn't the Idle Task run while waiting for the FIFO to become free?
RE: Problem with blocking a taskPosted by Nobody/Anonymous on April 23, 2007 The idle task will run if there are not other tasks, no doubt about that. Maybe you have a race condition on the checking of the FIFO. I'm not sure why you are checking the fifo before calling the semaphore function. You should just be able to check the semaphore on the assumption that it is given by the interrupt service routine. This way the race condition will be avoided. Maybe I am missing the point?
RE: Problem with blocking a taskPosted by Ricky on April 24, 2007 The semaphore is there to let me know when the FIFO becomes empty (actually, the number of bytes left in the FIFO goes below a certain threshold).
Here's the function to send a character in its entirety:
void Serial_SendChar (int ziUART, const char zcChar) {
// If the transmit FIFO is full, the task blocks to wait for space to become // free. It's okay to block in a critical section since interrupts will be // enabled for other tasks once a switch is forced.
___portENTER_CRITICAL(); ___while (UART_GetFlagStatus (mkapsUARTBase [ziUART], UART_FLAG_TxFIFOFull)) { ______xSemaphoreTake (mapsTxSemaphore [ziUART], portMAX_DELAY); ___}
// The character is transmitted.
___UART_SendData (mkapsUARTBase [ziUART], zcChar); ___portEXIT_CRITICAL(); }
I make sure that the FIFO has space available before sending a character to it. Once the FIFO is full, I take the semaphore which has already been taken when the UART was initialized, so the task blocks waiting for it to be given back. When the FIFO becomes free again, the UART causes a serial transmit interrupt. The code that handles this interrupt is shown here:
___if (UART_GetFlagStatus (mkapsUARTBase [ziUART], UART_RawIT_Transmit)) { ______xlWakeTask = xSemaphoreGiveFromISR (mapsTxSemaphore [ziUART], xlWakeTask); ______UART_ClearITPendingBit (mkapsUARTBase [ziUART], UART_IT_Transmit); ___}
The semaphore is given back in the interrupt, and the task that called Serial_SendChar is awakened. The semaphore is taken again and the character is sent to the UART.
So the interrupt does nothing but unblock the task when the FIFO becomes free. The task is responsible for sending the character and checking to see if the FIFO is full. Granted, it's not exactly your standard serial port functionality, but it saves some code and it works.
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.
|