{"id":19877,"date":"2024-01-05T19:01:33","date_gmt":"2024-01-05T19:01:33","guid":{"rendered":"https:\/\/wolles-elektronikkiste.de\/?p=19877"},"modified":"2024-01-06T10:33:29","modified_gmt":"2024-01-06T10:33:29","slug":"using-freertos-with-esp32-and-arduino","status":"publish","type":"post","link":"https:\/\/wolles-elektronikkiste.de\/en\/using-freertos-with-esp32-and-arduino","title":{"rendered":"Using FreeRTOS with ESP32 and Arduino"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">About this post<\/h2>\n\n<p>With this article, I try to offer users with less experience a reasonably understandable introduction to FreeRTOS. I know from my own experience that the topic takes some getting used to, but it is just as exciting.<\/p>\r\n\n<ul>\r\n<li><a href=\"#freertos_doku\">FreeRTOS Documentation <\/a><\/li>\r\n<li><a href=\"#tasks\">Creating and Using Tasks with FreeRTOS<\/a><\/li>\r\n<li><a href=\"#ticks\">Ticks and vTaskDelay()<\/a><\/li>\r\n<li><a href=\"#stack_space\">Determining the Memory Space Requirements of a FreeRTOS Task<\/a><\/li>\r\n<li><a href=\"#suspend_resume\">Suspending and Resuming Tasks <\/a><\/li>\r\n<li><a href=\"#choose_core\">Determining the Executing Core<\/a><\/li>\r\n<li><a href=\"#task_synchronization\">Synchronizing FreeRTOS Tasks &#8211; Semaphore and Mutex<\/a>\r\n<ul>\r\n<li><a href=\"#semaphores\">Semaphores<\/a>\r\n<ul>\r\n<li><a href=\"#binary_semaphores\">Binary Semaphores<\/a><\/li>\r\n<li><a href=\"#binary_semaphores_interrupt_controlled\">Binary Semaphores &#8211; Interrupt-Controlled<\/a><\/li>\r\n<li><a href=\"#counting_semaphores\">Counting Semaphores &#8211; Counting Semaphores<\/a><\/li>\r\n<\/ul>\r\n<\/li>\r\n<li><a href=\"#mutex\">Mutex Objects<\/a><\/li>\r\n<\/ul>\r\n<\/li>\r\n<li><a href=\"#passing_parameters\">Passing Parameters to a task<\/a>\r\n<ul>\r\n<li><a href=\"#pv_parameters\">One-time Passing as *pvParameters<\/a><\/li>\r\n<li><a href=\"#queues\">Passing Parameters with Queues <\/a><\/li>\r\n<\/ul>\r\n<\/li>\r\n<\/ul>\r\n\n<h2 class=\"wp-block-heading\">What is FreeRTOS?<\/h2>\n\n<p>FreeRTOS is an open-source real-time operating system (RTOS) that has been specially developed for embedded systems. It offers a preemptive multitasking environment to fulfill real-time requirements in various applications. What? OK, this explanation probably needs a few explanations itself:<\/p>\r\n<ul>\r\n<li>RTOS stands for Real-Time Operating System. In a real-time system, the focus is on the time frame for the execution of tasks.<\/li>\r\n<li>Embedded systems are &#8211; among other things &#8211; microprocessors that are installed in certain devices or just microcontrollers. In contrast to conventional computers, which are suitable for a wide range of applications, embedded systems are designed for specific tasks or functions.<\/li>\r\n<li>Preemptive means that a task can be interrupted to allow another task to be carried out.<\/li>\r\n<\/ul>\r\n<p>FreeRTOS was developed by Richard Barry in the early 2000s. It may be freely used, modified and redistributed. FreeRTOS supports various architectures and processors, including AVR, ARM, ESP, x86 and more. So there is not just <em>one<\/em> FreeRTOS, but various customizations.<\/p>\r\n\n<h2 class=\"wp-block-heading\" id=\"freertos_doku\">FreeRTOS Documentation<\/h2>\n\n<p>For more in-depth information, I recommend that you take a look at the FreeRTOS documentation in parallel to this article, in particular the API reference(<strong>A<\/strong>pplication <strong>P<\/strong>rogramming <strong>I<\/strong>nterface), which you can find <a href=\"https:\/\/www.freertos.org\/a00106.html\" target=\"_blank\" rel=\"noopener\">here<\/a>. It is clearly organized and should be easy to understand in conjunction with this article.<\/p>\r\n\n<h3 class=\"wp-block-heading\">Is Real Multitasking Possible with FreeRTOS?<\/h3>\n\n<p>Yes and no. Most microcontrollers only have one core. In these cases, so-called time slicing is used, which means that a certain processor time is allocated to each task. After the allocated time has elapsed, the task is interrupted, and it is the next task&#8217;s turn. These changes happen in quick succession, giving the impression of multitasking. One exception is the ESP32 because it has two cores. Tasks can actually be processed in parallel here. <\/p>\r\n\n<h3 class=\"wp-block-heading\">Which FreeRTOS implementations do we look at in this article?<\/h3>\n\n<p>In this article, I will look at the ESP32 and the AVR-based Arduino boards (e.g. the UNO R3, the classic Nano or the Pro Mini). The ESP32 already uses FreeRTOS in the Arduino environment. It is integrated via the <a href=\"https:\/\/github.com\/espressif\/arduino-esp32\/tree\/master\" target=\"_blank\" rel=\"noopener\">esp32 board package<\/a>, so you don&#8217;t have to worry about the inclusion of FreeRTOS libraries. For the AVR Arduinos, there is the <a href=\"https:\/\/github.com\/feilipu\/Arduino_FreeRTOS_Library\" target=\"_blank\" rel=\"noopener\">Arduino_FreeRTOS_Library<\/a>, which you can find and install under the name &#8220;FreeRTOS&#8221; in the Arduino library manager.<\/p>\r\n<p>Since there are a few minor differences in the use of FreeRTOS on the ESP32 and the AVR-based Arduinos, I have written and tested all sketches in two versions.<\/p>\r\n<p>There are many other FreeRTOS libraries, for example for SAMD21, SAMD51 and STM32 boards. I couldn&#8217;t try them all out, and certainly couldn&#8217;t cover them in detail here. But once you have familiarized yourself with FreeRTOS, further variants should not cause you any major problems. <\/p>\r\n\n<h2 class=\"wp-block-heading\" id=\"tasks\">Creating and Using Tasks with FreeRTOS<\/h2>\n\n<p>We start quite simply with a blink sketch. Three LEDs should each flash at different frequencies. Without FreeRTOS you could achieve this with a <code>delay()<\/code> construction, but that would be the worst option. A solution \u00e0 la <code>if((millis() - lastToggle) &gt; blinkPeriod){...}<\/code> would be even better, as it would not be blocking. However, this can also cause problems if other processes delay the <code>millis()<\/code> query. Alternatively, timer interrupts would be an option &#8211; provided there are enough timers available.<\/p>\r\n<p>With FreeRTOS we simply avoid these problems by giving each LED its own task. In principle, there are three blink sketches running in parallel.<\/p>\r\n<p>First, let us take a look at the code:<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_basic.ino\" data-enlighter-title=\"freertos_esp32_basic.ino\">#define LED1 25\r\n#define LED2 26\r\n#define LED3 17\r\n\r\nvoid setup() {\r\n    pinMode(LED3, OUTPUT);\r\n  \r\n    xTaskCreate(\r\n        blink1,      \/\/ Function name of the task\r\n        \"Blink 1\",   \/\/ Name of the task (e.g. for debugging)\r\n        2048,        \/\/ Stack size (bytes)\r\n        NULL,        \/\/ Parameter to pass\r\n        1,           \/\/ Task priority\r\n        NULL         \/\/ Task handle\r\n    );\r\n\r\n    xTaskCreate(\r\n        blink2,     \/\/ Function name of the task\r\n        \"Blink 2\",  \/\/ Name of the task (e.g. for debugging)\r\n        2048,       \/\/ Stack size (bytes)\r\n        NULL,       \/\/ Parameter to pass\r\n        1,          \/\/ Task priority\r\n        NULL        \/\/ Task handle\r\n    );\r\n}\r\n\r\nvoid blink1(void *parameter) {\r\n    pinMode(LED1, OUTPUT);\r\n    while(1){\r\n        digitalWrite(LED1, HIGH);\r\n        delay(500); \/\/ Delay for Tasks \r\n        digitalWrite(LED1, LOW);\r\n        delay(500);\r\n    }\r\n}\r\n\r\nvoid blink2(void *parameter) {\r\n    pinMode(LED2, OUTPUT);\r\n    while(1) {\r\n        digitalWrite(LED2, HIGH);\r\n        delay(333);\r\n        digitalWrite(LED2, LOW);\r\n        delay(333);\r\n    }\r\n}\r\n\r\nvoid loop(){\r\n    digitalWrite(LED3, HIGH);\r\n    delay(1111);\r\n    digitalWrite(LED3, LOW);\r\n    delay(1111);\r\n}<\/pre>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_basic.ino\" data-enlighter-title=\"freertos_avr_basic.ino\">#include&lt;Arduino_FreeRTOS.h&gt;\r\n#define LED1 7\r\n#define LED2 8\r\n#define LED3 9\r\n\r\nvoid setup() {\r\n    xTaskCreate(\r\n        blink1,      \/\/ Function name of the task\r\n        \"Blink 1\",   \/\/ Name of the task (e.g. for debugging)\r\n        128,         \/\/ Stack size (bytes)\r\n        NULL,        \/\/ Parameter to pass\r\n        1,           \/\/ Task priority\r\n        NULL         \/\/ Task handle\r\n    );\r\n\r\n    xTaskCreate(\r\n        blink2,     \/\/ Function name of the task\r\n        \"Blink 2\",  \/\/ Name of the task (e.g. for debugging)\r\n        128,        \/\/ Stack size (bytes)\r\n        NULL,       \/\/ Parameter to pass\r\n        1,          \/\/ Task priority\r\n        NULL        \/\/ Task handle\r\n    );\r\n\r\n    xTaskCreate(\r\n        blink3,     \/\/ Function name of the task\r\n        \"Blink 3\",  \/\/ Name of the task (e.g. for debugging)\r\n        128,       \/\/ Stack size (bytes)\r\n        NULL,       \/\/ Parameter to pass\r\n        1,          \/\/ Task priority\r\n        NULL        \/\/ Task handle\r\n    );\r\n}\r\n\r\nvoid blink1(void *pvParameters){\r\n    pinMode(LED1, OUTPUT);\r\n    while(1){\r\n        digitalWrite(LED1, HIGH);\r\n        delay(500); \r\n        digitalWrite(LED1, LOW);\r\n        delay(500);\r\n    }\r\n}\r\n\r\nvoid blink2(void *pvParameters){\r\n    pinMode(LED2, OUTPUT);\r\n    while(1){\r\n        digitalWrite(LED2, HIGH);\r\n        delay(333);\r\n        digitalWrite(LED2, LOW);\r\n        delay(333);\r\n    }\r\n}\r\n\r\nvoid blink3(void *pvParameters){\r\n    pinMode(LED3, OUTPUT);\r\n    while(1){\r\n        digitalWrite(LED3, HIGH);\r\n        delay(1111); \r\n        digitalWrite(LED3, LOW);\r\n        delay(1111);\r\n    }\r\n}\r\n\r\nvoid loop(){}<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div>\r\n\n<h3 class=\"wp-block-heading\">Explanation of the code <\/h3>\n\n<h4 class=\"wp-block-heading\">Creating the Task <\/h4>\n\n<p>If you want to execute an operation in a separate task, you must first create the task with <code>xTaskCreate()<\/code>. However, what you are creating is just a kind of empty shell that you will only fill with life in a second step.&nbsp; Here is the general form of <code>xTaskCreate()<\/code>:<\/p>\r\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">BaseType_t xTaskCreate(    TaskFunction_t pvTaskCode,\r\n                            const char * const pcName,\r\n                            configSTACK_DEPTH_TYPE usStackDepth,\r\n                            void *pvParameters,\r\n                            UBaseType_t uxPriority,\r\n                            TaskHandle_t *pxCreatedTask\r\n                          );<\/pre>\r\n\n<h4 class=\"wp-block-heading\">xTaskCreate Parameters<\/h4>\n\n<p>The six parameters to be passed are:<\/p>\r\n<ul>\r\n<li><strong>pvTaskCode<\/strong>: This is the name of the function that contains the code to be executed in the task. The procedure is similar to assigning an interrupt service routine in <code>attachInterrupt()<\/code>.<\/li>\r\n<li><strong>pcName<\/strong>: This parameter allows you to give the task an easily understandable name, for example, &#8220;My favorite task&#8221;. pcName is passed as a pointer.<\/li>\r\n<li><strong>usStackdepth<\/strong>: The creation of your tasks also includes the definition of its size in the stack, which is a part of the SRAM. I have written an article about SRAM, stack and heap <a href=\"https:\/\/wolles-elektronikkiste.de\/en\/sram-management#sram_overview\" target=\"_blank\" rel=\"noopener\">here<\/a>. We will come back to how you determine the size of the task.<\/li>\r\n<li><strong>pvParameters<\/strong>: You can pass parameters to the task as pointer. The variable type &#8220;void&#8221; may be unusual for many people. It makes the function very flexible. In this example, we pass nothing, i.e. NULL (a pointer to nowhere).<\/li>\r\n<li><strong>uxPriority<\/strong>: You can use this parameter to set the priority of the task.<\/li>\r\n<li><strong>pxCreatedTask<\/strong>: A task handle is an optional variable that you can use, for example, to query the properties of the task. You could say it is an identifier for the task.&nbsp;<\/li>\r\n<\/ul>\r\n\n<p>The naming of the prefixes of the variables and functions results from the variable type or the variable type of the return value. A &#8220;c&#8221; stands for &#8220;char&#8221;, an &#8220;s&#8221; for &#8220;short&#8221;, &#8220;v&#8221; for &#8220;void&#8221;, a &#8220;u&#8221; for &#8220;unsigned&#8221; and &#8220;x&#8221; for all non-standard types. If a variable is a pointer, a &#8220;p&#8221; is placed in front of it. You can find out more about the naming conventions <a href=\"https:\/\/www.freertos.org\/FreeRTOS-Coding-Standard-and-Style-Guide.html#NamingConventions\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/p>\r\n<p>The <code>xTaskCreate()<\/code> function returns <code>pdPASS<\/code> when the task has been successfully created. You could therefore check this with <code>if(xTaskCreate(......)==pdPASS)){....}<\/code>. If the task could not be created, the function returns <code>errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY<\/code>.<\/p>\r\n\n<h4 class=\"wp-block-heading\">Filling the Task with Content &#8211; the Task Function<\/h4>\n\n<p>To fill the previously created task with life, use the task function that you have defined in <code>xTaskCreate()<\/code> (pvTaskCode). It is necessary to put <code>void *pvParameters<\/code> again in the receiving function, even if you pass <code>NULL<\/code>. For example: <code>void blink1(void *pvParameters){....}<\/code>.<\/p>\r\n<p>The following applies to the task function:<\/p>\r\n<ul>\r\n<li>It has no return value.<\/li>\r\n<li>Like a normal sketch, the task function consists of a kind of setup, i.e. code that is only executed once and a continuous loop that you realize with <code>while(1){....}<\/code> or <code>for(;;){....}<\/code>.<\/li>\r\n<li>A task can delete itself with <code>vTaskDelete( NULL );<\/code>. You can delete the task &#8220;from outside&#8221; using the task handle, i.e. <code>vTaskDelete(pxCreatedTask)<\/code>.<\/li>\r\n<\/ul>\r\n\n<p>The behavior of <code>delay()<\/code> is interesting. Within the task, <code>delay()<\/code> is blocking as usual. When switching tasks, however, the <code>delay()<\/code> is interrupted.<\/p>\r\n\n<h4 class=\"wp-block-heading\">Using loop()<\/h4>\n\n<p>As you can see, I have placed the code for LED3 in the ESP32 sketch in <code>loop()<\/code>. It&#8217;s not the best style, but I wanted to show that it works. If you do the same with an AVR-based Arduino, the program will hang. This is why the code for LED3 is outsourced to a third task.<\/p>\r\n\n<h2 class=\"wp-block-heading\" id=\"ticks\">Ticks and vTaskDelay()<\/h2>\n\n<p>The tasks must share the processor core(s). To organize this, FreeRTOS divides the time into ticks. The task can use the processor undisturbed for the duration of one tick. After the tick has expired, the system checks whether another task is due.<\/p>\r\n<p>A tick is preset to 1 millisecond on the ESP32, which you check using <code>Serial.println(portTICK_PERIOD_MS)<\/code>. In other words, the tick frequency is 1 kHz. You can query the tick frequency with <code>Serial.println(configTICK_RATE_HZ)<\/code>. The FreeRTOS version for the AVR-based Arduinos specifies a default tick frequency of 62 Hz, i.e. a tick has a length of approx. 16 milliseconds.<\/p>\r\n<p>If you search the net for FreeRTOS code examples, you will often come across the function <code>vTaskDelay()<\/code>. In principle, it does the same as <code>delay()<\/code>, with the difference that you pass <code>vTaskDelay()<\/code> ticks instead of milliseconds. This makes no difference with the ESP32, but it does with the AVR Arduinos. To achieve a waiting time of 500 milliseconds, you would have to write: <code>vTaskDelay(500\/portTICK_PERIOD_MS)<\/code>.<\/p>\r\n<p>I stick to the good old <code>delay()<\/code> in all examples.<\/p>\r\n\n<h2 class=\"wp-block-heading\" id=\"stack_space\">Determining the Memory Space Requirements of a FreeRTOS Task<\/h2>\n\n<p>Calculating the memory space required by the task is not trivial. Instead, we first reserve sufficient memory space and then use the function <code>uxTaskGetStackHighWaterMark()<\/code> to query the remaining free memory in the reserved area. To tell the function <code>uxTaskGetStackHighWaterMark()<\/code> which task we want to determine the free memory from, we pass it the task handle. You first create the handle with <code>TaskHandle_t name<\/code> and assign it to the task in <code>xTaskCreate()<\/code>.<\/p>\r\n<p>I have reduced the following sketch to two blink tasks. To make it more obvious that <code>uxTaskGetStackHighWaterMark()<\/code> actually displays the free memory, I have varied the reserved memory for the tasks.<\/p>\r\n<p>If we were to implement the memory requirement query in the task to be examined, this would falsify the result. The memory query therefore has its own task.<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_high_watermark.ino\" data-enlighter-title=\"freertos_esp32_high_watermark.ino\">#define LED1 25\r\n#define LED2 26\r\n\r\nTaskHandle_t taskBlink1Handle; \/\/ create task handle\r\nTaskHandle_t taskBlink2Handle;\r\n\r\nvoid setup() {\r\n    Serial.begin(115200);\r\n    pinMode(LED1, OUTPUT);\r\n    pinMode(LED2, OUTPUT);\r\n  \r\n    xTaskCreate(\r\n        blink1,      \/\/ Function name of the task\r\n        \"Blink 1\",   \/\/ Name of the task (e.g. for debugging)\r\n        2048,        \/\/ Stack size (bytes)\r\n        NULL,        \/\/ Parameter to pass\r\n        1,           \/\/ Task priority\r\n        &amp;taskBlink1Handle   \/\/ Assign task handle\r\n      );\r\n\r\n    xTaskCreate(\r\n        blink2,     \/\/ Function name of the task\r\n        \"Blink 2\",  \/\/ Name of the task (e.g. for debugging)\r\n        1048,       \/\/ Stack size (bytes)\r\n        NULL,       \/\/ Parameter to pass\r\n        1,          \/\/ Task priority\r\n        &amp;taskBlink2Handle   \/\/&nbsp;Assign&nbsp;task&nbsp;handle\r\n    );\r\n\r\n    xTaskCreate(\r\n        printWatermark,     \/\/ Function name of the task\r\n        \"Print Watermark\",  \/\/ Name of the task (e.g. for debugging)\r\n        2048,        \/\/ Stack size (bytes)\r\n        NULL,       \/\/ Parameter to pass\r\n        1,          \/\/ Task priority\r\n        NULL        \/\/ Task handle\r\n    );\r\n}\r\n\r\nvoid blink1(void *pvParameters){\r\n    while(1){\r\n        digitalWrite(LED1, HIGH);\r\n        delay(500); \r\n        digitalWrite(LED1, LOW);\r\n        delay(500);\r\n    }\r\n}\r\n\r\nvoid blink2(void *pvParameters){\r\n    while(1){\r\n        digitalWrite(LED2, HIGH);\r\n        delay(333);\r\n        digitalWrite(LED2, LOW);\r\n        delay(333);\r\n    }\r\n}\r\n\r\nvoid printWatermark(void *pvParameters){\r\n    while(1){\r\n        delay(2000);\r\n        Serial.print(\"TASK: \");\r\n        Serial.print(pcTaskGetName(taskBlink1Handle)); \/\/ Get task name with handler\r\n        Serial.print(\", High Watermark: \");\r\n        Serial.print(uxTaskGetStackHighWaterMark(taskBlink1Handle));\r\n        Serial.println();\r\n        Serial.print(\"TASK: \");\r\n        Serial.print(pcTaskGetName(taskBlink2Handle)); \/\/ Get task name with handler\r\n        Serial.print(\", High Watermark: \");\r\n        Serial.print(uxTaskGetStackHighWaterMark(taskBlink2Handle));\r\n        Serial.println();\r\n    }\r\n}\r\n\r\nvoid loop(){}<\/pre>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_high_watermark.ino\" data-enlighter-title=\"freertos_avr_high_watermark.ino\">#include&lt;Arduino_FreeRTOS.h&gt;\r\n#define LED1 7\r\n#define LED2 8\r\n\r\nTaskHandle_t taskBlink1Handle; \/\/ create task handle\r\nTaskHandle_t taskBlink2Handle;\r\n\r\nvoid setup() {\r\n    Serial.begin(9600);\r\n    pinMode(LED1, OUTPUT);\r\n    pinMode(LED2, OUTPUT);\r\n  \r\n    xTaskCreate(\r\n        blink1,      \/\/ Function name of the task\r\n        \"Blink 1\",   \/\/ Name of the task (e.g. for debugging)\r\n        128,         \/\/ Stack size (bytes)\r\n        NULL,        \/\/ Parameter to pass\r\n        1,           \/\/ Task priority\r\n        &amp;taskBlink1Handle   \/\/ Assign task handle\r\n      );\r\n\r\n    xTaskCreate(\r\n        blink2,     \/\/ Function name of the task\r\n        \"Blink 2\",  \/\/ Name of the task (e.g. for debugging)\r\n        98,         \/\/ Stack size (bytes)\r\n        NULL,       \/\/ Parameter to pass\r\n        1,          \/\/ Task priority\r\n        &amp;taskBlink2Handle   \/\/&nbsp;Assign&nbsp;task&nbsp;handle\r\n    );\r\n\r\n    xTaskCreate(\r\n        printWatermark,     \/\/ Function name of the task\r\n        \"Print Watermark\",  \/\/ Name of the task (e.g. for debugging)\r\n        128,        \/\/ Stack size (bytes)\r\n        NULL,       \/\/ Parameter to pass\r\n        1,          \/\/ Task priority\r\n        NULL        \/\/ Task handle\r\n    );\r\n}\r\n\r\nvoid blink1(void *pvParameters){\r\n    while(1){\r\n        digitalWrite(LED1, HIGH);\r\n        delay(500); \r\n        digitalWrite(LED1, LOW);\r\n        delay(500);\r\n    }\r\n}\r\n\r\nvoid blink2(void *pvParameters){\r\n    while(1){\r\n        digitalWrite(LED2, HIGH);\r\n        delay(333);\r\n        digitalWrite(LED2, LOW);\r\n        delay(333);\r\n    }\r\n}\r\n\r\nvoid printWatermark(void *pvParameters){\r\n    while(1){\r\n        delay(2000);\r\n        Serial.print(\"TASK: \");\r\n        Serial.print(pcTaskGetName(taskBlink1Handle)); \/\/ Get task name with handler\r\n        Serial.print(\", High Watermark: \");\r\n        Serial.print(uxTaskGetStackHighWaterMark(taskBlink1Handle));\r\n        Serial.println();\r\n        Serial.print(\"TASK: \");\r\n        Serial.print(pcTaskGetName(taskBlink2Handle)); \/\/ Get task name with handler\r\n        Serial.print(\", High Watermark: \");\r\n        Serial.print(uxTaskGetStackHighWaterMark(taskBlink2Handle));\r\n        Serial.println();\r\n    }\r\n}\r\n\r\nvoid loop(){}<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div>\r\n\n<p>And here is the output:<\/p>\r\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"702\" height=\"129\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2023\/12\/Output_freertos_watermark_esp32_avr.webp\" alt=\"\" class=\"wp-image-19777\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2023\/12\/Output_freertos_watermark_esp32_avr.webp 702w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2023\/12\/Output_freertos_watermark_esp32_avr-300x55.webp 300w\" sizes=\"auto, (max-width: 702px) 100vw, 702px\" \/><figcaption class=\"wp-element-caption\">Output of the FreeRTOS high watermark sketches, left: ESP32, right: AVR Arduino (Nano)<\/figcaption><\/figure>\n\n<p>We can deduce from this:<\/p>\r\n<ul>\r\n<li>The tasks require the following memory space on the ESP32: 1048 &#8211; 500 or 2048 &#8211; 1500 = 548 byte.<\/li>\r\n<li>On the AVR Arduino it is: 128 &#8211; 78 or 98 &#8211; 48 = 50 byte.<\/li>\r\n<\/ul>\r\n<p>The AVR Arduino therefore uses the memory more sparingly, which it has to, as its SRAM is only a fraction of the ESP32 SRAM.&nbsp;<\/p>\r\n<p>If you apply the exact values just determined, the sketch will probably crash. Reserve a few more bytes for the tasks.&nbsp;<\/p>\r\n<p>What you can also learn from the example sketch is how to get the name of the task using <code>pcTaskGetName()<\/code>.<\/p>\r\n\n<h2 class=\"wp-block-heading\" id=\"suspend_resume\">Suspending and Resuming tasks <\/h2>\n\n<p>Tasks can be suspended easily with <code>vTaskSuspend(taskHandle);<\/code> and resumed with <code>vTaskResume(taskHandle);<\/code>. In the following sketch, we use one task to make an LED flash and another task to stop it flashing regularly.<\/p>\r\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_suspend_resume.ino\" data-enlighter-title=\"freertos_esp32_suspend_resume.ino\">#define LED1 25\r\nTaskHandle_t blink1Handle;\r\n\r\nvoid setup() {\r\n    xTaskCreate(\r\n        blink1,       \/\/ Function name of the task\r\n        \"Blink 1\",    \/\/ Name of the task (e.g. for debugging)\r\n        2048,         \/\/ Stack size (bytes)\r\n        NULL,         \/\/ Parameter to pass\r\n        1,            \/\/ Task priority\r\n        &amp;blink1Handle \/\/ Task handle\r\n    );\r\n    xTaskCreate(\r\n        suspend_resume,       \/\/ Function name of the task\r\n        \"Suspend Resume\",    \/\/ Name of the task (e.g. for debugging)\r\n        2048,         \/\/ Stack size (bytes)\r\n        NULL,         \/\/ Parameter to pass\r\n        1,            \/\/ Task priority\r\n        NULL \/\/ Task handle\r\n    );\r\n}\r\n\r\nvoid blink1(void *pvParameters){\r\n    pinMode(LED1, OUTPUT);\r\n    while(1){\r\n        digitalWrite(LED1, HIGH);\r\n        delay(100); \r\n        digitalWrite(LED1, LOW);\r\n        delay(100);\r\n    }\r\n}\r\n\r\nvoid suspend_resume(void *pvParameters){\r\n    pinMode(LED1, OUTPUT);\r\n    while(1){\r\n        delay(1999);\r\n        vTaskSuspend(blink1Handle);\r\n        delay(999);\r\n        vTaskResume(blink1Handle);\r\n    }\r\n}\r\n\r\nvoid loop(){}<\/pre>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_suspend_resume.ino\" data-enlighter-title=\"freertos_avr_suspend_resume.ino\">#include&lt;Arduino_FreeRTOS.h&gt;\r\n#define LED1 7\r\nTaskHandle_t blink1Handle;\r\n\r\nvoid setup() {\r\n    xTaskCreate(\r\n        blink1,       \/\/ Function name of the task\r\n        \"Blink 1\",    \/\/ Name of the task (e.g. for debugging)\r\n        128,          \/\/ Stack size (bytes)\r\n        NULL,         \/\/ Parameter to pass\r\n        1,            \/\/ Task priority\r\n        &amp;blink1Handle \/\/ Task handle\r\n    );\r\n\r\n    xTaskCreate(\r\n        suspend_resume,    \/\/ Function name of the task\r\n        \"Suspend Resume\",  \/\/ Name of the task (e.g. for debugging)\r\n        128,               \/\/ Stack size (bytes)\r\n        NULL,              \/\/ Parameter to pass\r\n        1,                 \/\/ Task priority\r\n        NULL      \/\/ Task handle\r\n    );\r\n}\r\n\r\nvoid blink1(void *pvParameters){\r\n    pinMode(LED1, OUTPUT);\r\n    while(1){\r\n        digitalWrite(LED1, HIGH);\r\n        delay(100); \r\n        digitalWrite(LED1, LOW);\r\n        delay(100);\r\n    }\r\n}\r\n\r\nvoid suspend_resume(void *pvParameters){\r\n    while(1){\r\n        delay(1900);\r\n        vTaskSuspend(blink1Handle);\r\n        delay(900);\r\n        vTaskResume(blink1Handle);\r\n    }\r\n}\r\n\r\nvoid loop(){}<\/pre>\r\n<p>&nbsp;<\/p>\r\n\n<h2 class=\"wp-block-heading\" id=\"choose_core\">Determining the Executing Core<\/h2>\n\n<p>Two cores are available on the ESP32, 0 and 1. We can use the function <code>xTaskCreatePinnedToCore()<\/code> to determine on which of the cores the task is to be executed. The function is passed the same parameters as <code>xCreateTask()<\/code>, except that the core is added at the end. Here is a simple example.<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_choose_core.ino\" data-enlighter-title=\"freertos_choose_core.ino\">void setup() {\r\n    Serial.begin(115200);\r\n    xTaskCreatePinnedToCore(\r\n        print1,      \/\/ Function name of the task\r\n        \"Print 1\",   \/\/ Name of the task (e.g. for debugging)\r\n        2048,        \/\/ Stack size (bytes)\r\n        NULL,        \/\/ Parameter to pass\r\n        1,           \/\/ Task priority\r\n        NULL,        \/\/ Task handle\r\n        0            \/\/ run on Core 0\r\n    );\r\n\r\n    xTaskCreatePinnedToCore(\r\n        print2,     \/\/ Function name of the task\r\n        \"Print 2\",  \/\/ Name of the task (e.g. for debugging)\r\n        2048,       \/\/ Stack size (bytes)\r\n        NULL,       \/\/ Parameter to pass\r\n        1,          \/\/ Task priority\r\n        NULL,       \/\/ Task handle\r\n        1           \/\/ run on Core 1\r\n    );\r\n}\r\n\r\nvoid print1(void *pvParameters){\r\n    while(1){\r\n        Serial.print(\"Task is running on core \");\r\n        Serial.println(xPortGetCoreID());\r\n        delay(2500);\r\n    }\r\n}\r\n\r\nvoid print2(void *pvParameters){\r\n    while(1){\r\n        Serial.print(\"Task is running on core \");\r\n        Serial.println(xPortGetCoreID());\r\n        delay(1500);\r\n    }\r\n}\r\n\r\nvoid loop(){}<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div>\r\n\n<p>As you can see, you can use <code>xPortGetCoreID()<\/code> to check on which core the task is being executed.<\/p>\r\n\n<h4 class=\"wp-block-heading\">Which Core Should I Use? <\/h4>\n\n<p>By default, your Arduino code is executed on core 1. If you use Wi-Fi or BLE, a lot of work is required in the background, which is carried out on core 0. If you assign core 0 too many extra tasks, your Wi-Fi and BLE may no longer work reliably. If you don&#8217;t use these functions, you don&#8217;t need to worry about this issue.<\/p>\r\n\n<h2 class=\"wp-block-heading\" id=\"task_synchronization\">Synchronizing FreeRTOS Tasks &#8211; Semaphore and Mutex<\/h2>\n\n<p>If tasks access the same resources, such as external sensors, EEPROMs, ADCs, serial communication, etc., they could interfere with each other with unforeseeable consequences. If this could potentially happen, then the tasks must be synchronized (in the sense of coordinated, not simultaneously). There are two techniques for this, namely semaphores and mutex.<\/p>\r\n<p>The term semaphore comes from ancient Greek. Sema means sign and phoros means carrying. Put together, this means &#8220;signal transmitter&#8221;, like, for example, traffic lights. In other words: the (alternatively: the) semaphore gives the task the signal to be allowed to start.<\/p>\r\n<p>Mutex stands for &#8220;Mutual Exclusion Object&#8221;, which means that the tasks are mutually excluded. The mutex is very similar to the semaphore, but there are a few subtle differences (see also <a href=\"https:\/\/www.freertos.org\/CreateMutex.html\" target=\"_blank\" rel=\"noopener\">here<\/a> in the FreeRTOS documentation). <\/p>\r\n<p>You could say it&#8217;s like the baton at a relay race. Only those who have it are allowed to start running. However, the comparison is a little off because the handover runner is allowed to continue running. <\/p>\r\n\n<h2 class=\"wp-block-heading\" id=\"semaphores\">Semaphores<\/h2>\n\n<p>There are two types of semaphores, namely binary semaphores and counting semaphores. I will explain the difference using examples.<\/p>\r\n\n<h3 class=\"wp-block-heading\" id=\"binary_semaphores\">Binary Semaphores &#8211; Binary Semaphores<\/h3>\n\n<p>In the first step, you create a semaphore handle with <code>SemaphoreHandle_t xSemaphore;<\/code>, which you use in the second step to fill the semaphore with life: <code>xSemaphore = xSemaphoreCreateBinary();<\/code>. You can replace &#8220;xSemaphore&#8221; with a name of your choice. In the following, I will refer to the semaphore as &#8220;sem&#8221; for short.<\/p>\r\n<p>And these are the rules of the game: for the semaphore to be used, it must be released with <code>xSemaphoreGive(sem)<\/code>. To receive the semaphore, there is the function <code>xSemaphoreTake(sem, xTicksToWait)<\/code> with <code>xTicksToWait<\/code> as the maximum waiting time in ticks. If the semaphore was accepted within the waiting time, the function return value is <code>pdTRUE<\/code>, otherwise <code>pdFALSE<\/code>.<\/p>\r\n<p>Each task can release the semaphore provided it is in its possession. And every task can accept the semaphore if it is available.<\/p>\r\n<p>You often want the task to wait as long as necessary. In this case, you pass <code>portMAX_DELAY<\/code> as <code>xTicksToWait<\/code>. On the ESP32 <code>portMAX_DELAY<\/code> is 2<sup>32<\/sup> &#8211; 1, on the AVR Arduinos it is 2<sup>16<\/sup> &#8211; 1.<\/p>\r\n\n<h4 class=\"wp-block-heading\">Binary Semaphores &#8211; Example Sketch I<\/h4>\n\n<p>We flash two LEDs again, but this time alternately. First one LED should flash 10 times, then the other and so on alternately.<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_semaphores_binary_I.ino\" data-enlighter-title=\"freertos_esp32_semaphores_binary_I.ino\">#define LED1 25\r\n#define LED2 26\r\n\r\nSemaphoreHandle_t sem; \/\/ Create semaphore handle\r\n\r\nvoid setup() {\r\n    sem = xSemaphoreCreateBinary(); \/\/ Create binary semaphore\r\n         \r\n    xTaskCreate(\r\n        blink1,      \/\/ Function name of the task\r\n        \"Blink 1\",   \/\/ Name of the task (e.g. for debugging)\r\n        2048,        \/\/ Stack size (bytes)\r\n        NULL,        \/\/ Parameter to pass\r\n        1,           \/\/ Task priority\r\n        NULL         \/\/ Task handle\r\n    );\r\n    xTaskCreate(\r\n        blink2,     \/\/ Function name of the task\r\n        \"Blink 2\",  \/\/ Name of the task (e.g. for debugging)\r\n        2048,       \/\/ Stack size (bytes)\r\n        NULL,       \/\/ Parameter to pass\r\n        1,          \/\/ Task priority\r\n        NULL        \/\/ Task handle\r\n    );\r\n    xSemaphoreGive(sem);\r\n}\r\n\r\nvoid blink1(void *pvParameters){\r\n    pinMode(LED1, OUTPUT);\r\n    while(1){\r\n        xSemaphoreTake(sem,portMAX_DELAY);\r\n        for(int i=0; i&lt;10; i++){\r\n            digitalWrite(LED1, HIGH);\r\n            delay(250);\r\n            digitalWrite(LED1, LOW);\r\n            delay(250);\r\n        }\r\n        xSemaphoreGive(sem);\r\n        delay(100); \/\/ Short delay is needed!\r\n    }\r\n}\r\n\r\nvoid blink2(void *pvParameters){\r\n    pinMode(LED2, OUTPUT);\r\n    while(1){\r\n        xSemaphoreTake(sem,portMAX_DELAY);\r\n        for(int i=0; i&lt;10; i++){\r\n            digitalWrite(LED2, HIGH);\r\n            delay(333);\r\n            digitalWrite(LED2, LOW);\r\n            delay(333);   \r\n        }\r\n        xSemaphoreGive(sem);\r\n        delay(100); \/\/ Short delay is needed!\r\n    }\r\n}\r\n\r\nvoid loop(){}<\/pre>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_semaphores_binary_I.ino\" data-enlighter-title=\"freertos_avr_semaphores_binary_I.ino\">#include &lt;Arduino_FreeRTOS.h&gt;\r\n#include &lt;semphr.h&gt;  \/\/ Needed in case if you want to use semaphores\r\n\r\n#define LED1 7\r\n#define LED2 8\r\n\r\nSemaphoreHandle_t sem;  \/\/ Create semaphore handle\r\n\r\nvoid setup() {\r\n    sem = xSemaphoreCreateBinary(); \/\/ Create binary semaphore\r\n         \r\n    xTaskCreate(\r\n        blink1,      \/\/ Function name of the task\r\n        \"Blink 1\",   \/\/ Name of the task (e.g. for debugging)\r\n        128,         \/\/ Stack size (bytes)\r\n        NULL,        \/\/ Parameter to pass\r\n        1,           \/\/ Task priority\r\n        NULL         \/\/ Task handle\r\n    );\r\n    xTaskCreate(\r\n        blink2,     \/\/ Function name of the task\r\n        \"Blink 2\",  \/\/ Name of the task (e.g. for debugging)\r\n        128,        \/\/ Stack size (bytes)\r\n        NULL,       \/\/ Parameter to pass\r\n        1,          \/\/ Task priority\r\n        NULL        \/\/ Task handle\r\n    );\r\n    xSemaphoreGive(sem);  \/\/ Release semaphore\r\n}\r\n\r\nvoid blink1(void *pvParameters){\r\n    pinMode(LED1, OUTPUT);\r\n    while(1){\r\n        xSemaphoreTake(sem,portMAX_DELAY); \/\/ Take semaphore\r\n        for(int i=0; i&lt;10; i++){\r\n            digitalWrite(LED1, HIGH);\r\n            delay(250);\r\n            digitalWrite(LED1, LOW);\r\n            delay(250);\r\n        }\r\n        xSemaphoreGive(sem); \/\/ Release semaphore\r\n        delay(100); \/\/ Short delay is needed!\r\n    }\r\n}\r\n\r\nvoid blink2(void *pvParameters){\r\n    pinMode(LED2, OUTPUT);\r\n    while(1){\r\n        xSemaphoreTake(sem,portMAX_DELAY); \/\/ Take semaphore\r\n        for(int i=0; i&lt;10; i++){\r\n            digitalWrite(LED2, HIGH);\r\n            delay(333);\r\n            digitalWrite(LED2, LOW);\r\n            delay(333);   \r\n        }\r\n        xSemaphoreGive(sem);  \/\/ Release semaphore\r\n        delay(100); \/\/ Short delay is needed!\r\n    }\r\n}\r\n\r\nvoid loop(){}<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div>\r\n\n<p>The semaphore is created and released in the setup. One of the two tasks takes it, and this task can start. As long as the semaphore is not released again, the second task must wait. If the semaphore was released by the first task and accepted by the second, the first task must wait again when it encounters the <code>xSemaphoreTake()<\/code> function. <\/p>\r\n<p>Passing the semaphore does not work without a short <code>delay()<\/code> after <code>xSemaphoreGive()<\/code>. Apparently, the task currently executing &#8220;grabs&#8221; the semaphore itself. The <code>delay()<\/code> must therefore be at least one tick long.<\/p>\r\n<p>In this example, we have not clearly defined which of the two tasks is executed first after the program starts. You can control this by giving one of the two tasks in <code>xTaskCreate()<\/code> a higher priority. <\/p>\r\n<p>For the AVR Arduino version, you need to include the library file semphr.h in order to be able to use the semaphore functions.<\/p>\r\n\n<h4 class=\"wp-block-heading\">Binary Semaphores &#8211; Example Sketch II <\/h4>\n\n<p>The last example sketch may have given the impression that the binary semaphore is exclusive&nbsp;, i.e. it only allows one of the tasks to be executed. The next sketch shows that this is not the case:<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_semaphores_binary_II.ino\" data-enlighter-title=\"freertos_esp32_semaphores_binary_II.ino\">#define LED1 25\r\n#define LED2 26\r\n\r\nSemaphoreHandle_t sem; \/\/ Create semaphore handle&nbsp;\r\nvoid setup() {\r\n    sem = xSemaphoreCreateBinary(); \/\/ Create a binary semaphore\r\n         \r\n    xTaskCreate(\r\n        blink1,      \/\/ Function name of the task\r\n        \"Blink 1\",   \/\/ Name of the task (e.g. for debugging)\r\n        2048,        \/\/ Stack size (bytes)\r\n        NULL,        \/\/ Parameter to pass\r\n        1,           \/\/ Task priority\r\n        NULL         \/\/ Task handle\r\n    );\r\n    xTaskCreate(\r\n        blink2,     \/\/ Function name of the task\r\n        \"Blink 2\",  \/\/ Name of the task (e.g. for debugging)\r\n        2048,       \/\/ Stack size (bytes)\r\n        NULL,       \/\/ Parameter to pass\r\n        1,          \/\/ Task priority\r\n        NULL        \/\/ Task handle\r\n    );\r\n}\r\n\r\nvoid blink1(void *pvParameters){\r\n    pinMode(LED1, OUTPUT);\r\n    while(1){\r\n       for(int i=0; i&lt;10; i++){\r\n            digitalWrite(LED1, HIGH);\r\n            delay(250);\r\n            digitalWrite(LED1, LOW);\r\n            delay(250);\r\n        }\r\n        xSemaphoreGive(sem); \/\/ Release semaphore\r\n        delay(7000); \/\/ Give time to execute blink2\r\n    }\r\n}\r\n\r\nvoid blink2(void *pvParameters){\r\n    while(1){\r\n    pinMode(LED2, OUTPUT);\r\n        xSemaphoreTake(sem,portMAX_DELAY); \/\/ Take semaphore\r\n        for(int i=0; i&lt;10; i++){\r\n            digitalWrite(LED2, HIGH);\r\n            delay(333);\r\n            digitalWrite(LED2, LOW);\r\n            delay(333);   \r\n        }\r\n    }\r\n}\r\n\r\nvoid loop(){}<\/pre>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_semaphores_binary_II.ino\" data-enlighter-title=\"freertos_avr_semaphores_binary_II.ino\">#include &lt;Arduino_FreeRTOS.h&gt;\r\n#include &lt;semphr.h&gt;\r\n\r\n#define LED1 7\r\n#define LED2 8\r\n\r\nSemaphoreHandle_t sem; \/\/ Create semaphore handle\r\n\r\nvoid setup() {\r\n    sem = xSemaphoreCreateBinary(); \/\/ Create binary semaphore\r\n         \r\n    xTaskCreate(\r\n        blink1,      \/\/ Function name of the task\r\n        \"Blink 1\",   \/\/ Name of the task (e.g. for debugging)\r\n        128,         \/\/ Stack size (bytes)\r\n        NULL,        \/\/ Parameter to pass\r\n        1,           \/\/ Task priority\r\n        NULL         \/\/ Task handle\r\n    );\r\n    xTaskCreate(\r\n        blink2,     \/\/ Function name of the task\r\n        \"Blink 2\",  \/\/ Name of the task (e.g. for debugging)\r\n        128,        \/\/ Stack size (bytes)\r\n        NULL,       \/\/ Parameter to pass\r\n        1,          \/\/ Task priority\r\n        NULL   \/\/ Task handle\r\n    );\r\n}\r\n\r\nvoid blink1(void *pvParameters){\r\n    pinMode(LED1, OUTPUT);\r\n    while(1){\r\n       for(int i=0; i&lt;10; i++){\r\n            digitalWrite(LED1, HIGH);\r\n            delay(250);\r\n            digitalWrite(LED1, LOW);\r\n            delay(250);\r\n        }\r\n        xSemaphoreGive(sem); \/\/ Release semaphore\r\n        delay(7000); \/\/ Give time to execute blink2\r\n    }\r\n}\r\n\r\nvoid blink2(void *pvParameters){\r\n    pinMode(LED2, OUTPUT);\r\n    while(1){\r\n        xSemaphoreTake(sem, portMAX_DELAY); \/\/ Take semaphore\r\n        for(int i=0; i&lt;10; i++){\r\n            digitalWrite(LED2, HIGH);\r\n            delay(333);\r\n            digitalWrite(LED2, LOW);\r\n            delay(333);   \r\n        }\r\n    }\r\n}\r\n\r\nvoid loop(){}<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div>\r\n\n<p>In contrast to the previous example, the semaphore is not released in the setup here. The blink2 task is therefore initially blocked by <code>xSemaphoreTake()<\/code>. However, this does not apply to the blink1 task. After LED1 has flashed ten times, the semaphore is released, but blink1 continues to run for another seven seconds with a <code>delay()<\/code>. In these seven seconds, the while loop in blink2 is run through once before it blocks due to a missing free semaphore. So it&#8217;s blink1&#8217;s turn and the game starts all over again.<\/p>\r\n\n<h4 class=\"wp-block-heading\">Binary Semaphores &#8211; Example Sketch III<\/h4>\n\n<p>I would like to present a third example sketch to deepen the knowledge. Here we let LED1 flash ten times again, but after the fifth flash, LED2 flashes ten times quickly while LED 1 continues to flash. This perhaps shows a little more clearly how the tasks are controlled in terms of time by semaphores.<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_semaphores_binary_III.ino\" data-enlighter-title=\"freertos_esp32_semaphores_binary_III.ino\">#define LED1 25\r\n#define LED2 26\r\n\r\nSemaphoreHandle_t sem;  \/\/ Create semaphore handle&nbsp;\r\n\r\nvoid setup() {\r\n    sem = xSemaphoreCreateBinary(); \/\/ Create binary semaphore&nbsp;\r\n         \r\n    xTaskCreate(\r\n        blink1,      \/\/ Function name of the task\r\n        \"Blink 1\",   \/\/ Name of the task (e.g. for debugging)\r\n        2048,        \/\/ Stack size (bytes)\r\n        NULL,        \/\/ Parameter to pass\r\n        1,           \/\/ Task priority\r\n        NULL         \/\/ Task handle\r\n    );\r\n    xTaskCreate(\r\n        blink2,     \/\/ Function name of the task\r\n        \"Blink 2\",  \/\/ Name of the task (e.g. for debugging)\r\n        2048,       \/\/ Stack size (bytes)\r\n        NULL,       \/\/ Parameter to pass\r\n        1,          \/\/ Task priority\r\n        NULL        \/\/ Task handle\r\n    );\r\n}\r\n\r\nvoid blink1(void *pvParameters){\r\n    pinMode(LED1, OUTPUT);\r\n    while(1){\r\n       for(int i=0; i&lt;5; i++){\r\n            digitalWrite(LED1, HIGH);\r\n            delay(250);\r\n            digitalWrite(LED1, LOW);\r\n            delay(250);\r\n        }\r\n        xSemaphoreGive(sem); \/\/ Release semaphore\r\n        for(int i=0; i&lt;5; i++){\r\n            digitalWrite(LED1, HIGH);\r\n            delay(250);\r\n            digitalWrite(LED1, LOW);\r\n            delay(250);\r\n        }\r\n        delay(2000);\r\n    }\r\n}\r\n\r\nvoid blink2(void *pvParameters){\r\n    pinMode(LED2, OUTPUT);\r\n    while(1){\r\n        xSemaphoreTake(sem,portMAX_DELAY); \/\/ take semaphore\r\n        for(int i=0; i&lt;10; i++){\r\n            digitalWrite(LED2, HIGH);\r\n            delay(50);\r\n            digitalWrite(LED2, LOW);\r\n            delay(50);   \r\n        }\r\n    }\r\n}\r\n\r\nvoid loop(){}<\/pre>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_semaphores_binary_III.ino\" data-enlighter-title=\"freertos_avr_semaphores_binary_III.ino\">#include &lt;Arduino_FreeRTOS.h&gt;\r\n#include &lt;semphr.h&gt;\r\n#define LED1 7\r\n#define LED2 8\r\n\r\nSemaphoreHandle_t sem; \/\/ create semaphore handle&nbsp;\r\n\r\nvoid setup() {\r\n    sem = xSemaphoreCreateBinary(); \/\/ create binary semaphore\r\n         \r\n    xTaskCreate(\r\n        blink1,      \/\/ Function name of the task\r\n        \"Blink 1\",   \/\/ Name of the task (e.g. for debugging)\r\n        128,        \/\/ Stack size (bytes)\r\n        NULL,        \/\/ Parameter to pass\r\n        1,           \/\/ Task priority\r\n        NULL         \/\/ Task handle\r\n    );\r\n    xTaskCreate(\r\n        blink2,     \/\/ Function name of the task\r\n        \"Blink 2\",  \/\/ Name of the task (e.g. for debugging)\r\n        128,       \/\/ Stack size (bytes)\r\n        NULL,       \/\/ Parameter to pass\r\n        1,          \/\/ Task priority\r\n        NULL   \/\/ Task handle\r\n    );\r\n}\r\n\r\nvoid blink1(void *pvParameters){\r\n    pinMode(LED1, OUTPUT);\r\n    while(1){\r\n       for(int i=0; i&lt;5; i++){\r\n            digitalWrite(LED1, HIGH);\r\n            delay(250);\r\n            digitalWrite(LED1, LOW);\r\n            delay(250);\r\n        }\r\n        xSemaphoreGive(sem);  \/\/ release semaphore\r\n        for(int i=0; i&lt;5; i++){\r\n            digitalWrite(LED1, HIGH);\r\n            delay(250);\r\n            digitalWrite(LED1, LOW);\r\n            delay(250);\r\n        }\r\n        delay(2000);\r\n    }\r\n}\r\n\r\nvoid blink2(void *pvParameters){\r\n    pinMode(LED2, OUTPUT);\r\n    while(1){\r\n        xSemaphoreTake(sem,portMAX_DELAY); \/\/&nbsp;take&nbsp;semaphore\r\n        for(int i=0; i&lt;10; i++){\r\n            digitalWrite(LED2, HIGH);\r\n            delay(50);\r\n            digitalWrite(LED2, LOW);\r\n            delay(50);   \r\n        }\r\n    }\r\n}\r\n\r\nvoid loop(){}<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div>\r\n\n<h3 class=\"wp-block-heading\" id=\"binary_semaphores_interrupt_controlled\">Binary Semaphores &#8211; Interrupt-Controlled<\/h3>\n\n<p>In the last example sketch for binary semaphores, I would like to show you how to release semaphores in an interrupt routine (ISR). To try out the following sketch, connect two buttons to your ESP32 or AVR Arduino. Connect the buttons to an interrupt pin on one side and to GND on the other. Otherwise, the LEDs are used again. One push-button should cause LED1 to flash, the other push-button controls LED2.<\/p>\r\n<p>There is only one new aspect to this task. You do not use <code>xSemaphoreGive(xSemaphore)<\/code> in the ISR as before, but the function <code>xSemaphoreGiveFromISR(xSemaphore,*pxHigherPriorityTaskWoken)<\/code>. For the meaning of the second parameter, see <a href=\"https:\/\/www.freertos.org\/a00124.html\" target=\"_blank\" rel=\"noopener\">here<\/a>, in the FreeRTOS documentation. For the sake of simplicity, we set the parameter in the example to NULL.<\/p>\r\n<p>The rest of the sketch should be understandable without further explanation.<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_semaphores_binary_interrupt.ino\" data-enlighter-title=\"freertos_esp32_semaphores_bin_int.ino\">#define LED1 25\r\n#define LED2 26\r\n#define INT_PIN_1 15\r\n#define INT_PIN_2 16\r\n\r\nSemaphoreHandle_t interruptSemaphore1; \/\/ Create semaphore handle\r\nSemaphoreHandle_t interruptSemaphore2;\r\n\r\nvoid IRAM_ATTR keyISR1() {   \/\/ ISR definition\r\n    xSemaphoreGiveFromISR(interruptSemaphore1, NULL);\r\n}\r\n\r\nvoid IRAM_ATTR keyISR2() {\r\n    xSemaphoreGiveFromISR(interruptSemaphore2, NULL);\r\n}\r\n\r\nvoid setup() {\r\n    interruptSemaphore1 = xSemaphoreCreateBinary(); \/\/ Create semaphore\r\n    interruptSemaphore2 = xSemaphoreCreateBinary();\r\n\r\n    xTaskCreate(\r\n        blink1,      \/\/ Function name of the task\r\n        \"Blink 1\",   \/\/ Name of the task (e.g. for debugging)\r\n        2048,        \/\/ Stack size (bytes)\r\n        NULL,        \/\/ Parameter to pass\r\n        1,           \/\/ Task priority\r\n        NULL         \/\/ Task handle\r\n    );\r\n\r\n    xTaskCreate(\r\n        blink2,      \/\/ Function name of the task\r\n        \"Blink 2\",   \/\/ Name of the task (e.g. for debugging)\r\n        2048,        \/\/ Stack size (bytes)\r\n        NULL,        \/\/ Parameter to pass\r\n        1,           \/\/ Task priority\r\n        NULL         \/\/ Task handle\r\n    );\r\n\r\n    if (interruptSemaphore1 != NULL) {\r\n        attachInterrupt(digitalPinToInterrupt(INT_PIN_1), keyISR1, FALLING);\r\n    }\r\n    if (interruptSemaphore2 != NULL) {\r\n        attachInterrupt(digitalPinToInterrupt(INT_PIN_2), keyISR2, FALLING);\r\n    }\r\n}\r\n\r\nvoid blink1(void *pvParameters){\r\n    pinMode(LED1, OUTPUT);\r\n    pinMode(INT_PIN_1, INPUT_PULLUP);\r\n    while(1){\r\n        if (xSemaphoreTake(interruptSemaphore1, portMAX_DELAY)) {\r\n            for(int i=0; i&lt;10; i++){\r\n                digitalWrite(LED1, HIGH);\r\n                delay(50); \/\/ Delay for Tasks \r\n                digitalWrite(LED1, LOW);\r\n                delay(50);\r\n            }\r\n        }\r\n    }\r\n}\r\n\r\nvoid blink2(void *pvParameters){\r\n    pinMode(LED2, OUTPUT);\r\n    pinMode(INT_PIN_2, INPUT_PULLUP);\r\n    while(1){\r\n        if (xSemaphoreTake(interruptSemaphore2, portMAX_DELAY)) {\r\n            for(int i=0; i&lt;10; i++){\r\n                digitalWrite(LED2, HIGH);\r\n                delay(50);  \r\n                digitalWrite(LED2, LOW);\r\n                delay(50);\r\n            }\r\n        }\r\n    }\r\n}\r\n\r\nvoid loop(){}\r\n<\/pre>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_semaphores_binary_interrupt.ino\" data-enlighter-title=\"freertos_avr_semaphores_bin_int.ino\">#include &lt;Arduino_FreeRTOS.h&gt;\r\n#include &lt;semphr.h&gt;\r\n#define LED1 7\r\n#define LED2 8\r\n#define INT_PIN_1 2\r\n#define INT_PIN_2 3\r\n\r\nSemaphoreHandle_t interruptSemaphore1; \/\/ Create semaphore handle\r\nSemaphoreHandle_t interruptSemaphore2;\r\n\r\nvoid keyISR1() {  \/\/ ISR definition\r\n    xSemaphoreGiveFromISR(interruptSemaphore1, NULL);\r\n}\r\n\r\nvoid keyISR2() {\r\n    xSemaphoreGiveFromISR(interruptSemaphore2, NULL);\r\n}\r\n\r\nvoid setup() {\r\n    interruptSemaphore1 = xSemaphoreCreateBinary();  \/\/ Create semaphore\r\n    interruptSemaphore2 = xSemaphoreCreateBinary();\r\n\r\n    xTaskCreate(\r\n        blink1,      \/\/ Function name of the task\r\n        \"Blink 1\",   \/\/ Name of the task (e.g. for debugging)\r\n        128,         \/\/ Stack size (bytes)\r\n        NULL,        \/\/ Parameter to pass\r\n        1,           \/\/ Task priority\r\n        NULL         \/\/ Task handle\r\n    );\r\n\r\n    xTaskCreate(\r\n        blink2,      \/\/ Function name of the task\r\n        \"Blink 2\",   \/\/ Name of the task (e.g. for debugging)\r\n        128,         \/\/ Stack size (bytes)\r\n        NULL,        \/\/ Parameter to pass\r\n        1,           \/\/ Task priority\r\n        NULL         \/\/ Task handle\r\n    );\r\n\r\n    if (interruptSemaphore1 != NULL) {\r\n        attachInterrupt(digitalPinToInterrupt(INT_PIN_1), keyISR1, FALLING);\r\n    }\r\n    if (interruptSemaphore2 != NULL) {\r\n        attachInterrupt(digitalPinToInterrupt(INT_PIN_2), keyISR2, FALLING);\r\n    }\r\n}\r\n\r\nvoid blink1(void *pvParameters){\r\n    pinMode(LED1, OUTPUT);\r\n    pinMode(INT_PIN_1, INPUT_PULLUP);\r\n    while(1){\r\n        if (xSemaphoreTake(interruptSemaphore1, portMAX_DELAY)) {\r\n            for(int i=0; i&lt;10; i++){\r\n                digitalWrite(LED1, HIGH);\r\n                delay(50);  \r\n                digitalWrite(LED1, LOW);\r\n                delay(50);\r\n            }\r\n        }\r\n    }\r\n}\r\n\r\nvoid blink2(void *pvParameters){\r\n    pinMode(LED2, OUTPUT);\r\n    pinMode(INT_PIN_2, INPUT_PULLUP);\r\n    while(1){\r\n        if (xSemaphoreTake(interruptSemaphore2, portMAX_DELAY)) {\r\n            for(int i=0; i&lt;10; i++){\r\n                digitalWrite(LED2, HIGH);\r\n                delay(50);  \r\n                digitalWrite(LED2, LOW);\r\n                delay(50);\r\n            }\r\n        }\r\n    }\r\n}\r\n\r\nvoid loop(){}<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div>\r\n\n<h3 class=\"wp-block-heading\" id=\"counting_semaphores\">Counting Semaphores<\/h3>\n\n<p>You can create counting semaphores with <code>xSemaphoreCreateCounting( uxMaxCount, uxInitialCount )<\/code>. The parameter <code>uxMaxCount<\/code> specifies how many copies of this semaphore may be in circulation. The parameter <code>uxInitialCount<\/code> defines how many copies of the semaphore are initially available. Each <code>xSemaphoreTake()<\/code> reduces the number of available semaphores by 1, and each <code>xSemaphoreGive()<\/code> increases it by 1, provided that the limits 0 and <code>uxMaxCount<\/code> are not undercut or exceeded.<\/p>\r\n<p>The expression <code>xSemaphoreCreateCounting(1,0)<\/code> is therefore similar to <code>xSemaphoreCreateBinary()<\/code>. You can try this out by making the corresponding substitution in freertos_esp32_semaphores_binary_I.ino or freertos_avr_semaphores_binary_I.ino. With <code>xSemaphoreCreateCounting(1,1)<\/code> you could also save <code>xSemaphoreGive(sem)<\/code> in the setup.<\/p>\r\n\n<h4 class=\"wp-block-heading\">Counting Semaphores &#8211; Example Sketch I<\/h4>\n\n<p>In the first example sketch, we use two counting semaphores to make two LEDs flash ten times alternately. We use the first semaphore (countingSem) like a binary semaphore to prevent simultaneous flashing. The other semaphore (countingSem2) limits the total number of flashing sequences to four. We achieve this by setting <code>uxMaxCount<\/code> and <code>uxInitialCount<\/code> to 4 and by the tasks only taking the countingSem2 but not releasing it.<\/p>\r\n<p>We keep ourselves informed about how many of the countingSem2 semaphores are still available via <code>uxSemaphoreGetCount(countingSem2)<\/code>.<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_semaphores_count_I.ino\" data-enlighter-title=\"freertos_esp32_semaphores_count_I.ino\">#define LED1 25\r\n#define LED2 26\r\n\r\nSemaphoreHandle_t countingSem; \/\/ Create handle \r\nSemaphoreHandle_t countingSem2;\r\n\r\nvoid setup() {\r\n    Serial.begin(115200);\r\n    pinMode(LED1, OUTPUT);\r\n    pinMode(LED2, OUTPUT);\r\n\r\n    countingSem = xSemaphoreCreateCounting(1,1); \/\/ Create counting semaphore\r\n    countingSem2 = xSemaphoreCreateCounting(4,4); \/\/ Create second counting semaphore  \r\n\r\n    Serial.print(\"countingSem2 left: \");\r\n    Serial.println(uxSemaphoreGetCount(countingSem2));\r\n    \r\n    xTaskCreate(\r\n        blink1,      \/\/ Function name of the task\r\n        \"Blink 1\",   \/\/ Name of the task (e.g. for debugging)\r\n        2048,        \/\/ Stack size (bytes)\r\n        NULL,        \/\/ Parameter to pass\r\n        1,           \/\/ Task priority\r\n        NULL         \/\/ Task handle\r\n    );\r\n    \r\n    xTaskCreate(\r\n        blink2,     \/\/ Function name of the task\r\n        \"Blink 2\",  \/\/ Name of the task (e.g. for debugging)\r\n        2048,       \/\/ Stack size (bytes)\r\n        NULL,       \/\/ Parameter to pass\r\n        1,          \/\/ Task priority\r\n        NULL        \/\/ Task handle\r\n    );\r\n}\r\n\r\nvoid blink1(void *pvParameters){\r\n    while(1){\r\n        \/* Take the semaphore, no semaphore (countingSem) will be left *\/\r\n        xSemaphoreTake(countingSem, portMAX_DELAY);\r\n        \/* Take the semaphore countingSem2 if still available *\/\r\n        xSemaphoreTake(countingSem2, portMAX_DELAY);\r\n        Serial.print(\"countingSem2 left: \");\r\n        Serial.println(uxSemaphoreGetCount(countingSem2));\r\n        \r\n        for(int i=0; i&lt;10; i++){\r\n            digitalWrite(LED1, HIGH);\r\n            delay(250);\r\n            digitalWrite(LED1, LOW);\r\n            delay(250); \r\n        }\r\n        \/* Give only semaphore countingSem *\/\r\n        xSemaphoreGive(countingSem);\r\n        delay(200); \/\/ Short delay is needed!\r\n    }\r\n}\r\n\r\nvoid blink2(void *pvParameters){\r\n    while(1){\r\n        \/* Take the semaphore, no semaphore (countingSem) will be left *\/\r\n        xSemaphoreTake(countingSem, portMAX_DELAY);\r\n        \/* Take the semaphore countingSem2 if still available *\/\r\n        xSemaphoreTake(countingSem2, portMAX_DELAY);\r\n        Serial.print(\"countingSem2 left: \");\r\n        Serial.println(uxSemaphoreGetCount(countingSem2));\r\n\r\n        for(int i=0; i&lt;10; i++){\r\n            digitalWrite(LED2, HIGH);\r\n            delay(333);\r\n            digitalWrite(LED2, LOW);\r\n            delay(333);   \r\n        }\r\n        \/* Give only semaphore countingSem *\/\r\n        xSemaphoreGive(countingSem);\r\n        delay(200);  \/\/&nbsp;Short&nbsp;delay&nbsp;is&nbsp;needed!\r\n    }\r\n}\r\n\r\nvoid loop(){}<\/pre>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_semaphores_count_I.ino\" data-enlighter-title=\"freertos_avr_semaphores_count_I.ino\">#include &lt;Arduino_FreeRTOS.h&gt;\r\n#include &lt;semphr.h&gt;\r\n#define LED1 7\r\n#define LED2 8\r\n\r\nSemaphoreHandle_t countingSem; \/\/ Create handle \r\nSemaphoreHandle_t countingSem2; \r\n\r\nvoid setup() {\r\n    Serial.begin(115200);\r\n\r\n    countingSem = xSemaphoreCreateCounting(1,1); \/\/ Create counting semaphore\r\n    countingSem2 = xSemaphoreCreateCounting(4,4); \/\/ Create second counting semaphore \r\n\r\n    Serial.print(\"countingSem2 left: \");\r\n    Serial.println(uxSemaphoreGetCount(countingSem2));\r\n    \r\n    xTaskCreate(\r\n        blink1,     \/\/ Function name of the task\r\n        \"Blink 1\",  \/\/ Name of the task (e.g. for debugging)\r\n        128,        \/\/ Stack size (bytes)\r\n        NULL,       \/\/ Parameter to pass\r\n        1,          \/\/ Task priority\r\n        NULL        \/\/ Task handle\r\n    );\r\n    \r\n    xTaskCreate(\r\n        blink2,     \/\/ Function name of the task\r\n        \"Blink 2\",  \/\/ Name of the task (e.g. for debugging)\r\n        128,        \/\/ Stack size (bytes)\r\n        NULL,       \/\/ Parameter to pass\r\n        1,          \/\/ Task priority\r\n        NULL        \/\/ Task handle\r\n    );\r\n}\r\n\r\nvoid blink1(void *pvParameters){\r\n    pinMode(LED1, OUTPUT);\r\n    while(1){\r\n        \/* Take the semaphore, no semaphore (countingSem) will be left *\/\r\n        xSemaphoreTake(countingSem, portMAX_DELAY);\r\n        \/* Take the semaphore countingSem2 if still available *\/\r\n        xSemaphoreTake(countingSem2, portMAX_DELAY);\r\n        Serial.print(\"countingSem2 left: \");\r\n        Serial.println(uxSemaphoreGetCount(countingSem2));\r\n        \r\n        for(int i=0; i&lt;10; i++){\r\n            digitalWrite(LED1, HIGH);\r\n            delay(250);\r\n            digitalWrite(LED1, LOW);\r\n            delay(250);\r\n        }\r\n        \/* Give only semaphore countingSem *\/\r\n        xSemaphoreGive(countingSem);\r\n        delay(200);  \/\/ Short delay is needed!\r\n    }\r\n}\r\n\r\nvoid blink2(void *pvParameters){\r\n    pinMode(LED2, OUTPUT);\r\n    while(1){\r\n        \/* Take the semaphore, no semaphore (countingSem) will be left *\/\r\n        xSemaphoreTake(countingSem, portMAX_DELAY);\r\n        \/* Take the semaphore countingSem2 if still available *\/\r\n        xSemaphoreTake(countingSem2, portMAX_DELAY);\r\n        Serial.print(\"countingSem2 left: \");\r\n        Serial.println(uxSemaphoreGetCount(countingSem2));\r\n\r\n        for(int i=0; i&lt;10; i++){\r\n            digitalWrite(LED2, HIGH);\r\n            delay(333);\r\n            digitalWrite(LED2, LOW);\r\n            delay(333);   \r\n        }\r\n        \/* Give only semaphore countingSem *\/\r\n        xSemaphoreGive(countingSem);\r\n        delay(200);  \/\/&nbsp;Short&nbsp;delay&nbsp;is&nbsp;needed!\r\n    }\r\n}\r\n\r\nvoid loop(){}<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div>\r\n\n<p>A little tip: If you no longer need tasks after running them x times, you should delete them with <code>vTaskDelete( taskHandle )<\/code> so that you release the memory space. I have refrained from doing this in the example to focus on the essentials.<\/p>\r\n\n<h3 class=\"wp-block-heading\">Counting Semaphores &#8211; Example sketch II<\/h3>\n\n<p>In the second example sketch, we let four LEDs flash, but limit the number of LEDs that can flash simultaneously to two. We realize this with a counting semaphore, which we set to uxMaxCount = 2.<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_semaphores_count_II.ino\" data-enlighter-title=\"freertos_esp32_semaphores_count_II.ino\">#define LED1 25\r\n#define LED2 26\r\n#define LED3 17\r\n#define LED4 18\r\nSemaphoreHandle_t countingSem; \/\/ Create semaphore handle\r\n\r\nvoid setup() {\r\n    countingSem = xSemaphoreCreateCounting(2,2); \/\/ Create counting semaphore\r\n   \r\n    xTaskCreate(blink1, \"Blink 1\", 2048, NULL, 1, NULL); \r\n    xTaskCreate(blink2, \"Blink 2\", 2048, NULL, 1, NULL);\r\n    xTaskCreate(blink3, \"Blink 3\", 2048, NULL, 1, NULL);\r\n    xTaskCreate(blink4, \"Blink 4\", 2048, NULL, 1, NULL);   \r\n}\r\n\r\nvoid blink1(void *parameter){\r\n    pinMode(LED1, OUTPUT);\r\n    while(1){\r\n        \/* Take a semaphore if available *\/\r\n        xSemaphoreTake(countingSem, portMAX_DELAY); \r\n        for(int i=0; i&lt;10; i++){\r\n            digitalWrite(LED1, HIGH);\r\n            delay(250); \r\n            digitalWrite(LED1, LOW);\r\n            delay(250); \r\n        }\r\n        \/* Release the semaphore *\/\r\n        xSemaphoreGive(countingSem);\r\n        delay(200); \/\/ Short delay is needed\r\n    }\r\n}\r\n\r\nvoid blink2(void *parameter){\r\n    pinMode(LED2, OUTPUT);\r\n    while(1){\r\n        \/* Take a semaphore if available *\/\r\n        xSemaphoreTake(countingSem, portMAX_DELAY);\r\n        for(int i=0; i&lt;10; i++){\r\n            digitalWrite(LED2, HIGH);\r\n            delay(333);\r\n            digitalWrite(LED2, LOW);\r\n            delay(333);   \r\n        }\r\n        \/* Release the semaphore *\/\r\n        xSemaphoreGive(countingSem);\r\n        delay(200); \/\/ Short delay is needed\r\n    }\r\n}\r\n\r\nvoid blink3(void *parameter){\r\n    pinMode(LED3, OUTPUT);\r\n    while(1){\r\n        \/* Take a semaphore if available *\/\r\n        xSemaphoreTake(countingSem, portMAX_DELAY);\r\n        for(int i=0; i&lt;10; i++){\r\n            digitalWrite(LED3, HIGH);\r\n            delay(123);\/\/delay(333);\r\n            digitalWrite(LED3, LOW);\r\n            delay(123);   \r\n        }\r\n        \/* Release the semaphore *\/\r\n        xSemaphoreGive(countingSem);\r\n        delay(200); \/\/ Short delay is needed\r\n    }\r\n}\r\n\r\nvoid blink4(void *parameter){\r\n    pinMode(LED4, OUTPUT);\r\n    while(1){\r\n        \/* Take a semaphore if available *\/\r\n        xSemaphoreTake(countingSem, portMAX_DELAY);\r\n        for(int i=0; i&lt;10; i++){\r\n            digitalWrite(LED4, HIGH);\r\n            delay(444);\/\/delay(333);\r\n            digitalWrite(LED4, LOW);\r\n            delay(444);   \r\n        }\r\n        \/* Release the semaphore *\/\r\n        xSemaphoreGive(countingSem);\r\n        delay(200); \/\/ Short delay is needed\r\n    }\r\n}\r\n\r\nvoid loop(){}<\/pre>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_semaphores_count_II.ino\" data-enlighter-title=\"freertos_avr_semaphores_count_II.ino\">#include &lt;Arduino_FreeRTOS.h&gt;\r\n#include &lt;semphr.h&gt;\r\n#define LED1 7\r\n#define LED2 8\r\n#define LED3 9\r\n#define LED4 10\r\nSemaphoreHandle_t countingSem; \/\/ Create semaphore handle\r\n\r\nvoid setup() {\r\n    countingSem = xSemaphoreCreateCounting(2,2); \/\/ Create counting semaphore\r\n   \r\n    xTaskCreate(blink1, \"Blink 1\", 128, NULL, 1, NULL); \r\n    xTaskCreate(blink2, \"Blink 2\", 128, NULL, 1, NULL);\r\n    xTaskCreate(blink3, \"Blink 3\", 128, NULL, 1, NULL);\r\n    xTaskCreate(blink4, \"Blink 4\", 128, NULL, 1, NULL);   \r\n}\r\n\r\nvoid blink1(void *parameter){\r\n    pinMode(LED1, OUTPUT);\r\n    while(1){\r\n        \/* Take a semaphore if available *\/\r\n        xSemaphoreTake(countingSem, portMAX_DELAY); \r\n        for(int i=0; i&lt;10; i++){\r\n            digitalWrite(LED1, HIGH);\r\n            delay(250); \r\n            digitalWrite(LED1, LOW);\r\n            delay(250); \r\n        }\r\n        \/* Release the semaphore *\/\r\n        xSemaphoreGive(countingSem);\r\n        delay(200); \/\/ Short delay is needed\r\n    }\r\n}\r\n\r\nvoid blink2(void *parameter){\r\n    pinMode(LED2, OUTPUT);\r\n    while(1){\r\n        \/* Take a semaphore if available *\/\r\n        xSemaphoreTake(countingSem, portMAX_DELAY);\r\n        for(int i=0; i&lt;10; i++){\r\n            digitalWrite(LED2, HIGH);\r\n            delay(333);\/\/delay(333);\r\n            digitalWrite(LED2, LOW);\r\n            delay(333);   \r\n        }\r\n        \/* Release the semaphore *\/\r\n        xSemaphoreGive(countingSem);\r\n        delay(200); \/\/ Short delay is needed\r\n    }\r\n}\r\n\r\nvoid blink3(void *parameter){\r\n    pinMode(LED3, OUTPUT);\r\n    while(1){\r\n        \/* Take a semaphore if available *\/\r\n        xSemaphoreTake(countingSem, portMAX_DELAY);\r\n        for(int i=0; i&lt;10; i++){\r\n            digitalWrite(LED3, HIGH);\r\n            delay(123);\/\/delay(333);\r\n            digitalWrite(LED3, LOW);\r\n            delay(123);   \r\n        }\r\n         \/* Release the semaphore *\/\r\n        xSemaphoreGive(countingSem);\r\n        delay(200); \/\/ Short delay is needed\r\n    }\r\n}\r\n\r\nvoid blink4(void *parameter){\r\n    pinMode(LED4, OUTPUT);\r\n    while(1){\r\n        \/* Take a semaphore if available *\/\r\n        xSemaphoreTake(countingSem, portMAX_DELAY);\r\n        for(int i=0; i&lt;10; i++){\r\n            digitalWrite(LED4, HIGH);\r\n            delay(444);\/\/delay(333);\r\n            digitalWrite(LED4, LOW);\r\n            delay(444);   \r\n        }\r\n         \/* Release the semaphore *\/\r\n        xSemaphoreGive(countingSem);\r\n        delay(200); \/\/ Short delay is needed\r\n    }\r\n}\r\n\r\nvoid loop(){}<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div>\r\n\n<h3 class=\"wp-block-heading\" id=\"mutex\">Mutex Objects<\/h3>\n\n<p>Once you have understood the binary and counting semaphores, the mutex objects are no longer a challenge for you. You create a mutex with <code>xSemaphoreCreateMutex()<\/code>. Otherwise, you deal with it in the same way as you are used to with semaphores. The mutex does not have to be made available via <code>xSemaphoreGive()<\/code>. In this respect, it behaves similarly to a counting semaphore that you create with <code>xSemaphorCreateCounting(1,1)<\/code>.&nbsp;<\/p>\r\n<p>Another interesting feature is that you can use <code>xSemaphoreGetMutexHolder()<\/code> to find out which task currently owns the mutex. There is no such function for the semaphore.<\/p>\r\n<p>Here is an example sketch that illustrates the close relationship to the semaphore.<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_mutex.ino\" data-enlighter-title=\"freertos_esp32_mutex.ino\">#define LED1 25\r\n#define LED2 26\r\n\r\nSemaphoreHandle_t mutex; \/\/ Create handle\r\n\r\nvoid setup() {\r\n    mutex = xSemaphoreCreateMutex(); \/\/Create the mutex object\r\n         \r\n    xTaskCreate(\r\n        blink1,      \/\/ Function name of the task\r\n        \"Blink 1\",   \/\/ Name of the task (e.g. for debugging)\r\n        2048,        \/\/ Stack size (bytes)\r\n        NULL,        \/\/ Parameter to pass\r\n        1,           \/\/ Task priority\r\n        NULL         \/\/ Task handle\r\n    );\r\n\r\n    xTaskCreate(\r\n        blink2,     \/\/ Function name of the task\r\n        \"Blink 2\",  \/\/ Name of the task (e.g. for debugging)\r\n        2048,       \/\/ Stack size (bytes)\r\n        NULL,       \/\/ Parameter to pass\r\n        1,          \/\/ Task priority\r\n        NULL        \/\/ Task handle\r\n    );\r\n}\r\n\r\nvoid blink1(void *pvParameters){\r\n    pinMode(LED1, OUTPUT);\r\n    while(1){\r\n        xSemaphoreTake(mutex,portMAX_DELAY); \/\/ Take the mutex\r\n        for(int i=0; i&lt;10; i++){\r\n            digitalWrite(LED1, HIGH);\r\n            delay(250);  \r\n            digitalWrite(LED1, LOW);\r\n            delay(250); \r\n        }\r\n        xSemaphoreGive(mutex); \/\/ Releases the mutex\r\n        delay(200); \/\/ Short delay is needed!\r\n    }\r\n}\r\n\r\nvoid blink2(void *pvParameters){\r\n    pinMode(LED2, OUTPUT);\r\n    while(1){\r\n        xSemaphoreTake(mutex,portMAX_DELAY); \/\/ Take the mutex\r\n        for(int i=0; i&lt;10; i++){\r\n            digitalWrite(LED2, HIGH);\r\n            delay(333);\r\n            digitalWrite(LED2, LOW);\r\n            delay(333);   \r\n        }\r\n        xSemaphoreGive(mutex); \/\/ \/\/ Release the mutex\r\n        delay(200); \/\/&nbsp;Short&nbsp;delay&nbsp;is&nbsp;needed!\r\n    }\r\n}\r\n\r\nvoid loop(){}<\/pre>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_mutex.ino\" data-enlighter-title=\"freertos_avr_mutex.ino\">#include &lt;Arduino_FreeRTOS.h&gt;\r\n#include &lt;semphr.h&gt;\r\n#define LED1 7\r\n#define LED2 8\r\n\r\nSemaphoreHandle_t mutex;\r\n\r\nvoid setup() {\r\n    mutex = xSemaphoreCreateMutex();\r\n         \r\n    xTaskCreate(\r\n        blink1,      \/\/ Function name of the task\r\n        \"Blink 1\",   \/\/ Name of the task (e.g. for debugging)\r\n        128,         \/\/ Stack size (bytes)\r\n        NULL,        \/\/ Parameter to pass\r\n        1,           \/\/ Task priority\r\n        NULL         \/\/ Task handle\r\n    );\r\n    \r\n    xTaskCreate(\r\n        blink2,     \/\/ Function name of the task\r\n        \"Blink 2\",  \/\/ Name of the task (e.g. for debugging)\r\n        128,        \/\/ Stack size (bytes)\r\n        NULL,       \/\/ Parameter to pass\r\n        1,          \/\/ Task priority\r\n        NULL        \/\/ Task handle\r\n    );\r\n}\r\n\r\nvoid blink1(void *pvParameters){\r\n    pinMode(LED1, OUTPUT);\r\n    while(1){\r\n        xSemaphoreTake(mutex,portMAX_DELAY);\r\n        for(int i=0; i&lt;10; i++){\r\n            digitalWrite(LED1, HIGH);\r\n            delay(250);  \r\n            digitalWrite(LED1, LOW);\r\n            delay(250); \r\n        }\r\n        xSemaphoreGive(mutex);\r\n        delay(200); \/\/ Short delay is needed!\r\n    }\r\n}\r\n\r\nvoid blink2(void *pvParameters){\r\n    pinMode(LED2, OUTPUT);\r\n    while(1){\r\n        xSemaphoreTake(mutex,portMAX_DELAY);\r\n        for(int i=0; i&lt;10; i++){\r\n            digitalWrite(LED2, HIGH);\r\n            delay(333);\r\n            digitalWrite(LED2, LOW);\r\n            delay(333);   \r\n        }\r\n        xSemaphoreGive(mutex);\r\n        delay(200); \/\/\/&nbsp;Short&nbsp;delay&nbsp;is&nbsp;needed!\r\n    }\r\n}\r\n\r\nvoid loop(){}<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div>\r\n\n<h2 class=\"wp-block-heading\" id=\"passing_parameters\">Passing parameters to tasks<\/h2>\n\n<h3 class=\"wp-block-heading\" id=\"pv_parameters\">One-time Passing as *pvParameters<\/h3>\n\n<p>We have not yet used one of the parameters of <code>xCreateTask()<\/code>, namely <code>*pvParameters<\/code>. We want to change that now. <code>*pvParameters<\/code> allows us to pass parameters to the task to be created. It is in the nature of things that we can only use this access once, namely when creating the task.<\/p>\r\n<p>In the example sketches, we have used blink task functions that differ only in the flashing period and the LED to be controlled. This is where parameter passing can help us to streamline the code. However, we have to juggle a little with pointers.<\/p>\r\n<p>We play this out in a simple sketch. First, let&#8217;s take a look at the code.<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_passing_parameters.ino\" data-enlighter-title=\"freertos_esp32_passing_parameters.ino\">#define LED1 25\r\n#define LED2 26\r\n\r\nstruct genericBlink{\r\n    int pin;\r\n    int period;\r\n};\r\n\r\ngenericBlink ledBlink1 = {LED1, 500};\r\ngenericBlink ledBlink2 = {LED2, 333};\r\n\r\nvoid setup() {\r\n    xTaskCreate(\r\n        &amp;blink,      \/\/ Function name of the task\r\n        \"Blink 1\",   \/\/ Name of the task (e.g. for debugging)\r\n        2048,        \/\/ Stack size (bytes)\r\n        (void*) &amp;ledBlink1,  \/\/ Parameter to pass\r\n        1,           \/\/ Task priority\r\n        NULL         \/\/ Task handle\r\n    );\r\n    xTaskCreate(\r\n        &amp;blink,      \/\/ Function name of the task\r\n        \"Blink 2\",   \/\/ Name of the task (e.g. for debugging)\r\n        2048,        \/\/ Stack size (bytes)\r\n        (void*) &amp;ledBlink2,  \/\/ Parameter to pass\r\n        1,           \/\/ Task priority\r\n        NULL         \/\/ Task handle\r\n    );\r\n\r\n}\r\n\r\nvoid blink(void *ledx){\r\n    genericBlink *ledBlink = (genericBlink *) ledx;\r\n    pinMode(ledBlink-&gt;pin, OUTPUT);\r\n    while(1){\r\n        digitalWrite(ledBlink-&gt;pin, HIGH);\r\n        delay(ledBlink-&gt;period);\r\n        digitalWrite(ledBlink-&gt;pin, LOW);\r\n        delay(ledBlink-&gt;period);\r\n    }\r\n}\r\n\r\n\/\/ void blink(void *ledx){\r\n\/\/     genericBlink ledBlink = *(genericBlink *) ledx;\r\n\/\/     pinMode(ledBlink.pin, OUTPUT);\r\n\/\/     while(1){\r\n\/\/         digitalWrite(ledBlink.pin, HIGH);\r\n\/\/         delay(ledBlink.period);\r\n\/\/         digitalWrite(ledBlink.pin, LOW);\r\n\/\/         delay(ledBlink.period);\r\n\/\/     }\r\n\/\/ }\r\n\r\nvoid loop(){}<\/pre>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_passing_parameters.ino\" data-enlighter-title=\"freertos_avr_passing_parameters.ino\">#include&lt;Arduino_FreeRTOS.h&gt;\r\n#define LED1 7\r\n#define LED2 8\r\n\r\nstruct genericBlink{\r\n    int pin;\r\n    int period;\r\n};\r\n\r\ngenericBlink ledBlink1 = {LED1, 500};\r\ngenericBlink ledBlink2 = {LED2, 333};\r\n\r\nvoid setup() {\r\n    xTaskCreate(\r\n        &amp;blink,      \/\/ Function name of the task\r\n        \"Blink 1\",   \/\/ Name of the task (e.g. for debugging)\r\n        128,        \/\/ Stack size (bytes)\r\n        (void*) &amp;ledBlink1,  \/\/ Parameter to pass\r\n        1,           \/\/ Task priority\r\n        NULL         \/\/ Task handle\r\n    );\r\n    xTaskCreate(\r\n        &amp;blink,      \/\/ Function name of the task\r\n        \"Blink 2\",   \/\/ Name of the task (e.g. for debugging)\r\n        128,        \/\/ Stack size (bytes)\r\n        (void*) &amp;ledBlink2,  \/\/ Parameter to pass\r\n        1,           \/\/ Task priority\r\n        NULL         \/\/ Task handle\r\n    );\r\n\r\n}\r\n\r\nvoid blink(void *ledx){\r\n    genericBlink *ledBlink = (genericBlink *) ledx;\r\n    pinMode(ledBlink-&gt;pin, OUTPUT);\r\n    while(1){\r\n        digitalWrite(ledBlink-&gt;pin, HIGH);\r\n        delay(ledBlink-&gt;period);\r\n        digitalWrite(ledBlink-&gt;pin, LOW);\r\n        delay(ledBlink-&gt;period);\r\n    }\r\n}\r\n\r\n\/\/ void blink(void *ledx){\r\n\/\/     genericBlink ledBlink = *(genericBlink *) ledx;\r\n\/\/     pinMode(ledBlink.pin, OUTPUT);\r\n\/\/     while(1){\r\n\/\/         digitalWrite(ledBlink.pin, HIGH);\r\n\/\/         delay(ledBlink.period);\r\n\/\/         digitalWrite(ledBlink.pin, LOW);\r\n\/\/         delay(ledBlink.period);\r\n\/\/     }\r\n\/\/ }\r\n\r\nvoid loop(){}<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div>\r\n\n<h4 class=\"wp-block-heading\">Explanations to the sketch<\/h4>\n\n<p>Arrays or structures (struct) can be used to pass data as pointers. Structures are the method of choice if several parameters of different data types are to be passed. In our example sketch, we define a &#8220;genericBlink&#8221; structure that contains the LED (pin) and the flashing period. The variables ledBlink1 and ledBlink2 are implementations of this structure. ledBlink1 and ledBlink2 are passed to the tasks in <code>xCreateTask()<\/code> as a reference, i.e. with the preceding <code>&amp;<\/code>.<\/p>\r\n<p>The advantage of passing parameters is that we can limit ourselves to just one blink function.<\/p>\r\n<p>The blink function does not &#8220;know&#8221; which data type the pointer <code>*ledx<\/code> represents. Through the line:<\/p>\r\n<p><code>genericBlink *ledBlink = (genericBlink *) ledx;<\/code><\/p>\r\n<p>we create the pointer ledBlink from the undefined pointer ledx. For ledBlink, the function knows that it points to a structure of the type genericBlink. This allows us to access the elements of the structure. However, since ledBlink is not the structure itself, but only the pointer to the structure, the access is indirect, and we must therefore use the arrow operator <code>-&gt;<\/code> instead of the dot operator.<\/p>\r\n<p>The alternative would be to create a copy of the structure (which costs more memory). I have shown this in the commented-out lines of the example sketch. In this case, the pointer must be dereferenced using <code>*<\/code>:<\/p>\r\n<p><code>genericBlink ledBlink = *(genericBlink *) ledx;<\/code><\/p>\r\n<p>Enough of the pointers at this point. If you would like to know more about the topic, take a look <a href=\"https:\/\/wolles-elektronikkiste.de\/en\/pointers-and-references\" target=\"_blank\" rel=\"noopener\">here<\/a>, for example.<\/p>\r\n\n<h3 class=\"wp-block-heading\" id=\"queues\">Passing Parameters with Queues <\/h3>\n\n<h4 class=\"wp-block-heading\">Passing Simple Data Types with Queues<\/h4>\n\n<p>If tasks are to exchange data during their runtime, you have to use so-called queues. Let&#8217;s take a look at this using a simple, rather pointless example. We are creating two tasks for this. One task determines the time period since the program was started and communicates it to the other task, which then displays it on the screen.<\/p>\r\n<p>Four new elements and functions are used:<\/p>\r\n<ul>\r\n<li><code>QueueHandle_t xQueue<\/code>:&nbsp; generates the queue handle <code>xQueue<\/code>.<\/li>\r\n<li><code>xQueueCreate(uxQueueLength, uxItemSize)<\/code>:&nbsp; creates a queue. <code>uxQueueLength<\/code> is the maximum number of elements to be sent. <code>uxItemSize<\/code> defines the size of the individual elements in bytes.<\/li>\r\n<li><code>xQueueSend(xQueue, *pvItemToQueue, xTicksToWait)<\/code>:&nbsp; sends the queue. Here, <code>xQueue<\/code> is the queue handle and <code>*pvItemToQueue<\/code> is the pointer to the data to be sent. <code>xTicksToWait<\/code> is the maximum time in ticks that the task should wait to get sending time &#8211; or even more figuratively: to get a place in the queue.<\/li>\r\n<li><code>xQueueReceive(xQueue, *pvBuffer, xTicksToWait)<\/code>:&nbsp; receives the queue with the handle <code>xQueue<\/code>. <code>*pvBuffer<\/code> is the pointer to the address to which the data is copied. <code>xTicksToWait<\/code> is the maximum time in ticks that the receiving task should wait until it receives data.<\/li>\r\n<\/ul>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_queue.ino\" data-enlighter-title=\"freertos_esp32_queue.ino\">QueueHandle_t queue1; \/\/ Create handle\r\n\r\nvoid setup() {\r\n    Serial.begin(115200);\r\n    queue1 = xQueueCreate(1, sizeof(unsigned long));  \/\/ Create queue\r\n  \r\n    xTaskCreate(\r\n        measureTime,    \/\/ Function name of the task\r\n        \"Measure Time\", \/\/ Name of the task (e.g. for debugging)\r\n        2048,           \/\/ Stack size (bytes)\r\n        NULL,           \/\/ Parameter to pass\r\n        1,              \/\/ Task priority\r\n        NULL            \/\/ Task handle\r\n    );\r\n    xTaskCreate(\r\n        printTime,    \/\/ Function name of the task\r\n        \"Print time\", \/\/ Name of the task (e.g. for debugging)\r\n        2048,         \/\/ Stack size (bytes)\r\n        NULL,         \/\/ Parameter to pass\r\n        1,            \/\/ Task priority\r\n        NULL          \/\/ Task handle\r\n    );\r\n}\r\n\r\nvoid measureTime(void *pvParameters){\r\n    while(1){\r\n        static unsigned long startTime = millis();\r\n        unsigned long timeSinceStart = (millis() - startTime)\/1000;\r\n        xQueueSend(queue1, &amp;timeSinceStart, 0);  \/\/ Send queue\r\n        delay(100);\r\n    }\r\n}\r\n\r\nvoid printTime(void *pvParameters){\r\n    while(1){\r\n        unsigned long buf;\r\n        xQueueReceive(queue1, &amp;buf, 0); \/\/ Receive queue\r\n        Serial.print(\"Time since start: \");\r\n        Serial.println(buf);\r\n        delay(2000);\r\n    }\r\n}\r\n\r\nvoid loop(){}<\/pre>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_queue.ino\" data-enlighter-title=\"freertos_avr_queue.ino\">#include &lt;Arduino_FreeRTOS.h&gt;\r\n#include &lt;queue.h&gt;\r\n\r\nQueueHandle_t queue1;  \/\/ Create handle\r\n\r\nvoid setup() {\r\n    Serial.begin(9600);\r\n    queue1 = xQueueCreate(1, sizeof(unsigned long));  \/\/ Create queue\r\n  \r\n    xTaskCreate(\r\n        measureTime,    \/\/ Function name of the task\r\n        \"Measure Time\", \/\/ Name of the task (e.g. for debugging)\r\n        128,            \/\/ Stack size (bytes)\r\n        NULL,           \/\/ Parameter to pass\r\n        1,              \/\/ Task priority\r\n        NULL            \/\/ Task handle\r\n    );\r\n    \r\n    xTaskCreate(\r\n        printTime,    \/\/ Function name of the task\r\n        \"Print time\", \/\/ Name of the task (e.g. for debugging)\r\n        128,          \/\/ Stack size (bytes)\r\n        NULL,         \/\/ Parameter to pass\r\n        1,            \/\/ Task priority\r\n        NULL          \/\/ Task handle\r\n    );\r\n}\r\n\r\nvoid measureTime(void *pvParameters){\r\n    while(1){\r\n        static unsigned long startTime = millis();\r\n        unsigned long timeSinceStart = (millis() - startTime)\/1000;\r\n        xQueueSend(queue1, &amp;timeSinceStart, 0);  \/\/ Send queue\r\n        delay(100);\r\n    }\r\n}\r\n\r\nvoid printTime(void *pvParameters){\r\n    while(1){\r\n        unsigned long buf;\r\n        xQueueReceive(queue1, &amp;buf, 0);  \/\/ Receive queue\r\n        Serial.print(\"Time since start: \");\r\n        Serial.println(buf);\r\n        delay(2000);\r\n    }\r\n}\r\n\r\nvoid loop(){}<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div>\r\n\n<p>I don&#8217;t think the sketch needs much explanation, do you? Again, please note that the data is sent or received as a pointer, so please remember the <code>&amp;<\/code> operators. And just try out what happens if you set <code>delay()<\/code> in <code>measureTime()<\/code> to 10000, for example. In a second step, you could also set <code>xTicksToWait<\/code> in <code>printTime()<\/code> to 15000. <\/p>\r\n\n<h4 class=\"wp-block-heading\">Passing structures with queues<\/h4>\n\n<p>As the last point of this FreeRTOS introduction, we will look at passing a structure to a task. In the example, the structure consists of the result of a <code>analogRead()<\/code> (i.e. some imaginary sensor measurement) and the time of the measurement.<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_struct_queue.ino\" data-enlighter-title=\"freertos_esp32_struct_queue.ino\">#define SENSOR_PIN 34\r\n\r\nQueueHandle_t queue1;  \/\/ Create handle\r\n\r\nstruct dataPack{    \/\/ define struct for the variables to be sent\r\n    unsigned long sensorTime;\r\n    int sensorValue;\r\n};\r\n\r\nvoid setup() {\r\n    Serial.begin(115200);\r\n    queue1 = xQueueCreate(1, sizeof(dataPack));  \/\/ Create queue\r\n    \r\n    xTaskCreate(\r\n        getSensorData,      \/\/ Function name of the task\r\n        \"Get Sensor Data\",  \/\/ Name of the task (e.g. for debugging)\r\n        2048,               \/\/ Stack size (bytes)\r\n        NULL,               \/\/ Parameter to pass\r\n        1,                  \/\/ Task priority\r\n        NULL                \/\/ Task handle\r\n    );\r\n    xTaskCreate(\r\n        printSensor,        \/\/ Function name of the task\r\n        \"Print sensor\",     \/\/ Name of the task (e.g. for debugging)\r\n        2048,               \/\/ Stack size (bytes)\r\n        NULL, \/\/ Parameter to pass\r\n        1,                  \/\/ Task priority\r\n        NULL                \/\/ Task handle\r\n    );\r\n}\r\n\r\nvoid getSensorData(void *pvParameters){\r\n    static unsigned long startTime = millis();\r\n    while(1){\r\n        dataPack sensorData = {0,0};\r\n        sensorData.sensorTime = (millis() - startTime)\/1000;\r\n        sensorData.sensorValue = (analogRead(SENSOR_PIN));\r\n        xQueueSend(queue1, &amp;sensorData, 0);  \/\/ Send queue\r\n        delay(500);\r\n    }\r\n}\r\n\r\nvoid printSensor(void *pvParameters){\r\n    while(1){\r\n        dataPack currentData;\r\n        xQueueReceive(queue1, &amp;currentData,0); \/\/ Receive queue\r\n        Serial.print(\"Time: \");\r\n        Serial.println(currentData.sensorTime);\r\n        Serial.print(\"Value: \");\r\n        Serial.println(currentData.sensorValue);\r\n        delay(2000);\r\n    }\r\n}\r\n\r\nvoid loop(){}<\/pre>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"freertos_struct_queue.ino\" data-enlighter-title=\"freertos_avr_struct_queue.ino\">#include &lt;Arduino_FreeRTOS.h&gt;\r\n#include &lt;queue.h&gt;\r\n#define SENSOR_PIN A0\r\n\r\nQueueHandle_t queue1;  \/\/ Create handle\r\n\r\nstruct dataPack{  \/\/ Create struct for the data to be sent\r\n    unsigned long sensorTime;\r\n    int sensorValue;\r\n};\r\n\r\nvoid setup() {\r\n    Serial.begin(9600);\r\n    queue1 = xQueueCreate(1, sizeof(dataPack)); \/\/ Create queue\r\n    \r\n    xTaskCreate(\r\n        getSensorData,     \/\/ Function name of the task\r\n        \"Get Sensor Data\", \/\/ Name of the task (e.g. for debugging)\r\n        128,               \/\/ Stack size (bytes)\r\n        NULL,              \/\/ Parameter to pass\r\n        1,                 \/\/ Task priority\r\n        NULL               \/\/ Task handle\r\n    );\r\n    \r\n    xTaskCreate(\r\n        printSensor,       \/\/ Function name of the task\r\n        \"Print sensor\",    \/\/ Name of the task (e.g. for debugging)\r\n        128,               \/\/ Stack size (bytes)\r\n        NULL, \/\/ Parameter to pass\r\n        1,                 \/\/ Task priority\r\n        NULL               \/\/ Task handle\r\n    );\r\n}\r\n\r\nvoid getSensorData(void *pvParameters){\r\n    while(1){\r\n        static unsigned long startTime = millis();\r\n        dataPack sensorData = {0,0};\r\n        sensorData.sensorTime = (millis() - startTime)\/1000;\r\n        sensorData.sensorValue = (analogRead(SENSOR_PIN));\r\n        xQueueSend(queue1, &amp;sensorData, 0); \/\/ Send queue\r\n        delay(500);\r\n    }\r\n}\r\n\r\nvoid printSensor(void *pvParameters){\r\n    while(1){\r\n        dataPack currentData;\r\n        xQueueReceive(queue1, &amp;currentData, 0);  \/\/ Receive queue\r\n        Serial.print(\"Time: \");\r\n        Serial.println(currentData.sensorTime);\r\n        Serial.print(\"Value: \");\r\n        Serial.println(currentData.sensorValue);\r\n        delay(2000);\r\n    }\r\n}\r\n\r\nvoid loop(){}<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div>\r\n\n<p>The sketch should not really need any further explanation.<\/p>\r\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>FreeRTOS is a real-time system, with which multitasking can also be realized on relatively small MCUs. This article is an introduction to the topic, whereby I will limit myself to the ESP32 and the AVR-based Arduinos.<\/p>\n","protected":false},"author":1,"featured_media":19826,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[575],"tags":[556,2295,1726,2305,2306,2307,1044,2293,2298,691,2299,2294,2304,1995,2309,2301,2303,2300,2311,2297,2310,2308,2296,2302],"class_list":["post-19877","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-software-and-tools","tag-arduino-en-2","tag-arduino_freertos-en","tag-avr-en","tag-binary-semaphores-en","tag-binary-semaphores-en-2","tag-counting-semaphores-en","tag-esp32-en","tag-freertos-en","tag-high-watermark-en","tag-interrupt-en-2","tag-memory-space-requirement","tag-multitasking-en","tag-mutex-en","tag-parameter-passing","tag-queues-en","tag-resume-en","tag-semaphore","tag-suspend-en","tag-task-handle-en","tag-ticks-en","tag-xqueuecreate-en","tag-xsemaphoregivefromisr-en","tag-xtaskcreate-en","tag-xtaskcreatepinnedtocore-en"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Using FreeRTOS with ESP32 and Arduino &#8226; Wolles Elektronikkiste<\/title>\n<meta name=\"description\" content=\"FreeRTOS is a real-time system, with which multitasking can also be realized on relatively small MCUs. An introduction.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/wolles-elektronikkiste.de\/en\/using-freertos-with-esp32-and-arduino\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Using FreeRTOS with ESP32 and Arduino &#8226; Wolles Elektronikkiste\" \/>\n<meta property=\"og:description\" content=\"FreeRTOS is a real-time system, with which multitasking can also be realized on relatively small MCUs. An introduction.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/wolles-elektronikkiste.de\/en\/using-freertos-with-esp32-and-arduino\" \/>\n<meta property=\"og:site_name\" content=\"Wolles Elektronikkiste\" \/>\n<meta property=\"article:published_time\" content=\"2024-01-05T19:01:33+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-01-06T10:33:29+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2024\/01\/multitasking-1.webp\" \/>\n\t<meta property=\"og:image:width\" content=\"1000\" \/>\n\t<meta property=\"og:image:height\" content=\"1000\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/webp\" \/>\n<meta name=\"author\" content=\"Wolfgang Ewald\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Wolfgang Ewald\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"41 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/using-freertos-with-esp32-and-arduino#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/using-freertos-with-esp32-and-arduino\"},\"author\":{\"name\":\"Wolfgang Ewald\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#\\\/schema\\\/person\\\/b774e4d64b4766889a2f7c6e5ec85b46\"},\"headline\":\"Using FreeRTOS with ESP32 and Arduino\",\"datePublished\":\"2024-01-05T19:01:33+00:00\",\"dateModified\":\"2024-01-06T10:33:29+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/using-freertos-with-esp32-and-arduino\"},\"wordCount\":3645,\"commentCount\":8,\"publisher\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#\\\/schema\\\/person\\\/b774e4d64b4766889a2f7c6e5ec85b46\"},\"image\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/using-freertos-with-esp32-and-arduino#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2024\\\/01\\\/multitasking-1.webp\",\"keywords\":[\"Arduino\",\"Arduino_FreeRTOS\",\"AVR\",\"Binary semaphores\",\"binary semaphores\",\"counting semaphores\",\"ESP32\",\"FreeRTOS\",\"high watermark\",\"Interrupt\",\"memory space requirement\",\"multitasking\",\"mutex\",\"parameter passing\",\"queues\",\"resume\",\"semaphore\",\"suspend\",\"task handle\",\"ticks\",\"xQueueCreate\",\"xSemaphoreGiveFromISR\",\"xTaskCreate\",\"xTaskCreatePinnedToCore\"],\"articleSection\":[\"Software and tools\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/using-freertos-with-esp32-and-arduino#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/using-freertos-with-esp32-and-arduino\",\"url\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/using-freertos-with-esp32-and-arduino\",\"name\":\"Using FreeRTOS with ESP32 and Arduino &#8226; Wolles Elektronikkiste\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/using-freertos-with-esp32-and-arduino#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/using-freertos-with-esp32-and-arduino#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2024\\\/01\\\/multitasking-1.webp\",\"datePublished\":\"2024-01-05T19:01:33+00:00\",\"dateModified\":\"2024-01-06T10:33:29+00:00\",\"description\":\"FreeRTOS is a real-time system, with which multitasking can also be realized on relatively small MCUs. An introduction.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/using-freertos-with-esp32-and-arduino#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/using-freertos-with-esp32-and-arduino\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/using-freertos-with-esp32-and-arduino#primaryimage\",\"url\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2024\\\/01\\\/multitasking-1.webp\",\"contentUrl\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2024\\\/01\\\/multitasking-1.webp\",\"width\":1000,\"height\":1000},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/using-freertos-with-esp32-and-arduino#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Startseite\",\"item\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Using FreeRTOS with ESP32 and Arduino\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#website\",\"url\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\",\"name\":\"Wolles Elektronikkiste\",\"description\":\"Die wunderbare Welt der Elektronik\",\"publisher\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#\\\/schema\\\/person\\\/b774e4d64b4766889a2f7c6e5ec85b46\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#\\\/schema\\\/person\\\/b774e4d64b4766889a2f7c6e5ec85b46\",\"name\":\"Wolfgang Ewald\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/cropped-Logo-1.png\",\"url\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/cropped-Logo-1.png\",\"contentUrl\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/cropped-Logo-1.png\",\"width\":512,\"height\":512,\"caption\":\"Wolfgang Ewald\"},\"logo\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/cropped-Logo-1.png\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Using FreeRTOS with ESP32 and Arduino &#8226; Wolles Elektronikkiste","description":"FreeRTOS is a real-time system, with which multitasking can also be realized on relatively small MCUs. An introduction.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/wolles-elektronikkiste.de\/en\/using-freertos-with-esp32-and-arduino","og_locale":"en_US","og_type":"article","og_title":"Using FreeRTOS with ESP32 and Arduino &#8226; Wolles Elektronikkiste","og_description":"FreeRTOS is a real-time system, with which multitasking can also be realized on relatively small MCUs. An introduction.","og_url":"https:\/\/wolles-elektronikkiste.de\/en\/using-freertos-with-esp32-and-arduino","og_site_name":"Wolles Elektronikkiste","article_published_time":"2024-01-05T19:01:33+00:00","article_modified_time":"2024-01-06T10:33:29+00:00","og_image":[{"width":1000,"height":1000,"url":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2024\/01\/multitasking-1.webp","type":"image\/webp"}],"author":"Wolfgang Ewald","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Wolfgang Ewald","Est. reading time":"41 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/wolles-elektronikkiste.de\/en\/using-freertos-with-esp32-and-arduino#article","isPartOf":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/using-freertos-with-esp32-and-arduino"},"author":{"name":"Wolfgang Ewald","@id":"https:\/\/wolles-elektronikkiste.de\/en#\/schema\/person\/b774e4d64b4766889a2f7c6e5ec85b46"},"headline":"Using FreeRTOS with ESP32 and Arduino","datePublished":"2024-01-05T19:01:33+00:00","dateModified":"2024-01-06T10:33:29+00:00","mainEntityOfPage":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/using-freertos-with-esp32-and-arduino"},"wordCount":3645,"commentCount":8,"publisher":{"@id":"https:\/\/wolles-elektronikkiste.de\/en#\/schema\/person\/b774e4d64b4766889a2f7c6e5ec85b46"},"image":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/using-freertos-with-esp32-and-arduino#primaryimage"},"thumbnailUrl":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2024\/01\/multitasking-1.webp","keywords":["Arduino","Arduino_FreeRTOS","AVR","Binary semaphores","binary semaphores","counting semaphores","ESP32","FreeRTOS","high watermark","Interrupt","memory space requirement","multitasking","mutex","parameter passing","queues","resume","semaphore","suspend","task handle","ticks","xQueueCreate","xSemaphoreGiveFromISR","xTaskCreate","xTaskCreatePinnedToCore"],"articleSection":["Software and tools"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/wolles-elektronikkiste.de\/en\/using-freertos-with-esp32-and-arduino#respond"]}]},{"@type":"WebPage","@id":"https:\/\/wolles-elektronikkiste.de\/en\/using-freertos-with-esp32-and-arduino","url":"https:\/\/wolles-elektronikkiste.de\/en\/using-freertos-with-esp32-and-arduino","name":"Using FreeRTOS with ESP32 and Arduino &#8226; Wolles Elektronikkiste","isPartOf":{"@id":"https:\/\/wolles-elektronikkiste.de\/en#website"},"primaryImageOfPage":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/using-freertos-with-esp32-and-arduino#primaryimage"},"image":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/using-freertos-with-esp32-and-arduino#primaryimage"},"thumbnailUrl":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2024\/01\/multitasking-1.webp","datePublished":"2024-01-05T19:01:33+00:00","dateModified":"2024-01-06T10:33:29+00:00","description":"FreeRTOS is a real-time system, with which multitasking can also be realized on relatively small MCUs. An introduction.","breadcrumb":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/using-freertos-with-esp32-and-arduino#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/wolles-elektronikkiste.de\/en\/using-freertos-with-esp32-and-arduino"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/wolles-elektronikkiste.de\/en\/using-freertos-with-esp32-and-arduino#primaryimage","url":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2024\/01\/multitasking-1.webp","contentUrl":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2024\/01\/multitasking-1.webp","width":1000,"height":1000},{"@type":"BreadcrumbList","@id":"https:\/\/wolles-elektronikkiste.de\/en\/using-freertos-with-esp32-and-arduino#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Startseite","item":"https:\/\/wolles-elektronikkiste.de\/en"},{"@type":"ListItem","position":2,"name":"Using FreeRTOS with ESP32 and Arduino"}]},{"@type":"WebSite","@id":"https:\/\/wolles-elektronikkiste.de\/en#website","url":"https:\/\/wolles-elektronikkiste.de\/en","name":"Wolles Elektronikkiste","description":"Die wunderbare Welt der Elektronik","publisher":{"@id":"https:\/\/wolles-elektronikkiste.de\/en#\/schema\/person\/b774e4d64b4766889a2f7c6e5ec85b46"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/wolles-elektronikkiste.de\/en?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/wolles-elektronikkiste.de\/en#\/schema\/person\/b774e4d64b4766889a2f7c6e5ec85b46","name":"Wolfgang Ewald","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/03\/cropped-Logo-1.png","url":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/03\/cropped-Logo-1.png","contentUrl":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/03\/cropped-Logo-1.png","width":512,"height":512,"caption":"Wolfgang Ewald"},"logo":{"@id":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/03\/cropped-Logo-1.png"}}]}},"_links":{"self":[{"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/posts\/19877","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/comments?post=19877"}],"version-history":[{"count":0,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/posts\/19877\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/media\/19826"}],"wp:attachment":[{"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/media?parent=19877"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/categories?post=19877"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/tags?post=19877"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}