Hi,
I am new to RTOS and am trying to do the following.
There are two boards connected via SPI. Board A generates a black and white image and stores it in as a one-dimensional array. Once the image is ready it is sent via SPI to board B which prints it through a compact printer.
Board B continually prints the same image until a new one is received from board A via the SPI. We never know when a new image arrives. It could be every few seconds for the first hour and every minute later in the day.
My part of the software is the board B.
The main part is that the printing cannot be stopped while the new image is being received by the SPI.
So I am thinking of doing the following:
have a global shared two-dimensional array so two images can be stored (a kind of double buffer). One of the two array indexes is used for printing and the other is used for storing the data received
I create two threads in board B. One continually monitors the SPI, receives data and stores it into one of the two array indexes (say 0) and at the same time the other thread is continually printing from the other index/half of the array
to make it fast instead of copying the data I swap the indexes pointed to every time a new image is fully received. So for example image at array index 0 is printing while array index 1 is being filled with the new image data from the SPI. Once the image is fully received then all I do is swap the indexes so next image being printed comes from the other index of the array.
Questions:
is that a good way to implement it? If not, can you please provide some suggestions and guidelines please?
I am thinking about the global two-dimensional array might not be able to get accessed by one thread if the other is using it? Is that so?
It’s a common and reasonable pattern to implement an application like yours.
There is no access problem of global data by multiple tasks.
Of course concurrent access (read/modify/write) to shared data by multiple tasks might require mutex-protection to avoid data corruption.
That’s nothing special. This also applies to multithreaded applications on other OS.
According to your own design description the printing backend determines the overall timing of your application. So instead of swapping the buffers on reception of an image only the printing task knows when it’s safe to do so.
So I’d propose to let the tasks waiting for a notification (or a binary semaphore) from the other task to synchronize their respective work.
This means the printing task waits for the notification from the receiving task when a new image is fully received. After signaling image ready the receiving task in turn waits for the notification from the printing task to start the receiption of a new image.
After the printing tasks got notified/signaled it switches the buffers, signals back get new image to the receiving task and starts printing the current image. After print completion it loops back waiting for the next image ready and so on.
Initially the printing task sets up the initial buffer, signals the (1st) notification to the receiving task to start the image receiption and finally enters its task loop as described above. The receiving task straight enters its task loop waiting the notification from the printing task…
A couple of case to think about in this design:
Will the printing task get mess up if the buffer it is printing changes in the middle of the print, or do you need to delay the switch until the buffer is done printing?
If you are going to wait, what should you do if a second new image comes before you do swap the buffers?
any reason for using a binary semaphore instead of a mutex?
how would you signal the image is ready? With the semaphore itself? Or a global variable?
Richard,
yes, the switching needs to occur only after the current image finished printing.
About your second point, I am thinking of preventing a second image arriving before the buffer swap by signalling the other micro to not send any via a dedicated pin/line. Any thoughts/feedback about that solution or perhaps a better one?
What I see as a simple solution here is that needs syncronization primitives between the tasks is:
When Receiving task gets a image, set the hold off flag and sets a flag word that the printer task checks. Then waits for the next message to come in over the SPI bus.
Printer task, after each printout checks the flag, and if set swaps the buffers and turns off the hold off flag and then starts printing that image.
You could even use the flag to hold off the sender as the flag to the printer if that works for the hardware.
Sorry, I wasn’t clear enough. In case you’re using binary semaphores then 2 different semaphores are needed. So 1 dedicated semaphore per task it’s waiting for to get signaled by the other one. Normally you can’t signal and immediately wait for the same semaphore (ignoring having different task priorities here).
Alternatively you could use light weight task notifications. They’re specific to FreeRTOS. Please see the FreeRTOS docs for the details.
Although it’s possible to use mutexes for this purpose I wouldn’t do that since their primary purpose is to protect data structures or hardware from concurrent access. Here we’re dealing just with notifications.
Considering the overall system design Richard is right that a busy flag or something else signaled to the other board would help a lot. I’d set it in the receiving task right after receiption of an image and before waiting for it’s notification (semaphore) from the printing task. It’’s then cleared after getting notified from the printing task after arming the SPI interface with the new buffer.