I have two modules of code in a FreeRTOS application:
- Parser (receives bytes from a UART and parses them into messages)
- Handler (handles these messages)
What is the best way to pass the messages from the parser to the handler?
I am currently using a callback function provided by the handler. Once the parser has a message, it calls that function. I am aware that the callback function is executed in the context of the receiving task within the parser, although it logically belongs to the handler... but I cannot think of a reason why that would be a problem.
I could also use a queue. Then the parser would put messages into the queue and the handler would receive and handle them. It would be a cleaner seperation between tasks. But it would require FreeRTOS to do a context switch whenever a message is received (how expensive is that really?), and I imagine that it would also mean higher latency.
As long as I don't need to run the two modules with different priorities, is there any valid reason why I should NOT use the callback function?
It is not easy to give a specific answer without understanding what you really want to parse, how fast is the data stream, what is the frequency of the incoming message, if it is periodic or not, what are the capabilities of your MCU etc.
In my opinion the best practice would be using the DMA to store the incoming data in a buffer. This frees the CPU from the load of continuously reading the bus. Once there is enough number of bytes to parse, or whatever the condition is for parsing the buffer data, you can do parsing in a task and keep parsed data in a queue. Then the consumer (handler) task waits that the content of the queue is not NULL and once there is something to handle, it gets the object from the queue and does whatever it wants to do.
It is not easy to answer how expensive is the context switch. If you are working with a recent 32 bit MCU, I would say it is pretty "cheap". Instead if you are trying something experimental with a tiny platform, like an ATMEGA328, it could be considerably expensive. In any case if you are talking about UART (and in general any communication interface), it is very less likely the context switch is the bottle neck that you have to worry about for the latency.
FreeRTOS has a very lightweight yet powerful kernel and used in many real time industrial applications from automotive to robot control. In the end, the answer strictly depends on what you really want to achieve. I do not understand why you need an RTOS in your case. But if you have two tasks, a producer and a consumer, then your example is typical example of race condition and there is no way to resolve it without using a synchronization API.