Try   HackMD

Lecture 1: Introduction to RTOS and FreeRTOS/Zephyr Installation

Slide 1:

Introduction to RTOS and FreeRTOS/Zephyr Installation

Speaker Notes:

Welcome to the first lecture on Real-Time Operating Systems (RTOS). Today, we'll be introducing the concept of RTOS and guiding you through the installation of FreeRTOS or Zephyr on the RPi Pico 2040. We'll also discuss an assignment that will give you hands-on experience with implementing RTOS-based projects.

Slide 2: Agenda

  • Overview of RTOS
  • Differences between RTOS and GPOS
  • Need for RTOS in embedded systems
  • Common RTOS examples: FreeRTOS, Zephyr, etc.
  • Introduction to RPi Pico 2040
  • Installing FreeRTOS or Zephyr on RPi Pico 2040
  • Assignment

Speaker Notes:

Today's agenda includes the following topics:

An overview of RTOS
Differences between RTOS and General-Purpose Operating Systems (GPOS)
The need for RTOS in embedded systems
Common RTOS examples, such as FreeRTOS and Zephyr
Introduction to the RPi Pico 2040 microcontroller
Installing FreeRTOS or Zephyr on RPi Pico 2040
An assignment to help you apply your newfound knowledge

Slide 3: Overview of RTOS

  • Real-Time Operating System (RTOS)
  • Designed for real-time applications
  • Ensures time-bound and deterministic behavior
  • Manages resources efficiently
  • Focus on predictability and reliability

Speaker Notes:

A Real-Time Operating System or RTOS is a specialized operating system designed for real-time applications. Real-time applications have specific requirements that demand precise timing responses from the operating system. These requirements can range from ensuring that a sensor continuously reads data at specific intervals to managing the movement of a robotic arm with high precision.

Deterministic behavior in an RTOS means that the system's actions and responses should be predictable and follow specific time constraints. For example, imagine a monitoring system for an industrial plant that must respond to safety incidents, such as pressure levels rising too high. In such a system, the RTOS should consistently execute safety routines within a guaranteed time to maintain the safety standards associated with the plant.

Efficient resource management is another critical aspect of an RTOS. Because embedded systems often possess constraints in terms of processing power, memory, and even energy, the RTOS must optimize the use of these resources, ensuring that critical tasks receive the necessary attention they deserve.

One example of efficient resource management is having redundant sensors to measure the same physical quantity. The RTOS can prioritize data from the primary sensor but switch to the secondary sensor if the primary one fails, ensuring that the system continues to function predictably even in the presence of component failures.

Predictability and reliability are essential components for RTOS-based systems, especially when they support critical applications like medical devices or transportation systems. The predictability aspect ensures that the system works the way it is designed to without unexpected delays, while reliability ensures a stable operating environment that can handle errors and failures.

To better illustrate the concept of an RTOS, let's take the example of a self-driving car. The car's control system must process data from multiple sources like cameras, LIDAR, and GPS in real-time. The RTOS's deterministic behavior ensures that the car's actions, like acceleration, braking, or lane changes, are executed within a specific time to maintain safety. The predictability and reliability of the RTOS enable the car's control system to keep functioning uninterrupted, regardless of the challenges it may face during its operation.

Slide 4: Differences between RTOS and GPOS

  • RTOS vs GPOS
  • RTOS:
    • Predictable, deterministic behavior
    • Time-sensitive tasks
    • Minimal resource overhead
    • Efficient task management
  • GPOS:
    • General-purpose computing
    • Time-insensitive tasks
    • Rich feature set
    • Designed for user experience

Speaker Notes:

Let's compare Real-Time Operating Systems (RTOS) with General-Purpose Operating Systems (GPOS).

RTOSes are designed for:

Predictable, deterministic behavior: They ensure that tasks are completed within their deadlines.
Time-sensitive tasks: RTOSes prioritize tasks with strict timing requirements.
Minimal resource overhead: RTOSes are optimized for resource-constrained systems, like embedded devices.
Efficient task management: RTOSes can handle multiple tasks concurrently and manage resources efficiently.
On the other hand, GPOSes are designed for:

General-purpose computing: They can run a wide range of applications, from word processors to games.
Time-insensitive tasks: GPOSes do not prioritize tasks based on their timing requirements.
Rich feature set: GPOSes offer many features and services for a better user experience.
Designed for user experience: GPOSes prioritize user experience over deterministic behavior and resource optimization.

There are fundamental differences between Real-Time Operating Systems (RTOS) and General-Purpose Operating Systems (GPOS). Understanding these differences will help you appreciate the unique requirements and characteristics of each type of operating system.

Predictable, deterministic behavior (RTOS): The core function of an RTOS is to provide predictable and deterministic behavior. In critical systems, like medical devices or industrial control units, the guarantee that tasks will complete within specific time constraints is crucial for system reliability and safety. For example, a heart rate monitor must consistently and accurately measure and report a patient's heart rate under all situations.

Time-sensitive tasks (RTOS): RTOSs are designed to cater to time-sensitive tasks that need to be executed within strict time limits. A task's priority is often determined by its timing requirements. An example of time-sensitive tasks is a sensor data processing system in a drone that needs to adjust its position constantly based on incoming data to maintain its stability in real-time.

Minimal resource overhead (RTOS): RTOSs are optimized for systems with limited resources, like embedded devices. They aim to minimize the overhead in terms of memory, processing power, and energy usage. For instance, in a battery-powered environmental monitoring system, conserving energy and utilizing resources efficiently is critical to prolonging its operating time.

Efficient task management (RTOS): RTOSs must efficiently manage multiple tasks, provide cooperative or preemptive multitasking, and handle task priority according to their timing requirements. A weather monitoring station that measures temperature, humidity, and air pressure at specific intervals is an example where an RTOS schedules tasks and allocates resources efficiently, ensuring accurate data collection and analysis.

On the other hand, GPOSs have their own set of characteristics designed to meet the requirements of general-purpose computing:

General-purpose computing (GPOS): GPOSs are designed to handle a wide variety of applications, ranging from web browsing to word processing and gaming. They provide an environment that supports multiple computing tasks running simultaneously, yet do not prioritize them based on timing requirements.

Time-insensitive tasks (GPOS): In a GPOS, tasks do not generally have time-critical deadlines. For instance, while streaming a video or loading a webpage, the time taken is more flexible compared to an RTOS where tasks need to be completed within a strict time frame.

Rich feature set (GPOS): GPOSs provide a rich set of features, libraries, and services for the end user. These features may include a graphic user interface (GUI), multimedia support, networking capabilities, and other functionalities to improve overall user experience.

Designed for user experience (GPOS): Unlike RTOSs, which focus on system reliability and predictable behavior, GPOSs prioritize user experience. For example, a GPOS might prioritize smooth animations or quicker response times to user input over timely completion of background tasks.

In summary, understanding the differences between RTOS and GPOS is essential to recognize the unique requirements of each operating system type. RTOSs are designed for predictable and deterministic behavior, time-sensitive tasks, minimal resource overhead, and efficient task management. In contrast, GPOSs cater to general-purpose computing, time-insensitive tasks, and provide a rich feature set designed to enhance user experience.

Slide 5: Need for RTOS in embedded systems

  • Time-sensitive tasks
  • Resource constraints
  • Concurrent tasks
  • Deterministic behavior

Speaker Notes:

Embedded systems often have specific requirements that make the use of an RTOS necessary. Some of these requirements include:

Time-sensitive tasks: Embedded systems frequently interact with their environment and need to respond to events within a specific time frame.
Resource constraints: Embedded devices typically have limited memory, processing power, and energy resources. RTOSes are designed to optimize resource usage.
Concurrent tasks: Many embedded systems must manage multiple tasks simultaneously, which requires efficient task scheduling and resource management.
Deterministic behavior: In critical systems, predictable and deterministic behavior is essential to ensure safety and reliability.

Embedded systems often require Real-Time Operating Systems (RTOS) due to their unique requirements and system constraints. In this section, we will discuss the main reasons behind the need for RTOS in embedded systems, supported by illustrative examples.

Time-sensitive tasks: Embedded systems frequently interact with their environment, meaning they need to process and respond to events within specific time frames. A home security system is an example where an RTOS is crucial, as it must process data from sensors (e.g., motion detectors) and respond promptly (e.g., by sounding an alarm) when an intruder is detected.

Resource constraints: Embedded devices usually have limited processing power, memory, and energy resources, making resource management an essential aspect. RTOSs are designed to optimize resource usage, which is highly beneficial for devices that run on battery power or have strict power consumption requirements. A wearable fitness tracker is an example of a resource-constrained embedded system that benefits from an RTOS to extend battery life and deliver reliable functionality.

Concurrent tasks: Many embedded systems need to manage multiple tasks simultaneously, which requires efficient scheduling, management, and prioritization of tasks. In a smart thermostat, for instance, an RTOS manages temperature monitoring, user input, and control algorithms concurrently. It ensures that temperature readings are gathered at the required intervals while adjusting the heating/cooling output based on user preferences and control algorithms.

Deterministic behavior: In critical systems, it is essential to have predictable and deterministic behavior to ensure the system operates safely and reliably. Automotive control systems, like anti-lock braking systems (ABS) or electronic stability control (ESC), require RTOSs to guarantee timely response to various sensors' inputs, make rapid decisions, and maintain the desired level of system safety.

In conclusion, the use of an RTOS in embedded systems is primarily driven by the need for time-sensitive task management, resource constraints, concurrent task handling, and deterministic behavior. By employing an RTOS, developers can create embedded applications that fulfill these requirements, resulting in reliable and efficient systems that meet the specific demands of their operational environment.

Slide 6: Common RTOS examples: FreeRTOS, Zephyr, etc.

  • FreeRTOS: Popular, open-source, small footprint, wide platform support, simplicity and ease of use
  • Zephyr: Open-source, modularity, security, IoT support, variety of platforms, advanced features like Bluetooth and Wi-Fi

Speaker Notes:

There are numerous RTOSes available, each with its own features and strengths. Some common examples include:

FreeRTOS: A popular, open-source RTOS with a small footprint and wide platform support. It's known for its simplicity and ease of use.
Zephyr: Another open-source RTOS with a focus on modularity, security, and support for IoT devices. It supports a variety of platforms and offers advanced features like Bluetooth and Wi-Fi connectivity.

There are numerous Real-Time Operating Systems (RTOS) available, each with their distinctive features and strengths. A deeper understanding of RTOSs calls for studying examples of some popular and widely-used RTOSs and their unique characteristics.

FreeRTOS: FreeRTOS is a popular, open-source RTOS known for its simplicity, ease of use, and small footprint. It requires less memory and processing power compared to other RTOSs, making it an ideal choice for resource-constrained embedded systems. FreeRTOS supports a wide range of platforms, including various microcontrollers and processor architectures, making it a go-to choice for many development projects. Furthermore, its extensive documentation and vast community support make it a beginner-friendly and accessible option.

For example, consider an IoT-enabled smart irrigation system that measures soil moisture levels and sends data to a smartphone app. FreeRTOS provides an efficient, low-resource, real-time environment for the microcontroller to execute tasks like reading sensors, controlling water valves, and establishing Bluetooth or Wi-Fi communication.

Zephyr: Zephyr is another open-source RTOS with a focus on modularity, security, and support for IoT devices. It accommodates a variety of platforms, from small microcontrollers to more powerful system-on-chips (SoCs). Zephyr's modular architecture allows developers to include only the necessary components for their projects, optimizing the memory footprint and power consumption. Additionally, Zephyr offers advanced features like Bluetooth LE and Wi-Fi connectivity, which makes it a strong contender for IoT applications.

Imagine a smart door lock system that uses Zephyr as its underlying RTOS. Zephyr's built-in security features ensure secure communication between the lock, an accompanying smartphone app, and a remote server. Its IoT capabilities allow for seamless connectivity through Wi-Fi or Bluetooth, while its efficient resource management ensures the device operates reliably and with minimal power consumption.

By having a clear understanding of available RTOS options like FreeRTOS and Zephyr, developers can make informed choices for their specific embedded system projects, selecting the RTOS that best supports their requirements and priorities. Each RTOS offers unique features, strengths, and trade-offs, which significantly influence the performance and capabilities of the embedded system in question.

Slide 7: Introduction to RPi Pico 2040

  • Developed by Raspberry Pi Foundation
  • ARM Cortex-M0+ processor
  • 264KB of SRAM
  • 2MB of onboard flash memory
  • Wide range of GPIO pins
  • Suitable for embedded projects

Speaker Notes:

The Raspberry Pi Pico 2040 is a microcontroller board developed by the Raspberry Pi Foundation. It features an ARM Cortex-M0+ processor, 264KB of SRAM, and 2MB of onboard flash memory. The RPi Pico 2040 is well-suited for embedded projects and offers a wide range of GPIO pins for interfacing with various sensors, LEDs, buzzers, and communication modules.

The Raspberry Pi Pico 2040 is a microcontroller board developed by the Raspberry Pi Foundation, which is designed for embedded systems and projects. It offers a powerful yet cost-effective computing platform suitable for various applications ranging from hobbyist projects to industrial scenarios.

The RPi Pico 2040 features an ARM Cortex-M0+ processor, which is a widely-used, energy-efficient, and powerful processor suited for embedded applications. The board provides 264KB of SRAM and 2MB of onboard flash memory, which helps balance computational capabilities and resource-efficiency.

The RPi Pico 2040 offers a wide range of General Purpose Input/Output (GPIO) pins, allowing it to interface with a diverse array of sensors, actuators, LEDs, buzzers, and communication modules. This flexibility makes it an attractive choice for creating prototypes and implementing embedded applications with varying hardware requirements.

Examples of applications that can be developed using the RPi Pico 2040 include home automation, weather monitoring stations, robotic projects, smart wearables, and IoT devices. In the context of RTOS-based projects, the RPi Pico 2040 can be efficiently employed by installing an RTOS like FreeRTOS or Zephyr, which supports its hardware characteristics and grants predictable and deterministic behavior to the applications running on the microcontroller board.

Slide 8: Installing FreeRTOS or Zephyr on RPi Pico 2040

  • Set up the development environment
  • Download the RTOS source code
  • Configure and deploy a sample application

Speaker Notes:

During this lecture, we'll guide you through the installation of either FreeRTOS or Zephyr on your RPi Pico 2040. You can choose the RTOS that best suits your needs and preferences. We'll cover the necessary steps to set up the development environment, download the RTOS source code, and deploy a simple example application to your RPi Pico 2040.

During this lecture, we'll guide you through the installation of either FreeRTOS or Zephyr on your RPi Pico 2040. You can choose the RTOS that best suits your needs and preferences. We'll cover the necessary steps to set up the development environment, download the RTOS source code, and deploy a simple example application to your RPi Pico 2040.

Set up the development environment: Begin by configuring your development environment according to the specific requirements of the chosen RTOS (FreeRTOS or Zephyr). This process may involve setting up the appropriate toolchain, installing required dependencies, and configuring your workspace. Follow the RTOS's official documentation for a detailed guide on setting up.

For example, when setting up Zephyr, you'll need to install Python, CMake, and Devicetree compiler, while FreeRTOS may require different tools depending on your development platform.

Download the RTOS source code: Once your development environment is correctly set up, download the source code for the chosen RTOS. The RTOS will typically provide pre-configured demo projects for various platforms, enabling you to become acquainted with the RTOS more quickly.

Configure and deploy a sample application: Lastly, build and deploy a sample application onto your RPi Pico 2040. Sample applications, such as a simple "Blinky" program that toggles an LED, can help verify that the RTOS is installed and configured correctly. Follow the official documentation for your chosen RTOS to understand how to build, flash, and execute the sample application on your RPi Pico 2040.

By following these steps, you will successfully install and configure an RTOS (FreeRTOS or Zephyr) on your RPi Pico 2040. This setup will enable you to develop real-time applications, experiment with the RTOS features, and gain hands-on experience working with embedded systems in a real-time context.

Slide 9: Assignment

  • Develop a real hardware project using RTOS
  • Implement a system with hard time constraints
  • Use at least one sensor, one button, and a buzzer or Wi-Fi communication module
  • Prove the necessity of an RTOS
  • Create a simpler version using MicroPython or CircuitPython
  • Duration: Approximately 30 hours
  • Work individually
  • Submit a report and give a live demonstration

Speaker Notes:

In the upcoming assignment, you'll be tasked with creating a real hardware project that showcases the use of an RTOS. The goal is to demonstrate the importance of an RTOS for systems with hard time constraints by developing a project using at least one sensor, one button, and either a buzzer or Wi-Fi communication module.

Based on the acquired knowledge of RTOS and practical experience using the RPi Pico 2040, you will implement all required real-time functionalities to ensure that the system fulfills its time-critical deadlines. The RTOS's predictability and deterministic behavior will be highlighted in the essential aspects of your project.

Additionally, you will create a simpler version of the same project using either MicroPython or CircuitPython. This version will serve as a comparison to demonstrate that without an RTOS, the system cannot meet the stringent timing requirements.

The assignment will take approximately 30 hours to complete, and you'll be working individually. When you have completed the assignment, you will submit a written report outlining your findings and demonstrating the necessity of an RTOS for your project. Finally, you'll give a live demonstration of your project to showcase its functionality and how the RTOS version provides a more reliable and predictable system compared to the non-RTOS alternative.

Embarking on this assignment will not only give you valuable hands-on experience in implementing RTOS-based systems but also a deeper understanding of the unique features, strengths, and benefits of using an RTOS in real-world applications.

Lecture 2 Implementing Applications on RTOS

Slide 1: Title

Implementing Applications on RTOS

Slide 2: Agenda

  • Tasks, threads, and processes in RTOS
  • Scheduling and real-time constraints
  • Task creation, management, and synchronization
  • Inter-task communication using queues and semaphores
  • Hands-on example with RPi Pico 2040 and FreeRTOS/Zephyr

Slide 3: Tasks, threads, and processes

  • Definition and differences
  • Task states in RTOS

Speaker Notes:

Tasks: In the context of RTOS, a task is a unit of work or a sequence of program instructions that are executed by the system. Each task can be thought of as an independent program with its own lifecycle and control. Tasks are scheduled and executed by the RTOS, making use of the available system resources like CPU, memory, and peripherals. Since tasks are the smallest units of work in RTOS, they are often created to perform specific, well-defined functions. For example, a temperature control task in a thermostat that periodically reads temperature data from a sensor and makes adjustments based on the desired temperature.

Threads: A thread is a lightweight subcomponent of a process that shares resources such as memory and file handlers with other threads within the same process. Since threads share resources, they can communicate with each other more efficiently compared to separate processes. In embedded systems with an RTOS, tasks can be considered as threads, sharing some common resources. In some operating systems, tasks and threads can be used interchangeably. In a multi-threaded system, multiple threads can run concurrently, which simplifies the programming of complex systems. For example, a web server may create multiple threads to handle multiple incoming requests efficiently.

Processes: A process is an instance of a running program that contains its own address space, data, and resources. Processes are independent from each other, which means they do not share resources directly, and if one process crashes, it does not affect other processes running on the same system. In general-purpose operating systems like Linux, Windows, or macOS, applications are typically structured as processes. In embedded systems with an RTOS, processes are rarely used due to the overhead of managing separate address spaces and the limited resources available on the system.

Task States: In an RTOS, tasks can transition through different states during their lifecycle. Common task states include Ready (waiting to be executed), Running (currently executing on the CPU), and Blocked (waiting for a resource or an event). Identifying and understanding these task states is crucial for real-time systems design and performance analysis.

Example: Think of a smart home system where separate tasks control lighting, security, and heating. The lighting task may be responsible for periodically checking ambient light and adjusting brightness, while the security and heating tasks have their own specific responsibilities. Each of these tasks may operate as separate threads, sharing certain resources within the smart home system for efficient communication, control, and data exchange.

Slide 4: Scheduling in RTOS

  • Importance of real-time scheduling
  • Hard and soft real-time systems

Speaker Notes:

Importance of real-time scheduling: In a real-time operating system (RTOS), tasks have strict timing constraints known as deadlines. Meeting these deadlines is critical for the proper functioning of the systems. For example, in a flight control system, if a task responsible for managing wing flaps doesn't execute on time, it can cause serious consequences. Similarly, in a medical device such as a pacemaker, a delay in the task responsible for delivering electrical pulses could lead to life-threatening situations. Therefore, scheduling tasks efficiently to meet their deadlines is a key aspect of RTOS design.

Hard and soft real-time systems: There are two types of real-time systems based on the strictness of their task deadlines:

Hard real-time systems: In these systems, tasks have strict deadlines that must always be met. Failing to meet a deadline can result in catastrophic consequences or complete system failure. Examples include flight control systems, medical devices, and nuclear power plant control systems.

Soft real-time systems: In soft real-time systems, tasks have deadlines, but occasional deadline misses are acceptable and do not lead to critical consequences. These systems prioritize responsiveness and low-latency. Although deadline misses in soft real-time systems may reduce the system's efficiency or result in temporary delays, they usually do not result in catastrophic failures. Examples include multimedia systems, robotics, and video games.

Example: Consider a robotic assembly line at a factory, where different tasks are controlling the movement and operation of the robot arm. These tasks need to be executed in a timely manner to make sure the assembly line runs smoothly. However, if the task responsible for rotating the robot arm misses its deadline occasionally, it would only cause a temporary delay, making this system a soft real-time system. In contrast, if a medical ventilator fails to deliver oxygen on time, it can have severe consequences for a patient, making it a hard real-time system.

Slide 5: Real-time scheduling algorithms

  • Rate Monotonic Scheduling (RMS)
  • Deadline Monotonic Scheduling (DMS)
  • Earliest Deadline First (EDF)

Speaker Notes:

Rate Monotonic Scheduling (RMS): RMS is a priority-based scheduling algorithm for periodic tasks in hard real-time systems. In RMS, tasks are assigned priorities based on their periods, with shorter periods receiving higher priorities. The assumption in RMS is that a task with a shorter period has stricter time constraints and needs to be executed more often. RMS can provide a schedulability guarantee when the total utilization of the system is less than or equal to a certain threshold (approx. 69% for an infinite number of tasks).

Example: Consider an RTOS with two periodic tasks, A and B, where task A has a period of 5ms, and task B has a period of 10ms. In RMS, task A would be assigned a higher priority because it has a shorter period.

Deadline Monotonic Scheduling (DMS): DMS is an extension of RMS, taking into account task deadlines instead of task periods. In DMS, tasks are assigned priorities based on their relative deadlines, with shorter deadlines receiving higher priorities. DMS provides better schedulability than RMS, especially when task periods and deadlines are different.

Example: Consider an RTOS with two tasks, A and B, where task A has a deadline of 5ms and task B has a deadline of 10ms. In DMS, task A would be assigned a higher priority because it has a shorter deadline.

Earliest Deadline First (EDF): EDF is a dynamic scheduling algorithm for real-time systems that assigns priorities to tasks based on their absolute deadlines. In EDF, the task with the earliest deadline is always assigned the highest priority. EDF can achieve 100% utilization of the system, meaning that it can schedule tasks efficiently, even when the total CPU utilization is close to 100%. One drawback of using EDF is its complexity and overhead due to dynamic priority assignment during runtime.

Example: Consider an RTOS with two tasks, A and B, that are both released at t=0. Task A has a deadline at t=5ms, and task B has a deadline at t=10ms. In EDF, task A would initially be assigned a higher priority because it has an earlier deadline. However, if task A completes execution, and new tasks are released, the priorities of tasks may change dynamically based on their absolute deadlines at that time.

Slide 6: Task creation with FreeRTOS/Zephyr

  • Creating tasks
  • Task properties: states, priorities, delays

Slide 6: Task creation with FreeRTOS/Zephyr

Speaker Notes:

  • Creating tasks: In both FreeRTOS and Zephyr, tasks are created by defining a function that represents the task's functionality and then using an API function to create the task. The API function specifies the task's priority, stack size, and initial arguments, among other properties.

    For FreeRTOS, a task can be created using the xTaskCreate function:

    ​​BaseType_t xTaskCreate(TaskFunction_t pvTaskCode,
    ​​                        const char *const pcName,
    ​​                        uint16_t usStackDepth,
    ​​                        void *pvParameters,
    ​​                        UBaseType_t uxPriority,
    ​​                        TaskHandle_t *pvCreatedTask);
    

    For Zephyr, a task can be created using the k_thread_create function:

    ​​int k_thread_create(struct k_thread *new_thread,
    ​​                    k_thread_stack_t *stack,
    ​​                    size_t stack_size,
    ​​                    k_thread_entry_t entry,
    ​​                    void *p1,
    ​​                    void *p2,
    ​​                    void *p3,
    ​​                    int priority,
    ​​                    uint32_t options,
    ​​                    k_timeout_t delay);
    
  • Task properties: When creating tasks, several important properties are specified, including:

    1. States: Tasks can be in different states like Ready, Running, or Blocked. The task's state determines the control it has over the system's resources.

    2. Priorities: Tasks are assigned priorities that determine their order of execution. Higher priority tasks are executed before lower priority tasks. In real-time scheduling algorithms like RMS or DMS, priorities are associated with task deadlines or periods.

    3. Delays: Tasks can include delays to control their execution frequency. For example, in the case of periodic tasks, delays control the time interval between task executions.

Example: Let's create a task in FreeRTOS that is responsible for reading sensor data in an IoT device. We will define a function called ReadSensorData that implements the functionality of reading and processing the sensor data. Then, we can create a task with the following properties: a priority of 3, a stack depth of 256, and the function name as ReadSensorData. The FreeRTOS code would look like this:

void ReadSensorData(void *pvParameters) {
  // Task function implementation
}

TaskHandle_t ReadSensorDataTask;
xTaskCreate(ReadSensorData, "Read Sensor Data", 256, NULL, 3, &ReadSensorDataTask);

Slide 7: Task management

  • Task states, priorities
  • Task delays and termination

Slide 7: Task management

Speaker Notes:

  • Task states: A task in an RTOS can be in one of the following states:

    1. Ready: The task is ready to execute but is waiting for its turn to run on the CPU. Tasks with higher priorities will run before tasks with lower priorities.

    2. Running: The task is currently executing on the CPU. At any given time, only one task can be in the Running state on a single-core system.

    3. Blocked: The task cannot be executed because it is waiting for a resource, such as a semaphore or a mutex, or it is waiting for an event or a message.

    Understanding these states is crucial for managing tasks in an RTOS, as these states determine when tasks can run and access system resources.

  • Task priorities: Each task in an RTOS has an assigned priority, which is a key factor in determining the order in which tasks are executed. Higher priority tasks are executed before lower priority tasks. In real-time scheduling algorithms like RMS or DMS, priorities are associated with task deadlines or periods. Task priorities can be adjusted during runtime if needed to provide better system responsiveness and meet real-time constraints.

  • Task delays and termination: To control the execution frequency of a task, you can introduce delays. Delays can be useful for periodic tasks to specify the time intervals between their executions. In FreeRTOS, you can use the vTaskDelay() function, and in Zephyr, you can use the k_sleep() function to introduce delays.

    Terminating a task means ending its execution permanently. In some cases, you may need to terminate a task when it is no longer required or when an error occurs. In FreeRTOS, you can use the vTaskDelete() function, and in Zephyr, you can use the k_thread_abort() function.

Example: Let's say we have an embedded system with three tasks: Task A (priority 3), Task B (priority 2), and Task C (priority 1). Task A reads temperature data from a sensor every 500ms, Task B controls an LED based on the temperature data, and Task C handles user input. In this example, Task A has the highest priority and accesses the critical resource, which is the temperature sensor. Task B and Task C have lower priorities and work based on Task A's output. Task A introduces a delay of 500ms using vTaskDelay() (FreeRTOS) or k_sleep() (Zephyr) to control its execution frequency. If for any reason Task A fails to retrieve valid temperature data, it could be terminated using vTaskDelete() (FreeRTOS) or k_thread_abort() (Zephyr) as an error-handling mechanism.

Slide 8: Task synchronization

  • Mutexes and semaphores
  • Use cases for synchronization

Slide 8: Task synchronization

Speaker Notes:

  • Mutexes and semaphores: Task synchronization is essential when multiple tasks access shared resources or need to coordinate their execution based on events. Mutexes and semaphores are two key mechanisms for synchronizing tasks in an RTOS:

    1. Mutexes (short for "Mutual Exclusion"): Mutexes are used to ensure that only one task can access a shared resource at a time, avoiding race conditions and potential unpredictability in the system behavior. When a task acquires a mutex, it gains exclusive access to a shared resource, and other tasks attempting to access the same resource will be blocked until the mutex is released.

    2. Semaphores: Semaphores can be used for signaling between tasks and for controlling access to limited resources. There are two types of semaphores: binary and counting semaphores. Binary semaphores are similar to mutexes but do not have an owner, which means they can be given (released) by any task. Counting semaphores represent the availability of a limited number of resources and can take any non-negative value. A semaphore value of 0 indicates all resources are occupied, whereas a positive value indicates available resources.

  • Use cases for synchronization: Task synchronization is necessary in different scenarios, such as:

    1. Avoiding data races: To prevent data corruption when multiple tasks access a shared resource, mutexes can be used to enforce mutual exclusion. For example, tasks writing to a shared log file can use a mutex to ensure only one task writes at a time, preventing data corruption.

    2. Signaling between tasks: Semaphores can be used to signal other tasks that an event occurred or a condition is met. For instance, a task responsible for reading sensor data can use a semaphore to signal another task that processes the data whenever new data is available.

    3. Resource management: When managing a limited number of resources (e.g., a pool of communication buffers), counting semaphores can be used to track the availability of these resources and prevent overconsumption. When a task consumes a resource, it acquires a semaphore, and when it releases the resource, it gives the semaphore back.

Example: In a factory automation system, Task A controls the conveyor belt, and Task B controls a robotic arm. The conveyor belt moves items to the robotic arm, which then picks them up and places them in their corresponding locations. Task A and Task B need to synchronize their actions to avoid misplacing items. In this case, Task A can use a binary semaphore to signal Task B that an item is in position for pick-up. Task B, after receiving the signal, picks up the item and then signals Task A that it is ready for the next item using the same semaphore.

Slide 9: Queues in RTOS

  • Basics and use cases
  • Creating, sending, and receiving messages

Slide 9: Queues in RTOS

Speaker Notes:

  • Basics and use cases of queues: Queues are a data structure used for inter-task communication in an RTOS. They allow tasks to send and receive messages (e.g., data, commands, or events) in a first-in, first-out (FIFO) order. Queues are particularly useful when tasks need to exchange information, coordinate their actions, or communicate the occurrence of events asynchronously. Some common use cases of queues include:

    1. Sharing sensor data between tasks in IoT devices.
    2. Transmitting commands from a user interface task to a task controlling a motor.
    3. Communicating events, such as button presses, from an interrupt service routine to a task handling user input.
  • Creating, sending, and receiving messages with queues:

    In both FreeRTOS and Zephyr, you can create, send, and receive messages using queues through API functions. For creating a queue, you need to specify the number of elements in the queue and the size of each element.

    For FreeRTOS, you can use the following functions to work with queues:

    • xQueueCreate(): Create a new queue

      ​​​​QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength,
      ​​​​                           UBaseType_t uxItemSize);
      
    ​​- `xQueueSend()`: Send an item to the back of the queue
    
    ​​  ```c
    ​​  BaseType_t xQueueSend(QueueHandle_t xQueue,
    ​​                        const void *pvItemToQueue,
    ​​                        TickType_t xTicksToWait);
    
    • xQueueReceive(): Receive an item from the front of the queue

      ​​​​BaseType_t xQueueReceive(QueueHandle_t xQueue,
      ​​​​                         void *pvBuffer,
      ​​​​                         TickType_t xTicksToWait);
      
    
    ​​For Zephyr, you can use the following functions to work with queues:
    
    ​​- `k_queue_init()`: Initialize a new queue
    
    ​​  ```c
    ​​  void k_queue_init(struct k_queue *queue);
    
    • k_queue_append(): Send an item to the back of the queue

      ​​​​void k_queue_append(struct k_queue *queue, void *data);
      
    ​​- `k_queue_get()`: Receive an item from the front of the queue
    
    ​​  ```c
    ​​  void *k_queue_get(struct k_queue *queue, k_timeout_t timeout);
    

Example: Imagine an IoT weather station with tasks responsible for collecting temperature, humidity, and pressure data from different sensors. This system also has a task responsible for processing and aggregating this data for reporting. To facilitate the communication between data collection tasks and data processing task, you can use queues to send sensor readings from data collection tasks to the data processing task, which then receives messages from the queues to form a comprehensive weather report.

Slide 10: Semaphores in RTOS

  • Signaling and synchronization
  • Binary and counting semaphores

Slide 10: Semaphores in RTOS

Speaker Notes:

  • Signaling and synchronization: Semaphores play a crucial role in task signaling and synchronization in an RTOS. They can be used to signal the occurrence of events or conditions, as well as control access to shared resources, manage a pool of limited resources, or enforce an order in which tasks are executed. Semaphores are particularly useful in coordinating tasks with different execution rates, priorities, or deadlines.

  • Binary and counting semaphores:

    1. Binary semaphores: A binary semaphore can have only two states: taken (0) or available (1). They can be used for signaling, controlling access to shared resources, or synchronizing tasks. Binary semaphores are similar to mutexes, but unlike mutexes, they don't have an owner, which means any task can release a binary semaphore, regardless of which task acquired it. In FreeRTOS, you can use xSemaphoreCreateBinary() to create a binary semaphore, and in Zephyr, you can use the K_SEM_DEFINE() macro or k_sem_init() function.

    2. Counting semaphores: A counting semaphore can have any non-negative integer value and represent the availability of a limited number of resources. When a task acquires a counting semaphore, the semaphore value is decremented, and when a task releases the semaphore, the value is incremented. A semaphore value of 0 indicates that no resources are available. Counting semaphores are useful for managing pools of limited resources, such as buffers or memory. In FreeRTOS, use xSemaphoreCreateCounting() to create a counting semaphore, and in Zephyr, use the K_SEM_DEFINE() macro or k_sem_init() function.

Example: Let's consider a printing system with two tasks: Task A collects print jobs from multiple sources and Task B sends the collected jobs to a printer. To ensure the printer receives the jobs in the correct order and without overlapping, you can use a binary semaphore. Task A acquires the semaphore when it collects a new job and releases it once it has sent the job to Task B. Task B, after receiving the job, acquires the semaphore before sending the job to the printer and releases it once the printer starts processing the job. This example demonstrates how binary semaphores can be used to coordinate and synchronize tasks' execution.

Slide 11: Hands-on example overview

  • Implementing a basic application with multiple tasks on RPi Pico 2040 using FreeRTOS or Zephyr

Slide 11: Hands-on example overview

Speaker Notes:

  • In this hands-on example, we will implement a basic application with multiple tasks on the Raspberry Pi Pico 2040 using either FreeRTOS or Zephyr. The example application will feature the following tasks:

    1. Task A: Periodically reads data from a sensor (e.g., a temperature sensor)
    2. Task B: Processes the sensor data (e.g., calculates the average temperature)
    3. Task C: Displays the processed data on an output device (e.g., an OLED display)

    The three tasks will collaborate and communicate using synchronization and communication mechanisms like semaphores and queues that we've discussed in previous slides.

  • The example project will cover the following important aspects of RTOS application development:

    1. Creating tasks with priorities and stack sizes
    2. Synchronizing tasks using semaphores
    3. Communicating between tasks using queues
  • During this hands-on example, you will learn how to set up the development environment, write code for the tasks, and make use of the synchronization and communication mechanisms provided by the chosen RTOS (FreeRTOS or Zephyr).

Example: Think of the IoT weather station example mentioned earlier. The hands-on project will take a similar approach by creating three tasks that handle different aspects of data collection, processing, and display. Each task will be given a specific priority, and synchronization between tasks will be ensured using semaphores and queues to handle data sharing and prevent data corruption. As you follow along with this hands-on example, you will gain experience in implementing RTOS applications, managing task priorities, and coordinating tasks to ensure efficient operation of the system.

Slide 12: Example project setup

  • Required hardware and software
  • Setting up the development environment

Slide 12: Example project setup

Speaker Notes:

  • Required hardware and software: To implement the hands-on example on the Raspberry Pi Pico 2040, you will need the following hardware and software components:

    1. Raspberry Pi Pico 2040 board
    2. A sensor (e.g., a temperature sensor) compatible with the board
    3. An output device (e.g., an OLED display) compatible with the board
    4. Development software, such as a code editor (e.g., Visual Studio Code) and an appropriate SDK (based on your choice of FreeRTOS or Zephyr)
  • Setting up the development environment:

    1. Install the code editor on your computer if you haven't already.
    2. Configure the SDK for FreeRTOS or Zephyr based on your choice. This may involve installing some additional tools, such as the ARM GCC toolchain and CMake, and downloading the respective RTOS source code.
    3. Set up the Raspberry Pi Pico 2040 board and connect it to your computer.
    4. Connect the sensor and output device to the board according to their specifications and requirements.

    Make sure to consult the official documentation for FreeRTOS or Zephyr to ensure a proper setup of your development environment.

  • The purpose of the example project setup is to prepare your hardware and software environment for implementing the hands-on project. This step is crucial for a smooth development process and seamless integration between the RTOS, the Raspberry Pi Pico 2040 board, and the peripheral devices (sensor and output device). Note that you may need to install additional drivers, tools, or software packages depending on your choice of RTOS and development software.

Slide 13: Example project task creation

  • Defining and creating tasks
  • Assigning priorities

Slide 13: Example project task creation

Speaker Notes:

  • Defining and creating tasks: In the hands-on example, we will create three tasks that handle different aspects of the application. For each task, you will define a function that encapsulates its unique functionality, and then create the task using the appropriate RTOS API call (as discussed in Slide 6).

    Example:

    1. Task A: Read sensor data

      • Function: ReadSensorData(void *pvParameters)
      • Task creation API call (FreeRTOS): xTaskCreate(ReadSensorData, "Read Sensor Data", 256, NULL, 3, &TaskA);
      • Task creation API call (Zephyr): k_thread_create(&TaskA, TaskA_stack, TASKA_STACKSIZE, ReadSensorData, NULL, NULL, NULL, TASKA_PRIORITY, 0, K_NO_WAIT);
    2. Task B: Process sensor data

      • Function: ProcessSensorData(void *pvParameters)
      • Task creation API call (FreeRTOS): xTaskCreate(ProcessSensorData, "Process Sensor Data", 256, NULL, 2, &TaskB);
      • Task creation API call (Zephyr): k_thread_create(&TaskB, TaskB_stack, TASKB_STACKSIZE, ProcessSensorData, NULL, NULL, NULL, TASKB_PRIORITY, 0, K_NO_WAIT);
    3. Task C: Display processed data

      • Function: DisplayData(void *pvParameters)
      • Task creation API call (FreeRTOS): xTaskCreate(DisplayData, "Display Data", 256, NULL, 1, &TaskC);
      • Task creation API call (Zephyr): k_thread_create(&TaskC, TaskC_stack, TASKC_STACKSIZE, DisplayData, NULL, NULL, NULL, TASKC_PRIORITY, 0, K_NO_WAIT);
  • Assigning priorities: When creating tasks, it is important to assign priorities to control their execution order. In our example, Task A, which reads the sensor data, has the highest priority (3), followed by Task B, which processes the data (priority 2), and finally Task C, which displays the data (priority 1). By assigning different priorities, we ensure that the most crucial task (Task A) gets executed before less crucial tasks (Task B and Task C).

  • During task creation, remember to take into account task priorities, stack sizes, and any other parameters specific to the application requirements. Adjust these properties based on the desired system performance or any real-time constraints.

Slide 14: Task synchronization in the example project

  • Using mutexes and semaphores for synchronization

Slide 14: Task synchronization in the example project

Speaker Notes:

  • Using mutexes and semaphores for synchronization: In the hands-on example project with the Raspberry Pi Pico 2040, synchronization between tasks is crucial to ensure proper system operation and prevent issues like race conditions, data corruption, or missed event signals. We will use mutexes and semaphores discussed in previous slides (Slides 8 and 10) to synchronize the execution of tasks A, B, and C.

    Example:

    1. Mutex for accessing sensor data: Task A reads sensor data and stores it in a shared data structure, while Task B processes this data. To prevent data corruption due to simultaneous access, we can use a mutex to protect the shared data structure.

      • Mutex creation (FreeRTOS): xSemaphoreCreateMutex()
      • Mutex creation (Zephyr): k_mutex_init()
      • Task A acquires the mutex before writing to the shared data structure and releases it after updating the data.
      • Task B acquires the mutex before reading the shared data structure and releases it after processing the data.
    2. Semaphore for signaling between tasks: Task A can use a binary semaphore to signal Task B when new sensor data is available for processing.

      • Semaphore creation (FreeRTOS): xSemaphoreCreateBinary()
      • Semaphore creation (Zephyr): K_SEM_DEFINE() macro or k_sem_init()
      • Task A gives (releases) the semaphore after updating the sensor data.
      • Task B waits (acquires) for the semaphore before processing the new data.
    3. Semaphore for coordinating display updates: Task C, responsible for displaying the processed data, should wait for Task B to finish processing the data before updating the display. A binary semaphore can be used for this purpose as well.

      • Task B gives (releases) the semaphore after processing the data.
      • Task C waits (acquires) for the semaphore before updating the display with the new processed data.
  • By using mutexes and semaphores in the example project, we achieve proper synchronization and coordination between tasks A, B, and C. This ensures that the sensor data is collected, processed, and displayed in a well-ordered and controlled manner while eliminating potential issues such as race conditions or data corruption.

Slide 15: Inter-task communication in the example project

  • Implementing queues for message passing

I assume you meant Slide 15, as we've already covered Slide 14.

Slide 15: Using queues for inter-task communication

Speaker Notes:

  • Implementing a queue for inter-task communication: In the example project, queues (discussed in Slide 9) can be used to facilitate inter-task communication between Task A (sensor data collection) and Task B (data processing).

    Example:

    1. Creating a queue for passing sensor data: To pass the sensor data from Task A to Task B, we will create a queue capable of storing a specific number of items, with each item representing the sensor data.
    • Queue creation (FreeRTOS): xQueueCreate(uxQueueLength, uxItemSize)
    • Queue creation (Zephyr): k_queue_init()
    1. Task A: Sending data: Task A, upon reading the sensor data, sends the data to Task B using the queue.
    • Sending data (FreeRTOS): xQueueSend(xQueue, pvItemToQueue, xTicksToWait)
    • Sending data (Zephyr): k_queue_append(queue, data)
    1. Task B: Receiving data: Task B waits for the data to arrive in the queue and processes it once received.
    • Receiving data (FreeRTOS): xQueueReceive(xQueue, pvBuffer, xTicksToWait)
    • Receiving data (Zephyr): k_queue_get(queue, timeout)
  • By using a queue for inter-task communication, we enable the efficient transfer of sensor data from Task A to Task B in a reliable, FIFO manner. Queues help us manage the flow of data between tasks independently of their execution rates and priorities, enhancing system robustness and simplifying data handling.

Slide 16: Building and running the project

  • Compiling and uploading code to RPi Pico 2040
  • Demonstrating multi-task application

Slide 16: Example project wrap-up and key takeaways

Speaker Notes:

  • Key takeaways from the hands-on example:

    1. RTOS task creation and management: By implementing Task A, Task B, and Task C, you've gained experience in creating and managing tasks in an RTOS using FreeRTOS or Zephyr. You are now familiar with specifying task priorities, stack sizes, and entry functions to suit the specific requirements of embedded system applications.

    2. Task synchronization with semaphores and mutexes: The use of semaphores and mutexes in the example project demonstrated their essential role in ensuring proper inter-task synchronization, protecting shared resources, and coordinating the execution of tasks with different priorities or deadlines.

    3. Inter-task communication with queues: Implementing queues for inter-task communication enabled you to understand their significance in ensuring reliable, efficient data transfer between tasks in an RTOS application, further contributing to a well-orchestrated, robust system.

  • Recap: In this hands-on example, you've developed a multi-task application on the Raspberry Pi Pico 2040 board by implementing tasks responsible for reading sensor data, processing the data, and displaying the results. You've learned about various RTOS concepts, such as task creation, priorities, state management, synchronization, and inter-task communication, while applying them in the example project using FreeRTOS or Zephyr.

  • With the skills and knowledge gained through this example, you are now prepared to tackle more complex real-time application development tasks using an RTOS. Keep exploring further resources, gain deeper understanding of RTOS concepts, and practice implementing more advanced projects to become proficient in real-time embedded systems design and development.

Slide 17: Troubleshooting and debugging

  • Common issues and solutions

Slide 17: Troubleshooting and common problems

Speaker Notes:

  • As you work on RTOS-based projects, you may encounter various challenges and common problems. Being aware of these issues and knowing how to troubleshoot them will improve your problem-solving skills and help you become more efficient in your development process. Here are some common problems and troubleshooting strategies:

    1. Task starvation or priority inversion: When tasks with lower priorities continually block tasks with higher priorities, task starvation or priority inversion can occur. Starved tasks struggle to get CPU time, which can negatively impact system performance.
    • Troubleshooting: Consider implementing priority inheritance in your RTOS, which temporarily boosts the priority of a lower-priority task holding a shared resource that a higher-priority task needs. This will prevent priority inversion and ensure that higher-priority tasks receive sufficient CPU time.
    1. Race conditions and data corruption: Race conditions occur when two or more tasks access a shared resource simultaneously, leading to data corruption and unpredictable behavior.
    • Troubleshooting: Use mutexes to protect access to shared resources or implement critical sections using FreeRTOS's taskENTER_CRITICAL() and taskEXIT_CRITICAL() functions or Zephyr's k_sched_lock() and k_sched_unlock() functions to disable preemption during critical operations.
    1. Deadlocks: A deadlock occurs when tasks are circularly dependent on shared resources or are stuck waiting for each other in a way that prevents further progress.
    • Troubleshooting: Make sure that tasks follow a consistent order when acquiring shared resources or use timeout-based resource allocation to prevent indefinite waiting. Careful resource management and a proper understanding of the task dependencies will help to avoid deadlocks.
    1. Task synchronization issues: Tasks in an RTOS may not be properly synchronized if they are unable to communicate or coordinate their actions effectively, leading to undesired system behavior.
    • Troubleshooting: Make use of semaphores, mutexes, or other synchronization mechanisms like event flags or condition variables to coordinate task execution and ensure a well-orchestrated system behavior.
    1. Resource allocation issues: Insufficient resources, such as memory or CPU time, can lead to poor system performance or unresponsive tasks.
    • Troubleshooting: Monitor task execution, memory usage, CPU time, and other resources to identify over- or under-utilization. Increase the allocated resources or optimize the application to make better use of the available memory and processing power. Also, explore dynamic memory allocation techniques like heap or pool allocators to manage memory more efficiently.
  • Developing a strong troubleshooting skill set is essential for working with RTOS-based projects. Understanding the common issues and practicing effective troubleshooting techniques will significantly improve your ability to address potential problems and create robust, efficient RTOS applications.

Slide 18: Summary

  • Recap of the key concepts covered in the lecture

Slide 19: Summary and key takeaways

Speaker Notes:

Throughout this lecture, we have covered several essential concepts related to Real-Time Operating Systems (RTOS) and their application in embedded systems. Here's a comprehensive summary of the key points and takeaways:

  1. Real-Time Operating Systems (RTOS): RTOS are specialized operating systems designed for managing time-critical applications in embedded systems. They ensure deterministic execution, provide advanced scheduling algorithms, and support various synchronization and communication features.

  2. Task creation and management: In an RTOS, tasks are created by defining a function and using an API function to create the task. Task properties, like task states (Ready, Running, Blocked), priorities, and delays, are crucial for managing tasks and ensuring efficient system operation.

  3. Task synchronization: Mutexes and semaphores are primary mechanisms for synchronizing tasks in an RTOS. Mutexes protect shared resources and ensure mutual exclusion, while semaphores signal events, control access to resources, and manage limited resources. Proper synchronization prevents race conditions, data corruption, and deadlocks.

  4. Inter-task communication with queues: Queues are an important data structure in an RTOS for inter-task communication. They provide a way to reliably send and receive messages between tasks in a FIFO order, facilitating efficient data sharing and coordination among tasks with different execution rates, priorities, or deadlines.

  5. Hands-on example: Through the hands-on example application for Raspberry Pi Pico 2040, you have gained practical experience with key RTOS concepts like task creation, management, synchronization, and inter-task communication. This hands-on project has equipped you with valuable experience in implementing RTOS-based applications using FreeRTOS or Zephyr.

  6. Troubleshooting and common problems: Being familiar with common problems in RTOS-based projects, such as task starvation, priority inversion, race conditions, deadlocks, and resource allocation issues, and knowing how to troubleshoot them, is crucial for efficient development and improved problem-solving skills.

The knowledge and skills gained through this lecture will serve as a strong foundation for further exploration and experimentation with RTOS in embedded systems. As you delve deeper into real-time systems and continue expanding your skill set, you'll become proficient in designing and developing robust, efficient RTOS applications to tackle a wide range of time-critical tasks in embedded systems.