Tag: Embedded Systems

STM32 Timers – Output Compare

Keywords: Embedded systems, ARM, STM32F4, Timers, Counter Code Link: Source Code Github Keil- Bare-Metal Code Link: Source Code Github Keil- HAL Libraries In the introductory tutorial, we discussed main building blocks of STM32 Timers. The tutorial can be accessed via the following link. Introduction to […]

STM32F Timers – Simple Up/Down Counter Demo – Blinky LED

Keywords: Embedded systems, ARM, STM32F4, Timers, Counter, LED Code Link: Source Code Github Keil- Bare-Metal Code Link: Source Code Github Keil- HAL Libraries In this tutorial we will go one step further into programming STM32 timers to blink an LED each time the timer count […]

FreeRTOS Mutual Exclusion – Mutex

Keywords: Embedded systems, ARM, FreeRTOS, Semaphore, Tasks Mutual Exclusion, Mutex

Code Link: Tutorial Source Code Github – Keil

As discussed in the introductory tutorial Mutexes are almost similar to Binary Semaphore with the exception of resource ownership. In Mutex Tasks owns a resource and can’t be taken even by high priority Tasks. Whereas binary semaphores are the better choice for implementing synchronisation (between tasks or between tasks and an interrupt), mutexes are the better choice for implementing simple mutual exclusion (hence ‘MUT’ual ‘EX’clusion).

Embedded Systems are normally resource limited and non-expandable. A common example is the use of UART. There may be multiple independent software parts writing to a single UART. UART is normally used to transmit ASCII characters. If multiple parts of software parts are writing to the same UART, the output on the serial window will display all the strings mix up. As an example, the following videos shows how to freeRTOS Tasks are writing string simultaneously to serial debug window.

* Task1 Prints: “Message From Task-1: FreeRTOS Task-1 Running…
* Task2 Prints: “Message From Task-2: FreeRTOS Task-2 Running…

As can be seen while the one task has not yet finished writing to serial port, the context switch preempt the first task and runs the second task resulting into mixing of two strings.

To solve these situation where a common resource is required to be used by one process (independent of priority) at a time until completion, Mutex (Mutual-Exclusion) is best suited.

Tutorial Scenario:

In this tutorial two freeRTOS Tasks writes messages to the same serial debug port of STM32F4-Discovery. Each Task before using the debug serial port, locks the resource (debug serial port) via an earlier created Mutex and once the Task is finished writing to the debug serial port, it unlock the resource to be used by other Task.

Follow are the tutorial steps.

Steps:

1. The first step is to create a Mutex via xSemaphoreCreateMutex() to be used later by tutorial Tasks.

mutexHandle = xSemaphoreCreateMutex();

Where mutexHandle is Mutex handle declared globally and used to reference Mutex later in code.

/*
  Mutex Handle
*/
SemaphoreHandle_t mutexHandle;

xSemaphoreCreateMutex() is already explained in the introductory tutorial.

Once the mutex creation is successful, two freeRTOS tasks are created (vTask1, vTask2) and Scheduler is started else an error message is sent to the debug port.

if (mutexHandle != NULL ) {

  xTaskCreate (vTask1, "T1", 200, NULL, 1, NULL);

  xTaskCreate (vTask2, "T2", 200, NULL, 1, NULL);

  vTaskStartScheduler();
    
}else {
    
  printf ("failed to create Mutex!\n");
  while (1);
}

Note: If you don’t know how freeRTOS tasks are created, we have a dedicated tutorial for freeRTOS Tasks. Link to the tutorial is given bellow.

2. Next step is to define Task Functions i.e. vTask1 and vTask2 for the tasks created in the first step. Both are similar. only vTask1 definition is given bellow.

void vTask1(void * pvParams) {

  volatile unsigned int i = 0;

  for (;;) {
    
    xSemaphoreTake(mutexHandle, portMAX_DELAY); 
    
    printf("Message From Task-1: FreeRTOS Task-1 Running...\n");

    xSemaphoreGive( mutexHandle );    
    
    /*Dummy Delay - Lazy work */
    for (i =0; i < 200000; ++i);
  }
}

Note: As mentioned in the introductory tutorial both xSemaphoreTake() and xSemaphoreGive() APIs are used for both Semaphore and Mutexes.

xSemaphoreTake(mutexHandle, portMAX_DELAY) tries to Lock the the Mutex mutexHandle. If mutex is not available, the Task will be sent to Block State for indefinite time. Once the Mutex is available, it locks it and print message to debug serial port. and once printing completes, the mutex is released/unlocked to be used by other tasks. Once the mutex is locked, no other task can interrupt the printf operation. The dummy delay via for (i =0; i < 200000; ++i); is given to slow down the rate at which the messages are displayed on debug window.

The following videos demonstrate the message sent from freeRTOS tasks to debug serial window. As the difference can be clearly seen between the video present earlier in this tutorial and the bellow video. In the bellow video no message interfere with each other.

For complete source code refer to Github link given at the start of this tutorial.

Note: We have routed printf messages to ST-Link debugger via ARM-ITM. There is a dedicated tutorial on how to redirect printf messages to debugger. Link to the tutorial is given bellow.

Click the full screen button for more clear view.

References:

[1] – FreeRTOS Official Website

FreeRTOS Binary Semaphores – Process Synchronization

Keywords: Embedded systems, ARM, FreeRTOS, Semaphore, Tasks Synchronization, Mutex Code Link: Tutorial Source Code Github – Keil In the introductory tutorial we mentioned that Binary Semaphores are used for process Synchronization. In this tutorial we will explain what does process synchronization means and how freeRTOS Binary Semaphores can be used to […]

Introduction to Semaphores and Mutexes

Keywords: Embedded systems, ARM, FreeRTOS, Semaphore, Tasks, Mutex “A Semaphores is a Synchronization technique used to control access to common resources in a multi-threaded Environment”. “A Semaphores is a resource management technique used to manage access to shared resources in a multi-threaded environment”. Most of […]

Exchange data between a Task and an ISR via Queue

Keywords: Embedded systems, ARM, FreeRTOS, STM32F4, Tasks, Queues, ISR,

Code Link: Tutorial Source Code Github – Keil

In the previous tutorial we demonstrated how to establish inter-task communication via queue. The link to the tutorial is given bellow.

This tutorial is not much different from the previous one except in this tutorial we will demostrate how to create link between a Hardware interrupt ISR and a freeRTOS Task.

When inter Task-ISR comm is needed:

Most of the embedded systems uses interrupts to handle various on chip and off-chip events. As an example, interrupt generated by a serial buffer indicating data is ready to be received and processed. The data processing may be time consuming and if done inside ISR, it MAY starve normal application flow.

In embedded systems it is highly recommended to keep the ISR as short as possible to avoid blocking/starving of normal application flow especially in time critical systems. The problem becomes more sever if interrupts are arriving at high rate like in case of Serial communication at 115200kbps. The case bacomes even more severe if Interrupt Nesting and Interrupt Re-entrant are allowed.

In order to tackle this problem, queues and binary semaphores (discussed in separate tutorial) best fit. A Task/process responsible for data processing is sent to block state via an empty queue and when interrupt occurs, the Task is unblocked by simply sending a signal via queue and exiting ISR immediately. This achieve two thing, i.e. the ISR remains short and extensive processing is done outside ISR.

Tutorial Scenario:

In this tutorial a freeRTOS task is created that waits for the data to be available on queue. The task remains in block state until an external event (button press in this case) fills the queue. Once the ISR places data on queue, the task is automatically unblocked by freeRTOS kernel. The Task runs and print a message to the debugger serial console.

Button-Press –> ISR –> Queue –> Task

–> Inter Task-Interrupt Communication

Following are the tutorial steps.

Steps:

1. First of all let’s define what messages will be passed to queue. For the purpose of simplicity we will define a global string literal.

/*
  string literals
*/
const char *t1_Msg = "Message received From Button ISR...";

2. Next we will create freeRTOS Queue of length `2` and accepting item size of Pointer to char (char *).

/*
     freeRTOS Queue
*/
qHandle = xQueueCreate(2, sizeof(char *));

qHandle is globally defined variable of type QueueHandle_t.

/*
	freeRTOS Queue Handler
*/
QueueHandle_t qHandle;

3. If queue is created successfully (memory is allocated), a freeRTOS Tasks i.e. “RxTask” is created and Scheduler is started. Otherwise a failed message is sent to serial window and processor is trapped via while(1).

Note: If you don’t know how to create freeRTOS Tasks, refer to the following Tutorial.

if (qHandle != NULL) {
    
  xTaskCreate (vRxTask, "RxTask", 200, NULL, 2, NULL);    
  vTaskStartScheduler();
    
}else {
    
  printf ("Failed to create Queue! :-(\n");
  while (1);
    
}

4. “Inside “RxTask” Task Function”: The following is the definition of “RxTask” Task Function.

void vRxTask(void * pvParams) {

  volatile unsigned int i = 0;
  char * msgPtr;
  
  int rxStatus = 0;
  
  for (;;) {
    
    rxStatus = xQueueReceive(qHandle, &amp;msgPtr, 500);

    if (0 == rxStatus) {
      printf ("Awaiting Message...\n");
    }else {
      printf ("Rx Msg: %s\n", msgPtr);    
    }
  }
}

What happens is:

rxStatus = xQueueReceive(qHandle, &amp;msgPtr, 500); /* 500 is enough to compensate dummy delay in transmitter tasks.*/

xQueueReceive is called to check if data in qHandle Queue is available. If data is available (pointer to string in this case), the data (pointer) is copied into msgPtr pointer variable otherwise the Receiver Task “vRxTask” is sent to Block State waiting for the data to be available in next 500 Ticks. If data is not sent to queue within next 500 Ticks, the message “Awaiting Message…” is displayed and the Receiver Task (vRxTask) goes back to Block State. As soon as the data (pointer to string) becomes available on qHandle Queue, the Receiver task (Rx1) receives the pointer and displays string pointed by the received pointer and wait for the next message (pointer) reception.

5. The next step is to configure User button GPIO on STM32F4-Discovery as input and its interrupt configuration on button press. We already have a dedicated tutorial for STM32F4 interrupts and demo tutorial. Therefor the code will not be repeated here. The link to the tutorial is given bellow. Kindly go through the link bellow and relate it to the source code link given at the start of this tutorial.

6. The next step is to define an ISR for button interrupt. On STM32F4-Discovery User button is connected to PA.0 which produces interrupt on EXTI0 and subsequently calls ISR defined by void EXTI0_IRQHandler (void) functions definition.

Note: See the STM32F4 Interrupt tutorial for more detail. Link given above.

void EXTI0_IRQHandler (void) {

    int txStatus = 0;
    BaseType_t xHigherPriorityTaskWoken;
    /*
        Clear the pending interrupt
    */
    __setbit (EXTI->PR, 0);

      printf("Button Pressed, Sending message to Queue!\n");
  
    txStatus = xQueueSendToBackFromISR(qHandle, &amp;t1_Msg, &amp;xHigherPriorityTaskWoken);

    if (0 == txStatus) {
      
      printf("Sending failed Task-1!\n");
    
    } else {

      portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
	  
    }
}

What happens is:

The __setbit (EXTI->PR, 0); clears the interrupt so that next interrupt/button press can be detected.

printf("Button Pressed, Sending message to Queue!\n"); prints to the user that the button interrupt received and now ISR is about to write to Queue.

txStatus = xQueueSendToBackFromISR(qHandle, &t1_Msg, &xHigherPriorityTaskWoken); statement (API explained in the introductory tutorial) fills the queue with the pointer of string created in step-1 and send it. If queue operation is successful and it caused a higher priority Task to unblock i.e. A low priority Task was running and a Task with higher priority was waiting (blocked) for the qHandle data to be available and mean while the interrupt occurs than the xHigherPriorityTaskWoken flag will be set to indicate to the user to Yield from ISR immediately.

If queue operation is successful, an immediate return from ISR is required DIRECTLY to the high priority Task being unblocked by queue. In freeRTOS in order to switch directly to the that higher priority task being unblocked, portEND_SWITCHING_ISR and portYIELD_FROM_ISR are used and depends upon the freeRTOS Port used. In case of STM32F4 (ARM Cortex-M) the first one is used. portEND_SWITCHING_ISR will cause the kernel to directly jump to the high priority task instead of returning from ISR to the low priority task and then waiting for the context switch upon which the high priority will be selected. This minimize the delay between unblocking a Task from an ISR and subsequently achieving perfect synchronization.

Now as soon as the button is pressed, EXTI0_IRQHandler will be called. The EXTI0_IRQHandler will fill the queue with string pointer and return immediately. Once the data is available in queue, the “vRxTask” will be unblocked to receive the string pointer from queue and print the string pointer by the sent pointer thus achieving inter Task-ISR Communication.

7. Finally Compile source code, connect STM32F4-Discovery board to PC and enter debug mode. Open printf serial window via View -> Serial Windows -> Debug (printf) Viewer. Run the Program, Press the Blue User button, You will see printf messages as shown in bellow Video.

Note: We have routed printf messages to ST-Link debugger via ARM-ITM. There is a dedicated tutorial on how to redirect printf messages to debugger. Link to the tutorial is given bellow.

For complete source code refer to Github link given at the start of this tutorial.

Click the full screen button for more clear view.

References:

[1] – FreeRTOS Official Website

Inter Tasks Communication via Queues

Keywords: Embedded systems, ARM, FreeRTOS, STM32F4, Tasks, Queues Code Link: Tutorial Source Code Github – Keil In the previous tutorial we introduced Queues in general and freeRTOS queues in specific. We introduced freeRTOS APIs for Queues management. The link to the tutorial is given bellow. […]

Introduction to FreeRTOS Queues

Keywords: Embedded systems, ARM, FreeRTOS, STM32F4, Tasks, Queues “A Queue is a Data Structure that holds a finite number of fixed-size data items and follows FIFO (First in First Out) access mechanism”. Most of the low power low end embedded systems follows legacy hardware architecture […]

FreeRTOS – Task Yielding

Keywords: Embedded systems, ARM, FreeRTOS, STM32F4, Tasks, Tasks Yielding

Code Link: Tutorial Source Code Github – Keil

As we know from introductory tutorial that scheduler divides time line into small time slots based on tick timer. In each time slot only one task is selected and allowed to run. When the tick timer ticks again, another ready task is selected to run while the current task is sent to ready state.

Whats the problem with this approach?

As each task is allowed fixed time slot based on Tick timer ticking frequency, what if a task requires more time to complete than the alloted time slot? Similarly if a task completes its functionality before its time slot finishes than what should it do? For example a task dedicated to take some sensors data on regular bases – Figure-1. Lets say data acquisition requires 10% of time slot than what the task suppose to do in remaining 90% time?

In FreeRTOS a task runs indefinitely. It can’t return whether it finishes earlier or past the time slot. But FreeRTOS has a way around for tasks that completed their functionality earlier. The solution is called Task Yielding. In FreeRTOS a task can handover processor cycles (meant for it) any time it wants by calling FreeRTOS Task Yielding API. Using Task Yielding API a task can inform Scheduler to hand over processor cycles to another ready task as it has completed its functionality and can’t wait for tick timer based context switching!

Figure-1: Dummy Task that is required to run after specific Time

The FreeRTOS Task Yielding API is given bellow.

  • void taskYIELD( void )

void taskYIELD(void):

taskYIELD() is used to request a context switch to another task. Yielding occurs when a task volunteers to leave the Running state without being preempted and before its time slice has been fully used.

taskYIELD() must only be called from an executing task and therefore must not be called while the scheduler is in the Initialization state (before the scheduler is started).

When a task calls taskYIELD(), the scheduler will select another Ready state task of equal priority to enter the Running state in its place. If there are no other Ready state tasks of equal priority, then the task that called taskYIELD() will be transitioned into the Running state.

Parameter NameDescription
voidvoid
Return Valuevoid

In all our previous tutorials we put some delay in each task to ensure task consumes enough time to exceed time slot and same functionality is not executed multiple times with the same time slot. But real time Embedded Systems are quite different. They have deadlines to meet. They can’t wast time just to consume complete time slot. In real time systems, if a task completes, it must allow other tasks in queue to take consume processor cycles. The purpose of task yielding is simply to allow other tasks to execute once it completes its own functionality.

Tutorial Scenario:

In this tutorial we will create two FreeRTOS tasks. Each task when runs, it simply prints a message. After printing message it has nothing else to do, so instead of waiting for the context switch, it simply Yield to scheduler by calling FreeRTOS Scheduler API i.e. taskYIELD().

Following are the tutorial steps.

Steps:

1. The first step is to create two FreeRTOS Tasks i.e. “T1” and “T2” are created.

Note: If you don’t know how to create freeRTOS Tasks, refer to the following Tutorial.

const int task_1_Param = 1;
const int task_2_Param = 2;

xTaskCreate (vTask, "T1", 150, (void *)&amp;task_1_Param, 1, NULL);

xTaskCreate (vTask, "T2", 150, (void *)&amp;task_2_Param, 1, NULL);

2. Next Step is to create a task function which will be called by FreeRTOS Tasks when scheduled.

void vTask(void * pvParams) {

  volatile unsigned int i = 0;
  const int * tParam = (const int *)pvParams;
 
  for (;;) {
    
    /*
      Do what every Task is meant to do
    */
    printf("Task-%d Running.\n", *tParam);
    
    /*
      Now that task has completed its function,
      so let's yield so that other tasks are 
      waiting to be scheduled are allowed to 
      run.
    */
    printf("Task-%d Complete - Yielding Task.\n\n\n", *tParam);
    taskYIELD();
    
  }
}

As can be seen from above task function implementation, the task prints the a message to debug console and once it prints the message it has noting more to do. So in order to handover processor to other task it simply calls the task Yield API taskYIELD(). Calling the taskYIELD() immediately calls initiate context switch and allow other task to run before the tick timer based context switch occurs.

3. The last step is to start the scheduler to allow created tasks to run.

/*
    Start the Scheduler
*/
vTaskStartScheduler();

Note: We have routed printf messages to ST-Link debugger via ARM-ITM. There is a dedicated tutorial on how to redirect printf messages to debugger. Link to the tutorial is given bellow.

For complete source code refer to Github link given at the start of this tutorial.

Click the full screen button for more clear view.

References:

[1] – FreeRTOS Official Website

FreeRTOS – Delaying Tasks

Keywords: Embedded systems, ARM, FreeRTOS, STM32F4, Tasks Delay, Tasks Code Link: Tutorial Source Code Github (vTaskDelay)- Keil Code Link: Tutorial Source Code Github (vTaskDelayUntil)- Keil By default any FreeRTOS task should run indefinitely under normal operation. This means a task will always be scheduled to […]