Hello,
Starting today, I will be going through the examples provided by FreeRTOS one by one.
First, let’s take a look at the example structure.
In this example, let’s assume we have created two tasks: vTask1 and vTask2, both with a priority of 1.
The tasks will operate as follows:
They will enter an infinite loop, and within that loop, they will introduce a certain delay. During this delay, they will send the message ‘Task 1 is running’ via UART.
Task 2 behaves similarly. Let’s implement how it works in practice.
The code I designed is as follows:
static void vTask_1(void *pvParameters)
{
uint32_t i;
for ( ;; )
{
AscPrintf("Task1 is running!\n\r");
for(i=0u;i<10000000u;i++)
{
/*No Code*/
}
}
}
static void vTask_2(void *pvParameters)
{
uint32_t i;
for ( ;; )
{
AscPrintf("Task2 is running!\n\r");
for(i=0u;i<10000000u;i++)
{
/*No Code*/
}
}
}
int core0_main(void)
{
IfxCpu_enableInterrupts();
/* !!WATCHDOG0 AND SAFETY WATCHDOG ARE DISABLED HERE!!
* Enable the watchdogs and service them periodically if it is required
*/
IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());
/* Wait for CPU sync event */
IfxCpu_emitEvent(&g_cpuSyncEvent);
IfxCpu_waitEvent(&g_cpuSyncEvent, 1);
/*Init UART*/
Driver_AscShell_Init();
/* Create Task */
xTaskCreate(vTask_1, "vTask_1", configMINIMAL_STACK_SIZE, NULL, 2u, NULL);
xTaskCreate(vTask_2, "vTask_2", configMINIMAL_STACK_SIZE, NULL, 2u, NULL);
/* Start the tasks running. */
vTaskStartScheduler();
while(1)
{
}
return (1);
}
Let’s take a look at how it runs. You can see it running as follows:
Then, the execution would have happened as follows:
First, Task1 runs, and at time t2, Task2 starts running. Then, at time t3, Task1 resumes execution.
This is called Round Robin, a scheduling method where tasks do not have priority, and CPU resources are allocated in a sequential time-based manner.
However, I suddenly became curious: what is the interval between t2 and t1? This interval is defined by the TICK_RATE_HZ
frequency.
#define configTICK_RATE_HZ ( ( TickType_t ) 1000UL )
In our case, it’s 1ms.
To depict the situation more precisely, every 1ms, an interrupt is generated by a timer, and in the ISR, a context switch occurs from Task1 to Task2, and vice versa.
Let’s continue a bit further.
This example focuses on using parameters while creating tasks in an RTOS.
As shown above, a pointer is assigned the address of a string, and this pointer is passed as a parameter when creating the task. The task then receives and uses this parameter.
Let’s run the example to see it in action.
I see you’ve written the code as follows:
static void vTask_1(void *pvParameters)
{
uint32_t i;
char *pcTaskName;
pcTaskName = (char *)pvParameters;
for ( ;; )
{
AscPrintf(pcTaskName);
for(i=0u;i<10000000u;i++)
{
/*No Code*/
}
}
}
static void vTask_2(void *pvParameters)
{
uint32_t i;
char *pcTaskName;
pcTaskName = (char *)pvParameters;
for ( ;; )
{
AscPrintf(pcTaskName);
for(i=0u;i<10000000u;i++)
{
/*No Code*/
}
}
}
int core0_main(void)
{
IfxCpu_enableInterrupts();
/* !!WATCHDOG0 AND SAFETY WATCHDOG ARE DISABLED HERE!!
* Enable the watchdogs and service them periodically if it is required
*/
IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());
/* Wait for CPU sync event */
IfxCpu_emitEvent(&g_cpuSyncEvent);
IfxCpu_waitEvent(&g_cpuSyncEvent, 1);
/*Init UART*/
Driver_AscShell_Init();
/* Create Task */
xTaskCreate(vTask_1, "vTask_1", configMINIMAL_STACK_SIZE, (void*)pcTextForTask1, 2u, NULL);
xTaskCreate(vTask_2, "vTask_2", configMINIMAL_STACK_SIZE, (void*)pcTextForTask2, 2u, NULL);
/* Start the tasks running. */
vTaskStartScheduler();
while(1)
{
}
return (1);
}
It looks like the results are as expected.
In the end, FreeRTOS is about porting the software and effectively using the functionalities defined within that software. So, in the next example, we will delve deeper into the specific operational characteristics of an RTOS.