Hello:
I’m hoping to get an idea on a best way to approach what is likely a fairly trivial task in FreeRTOS.
I send a command to a device via UART, and expect a string back, perhaps 100 chars.
I have an interrupt handler (DMA or character terminated) that I can use either a task notify (have not used before) or a send to queue (have used before)
It may take up to 4 seconds for the data to come back. However, the receiver may not get it for whatever reason so it could be longer than 4 seconds.
So the question is, after I launch the scheduler, from what FreeRTOS “method” should I send the “request” to the target UART? (i.e., task? )
Assume I use a task notify once the data has been received in the ISR. I know that the data could take up to 4 seconds; what’s the method in the task to wait that long to get a task notification? Not polling I hope…
Then, once I get the notification the data has to be parsed. Assume I send it to a function. Again, in the task, do I just send it and use vTaskDelay, making a bad assumption it will be ready within that delay period?
Is there a ready made example that would illustrate this task which I’m thinking is pretty straightforward in FreeRTOS?
Thanks!
Depending on exactly how the device is used, I would either define a special task to process the device which other tasks communicate to with requests, or a set of functions that other tasks call to work with the device. Mostly depends if the tasks that need the operations done should just wait for an answer (and thus a function works fine) or have other things to do (so a separate task is needed).
Unless the UART is running at a very high speed, I tend to use a generic ISR that gets each received character and puts it into a queue or stream buffer, and the receiving task waits for it, blocking with a timeout for the data to arrive. Since it is blocking on the queue/stream buffer, it isn’t using processor until a character arrives. Once the full message arrives, it can process it.
hi richard-damon,
Thanks for your reply. I think I’ve got it figured out then. After a few tests using the tasknotify from isr works very well and should be suitable for the job.
Now here is a question that was alluded to in my original post. The task being notified “to”:
void task1( void *pvParameters )
{
while(1)
{
vTaskSuspend(NULL);
//if I’m notified, send my data to the process queue…
}
}
I another task, I send the query to the other device. If the device does not respond, is there any way to add a timeout to the process here? For example, the ISR terminates upon receipt of the ‘\r’, and does the xQueueSendFromISR. What if that is never received? I know how to do it used “heavy-handed” methods, but I would like to skip those in favor of a better approach using FreeRTOS if possible!
Thanks!
Don’t use suspend, but wait on a condition, either a semaphore or a direct to task notification. Then you can add a timeout parameter.
The Suspend/Resume protocol is a very light weight one, with little overhead, but is subject to a number of race conditions which you want to avoid if possible. (I have NEVER needed to suspend a task)
Your advice on using suspend was taken into consideration as good advice.
I ended up using this: ulTaskNotifyTake(pdTRUE, 5000), a queue with the parser, and a state machine to handle the process. working good!
It was my first time using direct to task notify…great! And I’ve done something similar before with semaphores, but if this is more space-efficient it makes sense to use it.
Thanks again richard-damon!
Yes, the Direct-to-task notification, when applicable, are more efficient than a discrete semaphore. The main limitations are that you always are notifying a specific task (which often isn’t a problem, because only one task will be trying to take the semaphore), and the giver can’t tell if the semaphore was still in the given state.
It avoids all the memory cost of the semaphore, and is a bit faster to execute.