There are lots of ways to implement a thread safe printf for DuinOS (or free RTOS). The following is a version that renames printf as mprintf. Like an fprintf function, mprintf has a leading parameter which must be passed with the rest of the printf variables. This implementation exposes the methodology used to make printf thread safe. A future version will incorporate the methodology and hide the implementation details from the user.
There are 3 steps to make mprintf available for use:
- Enable MUTEX semaphores in our DuinOS (or freeRTOS)
- Create an mprintf variadic macro.
- Initialize the MUTEX to be used in your program when calling mprintf
Enabling MUTEX capabilities in your DuinOS.
Mutexs come disabled in the DuinOS. You must find the freeRTOSConfig.h file in your installation. Usually located at
~/arduino-0017/hardware/cores/arduino.DuinOS
directory. Open this file in your favorite text editor and add the following line (if not already there):
#define configUSE_MUTEXES 1
A good place to add this line is after the
#define INCLUDE_vTaskDelay 1
line. Your sketches and programs will no compile with MUTEXES enabled.
Building the variadic macro.
First, be sure to add the following #includes to the top of your sketch/program:
#include <cserial.h>
#include “DuinOS/FreeRTOS.h”
#include “DuinOS/semphr.h”
#include “DuinOS/queue.h”
I’m not going to go into how variadic macros work. It’s safe to say that they do work and they allow us to define a macro that looks like a function which can have a varying number of parameter. This is required because printf support varying numbers of parameters. Place the following code at the beginning of your sketch/program but after your includes:
#define mprintf(xM,…) while (xSemaphoreTake(xM,1000)==pdTRUE) {}\
printf(__VA_ARGS__);\
xSemaphoreGive(xM);\
The back slashes are required and no, they are not comments. They are used to extend the #define as if it were a single line.
Initialize the MUTEX.
The mutex to be used must be global as we will be using mprintf in any of our sketch or program functions. Some where after the #includes at the top of of our sketch/program, place the following line:
xSemaphoreHandle pMutex;
We can use any Mutex name you like. Here I use pMutex.
Next add the following lines at the beginning of your setup() function:
pMutex = xSemaphoreCreateMutex();
if( pMutex != NULL ) {
// The semaphore was created successfully.
printf(“could create pMutex semaphore\n”);
// The semaphore can now be used.
}
Note, I use printf here rather then mprintf. Why? because pMutex, which we will use as the first parameter in mprintf, must be used within one of the tasks in DuinOS. As we have not launched any tasks yet, the scheduler has not started so no mutex checks will be made (bad thing), however, no threads have started so no one else will be calling printf (good thing).
You now can add an mprintf call to one of your tasks or routines called by your tasks (note: you MUST use mprintf from within a task environment or you will get unpredictable results. Add a line that looks like this to one of your t asks:
mprintf(pMutex,”%s\n”,”Hello World”);
If all goes well (you have implemented unthread safe printf and thread safe mprintf) the message will be sent out the hardware serial port.
Good luck and have fun!
Paula