Kamil
Kamil

Reputation: 13931

How to handle timeout in FreeRTOS - wake up task from interrupt before vTaskDelay expires?

Can I wake up task before vTaskDelay expires?

I have code like this:

In the task (hnd_uart_task) code:

transmit_frame();
vTaskDelay(100);  // task should wait 100 ticks or be woken up by uart ISR
parse_response();

UART Interrupt:

// if byte was received
BaseType_t xYieldRequired = xTaskResumeFromISR(hnd_uart_task);
portYIELD_FROM_ISR(xYieldRequired);

Upvotes: 1

Views: 2810

Answers (2)

Tagli
Tagli

Reputation: 2592

Instead of using vTaskDelay(), you can use task notifications with timeout.

USART Interrupt:

// if byte was received
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR(hnd_uart_task, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);

Task Code:

transmit_frame();
ulTaskNotifyTake(pdTRUE, 100);
parse_response();

ulTaskNotifyTake(pdTRUE, 100) returns when a task notification is received from the ISR, or when 100 tick timeout period elapses.

But as @Jacek Ślimok pointed out, a byte-by-byte parsing may not be good idea. The exact method depends on the protocol used. But in general, you set up your DMA or interrupts to fill a reception buffer with incoming bytes. For example, when parsing Modbus frames, you can use idle line detection hardware interrupt and give notification to a task which parses the RX buffer.

Upvotes: 1

J_S
J_S

Reputation: 3252

No, because that's not what vTaskDelay was meant to be used for.

The closest solution to yours would be to create a semaphore that you attempt to take inside the task with a 100ms delay and that you give from ISR. This way the task will block for a maximum of 100ms waiting for semaphore to be given, after which it'll unblock and resume execution anyway. If it's given earlier, it'll unblock earlier, which is what I assume you want.

However, from what you've written I assume you want to achieve something like the following:

  • Send some data over UART
  • Wait for response
  • As soon as response is received, do something with the response

In this case, doing both blocking and parsing in the same task is going to be hard (you reaaaalllly don't want to do any sort of parsing inside of your ISR). I'd therefore recommend the following "layout" of two tasks, an interrupt and one shared smepahore between the two tasks:

  1. "High level" task (let's call it ApplicationTask) that can do the following:
  • Construct whole frames and request them to be sent over UART (add them to some kind of queue). This "construction of whole frames" and sending them over to the other tasks would usually be wrapped into some functions.
  • Will block waiting for response
  • Will receive already parsed data (full frame or object/structure holding that parsed data)
  1. "Byte level" task (let's call it ByteTask) that can do the following:
  • Has a queue for transmitted data (queue of frames or queue of raw bytes)
  • Has a queue for received data
  • "Pushes" data from "data to be transmitted" queue into UART
  • Parses UART data that appears in "received data" queue and gives semaphore to unblock the ApplicationTask
  1. UART Interrupt:
  • Only transmits data that it's told to transmit by ByteTask
  • Pushes received data into ByteTask receive queue
  1. Shared semaphore between ApplicationTask and ByteTask:
  • Whenever ApplicationTask wants to "wait to receive response", it attempts to take this semaphore. Maximum blocking time can be used as a "response receiving timeout".
  • Whenever ByteTask receives and parses enough data to decide that "yes, this is a complete response", it gives this semaphore.

This above is a super simple example of something that should be easy enough to scale to more tasks as you develop your application. You can get a lot more fancy than that (e.g. ByteTask handling multiple UARTs at the same time, have a pool of semaphores used for blocking for multiple tasks, do some more sophisticated message dispatching etc.), but the example above should hopefully give you a better idea of how something like this can be approached.

Upvotes: 2

Related Questions