{"id":9915,"date":"2024-01-03T20:40:45","date_gmt":"2024-01-03T19:40:45","guid":{"rendered":"https:\/\/playembedded.org\/?p=9915"},"modified":"2024-02-24T16:30:49","modified_gmt":"2024-02-24T15:30:49","slug":"the-complete-reference-for-multithreading-in-chibios-rt","status":"publish","type":"post","link":"https:\/\/playembedded.org\/blog\/the-complete-reference-for-multithreading-in-chibios-rt\/","title":{"rendered":"The Complete Reference for Multithreading in ChibiOS\/RT"},"content":{"rendered":"<h2 class=\"wp-block-heading level_1\" id=\"1_Introduction\">Introduction<\/h2>\n\n\n\n<p><strong>ChibiOS\/RT<\/strong>&nbsp;is the core of the ChibiOS embedded collection and it is commonly referred to as RT. It is a&nbsp;<strong>Real-Time Operating System<\/strong>&nbsp;(<strong>RTOS<\/strong>) specifically tailored for embedded applications with stringent time requirements. It simplifies the design of such applications by providing multithreading and a preemptive priority-based scheduler. This scheduler ensures that threads are executed based on their priority levels, allowing higher-priority threads to interrupt lower-priority ones when necessary. This feature makes ChibiOS\/RT suitable for real-time applications that demand precise and predictable behavior. Moreover, the RTOS offers synchronization mechanisms like mutexes and semaphores, as well as virtual timers and asynchronous events to facilitate thread coordination.<\/p>\n\n\n\n<p>This article builds on top of <a href=\"https:\/\/playembedded.org\/mastering-multithreading-with-chibios-a-beginners-guide\/\" data-type=\"post\" data-id=\"8342\">Mastering multithreading with ChibiOS: a beginner&rsquo;s guide<\/a> and delves into the details of thread scheduling in ChibiOS\/RT. It focuses on how threads switch, the impact of thread priorities on scheduling, the effects of priority inversion, and guidelines for configuring the scheduler to optimize the RTOS performance.<\/p>\n\n\n\n<h2 class=\"wp-block-heading level_1\" id=\"2_Threads_and_multithreading\">Threads and multithreading<\/h2>\n\n\n\n<h3 class=\"wp-block-heading level_2\" id=\"3_Multithreading_101\">Multithreading 101<\/h3>\n\n\n\n<p>One of the key features of an RTOS, such as ChibiOS\/RT and perhaps its most fundamental feature, is multithreading. But what exactly is a thread? We can think of a thread as a single path of execution: a sequence of instructions that the system executes in order. A thread typically starts with some initial configuration and then enters a loop, where it performs a series of periodic tasks indefinitely. This loop continues unless the application stops (e.g. the MCU is powered down) or the thread is terminated through software commands.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>A thread is a continuous stream of code execution that can potentially run endlessly.<\/p>\n<\/blockquote>\n\n\n\n<p>If we were to imagine a thread therefore, we could imagine it as straight arrow that starts at a point and extends indefinitely.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1520\" height=\"320\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2024\/01\/Single-thread-application-PE.png\" alt=\"\" class=\"wp-image-9974\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Single-thread-application-PE.png 1520w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Single-thread-application-PE-300x63.png 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Single-thread-application-PE-1024x216.png 1024w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Single-thread-application-PE-150x32.png 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Single-thread-application-PE-1200x253.png 1200w\" sizes=\"auto, (max-width: 1520px) 100vw, 1520px\"><figcaption class=\"wp-element-caption\">Conceptual Representation: A Thread as a Unidirectional Arrow<\/figcaption><\/figure>\n<\/div>\n\n\n<p>An RTOS like ChibiOS\/RT enables multiple threads to operate in a parallel fashion, even on a single-core CPU. It achieves this by allocating CPU time to each thread according to specific rules. Hence, an RTOS is often referred to as a <strong>Scheduler<\/strong>, and the set of rules it uses to determine the execution order of threads is known as the <strong>Scheduling Strategy<\/strong>.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>An RTOS allows for execution of multiple threads in a parallel fashion. <\/p>\n<\/blockquote>\n\n\n\n<p>In ChibiOS\/RT, threads have the capability to spawn additional threads, and they can also terminate. There are a variety of synchronization mechanisms available to manage these events. Returning to our arrow analogy, we might envision a multithreaded application as follows:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1520\" height=\"320\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2024\/01\/Multithread-application-PE.png\" alt=\"\" class=\"wp-image-9973\" style=\"width:922px;height:auto\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Multithread-application-PE.png 1520w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Multithread-application-PE-300x63.png 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Multithread-application-PE-1024x216.png 1024w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Multithread-application-PE-150x32.png 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Multithread-application-PE-1200x253.png 1200w\" sizes=\"auto, (max-width: 1520px) 100vw, 1520px\"><figcaption class=\"wp-element-caption\">Multi Threaded Application: Parallel Execution Paths<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Here, the application consists of three threads: the main thread creates two additional threads, and all threads appear to operate independently of each other.<\/p>\n\n\n\n<h3 class=\"wp-block-heading level_2\" id=\"4_What_is_actually_a_thread_in_ChibiOS_RT_\">What is actually a thread in ChibiOS\/RT?<\/h3>\n\n\n\n<p>In ChibiOS\/RT, a thread comprises two essential components:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Firstly, the <strong>Thread Function<\/strong>, which is a function that executes the designated tasks continuously.<\/li>\n\n\n\n<li>Secondly, the <strong>Working Area<\/strong>, also known as the <strong>Thread Stack<\/strong>, is an exclusive memory segment allocated for the thread&rsquo;s use. This segment facilitates the thread&rsquo;s autonomy and its size is determined by the thread&rsquo;s requirements and the characteristics of the target platform.<\/li>\n<\/ul>\n\n\n\n<p>Upon creation, each thread is assigned a <strong>Priority level <\/strong>and it has access to shared variables located in RAM, external to any thread stack. Additionally, it can access hardware resources, including CPU registers and I\/O peripherals.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"845\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2023\/04\/Thread-block-diagram-PE-1024x845.png\" alt=\"\" class=\"wp-image-9979\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2023\/04\/Thread-block-diagram-PE-1024x845.png 1024w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2023\/04\/Thread-block-diagram-PE-300x248.png 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2023\/04\/Thread-block-diagram-PE-150x124.png 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2023\/04\/Thread-block-diagram-PE-1536x1267.png 1536w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2023\/04\/Thread-block-diagram-PE-1200x990.png 1200w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2023\/04\/Thread-block-diagram-PE.png 1842w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\"><figcaption class=\"wp-element-caption\">The Anatomy of a ChibiOS\/RT Thread <\/figcaption><\/figure>\n<\/div>\n\n\n<p>It&rsquo;s important to distinguish between the Thread Function and the thread itself. The Thread Function merely defines the thread&rsquo;s behavior. This distinction is evident from our exploration in the article <a href=\"https:\/\/playembedded.org\/parametric-threads-with-chibios\/\" data-type=\"post\" data-id=\"8523\">Parametric Threads with ChibiOS<\/a>, where we demonstrated the ability to instantiate multiple threads from the same Thread Function, each utilizing separate working areas.<\/p>\n\n\n\n<p>ChibiOS\/RT primarily supports two types of threads:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Static Thread<\/strong>: This is a thread with a working area that is statically allocated during compile time.<\/li>\n\n\n\n<li><strong>Dynamic Thread<\/strong>: This is a thread with a working area allocated at runtime from the heap or a memory pool.<\/li>\n<\/ol>\n\n\n\n<p>While static threads are generally favored to prevent <a href=\"https:\/\/playembedded.org\/demystifying-c-pointers\/#24_Memory_and_memory_fragmentation\" target=\"_blank\" rel=\"noreferrer noopener\">memory fragmentation<\/a>, there are cases where dynamic allocation is necessary. ChibiOS\/RT includes a comprehensive API to support dynamic thread allocation.<\/p>\n\n\n\n<p>Consider the following code snippet, which illustrates how to allocate a new static working area for a thread with 128 bytes of usable space, referred to as <code>waThread1<\/code>. It also defines a Thread Function named <code>Thread1<\/code> and, in the <code>main<\/code> function, it creates and starts the thread:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">static THD_WORKING_AREA(waThread1, 128);\nstatic THD_FUNCTION(Thread1, arg) {\n\n  \/* One-time setup for Thread1. *\/\n  \/\/ Your one-time code here\n\n  while (true) {\n  \n    \/* Periodic task for Thread1. *\/\n    \/\/ Your periodic action code here\n\n    chThdSleepMilliseconds(100);\n  }\n}\n\nint main(void) {\n  \n  ...\n  chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO + 1, Thread1, NULL);\n  ...\n}<\/pre>\n\n\n\n<p>For readers already experienced with building applications using ChibiOS, this API will be familiar. It is assumed that you are reading this article to deepen your understanding of the scheduling dynamics. If you require a refresher, however, I recommend revisiting the section <a href=\"https:\/\/playembedded.org\/mastering-multithreading-with-chibios-a-beginners-guide\/#11_What_is_a_thread_\">What is a Thread?<\/a> from <a href=\"https:\/\/playembedded.org\/mastering-multithreading-with-chibios-a-beginners-guide\/\" data-type=\"post\" data-id=\"8342\">Mastering multithreading with ChibiOS: a beginner&rsquo;s guide<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading level_2\" id=\"5_Consideration_about_the_main_and_idle_thread\">Consideration about the main and idle thread<\/h3>\n\n\n\n<p>In ChibiOS\/RT, the <code>main<\/code> function is not just the entry point of the user application; it is also a thread, a special one at that. It initializes the scheduler by calling <code>chSysInit()<\/code>. When this occurs, the following actions are taken:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The scheduler is initialized.<\/li>\n\n\n\n<li><code>main<\/code> is registered as a thread with the priority <code>NORMALPRIO<\/code>.<\/li>\n\n\n\n<li>An additional thread, known as the <code>idle<\/code> thread, is created and added to the scheduling list.<\/li>\n<\/ul>\n\n\n\n<p>The <code>main<\/code> thread holds a unique status within ChibiOS\/RT as it is the initial thread, both in declaration and in execution. As the entry point, it not only kicks off the scheduler but also has the primary responsibility of spawning the first set of additional threads. From there, these newly created threads have the ability to create further threads, forming a branching hierarchy of operations, all tracing back to the <code>main<\/code> thread. This lineage emphasizes the <code>main<\/code> thread&rsquo;s pivotal role in the life cycle of the application&rsquo;s multithreading process.<\/p>\n\n\n\n<p>Another notable characteristic of the <code>main<\/code> thread is the way its Thread Stack is handled. Unlike other threads, whose stacks are explicitly declared within the C files, the <code>main<\/code> stack is implied in the project&rsquo;s makefile, as shown below:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># Stack size to be allocated to the Cortex-M process stack. This stack is\n# the stack used by the main() thread.\nifeq ($(USE_PROCESS_STACKSIZE),)\n  USE_PROCESS_STACKSIZE = 0x400\nendif<\/pre>\n\n\n\n<p>The <code>idle<\/code> thread is active by default and operates at <code>IDLEPRIO<\/code>, the lowest priority level in ChibiOS\/RT. To maintain system efficiency, no other thread should share this priority. The <code>idle<\/code> thread is executed when no other threads are running. ChibiOS provides hooks to execute code upon entering and exiting the <code>idle<\/code> thread, allowing for operations such as disabling peripherals and reconfiguring the clock for low power consumption, though this comes at the cost of increased latency.<\/p>\n\n\n\n<p>The <code>idle <\/code>thread can be disabled by modifying the configuration in <code>chconf<\/code>:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/**\n * @brief   Idle thread automatic spawn suppression.\n * @details When this option is activated the function @p chSysInit()\n *          does not spawn the idle thread. The application @p main()\n *          function becomes the idle thread and must implement an\n *          infinite loop.\n *\/\n#if !defined(CH_CFG_NO_IDLE_THREAD)\n#define CH_CFG_NO_IDLE_THREAD               FALSE\n#endif<\/pre>\n\n\n\n<p>In this scenario, the <code>main<\/code> function takes on the role of the <code>idle<\/code> thread, and its execution loop should be left empty.<\/p>\n\n\n\n<h3 class=\"wp-block-heading level_2\" id=\"6_Example_of_a_multithreading_application\">Example of a multithreading application<\/h3>\n\n\n\n<p>Here is an illustration of a simple multithreading application in ChibiOS\/RT, which comprises the <code>main<\/code> thread and an additional useful thread named <code>Thread1<\/code>, aside from the <code>idle<\/code> thread.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/*\n * Thread1 related declarations\n *\/\nstatic THD_WORKING_AREA(waThread1, 128);\nstatic THD_FUNCTION(Thread1, arg) {\n\n  \/* One-time setup for Thread1. *\/\n  \/\/ Your one-time code here\n\n  while (true) {\n  \n    \/* Periodic task for Thread1. *\/\n    \/\/ Your periodic action code here\n\n    chThdSleepMilliseconds(100);\n  }\n}\n\n\/*\n * Main thread related declarations\n *\/\nint main(void) {\n  \n  \/* Initial setup for the system. *\/\n  halInit();\n  chSysInit();\n\n  \/* Starting Thread1. *\/\n  chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO + 1, Thread1, NULL);\n\n  \/* One-time setup for main. *\/\n  \/\/ Your one-time code here\n\n  while (true) {\n  \n    \/* Periodic task for main. *\/\n    \/\/ Your periodic action code here\n\n    chThdSleepMilliseconds(150);\n  }\n}<\/pre>\n\n\n\n<p>In this example, placeholders indicate where to insert initialization and routine task code for each thread. It&rsquo;s noteworthy that <code>Thread1<\/code> and the <code>main<\/code> thread are assigned different priorities and operate at varying frequencies due to their respective sleep durations. A timing analysis of this setup will be conducted later to examine how these factors influence the scheduling.<\/p>\n\n\n\n<h2 class=\"wp-block-heading level_1\" id=\"7_How_can_multithread_happen_\">How can multithread happen?<\/h2>\n\n\n\n<h3 class=\"wp-block-heading level_2\" id=\"8_Context_switch_the_magic_behind_multithreading\">Context-switch: the magic behind multithreading<\/h3>\n\n\n\n<p>Microcontrollers often have single-core CPUs, yet they can run multiple code sequences seemingly in parallel. How is this possible? The key is the word &ldquo;seemingly&rdquo;. In reality, at any instant, only one thread actually runs. The job of the ChibiOS\/RT is to rapidly and efficiently allocate CPU time among the threads, creating the illusion of concurrent execution.<\/p>\n\n\n\n<p>The answer to our question posed at the beginning of this chapter is <strong>Context Switching<\/strong>. This involves temporarily stopping one thread and starting another. To grasp this concept, let us consider the following code<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">function void increase(int* p) {\n  int tmp = *p;\n  tmp++;\n  *p = tmp;\n}\n\nint main(void) {\n  int a = 0;\n  \n  while(1) {\n    increase(&amp;a);\n  }\n}<\/pre>\n\n\n\n<p>Focusing on the instruction within the while loop, if we translate it into assembly for an ARM Cortex-M architecture, it would look like this:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"asm\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">; Function: increase\nincrease:\n  PUSH {LR}          ; Push the return address onto the stack\n  LDR R1, [R0]       ; Load the value of 'a' from the address in R0 into R1\n  MOV R2, R1         ; Move the value of R1 (a) into R2 (tmp)\n  ADD R2, R2, #1     ; Increment the value in R2 (tmp)\n  STR R2, [R0]       ; Store the incremented value in R2 (tmp) back at the address in R0\n  POP {LR}           ; Pop the return address off the stack\n  BX LR              ; Return from the subroutine\n\n; Main function loop\nmain:\n  LDR R0, =a         ; Load the address of 'a' into R0\nloop:\n  BL increase        ; Call the increase function\n  B loop             ; Infinite loop back to itself<\/pre>\n\n\n\n<p>This example demonstrates how the CPU employs its <strong>General-Purpose registers<\/strong> for operations, specifically R0 and R1 in this case. Alongside these, <strong>Special-Purpose registers<\/strong> are critical for code execution. Among those:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Program Counter (PC)<\/strong>: Directs the flow of execution. For instance, executing the line &ldquo;<code>BL increase<\/code>&rdquo; causes the PC to jump to the first instruction of the &ldquo;<code>increase<\/code>&rdquo; function, rather than following a linear execution path.<\/li>\n\n\n\n<li><strong>Stack Pointer (SP)<\/strong>: Essential for handling local variables and function calls. When a new local variable, like <code>tmp<\/code>, is created, the SP adjusts to allocate space for it on the stack, pointing to the next available memory slot.<\/li>\n\n\n\n<li><strong>Link Register (LR)<\/strong>: Holds the return address for subroutine calls. In this code, when <code>increase<\/code> is called via <code>BL increase<\/code>, <code>LR<\/code> stores the return address. After <code>increase<\/code> completes, <code>LR<\/code> is used to return to the instruction following the call in the main function, ensuring a smooth continuation of the program flow.<\/li>\n<\/ol>\n\n\n\n<p>Like those, other Special Purpose registers are involved, directly or indirectly, in the code execution. Which brings us to the next statement<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>The values contained in the CPU (Special-Purpose and General-Purpose) registers represent the context of a thread or process that is currently being executed by the CPU.<\/p>\n<\/blockquote>\n\n\n\n<p>So, let&rsquo;s define the <strong>Current Execution Context<\/strong> (or simply <strong>Context<\/strong>) as the combined value of several CPU registers. It is important to notice that the registers which are crucial to the Context depends on the architecture in use: as example, In the ARM Cortex-M architecture, during a context switch, it is not typically necessary to manually save the contents of registers R0 to R3. This is because these registers are used as argument and return value registers and are not expected to be preserved across function calls. They are considered &ldquo;scratch&rdquo; registers or volatile registers. Additionally, if the MCU is equipped with a <strong>Floating Point Unit<\/strong> (<strong>FPU<\/strong>) &ndash; a dedicated hardware unit designed for floating-point calculations &ndash; the context saved during a switch will also include the registers of the FPU.<\/p>\n\n\n\n<p>The context switch is essentially the act of saving the current thread&rsquo;s context into memory and loading the context of the next thread. This allows the next thread to resume exactly where it left off during its last suspension, ensuring seamless task switching. <\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1840\" height=\"920\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2024\/01\/Context-Switch-PE.png\" alt=\"\" class=\"wp-image-9981\" style=\"width:922px;height:auto\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Context-Switch-PE.png 1840w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Context-Switch-PE-300x150.png 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Context-Switch-PE-1024x512.png 1024w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Context-Switch-PE-150x75.png 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Context-Switch-PE-1536x768.png 1536w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Context-Switch-PE-1200x600.png 1200w\" sizes=\"auto, (max-width: 1840px) 100vw, 1840px\"><figcaption class=\"wp-element-caption\">Context Switching: saving and restoring thread states<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Equipped with this comprehensive set of new insights, we can now update our depiction of a multi-threaded application to be more accurate and realistic.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1526\" height=\"800\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2024\/01\/Multithread-application-realityPE.png\" alt=\"\" class=\"wp-image-9983\" style=\"width:922px;height:auto\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Multithread-application-realityPE.png 1526w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Multithread-application-realityPE-300x157.png 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Multithread-application-realityPE-1024x537.png 1024w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Multithread-application-realityPE-150x79.png 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Multithread-application-realityPE-1200x629.png 1200w\" sizes=\"auto, (max-width: 1526px) 100vw, 1526px\"><figcaption class=\"wp-element-caption\">Ideal versus Real-World multithreading execution with Context Switches<\/figcaption><\/figure>\n<\/div>\n\n\n<p>But were exactly is the context saved? In ChibiOS\/RT, when we define a static working area using the <code>THD_WORKING_AREA<\/code> API, we provide two parameters: a name and a pointer to the working area, and the size in bytes for the thread&rsquo;s use, mainly for automatic variables and stack frames.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">static THD_WORKING_AREA(waThread1, 128);<\/pre>\n\n\n\n<p>However, the actual memory allocated is larger than the specified size. This is because ChibiOS\/RT&rsquo;s API automatically includes extra space for the <code>ch_thread<\/code> structure. This structure holds all the thread&rsquo;s pertinent information, including its current state but also ample space to save the thread&rsquo;s context during suspension: this explains why exactly each thread need his own working area.<\/p>\n\n\n\n<h3 class=\"wp-block-heading level_2\" id=\"9_Thread_states\">Thread states<\/h3>\n\n\n\n<p>In general, a thread can occupy one of three primary states. Although ChibiOS offers a more complex state system, for our current discussion, the following simplifications are sufficient:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Current<\/strong>: The thread is actively executing because the CPU is assigned to it.<\/li>\n\n\n\n<li><strong>Ready<\/strong>: The thread is not running but is prepared to execute, waiting in the queue for its turn.<\/li>\n\n\n\n<li><strong>Suspended<\/strong>: The thread is in a state of suspension, neither running nor prepared to run.<\/li>\n<\/ul>\n\n\n\n<p>In a single-core application, only one thread can be in the &lsquo;current&rsquo; state at any given time, actively utilizing the CPU. The user can employ APIs to transition a thread&rsquo;s state to &lsquo;Ready&rsquo; or &lsquo;Suspended&rsquo;. Additionally, the scheduler is equipped to automatically transition a thread to &lsquo;Ready&rsquo; when specific conditions are fulfilled. Common triggers for such transitions include:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The thread&rsquo;s resume function is invoked by the user application.<\/li>\n\n\n\n<li>A timer reaches its set duration.<\/li>\n\n\n\n<li>An item is added to a queue.<\/li>\n\n\n\n<li>An event flag is set.<\/li>\n\n\n\n<li>A mutex that the thread was waiting on is released.<\/li>\n<\/ul>\n\n\n\n<p>In ChibiOS\/RT, the thread state model is indeed more nuanced, encompassing a broader spectrum of states:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/**\n * @name    Thread states\n * @{\n *\/\n#define CH_STATE_READY      (tstate_t)0      \/**&lt; @brief Waiting on the ready list.       *\/\n#define CH_STATE_CURRENT    (tstate_t)1      \/**&lt; @brief Currently running.               *\/\n#define CH_STATE_WTSTART    (tstate_t)2      \/**&lt; @brief Just created.                    *\/\n#define CH_STATE_SUSPENDED  (tstate_t)3      \/**&lt; @brief Suspended state.                 *\/\n#define CH_STATE_QUEUED     (tstate_t)4      \/**&lt; @brief On a queue.                      *\/\n#define CH_STATE_WTSEM      (tstate_t)5      \/**&lt; @brief On a semaphore.                  *\/\n#define CH_STATE_WTMTX      (tstate_t)6      \/**&lt; @brief On a mutex.                      *\/\n#define CH_STATE_WTCOND     (tstate_t)7      \/**&lt; @brief On a cond.variable.              *\/\n#define CH_STATE_SLEEPING   (tstate_t)8      \/**&lt; @brief Sleeping.                        *\/\n#define CH_STATE_WTEXIT     (tstate_t)9      \/**&lt; @brief Waiting a thread.                *\/\n#define CH_STATE_WTOREVT    (tstate_t)10     \/**&lt; @brief One event.                       *\/\n#define CH_STATE_WTANDEVT   (tstate_t)11     \/**&lt; @brief Several events.                  *\/\n#define CH_STATE_SNDMSGQ    (tstate_t)12     \/**&lt; @brief Sending a message,in queue.      *\/\n#define CH_STATE_SNDMSG     (tstate_t)13     \/**&lt; @brief Sent a message, waiting answer.  *\/\n#define CH_STATE_WTMSG      (tstate_t)14     \/**&lt; @brief Waiting for a message.           *\/\n#define CH_STATE_FINAL      (tstate_t)15     \/**&lt; @brief Thread terminated.               *\/\n\/** @} *\/<\/pre>\n\n\n\n<p>The above definitions expand upon our initial overview. Here&rsquo;s how they correspond:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>CH_STATE_READY<\/code> and <code>CH_STATE_CURRENT<\/code> align with the <strong>ready<\/strong> and <strong>current <\/strong>states in our simplified model.<\/li>\n\n\n\n<li><code>CH_STATE_WTSTART<\/code> is the initial state of a new thread that is waiting to be added to the schedule, which you can achieve using <code>chThdCreateSuspended()<\/code>.<\/li>\n\n\n\n<li><code>CH_STATE_FINAL<\/code> represents a thread that has terminated.<\/li>\n<\/ul>\n\n\n\n<p>The remaining states are variations of suspension, each with different conditions for reactivation. Of particular note are:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>CH_STATE_SUSPENDED<\/code>: A general suspension state, entered by invoking <code>chThdSuspend()<\/code> on a thread.<\/li>\n\n\n\n<li><code>CH_STATE_SLEEPING<\/code>: Indicative of a thread that is temporarily inactive but scheduled to wake after a set period, typically initiated by calling one of the <code>chThdSleep()<\/code> and derived functions.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading level_2\" id=\"10_The_reason_behind_idle\">The reason behind idle<\/h3>\n\n\n\n<p>Understanding the sequence in which threads operate allows us to grasp the necessity of the <code>idle<\/code> thread. Consider a situation where all user threads are in a suspended state, each awaiting an event to proceed. In such instances, the CPU has no immediate tasks to perform, which is where the <code>idle<\/code> thread comes into play. It acts as a standby process, essentially filling the gap in CPU activity by executing a low-priority task that yields to any other thread as soon as it becomes ready.<\/p>\n\n\n\n<p>The time spent in the <code>idle<\/code> thread is indicative of the CPU&rsquo;s inactivity. By measuring the duration the CPU remains in this state within a specific time frame, we can determine the <code>idle<\/code> time percentage. This figure is a useful indicator of the application&rsquo;s CPU usage efficiency. If the <code>idle<\/code> thread is active for a large portion of time, it suggests that the CPU has a considerable amount of untapped processing capacity, which could mean the application is not demanding or that the system is highly efficient.<\/p>\n\n\n\n<h2 class=\"wp-block-heading level_1\" id=\"11_Absolving_to_Real_Time_applications\">Absolving to Real Time applications<\/h2>\n\n\n\n<h3 class=\"wp-block-heading level_2\" id=\"12_Determinism_repeatability_and_predictability\">Determinism: repeatability and predictability<\/h3>\n\n\n\n<p>ChibiOS\/RT is a Real Time Operating System and as such it needs to possess certain characteristics. Indeed an RTOS stands out due to its ability to efficiently process data and respond to inputs within a guaranteed timeframe, often referred to as a <strong>deadline<\/strong>. The crucial aspect here is the assurance of response within this timeframe, stemming from the first most important characteristic of an RTOS: <strong><strong>determinism<\/strong><\/strong>. In deterministic systems, like in mathematics, there is no randomness. Determinism leads to two outcomes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Repeatability <\/strong>which means that given the same conditions, the RTOS will consistently produce the same outcome. <\/li>\n\n\n\n<li><strong>Predictability<\/strong> which means that the behavior of the RTOS is well-known and can be precisely predicted, assuming the conditions are understood.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading level_2\" id=\"13_Low_latency_preemptiveness_and_priorities\">Low latency: preemptiveness and priorities<\/h3>\n\n\n\n<p>While determinism is what makes an OS Real Time capable, however the goodness of an RTOS falls on <strong>low latency<\/strong> or, in other words, the shortest deadline it can reliably meet. ChibiOS\/RT achieves low latency with a <strong>fully-preemptive priority scheduling<\/strong> where each thread is assigned a priority and the order of execution is influenced by it. <\/p>\n\n\n\n<p>In ChibiOS\/RT each thread is assigned a <strong>Priority<\/strong>: this determines the order in which threads are executed, with higher priority threads being attended to first. Whenever a Thread at higher priority becomes ready, the current one is immediately suspended: this process, known as <strong>Preemption<\/strong>, ensures that higher priority threads are served with low latency.<\/p>\n\n\n\n<p>It is important to notice that here is that, in ChibiOS\/RT, priorities are specific numbers:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/**\n * @name    Priority constants\n * @{\n *\/\n#define NOPRIO              (tprio_t)0      \/**&lt; @brief Ready list header priority. *\/\n#define IDLEPRIO            (tprio_t)1      \/**&lt; @brief Idle priority.              *\/\n#define LOWPRIO             (tprio_t)2      \/**&lt; @brief Lowest priority.            *\/\n#define NORMALPRIO          (tprio_t)128    \/**&lt; @brief Normal priority.            *\/\n#define HIGHPRIO            (tprio_t)255    \/**&lt; @brief Highest priority.           *\/\n\/** @} *\/<\/pre>\n\n\n\n<p>The <code>idle<\/code> thread is the only one set at <code>IDLEPRIO<\/code>. The main thread is automatically set at <code>NORMALPRIO<\/code> unless it acts as the <code>idle<\/code> thread. Thread priorities are relative, not absolute. For example, in a two-thread application with <code>main<\/code> and <code>Thread1<\/code>, <code>Thread1<\/code>&lsquo; priority being <code>NORMALPRIO + 1<\/code> or <code>NORMALPRIO + 10<\/code> will not affect the order of execution. The only thing that matters is that <code>Thread1<\/code>&lsquo; priority is higher than <code>main<\/code>&lsquo;s.<\/p>\n\n\n\n<h3 class=\"wp-block-heading level_2\" id=\"14_Interrupt_Requests_and_Critical_Zones\">Interrupt Requests and Critical Zones<\/h3>\n\n\n\n<p>We&rsquo;ve learned about threads, but what happens to them when an interrupt occurs? For instance, if a thread is put to sleep, what wakes it up?<\/p>\n\n\n\n<p>Interrupt Requests can interrupt even the highest-priority thread. Imagine Interrupt Service Routines (ISRs) running at a priority above the operating system itself. Therefore, ISRs should not have blocking functions, as this can cause delays, making our application not real-time. In fact, ISRs capture events that are frequently used to reschedule and determine which thread will run next. A common example is the IRQ generated by a timer when a thread is put to sleep for a specific amount of time.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1520\" height=\"482\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2023\/04\/Multithread-ISRPE.png\" alt=\"\" class=\"wp-image-9988\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2023\/04\/Multithread-ISRPE.png 1520w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2023\/04\/Multithread-ISRPE-300x95.png 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2023\/04\/Multithread-ISRPE-1024x325.png 1024w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2023\/04\/Multithread-ISRPE-150x48.png 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2023\/04\/Multithread-ISRPE-1200x381.png 1200w\" sizes=\"auto, (max-width: 1520px) 100vw, 1520px\"><figcaption class=\"wp-element-caption\">Multithreading with Interrupts: Scheduling and Rescheduling Process Flow<\/figcaption><\/figure>\n<\/div>\n\n\n<p>However, there are times when we don&rsquo;t want interrupts to preempt critical code sections. In ChibiOS\/RT, we can prevent this by using &ldquo;critical zones.&rdquo; We can protect code areas from IRQs and other threads using specific APIs. For example, the code below can be used in any thread to create a critical zone:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">chSysLock(void);\n\/* Your critical zone in thread context here. *\/\nchSysUnlock(void);<\/pre>\n\n\n\n<p>This code needs to be used carefully as it can introduce latency on higher priority thread or ISRs. Similarly, we can create a critical zone in ISR context with this API:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">chSysLockFromISR(void);\n\/* Your critical zone in ISR context here. *\/\nchSysUnlockFromISR(void);<\/pre>\n\n\n\n<p>So, who manages the ISRs in ChibiOS applications? ChibiOS\/RT does. The RTOS provides an API for handling ISRs. ChibiOS\/HAL uses this API to build device drivers that work efficiently with threads.<\/p>\n\n\n\n<h3 class=\"wp-block-heading level_2\" id=\"15_System_tick_and_tick_less_mode\">System tick and tick-less mode<\/h3>\n\n\n\n<p>To achieve precise deadlines, an RTOS utilizes a hardware timer for scheduling. ChibiOS\/RT follows this approach, typically assigning one of the high-resolution timers to a special peripheral exclusively for the Scheduler, known as the System Tick (ST). The assignment of this timer is configured in the <code>mcuconf.h<\/code> file:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/*\n * ST driver system settings.\n *\/\n#define STM32_ST_IRQ_PRIORITY               8\n#define STM32_ST_USE_TIMER                  2<\/pre>\n\n\n\n<p>Three additional important configurations are set in <code>chconf.h<\/code>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code><strong>CH_CFG_ST_RESOLUTION<\/strong><\/code>: Defines the precision of the hardware timer used. A high-precision timer is recommended for more accurate time measurement and better control over task scheduling and delays, improving system efficiency and responsiveness.<\/li>\n\n\n\n<li><code><strong>CH_CFG_ST_FREQUENCY<\/strong><\/code>: Determines the system tick frequency. In tick mode, this sets frequency of interrupt requests generated by the timer. This setting also defines the smallest time unit the RTOS can manage.<\/li>\n\n\n\n<li><code><strong>CH_CFG_ST_TIMEDELTA<\/strong><\/code>: Indicates whether the system operates in traditional or tick-less mode. A value of 0 means traditional mode; a value of 2 or higher means tick-less mode and sets the minimum safe number of ticks for timeout directives.<\/li>\n<\/ul>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/**\n * @brief   System time counter resolution.\n * @note    Allowed values are 16, 32 or 64 bits.\n *\/\n#if !defined(CH_CFG_ST_RESOLUTION)\n#define CH_CFG_ST_RESOLUTION                32\n#endif\n\n\/**\n * @brief   System tick frequency.\n * @details Frequency of the system timer that drives the system ticks. This\n *          setting also defines the system tick time unit.\n *\/\n#if !defined(CH_CFG_ST_FREQUENCY)\n#define CH_CFG_ST_FREQUENCY                 10000\n#endif\n\n\/**\n * @brief   Time delta constant for the tick-less mode.\n * @note    If this value is zero then the system uses the classic\n *          periodic tick. This value represents the minimum number\n *          of ticks that is safe to specify in a timeout directive.\n *          The value one is not valid, timeouts are rounded up to\n *          this value.\n *\/\n#if !defined(CH_CFG_ST_TIMEDELTA)\n#define CH_CFG_ST_TIMEDELTA                 2\n#endif<\/pre>\n\n\n\n<p>Traditional RTOS designs use a tick-based approach, where the system clock generates periodic interrupts (ticks) for task scheduling. With the above configuration (<code>CH_CFG_ST_FREQUENCY <\/code>equal to 10000), this interrupt would occur every 100&micro;s. However, ChibiOS\/RT also offers a<strong> tick-less mode<\/strong>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1526\" height=\"640\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2024\/01\/Tick-vs-Tickless-mode.png\" alt=\"\" class=\"wp-image-9989\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Tick-vs-Tickless-mode.png 1526w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Tick-vs-Tickless-mode-300x126.png 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Tick-vs-Tickless-mode-1024x429.png 1024w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Tick-vs-Tickless-mode-150x63.png 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Tick-vs-Tickless-mode-1200x503.png 1200w\" sizes=\"auto, (max-width: 1526px) 100vw, 1526px\"><figcaption class=\"wp-element-caption\">Comparison of Tick Mode and Tickless Mode in Interrupt Handling<\/figcaption><\/figure>\n<\/div>\n\n\n<p>In tick-less mode, ChibiOS\/RT forgoes the need for periodic tick interrupts for scheduling. Instead, the RTOS reconfigures the timer to generate interrupts only at task deadlines, thus avoiding superfluous IRQs. Rather than waking up at regular intervals to check for needed context switches (as in traditional mode), the system in tickless mode wakes only when necessary to perform a task. This mode is especially beneficial for low-power applications or in situations where minimizing power consumption is crucial.<\/p>\n\n\n\n<h3 class=\"wp-block-heading level_2\" id=\"16_Blocking_APIs\">Blocking APIs<\/h3>\n\n\n\n<p>ChibiOS provides various APIs that are crucial for thread management. Among these are specific APIs identified as blocking from the perspective of the calling thread. These APIs are designed to implicitly suspend the calling thread, and plan ahead to resume the thread at a subsequent moment when certain conditions are met. To aid our upcoming discussion, we will list and explain some of these APIs, focusing on their impact on the calling thread.<\/p>\n\n\n\n<h4 class=\"wp-block-heading level_3\" id=\"17_Sleep_functions\">Sleep functions<\/h4>\n\n\n\n<p>These APIs are preferred for simple applications, as they suspend a Thread for a specific time. They are essentially redefinitions of the <code>chThdSleep()<\/code>: while this function accepts an integer representing the system tick clock value these redefinitions specify delays in second, milliseconds or microseconds.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/** Delays thread for specified seconds, considering system tick clock and value limits. *\/\n#define chThdSleepSeconds(sec) chThdSleep(TIME_S2I(sec))\n\n\/** Delays thread for specified milliseconds, considering system tick clock and value limits. *\/\n#define chThdSleepMilliseconds(msec) chThdSleep(TIME_MS2I(msec))\n\n\/** Delays thread for specified microseconds, considering system tick clock and value limits. *\/\n#define chThdSleepMicroseconds(usec) chThdSleep(TIME_US2I(usec))\n<\/pre>\n\n\n\n<p>These functions set an alarm using a hardware timer and suspend the calling thread. When the alarm expires, it triggers an IRQ, and ChibiOS\/RT adds the thread back to the ready list. If it&rsquo;s the highest-priority thread, it resumes immediately. ChibiOS\/RT uses a hardware timer for accurate scheduling. The state of the calling thread is set to <code>CH_STATE_SLEEPING<\/code> when suspended.<\/p>\n\n\n\n<h4 class=\"wp-block-heading level_3\" id=\"18_ChibiOS_HAL_blocking_API\">ChibiOS\/HAL blocking API<\/h4>\n\n\n\n<p><strong>ChibiOS\/HAL<\/strong> is a crucial part of the ChibiOS project, consisting of a set of device drivers carefully crafted to offer a consistent API across various platforms. Its primary goal is to empower application developers by allowing them to design applications that are mostly independent of the specific hardware they run on. One notable feature of HAL is that is is perfectly coupled with ChibiOS\/RT offering a thread ready API.<\/p>\n\n\n\n<p>When a peripheral is enabled, HAL takes over the ISR handling from RT. HAL provides a set of APIs for each driver, known to be blocking. Examples of these APIs include:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/**\n * SPI Full Duplex Transfer\n * Performs a full duplex SPI transfer, blocking until operation is complete.\n *\/\nvoid spiExchange(SPIDriver *spip, size_t n, const void *txbuf, void *rxbuf);\n\n\/**\n * I2C Master Transmit\n * Transmits data as an I2C master, blocks until completion.\n *\/\nmsg_t i2cMasterTransmit(I2CDriver *i2cp, i2caddr_t addr, const uint8_t *txbuf, size_t txbytes, uint8_t *rxbuf, size_t rxbytes);\n\n\/**\n * ADC Conversion\n * Performs an ADC conversion, blocking until the conversion is completed.\n *\/\nmsg_t adcConvert(ADCDriver *adcp, const ADCConversionGroup *grpp, adcsample_t *samples, size_t depth);\n\n\/**\n * DAC Conversion\n * Performs a DAC conversion, blocking until the conversion is completed.\n *\/\nmsg_t dacConvert(DACDriver *dacp, const DACConversionGroup *grpp, dacsample_t *samples, size_t depth);\n\n\/**\n * USB Data Transmit\n * Transmits data over USB, blocks until the operation is complete.\n *\/\nsize_t usbTransmit(USBDriver *usbp, usbep_t ep, const uint8_t *buf, size_t n);\n\n\/**\n * USB Data Receive\n * Receives data over USB, blocks until data is received.\n *\/\nsize_t usbReceive(USBDriver *usbp, usbep_t ep, uint8_t *buf, size_t n);\n<\/pre>\n\n\n\n<p>These APIs usually utilize Direct Memory Access for transactions, depending on the low-level driver implementation. When called, the API configures the DMA for the transaction and suspends the calling thread. The DMA&rsquo;s Interrupt Service Routine (ISR) is intercepted by ChibiOS\/HAL which calls some RT API to wake up the original thread.<\/p>\n\n\n\n<h4 class=\"wp-block-heading level_3\" id=\"19_Event_API\">Event API<\/h4>\n\n\n\n<p>ChibiOS\/RT provides an event API which we&rsquo;ll delve into more in a future article. This event engine offers an API for waiting on single or multiple events using OR or AND logic.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/** Blocks until any one of the specified events occurs. *\/\neventmask_t chEvtWaitOne(eventmask_t events);\n\n\/** Blocks until one or more of the specified events occur. *\/\neventmask_t chEvtWaitAny(eventmask_t events);\n\n\/** Blocks until all of the specified events occur. *\/\neventmask_t chEvtWaitAll(eventmask_t events);\n<\/pre>\n\n\n\n<p>When a thread calls any of these APIs, it is suspended until the required combination of events is signaled from another part of the code (either thread or ISR). This causes the suspended thread to join the ready list. Depending on the API function used, the state of the calling thread is set to either <code>CH_STATE_WTOREVT<\/code> or <code>CH_STATE_WTALLEVT<\/code>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading level_3\" id=\"20_Mutex_API\">Mutex API<\/h4>\n\n\n\n<p>In our previous discussion on <a href=\"https:\/\/playembedded.org\/avoiding-race-conditions-in-chibiosrt-a-guide-to-mutex\/\" data-type=\"post\" data-id=\"9389\">Avoiding Race Conditions in ChibiOS\/RT: a guide to Mutex<\/a>, we introduced the concept of Mutex. A Mutex protects shared resources from simultaneous access by multiple threads. If a thread tries to access a resource that is already in use, it calls the <code>chMtxLock()<\/code> API and gets suspended until the Mutex is released. During this suspension, the calling thread enters the <code>CH_STATE_WTMTX<\/code> state.<\/p>\n\n\n\n<h4 class=\"wp-block-heading level_3\" id=\"21_Semaphore_API\">Semaphore API<\/h4>\n\n\n\n<p>The Counting Semaphore is another synchronization mechanism in ChibiOS, which is explained in detail in <a href=\"https:\/\/www.chibios.org\/dokuwiki\/doku.php?id=chibios:documentation:books:rt:kernel_counter_semaphores\">their documentation<\/a>. Essentially, it manages resources available in limited quantities. A thread can wait for such a resource using the semaphore with this API:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/** Waits for a semaphore counter to become greater than zero, blocks if the semaphore is not available. *\/\nvoid chSemWait(semaphore_t *sp);<\/pre>\n\n\n\n<p>When a thread calls this API, and the resource is unavailable (meaning the semaphore counter is less than or equal to zero), the thread is suspended until another part of the code (like a different thread or an ISR) signals the semaphore, thus increasing the counter. During suspension, the calling thread is in the <code>CH_STATE_WTSEM<\/code> state.<\/p>\n\n\n\n<h2 class=\"wp-block-heading level_1\" id=\"22_The_scheduling_strategy\">The scheduling strategy<\/h2>\n\n\n\n<p>The scheduling strategy of ChibiOS\/RT can be summarized with one statement<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>The thread with the highest priority that is ready to run will be executed &mdash; there are no exceptions to this rule.<\/p>\n<\/blockquote>\n\n\n\n<p>In the upcoming sections, we will explore various scheduling scenarios. This exploration will deepen our understanding of the fundamental statement above and demonstrate how to utilize the scheduling strategy in practical application development. We will examine real-case scenarios, each accompanied by pseudo-code and a time analysis to facilitate our discussion.<\/p>\n\n\n\n<h3 class=\"wp-block-heading level_2\" id=\"23_Example_1_Priority_Scheduling\">Example 1: Priority Scheduling<\/h3>\n\n\n\n<p>This first example builds on the one we used during our introduction to multithreading. To complete the example, we&rsquo;ve added two periodic actions in <code>Thread1<\/code> and <code>main<\/code>. These actions perform a simple task: they blink two different LEDs at set intervals.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/*\n * Thread1 related declarations\n *\/\nstatic THD_WORKING_AREA(waThread1, 128);\nstatic THD_FUNCTION(Thread1, arg) {\n\n  (void)arg;\n  chRegSetThreadName(\"Thread1\");\n\n  while (true) {\n    palToggleLine(LINE_LED_GREEN);\n    chThdSleepMilliseconds(100);\n  }\n}\n\n\/*\n * Main thread related declarations\n *\/\nint main(void) {\n  \n  \/* Initial setup for the system. *\/\n  halInit();\n  chSysInit();\n\n  \/* Starting Thread1. *\/\n  chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO + 1, Thread1, NULL);\n\n  while (true) {\n  \n    palToggleLine(LINE_LED_RED);\n    chThdSleepMilliseconds(150);\n  }\n}<\/pre>\n\n\n\n<p>The application uses three threads:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong><code>main<\/code><\/strong> has the priority <code>NORMALPRIO<\/code>. It&rsquo;s the initial thread that starts the system, creates <code>idle<\/code> during system initialization (<code>chSysInit<\/code>), and launches <code>Thread1<\/code>. In its loop, <code>main<\/code> toggles <code>LINE_LED_RED<\/code> and sleeps for 150ms.<\/li>\n\n\n\n<li><strong><code>Thread1<\/code><\/strong> has a higher priority (<code>NORMALPRIO + 1<\/code>). It names itself &ldquo;Thread1&rdquo; and alternates the <code>LINE_LED_GREEN<\/code> status, pausing for 100ms between each toggle.<\/li>\n\n\n\n<li><strong><code>idle<\/code><\/strong> has the lowest priority (<code>IDLEPRIO<\/code>). It runs when no other thread is active.<\/li>\n<\/ol>\n\n\n\n<h4 class=\"wp-block-heading level_3\" id=\"24_Timing_analysis\">Timing analysis<\/h4>\n\n\n\n<p>Next, we will present a timing diagram that illustrates the execution times for each thread. This diagram is straightforward to construct because ChibiOS\/RT operates deterministically. Without any randomness and with a known sequence of events, the timing of thread execution is predictable.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1880\" height=\"560\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2024\/01\/Example-1-Priority-schedulingPE.png\" alt=\"\" class=\"wp-image-10001\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-1-Priority-schedulingPE.png 1880w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-1-Priority-schedulingPE-300x89.png 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-1-Priority-schedulingPE-1024x305.png 1024w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-1-Priority-schedulingPE-150x45.png 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-1-Priority-schedulingPE-1536x458.png 1536w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-1-Priority-schedulingPE-1200x357.png 1200w\" sizes=\"auto, (max-width: 1880px) 100vw, 1880px\"><figcaption class=\"wp-element-caption\">The timing diagram of the Priority scheduling example<\/figcaption><\/figure>\n<\/div>\n\n\n<p>The timing diagram reveals that the <code>main<\/code> thread runs uninterrupted until <code>Thread1<\/code> is created (via <code>chThdCreateStatic<\/code>). Once <code>Thread1<\/code> is in the ready list, it competes with <code>main<\/code> for CPU time and, due to its higher priority, <code>Thread1<\/code> preempts <code>main<\/code>. Subsequently, the three threads&mdash;<code>main<\/code>, <code>Thread1<\/code>, and <code>idle<\/code>&mdash;execute in turn according to their respective timings and priority. Please note that the time taken to create <code>Thread1<\/code> and the duration of the <code>palToggleLine<\/code> execution have been intentionally exaggerated for illustrative purposes as will be shown in the next paragraph.<\/p>\n\n\n\n<h4 class=\"wp-block-heading level_3\" id=\"25_Note_on_palToggleLine_execution\">Note on palToggleLine execution<\/h4>\n\n\n\n<p>An important detail to note is that the instruction <code>palToggleLine<\/code> should be barely visible within the timing diagram. This instruction&rsquo;s impact is minimal because it simply reads a memory location, toggles a single bit, and writes back the result. Translated into assembly language for an ARM Cortex-M processor, the process resembles the following:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"asm\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">    LDR   R0, =LINE_LED_RED       ; Load LINE_LED_RED into R0\n    AND   R1, R0, #0xFFFFFFF0     ; Mask to get the register address\n    AND   R2, R0, #0xF            ; Mask to get the bit position\n    LDR   R3, [R1]                ; Load the value from the register address\n    MOV   R4, #1                  ; Load 1 into R4\n    LSL   R4, R4, R2              ; Shift left by bit position\n    EOR   R3, R3, R4              ; Toggle the bit in R3\n    STR   R3, [R1]                ; Store the value back to the register\n<\/pre>\n\n\n\n<p>This sequence takes approximately 10 CPU cycles, which translates to about 100 nanoseconds of execution time on a CPU running at 100 MHz. This duration is negligible compared to the shortest sleep duration in our scenario, which is 100 milliseconds. In this example, the CPU is predominantly in the IDLE state, accounting for an average CPU usage of just about 0.01%.<\/p>\n\n\n\n<h3 class=\"wp-block-heading level_2\" id=\"26_Example_2_Coercitive_Round_Robin\">Example 2: Coercitive Round Robin<\/h3>\n\n\n\n<p>In applications where threads share the same priority level, we encounter a scenario called Coercive Round Robin. In this mode, the scheduler allocates CPU time to each thread in sequence.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">static THD_WORKING_AREA(waThread1, 128);\nstatic THD_FUNCTION(Thread1, arg) {\n\n  (void)arg;\n  chRegSetThreadName(\"Thread1\");\n  while (true) {\n    \/*\n        ...\n        Operation block requires (75ms)\n        ...   \n     *\/\n  }\n}\n\nstatic THD_WORKING_AREA(waThread2, 128);\nstatic THD_FUNCTION(Thread2, arg) {\n\n  (void)arg;\n  chRegSetThreadName(\"Thread2\");\n  while (true) {\n    \/*\n        ...\n        Operation block requires (25ms)\n        ...   \n     *\/\n  }\n}\n\nstatic THD_WORKING_AREA(waThread3, 128);\nstatic THD_FUNCTION(Thread3, arg) {\n\n  (void)arg;\n  chRegSetThreadName(\"Thread3\");\n  while (true) {\n    \/*\n        ...\n        Operation block requires (50ms)\n        ...   \n     *\/\n  }\n}\n\nint main(void) {\n\n  halInit();\n  chSysInit();\n\n  chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL);\n  chThdCreateStatic(waThread2, sizeof(waThread2), NORMALPRIO, Thread2, NULL);\n  chThdCreateStatic(waThread3, sizeof(waThread3), NORMALPRIO, Thread3, NULL);\n \n  while (true) {\n    \/*\n        ...\n        Operation block requires (100ms)\n        ...   \n     *\/\n  }\n}<\/pre>\n\n\n\n<p>The application involves four threads operating at <code>NORMALPRIO<\/code>, in addition to the <code>idle<\/code> thread. Notably, each thread performs a distinct periodic task that takes a varying duration to complete. None of these tasks involve calling functions that would release the CPU.<\/p>\n\n\n\n<p>However, Coercive Round Robin is activated in <code>chconf.h<\/code> with a time quantum configured to be 50ms. Details on this configuration are provided at the conclusion of this example, allowing us to concentrate on the timing analysis for now.<\/p>\n\n\n\n<h4 class=\"wp-block-heading level_3\" id=\"27_Timing_analysis\">Timing analysis<\/h4>\n\n\n\n<p>The timing diagram will show that each thread is allotted precisely 50ms of runtime before being preempted, even if this interrupts an operation.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1880\" height=\"724\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2024\/01\/Example-2-Coercitive-Round-Robin-PE.png\" alt=\"\" class=\"wp-image-10002\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-2-Coercitive-Round-Robin-PE.png 1880w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-2-Coercitive-Round-Robin-PE-300x116.png 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-2-Coercitive-Round-Robin-PE-1024x394.png 1024w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-2-Coercitive-Round-Robin-PE-150x58.png 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-2-Coercitive-Round-Robin-PE-1536x592.png 1536w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-2-Coercitive-Round-Robin-PE-1200x462.png 1200w\" sizes=\"auto, (max-width: 1880px) 100vw, 1880px\"><figcaption class=\"wp-element-caption\">The timing diagram of the Coercitive Round Robin example<\/figcaption><\/figure>\n\n\n\n<p>In this scenario, the <code>idle<\/code> thread will never run, as all other threads are always either executing (<code>CH_STATE_CURRENT<\/code>) or ready to execute (<code>CH_STATE_READY<\/code>).<\/p>\n\n\n\n<h4 class=\"wp-block-heading level_3\" id=\"28_How_to_configure_the_time_quantum\">How to configure the time quantum<\/h4>\n\n\n\n<p>The time quantum for Coercive Round Robin is set in <code>chconf.h<\/code>, defined in system ticks with the parameter <code>CH_CFG_TIME_QUANTUM<\/code>.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/**\n * @brief   Round robin interval.\n * @details This constant is the number of system ticks allowed for the\n *          threads before preemption occurs. Setting this value to zero\n *          disables the preemption for threads with equal priority and the\n *          round robin becomes cooperative. Note that higher priority\n *          threads can still preempt, the kernel is always preemptive.\n * @note    Disabling the round robin preemption makes the kernel more compact\n *          and generally faster.\n * @note    The round robin preemption is not supported in tickless mode and\n *          must be set to zero in that case.\n *\/\n#if !defined(CH_CFG_TIME_QUANTUM)\n#define CH_CFG_TIME_QUANTUM                 500\n#endif<\/pre>\n\n\n\n<p>In this instance, we&rsquo;ve set the quantum to 500 System Ticks. As previously mentioned, the OS tick frequency is configurable, with the default set at 10kHz (<code>CH_CFG_ST_FREQUENCY<\/code> equals 10000), which equates to a tick period of 100us. Consequently, 500 ticks amount to a 50ms quantum.<\/p>\n\n\n\n<p>To conclude, it&rsquo;s crucial to understand that Coercive Round Robin is only feasible when tick mode is active. While it&rsquo;s a viable scheduling option, it is not typically favored due to potential inefficiencies in CPU utilization. Tasks may be interrupted frequently, which can lead to decreased performance in time-sensitive applications.<\/p>\n\n\n\n<h3 class=\"wp-block-heading level_2\" id=\"29_Example_3_Cooperative_Round_Robin\">Example 3: Cooperative Round Robin<\/h3>\n\n\n\n<p>This example shows a more convenient way to handle threads at same priority. It is a variation of the previous one and in this case CH_CFG_TIME_QUANTUM is set to 0 which means that the round robin preemption is disabled. However the situation in term of priorities remains the same. We still have 4 threads at same priority each one performing a blocking operation in its loop. If the thread that runs first (main in this case) is not releasing the CPU then the other threads will never have the chance to run: they would stay ready forever in the ready list without being executed once.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">static THD_WORKING_AREA(waThread1, 128);\nstatic THD_FUNCTION(Thread1, arg) {\n\n  (void)arg;\n  chRegSetThreadName(\"Thread1\");\n  while (true) {\n    \/*\n        ...\n        Operation block requires (75ms)\n        ...   \n     *\/\n    chThdYield();\n  }\n}\n\nstatic THD_WORKING_AREA(waThread2, 128);\nstatic THD_FUNCTION(Thread2, arg) {\n\n  (void)arg;\n  chRegSetThreadName(\"Thread2\");\n  while (true) {\n    \/*\n        ...\n        Operation block requires (25ms)\n        ...   \n     *\/\n    chThdYield();\n  }\n}\n\nstatic THD_WORKING_AREA(waThread3, 128);\nstatic THD_FUNCTION(Thread3, arg) {\n\n  (void)arg;\n  chRegSetThreadName(\"Thread3\");\n  while (true) {\n    \/*\n        ...\n        Operation block requires (50ms)\n        ...   \n     *\/\n    chThdYield();\n  }\n}\n\nint main(void) {\n\n  halInit();\n  chSysInit();\n\n  chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL);\n  chThdCreateStatic(waThread2, sizeof(waThread2), NORMALPRIO, Thread2, NULL);\n  chThdCreateStatic(waThread3, sizeof(waThread3), NORMALPRIO, Thread3, NULL);\n\n  while (true) {\n    \/*\n        ...\n        Operation block requires (100ms)\n        ...   \n     *\/\n    chThdYield();\n  }\n}<\/pre>\n\n\n\n<p>This type of scheduling is called Cooperative Round Robin for a reason: in this case each thread voluntarily releases the CPU after performing its operations calling the API chThdYield(). When a thread that yields, it moves from the state CH_STATE_CURRENT to the state CH_STATE_READY and it is moved at the end of the ready list. This means that the next thread in the list will be resumed and that the thread that yielded will need to wait an entire round before being executed again.<\/p>\n\n\n\n<h4 class=\"wp-block-heading level_3\" id=\"30_Timing_analysis\">Timing analysis<\/h4>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1880\" height=\"722\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2024\/01\/Example-3-Cooperative-Round-Robin-PE.png\" alt=\"\" class=\"wp-image-10003\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-3-Cooperative-Round-Robin-PE.png 1880w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-3-Cooperative-Round-Robin-PE-300x115.png 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-3-Cooperative-Round-Robin-PE-1024x393.png 1024w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-3-Cooperative-Round-Robin-PE-150x58.png 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-3-Cooperative-Round-Robin-PE-1536x590.png 1536w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-3-Cooperative-Round-Robin-PE-1200x461.png 1200w\" sizes=\"auto, (max-width: 1880px) 100vw, 1880px\"><figcaption class=\"wp-element-caption\">The timing diagram of the Cooperative Round Robin example<\/figcaption><\/figure>\n<\/div>\n\n\n<p>In this case each thread executes the entire operation block before voluntarily yielding. As we can see the threads are still running in a Round Robin but the time slice is variable and depends on the length of the operation block of each thread. <\/p>\n\n\n\n<h3 class=\"wp-block-heading level_2\" id=\"31_Example_4_Mixed_scenario\">Example 4: Mixed scenario<\/h3>\n\n\n\n<p>In this mixed scenario, we delve into an advanced application of Cooperative Round Robin. We have two threads (<code>main<\/code> and <code>Thread2<\/code>) operating under Cooperative Round Robin, and a third thread (<code>Thread1<\/code>) at a higher priority level. <code>Thread1<\/code>&lsquo;s function, derived from the article  <a href=\"https:\/\/playembedded.org\/mastering-push-buttons-chibios-pal\/\" data-type=\"post\" data-id=\"8958\">Mastering push buttons with ChibiOS PAL: Hands-on exercises<\/a>, involves waiting for the press of a button (an external event) to toggle an LED.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">static THD_WORKING_AREA(waThread1, 128);\nstatic THD_FUNCTION(Thread1, arg) {\n\n  (void)arg;\n  chRegSetThreadName(\"Thread1\");\n\n  \/* Setting the button line as digital input without pull resistors. *\/\n  palSetLineMode(LINE_EXT_BUTTON, PAL_MODE_INPUT);\n  \/* Enabling the event on the Line for a Rising edge. *\/\n  palEnableLineEvent(LINE_EXT_BUTTON, PAL_EVENT_MODE_RISING_EDGE);\n\n  while (true) {\n\n    \/* Waiting for the even to happen. *\/\n    palWaitLineTimeout(LINE_EXT_BUTTON, TIME_INFINITE);\n\n    \/* Our action. *\/\n    palRoggleLine(LINE_LED_GREEN);\n  }\n}\n\nstatic THD_WORKING_AREA(waThread2, 128);\nstatic THD_FUNCTION(Thread2, arg) {\n\n  (void)arg;\n  chRegSetThreadName(\"Thread2\");\n\n  while (true) {\n    \/*\n        ...\n        Operation block requires (75ms)\n        ...   \n     *\/\n    chThdYield();\n  }\n}\n\nint main(void) {\n\n  halInit();\n  chSysInit();\n\n  chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO + 1, Thread1, NULL);\n  chThdCreateStatic(waThread2, sizeof(waThread2), NORMALPRIO, Thread2, NULL);\n\n  while (true) {\n    \/*\n        ...\n        Operation block requires (50ms)\n        ...   \n     *\/\n    chThdYield();\n  }\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading level_3\" id=\"32_Timing_analysis\">Timing analysis<\/h4>\n\n\n\n<p>What happens in this scenario? <\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1880\" height=\"642\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2024\/01\/Example-4-Mixed-Scenario-PE.png\" alt=\"\" class=\"wp-image-10000\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-4-Mixed-Scenario-PE.png 1880w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-4-Mixed-Scenario-PE-300x102.png 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-4-Mixed-Scenario-PE-1024x350.png 1024w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-4-Mixed-Scenario-PE-150x51.png 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-4-Mixed-Scenario-PE-1536x525.png 1536w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-4-Mixed-Scenario-PE-1200x410.png 1200w\" sizes=\"auto, (max-width: 1880px) 100vw, 1880px\"><figcaption class=\"wp-element-caption\">The timing diagram of the Mixed scenario example<\/figcaption><\/figure>\n<\/div>\n\n\n<p>The <code>main<\/code> thread and <code>Thread2<\/code> alternate CPU time through Round Robin until the button is pressed. In the moment the user presses the button, Thread becomes ready and, due to its higher priority, it preempts the currently running thread to execute its task. Once <code>Thread1<\/code> is suspended waiting for the next event, the Round Robin between <code>main<\/code> and <code>Thread2<\/code> picks up where it left off.<\/p>\n\n\n\n<h4 class=\"wp-block-heading level_3\" id=\"33_Additional_consideration_on_the_priority_selection\">Additional consideration on the priority selection<\/h4>\n\n\n\n<p>It&rsquo;s crucial to understand the implications of priority levels. If <code>Thread1<\/code> had a lower priority than the others, it would not get a chance to execute since <code>main<\/code> and <code>Thread2<\/code> do not relinquish the CPU. This serves as a cautionary note on how improper priority assignments can disrupt your scheduling strategy, potentially leading to application malfunction or loss of real-time performance.<\/p>\n\n\n\n<p>As a guideline, threads that fully block should be assigned the same priority and designed to yield, permitting equal CPU time to other threads at the same level. These threads should also have the lowest priority possible so that the Round Robin happens when no other thread is ready. Threads that require prompt responses to events should be given higher priority, with a focus on optimizing their operations to prevent prolonged CPU blocking, which could delay the execution of other threads.<\/p>\n\n\n\n<h3 class=\"wp-block-heading level_2\" id=\"34_Example_5_Priority_inversion_and_priority_inheritance\">Example 5: Priority inversion and priority inheritance<\/h3>\n\n\n\n<p>This example is critical as it introduces the well-known issue of <strong>Priority Inversion<\/strong>, which occurs when two threads of different priorities access the same resource. Uncoordinated access can lead to a <strong>Race Condition<\/strong>. To mitigate this, threads must synchronize access to shared resources using a <strong>Mutex<\/strong>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading level_3\" id=\"35_A_quick_recap_about_Mutex\">A quick recap about Mutex<\/h4>\n\n\n\n<p>The concepts of race conditions and mutexes are extensively covered in <a href=\"https:\/\/playembedded.org\/avoiding-race-conditions-in-chibiosrt-a-guide-to-mutex\/\" data-type=\"post\" data-id=\"9389\">Avoiding Race Conditions in ChibiOS\/RT: a guide to Mutex<\/a>. However let us recall briefly the concepts.<\/p>\n\n\n\n<p>A mutex allows for the creation of a mutual exclusion zone within threads. Consider the following code where two threads synchronize using a mutex:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">static THD_WORKING_AREA(waThread1, 128);\nstatic THD_FUNCTION(Thread1, arg) {\n  (void) arg;\n  while (true) {\n\n    \/* Begin of the mutual exclusive zone. *\/\n    chMtxLock(&amp;my_mutex);\n    \n    \/* Mutual exclusion zone. *\/\n\n    chMtxUnlock(&amp;my_mutex);\n    \/* End of the mutual exclusive zone. *\/\n\n    chThdSleepMilliseconds(100);\n  }\n}\n\nstatic THD_WORKING_AREA(waThread2, 128);\nstatic THD_FUNCTION(Thread2, arg) {\n  (void) arg;\n  while (true) {\n\n    \/* Begin of the mutual exclusive zone. *\/\n    chMtxLock(&amp;my_mutex);\n\n    \/* Mutual exclusion zone. *\/\n\n    chMtxUnlock(&amp;my_mutex);\n    \/* End of the mutual exclusive zone. *\/\n\n    chThdSleepMilliseconds(100);\n  }\n}<\/pre>\n\n\n\n<p>In this setup, each thread has its own mutual exclusion zone. Essentially, a thread can enter its mutual exclusion zone only if the other thread is not already inside its zone. This means that the two threads cannot be in their mutual exclusion zones simultaneously.<br><br>If a thread attempts to lock the mutex with <code>chMtxLock<\/code> while it is already locked, it will be suspended in the <code>CH_STATE_WTMTX<\/code> state until the mutex is released.<\/p>\n\n\n\n<h4 class=\"wp-block-heading level_3\" id=\"36_Study_case\">Study case<\/h4>\n\n\n\n<p>In this scenario, we are intentionally using high CPU to clearly demonstrate Priority Inversion. While the issue is less obvious in real-world situations, it&rsquo;s still a significant concern.<\/p>\n\n\n\n<p>Let&rsquo;s examine the code:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">static ch_mutex_t mxt;\n\nstatic THD_WORKING_AREA(waThread1, 128);\nstatic THD_FUNCTION(Thread1, arg) {\n\n  (void)arg;\n  chRegSetThreadName(\"Thread1\");\n  while (true) {\n    \/*\n        ...\n        Operation block requires (25ms)\n        ...   \n     *\/\n    chThdSleepMilliseconds(50);\n  }\n}\n\nstatic THD_WORKING_AREA(waThread2, 128);\nstatic THD_FUNCTION(Thread2, arg) {\n\n  (void)arg;\n  chRegSetThreadName(\"Thread2\");\n  while (true) {\n    \/*\n        ...\n        Operation block requires (50ms)\n        ...   \n     *\/\n    chThdSleepMilliseconds(50);\n  }\n}\n\nstatic THD_WORKING_AREA(waThread3, 128);\nstatic THD_FUNCTION(Thread3, arg) {\n\n  (void)arg;\n  chRegSetThreadName(\"Thread3\");\n  while (true) {\n    \/* Begin of the mutual exclusive zone. *\/\n    chMtxLock(&amp;mxt);\n    \n    \/* Operation on shared resources that 75ms. *\/\n\n    chMtxUnlock(&amp;mxt);\n    \/* End of the mutual exclusive zone. *\/\n\n    chThdSleepMilliseconds(50);\n  }\n}\n\nint main(void) {\n\n  halInit();\n  chSysInit();\n  \n  chMtxObjectInit(&amp;mxt);\n\n  chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO - 1, Thread1, NULL);\n  chThdCreateStatic(waThread2, sizeof(waThread2), NORMALPRIO - 2, Thread2, NULL);\n  chThdCreateStatic(waThread3, sizeof(waThread3), NORMALPRIO - 3, Thread3, NULL);\n\n  chThdSleepMilliseconds(125);\n\n  while (true) {\n\n    \/* Begin of the mutual exclusive zone. *\/\n    chMtxLock(&amp;mxt);\n    \n    \/* Operation on shared resources that 25ms. *\/\n\n    chMtxUnlock(&amp;mxt);\n    \/* End of the mutual exclusive zone. *\/\n\n    chThdSleepMilliseconds(200);\n  }\n}<\/pre>\n\n\n\n<p>We have four threads plus <code>idle<\/code>, each at a different priority. Excluding <code>idle<\/code>, the <code>main<\/code> and <code>Thread3<\/code> are at opposite ends of the scale and share a resource protected by a mutex. In this example, all operation blocks are CPU-intensive to highlight the issue.<br><br>The sleep following the thread creation is intentional. It ensures that Thread3 starts and locks the mutex before the main thread can. Let&rsquo;s examine the consequences of this setup.<\/p>\n\n\n\n<h4 class=\"wp-block-heading level_3\" id=\"37_Priority_Inversion\">Priority Inversion<\/h4>\n\n\n\n<p>If <code>main<\/code> attempts to lock the Mutex while <code>Thread3<\/code> has it locked, it must wait until <code>Thread3<\/code> releases the resource. In this scenario, <code>main<\/code> is not only blocked by <code>Thread3<\/code>, but <code>Thread3<\/code> itself is repeatedly preempted by <code>Thread1<\/code> and <code>Thread2<\/code>, which have higher priorities. Let&rsquo;s illustrate this with the timing diagram.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1882\" height=\"722\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2024\/01\/Example-5a-Priotity-Inversion-PE.png\" alt=\"\" class=\"wp-image-10013\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-5a-Priotity-Inversion-PE.png 1882w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-5a-Priotity-Inversion-PE-300x115.png 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-5a-Priotity-Inversion-PE-1024x393.png 1024w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-5a-Priotity-Inversion-PE-150x58.png 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-5a-Priotity-Inversion-PE-1536x589.png 1536w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-5a-Priotity-Inversion-PE-1200x460.png 1200w\" sizes=\"auto, (max-width: 1882px) 100vw, 1882px\"><figcaption class=\"wp-element-caption\">The timing diagram of the Priority Inversion example<\/figcaption><\/figure>\n<\/div>\n\n\n<p>This dynamic creates a situation known as <strong>Priority Inversion<\/strong>. Essentially, <code>main<\/code> is forced to operate at an effectively lower priority than <code>Thread3<\/code> until the shared resource is released. .<\/p>\n\n\n\n<h4 class=\"wp-block-heading level_3\" id=\"38_Priority_Inheritance\">Priority Inheritance<\/h4>\n\n\n\n<p>The timing diagram described above is hypothetical. ChibiOS\/RT addresses the Priority Inversion by implementing what is known as <strong>Priority Inheritance<\/strong>. When <code>main<\/code> attempts to acquire the mutex and finds the mutex held by <code>Thread3<\/code>, <code>Thread3<\/code> temporarily inherits the higher priority of <code>main<\/code>. Consequently, <code>Thread3<\/code> is not preempted by <code>Thread1<\/code> and <code>Thread2<\/code>. Once <code>Thread3<\/code> releases the mutex with <code>spiReleaseBus<\/code>, the original priorities are restored, and <code>main<\/code> resumes execution. The following timing diagram illustrates this mechanism.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1880\" height=\"722\" src=\"https:\/\/playembedded.org\/wp-content\/uploads\/2024\/01\/Example-5b-Priotity-Inheritance-PE.png\" alt=\"\" class=\"wp-image-10012\" srcset=\"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-5b-Priotity-Inheritance-PE.png 1880w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-5b-Priotity-Inheritance-PE-300x115.png 300w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-5b-Priotity-Inheritance-PE-1024x393.png 1024w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-5b-Priotity-Inheritance-PE-150x58.png 150w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-5b-Priotity-Inheritance-PE-1536x590.png 1536w, https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/Example-5b-Priotity-Inheritance-PE-1200x461.png 1200w\" sizes=\"auto, (max-width: 1880px) 100vw, 1880px\"><figcaption class=\"wp-element-caption\">The timing diagram of the Priority Inheritance example<\/figcaption><\/figure>\n<\/div>\n\n\n<p>It&rsquo;s important to note that in ChibiOS\/RT, mutexes implement the priority inheritance mechanism, whereas semaphores do not. Additionally, it&rsquo;s important to emphasize that real applications should minimize blocking operations. Often, time-consuming operations like IO transactions are supported by DMA. This allows the thread initiating the operation to quickly relinquish the CPU, enabling other threads to run. This example deliberately exaggerates to demonstrate how Priority Inheritance benefits the higher-priority <code>main<\/code> thread by reducing its wait time for the mutex.<\/p>\n\n\n\n<h2 class=\"wp-block-heading level_1\" id=\"39_Conclusions\">Conclusions<\/h2>\n\n\n\n<p>Throughout this article, we have seen how the selection of priorities and the use of specific function calls can greatly influence thread scheduling. This understanding is crucial in the realm of Real Time systems. It brings us to a vital conclusion: <\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>An RTOS like ChibiOS\/RT is not a silver bullet. Its adoption doesn&rsquo;t automatically ensure that your system is real-time. <\/p>\n<\/blockquote>\n\n\n\n<p>An RTOS it is better thought of as a tool. In this analogy, even the finest screwdriver won&rsquo;t do much good if used for driving nails instead of screws.<\/p>\n\n","protected":false},"excerpt":{"rendered":"<p>This article provides a comprehensive guide on multithreading in ChibiOS\/RT, covering aspects like thread scheduling, priority inversion, and configuration guidelines for optimizing RTOS performance. <\/p>\n","protected":false},"author":3,"featured_media":10005,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1221],"tags":[1304,1299],"coauthors":[241],"class_list":["post-9915","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-further-readings","tag-chibios-rt","tag-rtos","pumpkin"],"views":6554,"jetpack_featured_media_url":"https:\/\/playembedded.org\/blog\/wp-content\/uploads\/2024\/01\/The-Complete-Reference-for-Multithreading.jpg","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/posts\/9915","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/comments?post=9915"}],"version-history":[{"count":0,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/posts\/9915\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/media\/10005"}],"wp:attachment":[{"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/media?parent=9915"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/categories?post=9915"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/tags?post=9915"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/playembedded.org\/blog\/wp-json\/wp\/v2\/coauthors?post=9915"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}