I have a product that has various commonly used tasks for example sequencing a bunch of power supplies on in order, or signalling and waiting for an external processor to indicate something. These tasks are re-used in different procedures.
I would like to know the recommended solution to use tasks one after the other procedurally.
In my opinion, a series of tasks that run in sequence, i.e. the first runs to completion, then the second starts, and runs to completion, then a third, should all be just one task.
If you mean the first runs to a certain point, but does continue, but the second starts, then having the second task block on a semaphore, or (preferably) a direct-to-task notification, as it starts, and then the first task signals that when it is time for the second task to run works well.
I thought about running each procedure in a single task but I want to reuse code where possible. for example the powering on sequence task is a little complex and I want to be at the beginning of most procedures.
One procedure is turning on a series of target devices, then programming them, then turning them off. The next procedure might be turning all the target devices on and checking some calibration data and turning them off. If I could, in this basic example, have turning target devices on in a task and turning them off in another task, I could just start those tasks when I need to in each procedure. Only one procedure can be run at one time.
Don’t underestimate the required synchronization between those tasklets and/or the main sequence.
If the procedures can be just (reusable) functions and can be called (sequentially) by a higher level state machine(s), the implementation will be probably much simpler.
/* simplified power on example */
void powerOn()
{
/* thread safe turning on of targets */
for(int i=0; i<15; i++)
{
/* do complex thread safe stuff here */
/* allow FreeRTOS scheduler to process other tasks */
vTaskDelay(1);
}
}
/* simplified power off example */
void powerOff()
{
/* thread safe turning on of targets */
for(int i=0; i<15; i++)
{
/* do complex thread safe stuff here */
/* allow FreeRTOS scheduler to process other tasks */
vTaskDelay(1);
}
}
/* Program target devices */
void vTask1()
{
powerOn();
/* Program targets code goes here */
powerOff();
}
/* Check calibration data */
void vTask2()
{
powerOn();
/* Check calibration data code goes here */
powerOff();
}
Are you suggesting not using an RTOS? The thought crossed my mind. I’m using it primarily because I have implemented a TCPIP stack (FreeRTOS+TCP) to control test equipment and save data to an SQL database.
No - using e.g. FreeRTOS+TCP bundle might be a good decision.
But not everything needs to implemented as task just because it’s possible
BTW ‘manually’ scheduling (other) tasks using vTaskDelay is usually be not the best idea.
If a task shouldn’t interfere with other, higher-prio tasks just give it a lower prio and enable preemption in your FreeRTOSConfig.h.