Best aproach to share/switch a single UART between two or more Tasks.
Hi there, right now I’m working with an application on FreeRTOS that allows me to collect data via UART from several sensors (two), and I also I have a SIM module that allows me to communicate via UART (note: each sensor is a task, and the communication with the SIM module, also is another Task).
So, I’m facing the problem that I’m just using a single UART to achieve all of these tasks.
But in some cases, I can’t use the UART when I need it at a specific moment because it has been acquired for another task.
Then, what could be the best approach to sharing or switching a single UART beyond more a timeout or a semaphore?
If it’s possible to share with me a diagram of what could be the best solution, I’d appreciate it a lot.
First, I am assuming this is something like an RS-488 shared bus, as otherwise using one UART to multiple devices is tricky. I will also assume everything you are talking to is based on a command-response system, and you are the “bus master”.
My normal solution to that sort of system is just a Mutex controlling access, and a task takes the Mutex when it wants to talk to its device, and when it gets the Mutex is sends its message and waits for the answer, and when it is done, and sure the device is finished, gives the Mutex back for the next task.
This works as long as you don’t get so much contention that you starve some task from getting access, then you may need a central task that “schedules” the access.
If some devices might send a message other than in response, then you need to have a single task receiving the messages, to handle those, and your other tasks work thorough it to communicate.
Many years ago, I had to do a power sequencer / monitor / diagnostic module for a custom circuit board that had multiple static FPGAs and an ARM SoC, several banks of different types of memory, and some other unusual things. The hardware designer had connected a single I2C bus to the microcontroller (a SmartFusion2 FPGA with Cortex-M core) along with a number of GPIOs, however all of the thermal sensors and I/O expanders that controlled things like the MOSFETs, A2D (for measuring the current and power level on various power rails), the status outputs from the various large FPGAs, and a number of signals into and out of the OMap SoC. Because there were too many I/O expanders to address individually on using i2c addresses alone, there were 3 bus switches controlled by GPIOs controlled from the microcontroller core.
I ended up creating a control task for the i2c bus that accepted requests from other tasks, performed the I/O, then used an event to notify the requesting task that their I/O was done. There was a priority queue for requests, so the client tasks didn’t have to wait for their request to be complete before continuing on to other things, and they could test the event to see if the request was done. It was up to the client task not to access the received data buffer until the particular request was complete.
Only 1 task controlled the i2c bus and the switches, so it was able to make sure a transaction was complete and notify the requesting task before moving on to the next request.
If you’re using a RS-485 or other shared serial device bus topology, I recommend the same approach. FreeRTOS provides a lot of the tools needed to create such an infrastructure, but it does not provide any sort of I/O sharing mechanism like that out of the box.