UART & SPI through FreeRTOS

borge_strand wrote on Friday, January 28, 2011:


I’m new to FreeRTOS and eager to learn more about it. I have just joined a project which uses FreeRTOS to perform full-speed USB transfers and some simple user interface tasks.

Now I wish to port a few low data rate tasks from a different MCU into the project, and wonder what is the best approach. The low data rate tasks are typicically receiving a few characters over the UART, interpreting them in a state machine, and then forward some of them to an SPI interface. In previous versions (without the USB) I didn’t mind the program hanging while waiting for this kind of slow data. But it would ruin the USB transfers. My data rates are typically 100kbaud, largest data file to forward from UART to SPI is 2kBytes. Response time is not very critical.

As a beginner, I wonder what is the best approach. Should I simply do the UART transfers in tasks with low priority, assuming the OS will sort things out, or should I rather have tasks blocked while waiting for data, with semaphores, interrupts etc.? Or are there better approaches still? Are there UART functions in FreeRTOS which already support blocking until data ready?

Existing code runs on AVR without FreeRTOS, port will run on AVR32 with FreeRTOS.


richard_damon wrote on Friday, January 28, 2011:

First, the way the OS sorts things out is by having tasks block on queue etc waiting for data. While you could have a task spin wait for data, that is almost always the wrong way to do it.

Based on the crude outline you have given, I would have a UART interrupt gathering characters and either place them directly into a queue or assemble them into a “message” that is somehow sent to the task. If messages really are as short as you describe, straight into queue sounds acceptable. (The queue will need to be big enough to handle as big as a processing backlog as you would expect, safety margins based on if the protocol has ways to signal  error and retransmission request or slow down I am getting full capability),

The task then processes the incoming data, runs the state machine and builds up the SPI data to send, and triggers the transmission. Depending on your requirements, resources and protocols, you may want to buffer up a full message to send out on the SPI interface, or you may be able to send the data to the SPI routine piecemeal (Biggest question is can the SPI interface pause for a moment while waiting for data).

borge_strand wrote on Saturday, January 29, 2011:

Hi Richard,

The SPI is a slave device to the MCU, so that shouldn’t be a problem. The MCU is UART slave to the PC, but on the PC side I have made my own slowcat() function which can be set up to know about MCU state machine latencies.

Generally, as a FreeRTOS novice, I wonder if there are OS-owned, blocking, wait_for_interrupt_X() functions which I can put into my tasks, or if I have to write my own ISRs with queues to communicate with the tasks. The tasks in question will have fairly low priorities, as the data rate is non-critical and low.

My device is an FPGA with an I2S audio source (CD drive) and a controlling MCU (AVR) connected to it. The MCU runs the user interface and state machine. For debug the MCU is connected to a PC with the UART. This works very well today. For the future I aim to replace the CD drive with a more advanced MCU (AVR32) running a USB interface in FreeRTOS. With time I want to move the state machine into a FreeRTOS task on this MCU. The UART is used for debug and for uploading new filter coefficient files from the PC, through the UART, to the FPGA.


richard_damon wrote on Saturday, January 29, 2011:

First, the FreeRTOS (as a kernel) has no I/O functions, the only interrupt it handles is the timer, and in some ports a Software interrupt for the task switch. There are some examples of I/O routines in the demos, but technically those are not part of the OS, You can probably find a simple UART implementation in the demos that you can copy to your project.

borge_strand wrote on Saturday, January 29, 2011:

OK Richards, thanks for the intro. I just wanted to know how much I could reuse before starting on wheel-reinvention!