{"id":4127,"date":"2025-02-07T21:09:00","date_gmt":"2025-02-07T20:09:00","guid":{"rendered":"https:\/\/msalamon.pl\/?p=4127"},"modified":"2025-12-27T15:17:42","modified_gmt":"2025-12-27T14:17:42","slug":"doing-3-things-at-once-or-how-to-implement-a-software-timer-stm32-on-registers-5","status":"publish","type":"post","link":"https:\/\/msalamon.pl\/en\/doing-3-things-at-once-or-how-to-implement-a-software-timer-stm32-on-registers-5\/","title":{"rendered":"Doing 3 Things at Once, or How to Implement a Software Timer? | STM32 on Registers #5"},"content":{"rendered":"\n<h1 class=\"wp-block-heading\">Doing 3 Things at Once, or How to Implement a Software Timer? | STM32 on Registers #5<\/h1>\n\n\n\n<p>Let\u2019s get to know one of the effective ways not to block the processor\u2019s work by waiting. It will be a <strong>Software Timer<\/strong>. This is an absolute foundation for an embedded programmer. A real ABC.<\/p>\n\n\n\n<p>You can often come across the term <em>multitasking<\/em>. For example, videos explaining the same mechanism on Arduino are often called <strong>multitasking on Arduino<\/strong>. This is <strong>both true and false at the same time<\/strong>.<\/p>\n\n\n\n<p>\ud83d\udc49 <strong>False<\/strong>, because on a processor, more than one task, one instruction cannot happen at the same time. We\u2019re not running two or more tasks simultaneously here.<\/p>\n\n\n\n<p>\ud83d\udc49 So why is it <strong>true <\/strong>and works? It\u2019s about the <strong>illusion of multitasking<\/strong>. Tasks are executed alternately and <strong>at such a fast pace<\/strong> that as humans <strong>we have the impression of simultaneity<\/strong> in their execution. That\u2019s the whole magic.<\/p>\n\n\n\n<p>The art now is to distribute these tasks over time on the processor in such a way that the whole big system gives the impression that all its elements are working simultaneously and correctly. In this series we won\u2019t be building a big system. Today I\u2019ll show you an example of multitasking and non-blocking code<strong> using a few LEDs as an example<\/strong>.<\/p>\n\n\n\n<p><strong>\ud83d\udc49 Do you want to learn STM32 register-level programming in full?<\/strong> I invite you to my full online course (conducted in Polish) on this topic: <a href=\"https:\/\/stm32narejestrach.pl\" target=\"_blank\" rel=\"noopener\">https:\/\/stm32narejestrach.pl<\/a><\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/sklep.msalamon.pl\/produkt\/stm32-nucleo-c031c6-nucleo-32-z-stm32c031c6t6-arm-cortex-m0?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=stm32narejestrach&amp;utm_content=banner\" target=\"_blank\" rel=\"noreferrer noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"341\" src=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/07\/stm32C031C6_BANER-1024x341.jpg\" alt=\"\" class=\"wp-image-2351\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/07\/stm32C031C6_BANER-1024x341.jpg 1024w, https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/07\/stm32C031C6_BANER-300x100.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/07\/stm32C031C6_BANER-768x256.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/07\/stm32C031C6_BANER.jpg 1200w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><\/figure>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">The STM32 on Registers Series on YouTube<\/h2>\n\n\n\n<p>These posts are created in parallel with the series&nbsp;<strong>on my YouTube<\/strong>&nbsp;on the same topic. If you prefer the video version, I invite you there. These articles are a summary of what I show on YouTube.<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"Robienie 3 rzeczy jednocze\u015bnie, czyli jak zrealizowa\u0107 Timer Programowy? | STM32 na Rejestrach #5\" width=\"750\" height=\"422\" src=\"https:\/\/www.youtube.com\/embed\/qgV1tABOhuQ?list=PLMr8JGWm4y7_l6qIVBSePaSQ0vuLWMfGp\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<p><a href=\"https:\/\/www.youtube.com\/watch?v=ShCWoicHkKM&amp;list=PLMr8JGWm4y7_l6qIVBSePaSQ0vuLWMfGp\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>Link to the entire YouTube playlist<\/strong><\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>What is a Software Timer<\/strong>?<\/h2>\n\n\n\n<p>We need to learn something called a Software Timer.<\/p>\n\n\n\n<p>A Software Timer is a programming technique based on checking the elapsed time and unblocking an action if enough of it has passed. It probably doesn\u2019t tell us that much\u2026<\/p>\n\n\n\n<p>Imagine the timeline of our program. If we take zero as the starting point, and we want to perform an action every 500 milliseconds, then at what time values do we have to perform the action?<\/p>\n\n\n\n<p>500, 1000, 1500, 2000, 2500, etc. At those moments and nowhere in between.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"384\" src=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2025\/03\/image-1024x384.png\" alt=\"\" class=\"wp-image-2718\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2025\/03\/image-1024x384.png 1024w, https:\/\/msalamon.pl\/wp-content\/uploads\/2025\/03\/image-300x112.png 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2025\/03\/image-768x288.png 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2025\/03\/image.png 1294w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>If the clock that measures time indicates something else, then we do nothing (or other actions scheduled at a different time). That\u2019s the ideal world. In our non-ideal world, the moment when the running time equals the action time will \u201cunblock\u201d the action to be performed, and we\u2019ll do it at the nearest possible opportunity.<\/p>\n\n\n\n<p>What will be our clock? We already configured it and used it in previous lessons. The <strong>SysTick Timer<\/strong>. It continuously measures our program runtime. In the background it counts every 1 millisecond how much time has already passed. It\u2019s no coincidence it\u2019s called SysTick \u2013 because it\u2019s used to count \u201csystem time\u201d, in other words \u2013 the <strong>time base.<\/strong><\/p>\n\n\n\n<p>So it\u2019s enough to check how much time has passed and compare it with the moments when we want to trigger the action. How do we do that?<\/p>\n\n\n\n<p>From the current global time marked in some way, let\u2019s say with a \u201cmarker\u201d, we wait a defined time interval. For example, those 500 ms from the beginning of the paragraph. If the action execution time \u201chits\u201d, we execute the action and move our \u201cmarker\u201d forward. And so on in a loop.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"384\" src=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2025\/03\/image-1-1024x384.png\" alt=\"\" class=\"wp-image-2719\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2025\/03\/image-1-1024x384.png 1024w, https:\/\/msalamon.pl\/wp-content\/uploads\/2025\/03\/image-1-300x112.png 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2025\/03\/image-1-768x288.png 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2025\/03\/image-1.png 1294w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Still not clear? It will be clearer with the algorithm and code \ud83d\ude42<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Operating algorithm<\/strong> of a Software Timer<\/h2>\n\n\n\n<p>The general operating algorithm can be as follows:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>We create a <strong>variable <\/strong>to remember the current time \u2013 the <strong>\u201cmarker\u201d<\/strong>.<\/li>\n\n\n\n<li>We \u201cfeed\u201d the marker with the current time (the system time, because it is our reference).<\/li>\n\n\n\n<li>We repeat in a loop:\n<ol class=\"wp-block-list\">\n<li>We check whether the <strong>specified interval<\/strong> of time has elapsed<\/li>\n\n\n\n<li>If <strong>yes<\/strong>:\n<ol class=\"wp-block-list\">\n<li>We <strong>execute<\/strong> the planned action<\/li>\n\n\n\n<li>We <strong>overwrite <\/strong>the marker with the current time*<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n\n\n\n<p>* there are several possibilities and moments for how to reload the marker with time. We can do it:<\/p>\n\n\n\n<p>1) <strong>Before the action \/ After the action. <\/strong>Then we decide from which moment we count this \u201cfixed\u201d time interval<\/p>\n\n\n\n<p>2) <strong>Reload with the current time \/ add a constant value.<\/strong> We decide whether the action execution time is included in the waiting time for the next action. A danger here may be that the action execution time will be longer than the interval between subsequent actions.<\/p>\n\n\n\n<p>My favorite method is to reload with the current time before performing the action, and that\u2019s what we\u2019ll do. So far, this method has worked best for me. Maybe another one will suit you? Try it and see. There are no obligations with me \ud83d\ude09<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Software Timer Code<\/strong><\/h2>\n\n\n\n<p>The theory is behind us. So we must <strong>move on to practice<\/strong>. Our exercise will be blinking multiple LEDs at different frequencies.<\/p>\n\n\n\n<p><strong>More LEDs = more pin configuration.<\/strong> Luckily, we can already do that. Let\u2019s connect the LEDs to pins adjacent to the LED on the NUCLEO-C031. LD4, which we blinked, was on PA5. So let\u2019s connect LD5 to PA6 and LD6 to PA7. They are next to each other on the Arduino Uno header. Let\u2019s make sure in the schematic that they aren\u2019t connected to something else.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"837\" height=\"110\" src=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2025\/03\/image-2.png\" alt=\"\" class=\"wp-image-2720\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2025\/03\/image-2.png 837w, https:\/\/msalamon.pl\/wp-content\/uploads\/2025\/03\/image-2-300x39.png 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2025\/03\/image-2-768x101.png 768w\" sizes=\"auto, (max-width: 837px) 100vw, 837px\" \/><\/figure>\n\n\n\n<p>As we can see, these are free pins. They are simply routed to the Arduino header, so we will use them. Connect the microcontroller pins to a resistor of about 330 ohms, and the resistor to the LED cathode. The anode to 3.3V on the Nucleo. The exact schematic is as follows.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"822\" height=\"398\" src=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2025\/03\/image-3.png\" alt=\"\" class=\"wp-image-2721\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2025\/03\/image-3.png 822w, https:\/\/msalamon.pl\/wp-content\/uploads\/2025\/03\/image-3-300x145.png 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2025\/03\/image-3-768x372.png 768w\" sizes=\"auto, (max-width: 822px) 100vw, 822px\" \/><\/figure>\n\n\n\n<p>Now the code. First, we can copy the functions for LD4 and adjust them.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ LEDs control macros\n#define LD4_ON GPIOA-&amp;gt;BSRR = GPIO_BSRR_BS5\n#define LD4_OFF GPIOA-&amp;gt;BSRR = GPIO_BSRR_BR5\n#define LD4_TOGGLE GPIOA-&amp;gt;ODR ^= GPIO_ODR_OD5\n\n#define LD5_ON GPIOA-&amp;gt;BSRR = GPIO_BSRR_BS6\n#define LD5_OFF GPIOA-&amp;gt;BSRR = GPIO_BSRR_BR6\n#define LD5_TOGGLE GPIOA-&amp;gt;ODR ^= GPIO_ODR_OD6\n\n#define LD6_ON GPIOA-&amp;gt;BSRR = GPIO_BSRR_BS7\n#define LD6_OFF GPIOA-&amp;gt;BSRR = GPIO_BSRR_BR7\n#define LD6_TOGGLE GPIOA-&amp;gt;ODR ^= GPIO_ODR_OD7\n\n\/\/ LEDs Configuration\nvoid ConfigureLD4(void);\nvoid ConfigureLD5(void);\nvoid ConfigureLD6(void);\n\nvoid ConfigureLD4(void)\n{\n\t\/\/ Enable Clock for PORTA\n\tRCC-&amp;gt;IOPENR |= RCC_IOPENR_GPIOAEN;\n\n\t\/\/ Configure GPIO Mode - Output\n\tGPIOA-&amp;gt;MODER |= GPIO_MODER_MODE5_0;\n\tGPIOA-&amp;gt;MODER &amp;amp;= ~(GPIO_MODER_MODE5_1);\n\n\t\/\/ Configure Output Mode - Push-pull\n\tGPIOA-&amp;gt;OTYPER &amp;amp;= ~(GPIO_OTYPER_OT5);\n\n\t\/\/ Configure GPIO Speed - Low\n\tGPIOA-&amp;gt;OSPEEDR &amp;amp;= ~(GPIO_OSPEEDR_OSPEED5);\n\n\t\/\/ Configure Pull-up\/Pull-down - no PU\/PD\n\tGPIOA-&amp;gt;PUPDR &amp;amp;= ~(GPIO_PUPDR_PUPD5);\n}\n\nvoid ConfigureLD5(void) \/\/ PA6\n{\n\t\/\/ Enable Clock for PORTA\n\tRCC-&amp;gt;IOPENR |= RCC_IOPENR_GPIOAEN;\n\n\t\/\/ Configure GPIO Mode - Output\n\tGPIOA-&amp;gt;MODER |= GPIO_MODER_MODE6_0;\n\tGPIOA-&amp;gt;MODER &amp;amp;= ~(GPIO_MODER_MODE6_1);\n\n\t\/\/ Configure Output Mode - Push-pull\n\tGPIOA-&amp;gt;OTYPER &amp;amp;= ~(GPIO_OTYPER_OT6);\n\n\t\/\/ Configure GPIO Speed - Low\n\tGPIOA-&amp;gt;OSPEEDR &amp;amp;= ~(GPIO_OSPEEDR_OSPEED6);\n\n\t\/\/ Configure Pull-up\/Pull-down - no PU\/PD\n\tGPIOA-&amp;gt;PUPDR &amp;amp;= ~(GPIO_PUPDR_PUPD6);\n}\n\nvoid ConfigureLD6(void) \/\/ PA7\n{\n\t\/\/ Enable Clock for PORTA\n\tRCC-&amp;gt;IOPENR |= RCC_IOPENR_GPIOAEN;\n\n\t\/\/ Configure GPIO Mode - Output\n\tGPIOA-&amp;gt;MODER |= GPIO_MODER_MODE7_0;\n\tGPIOA-&amp;gt;MODER &amp;amp;= ~(GPIO_MODER_MODE7_1);\n\n\t\/\/ Configure Output Mode - Push-pull\n\tGPIOA-&amp;gt;OTYPER &amp;amp;= ~(GPIO_OTYPER_OT7);\n\n\t\/\/ Configure GPIO Speed - Low\n\tGPIOA-&amp;gt;OSPEEDR &amp;amp;= ~(GPIO_OSPEEDR_OSPEED7);\n\n\t\/\/ Configure Pull-up\/Pull-down - no PU\/PD\n\tGPIOA-&amp;gt;PUPDR &amp;amp;= ~(GPIO_PUPDR_PUPD7);\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Returning the current time<\/strong><\/h3>\n\n\n\n<p>I will call our actions <strong>Tasks<\/strong>. Each Task should execute <strong>at a different interval<\/strong>. So each task will treat time differently. We need <strong>3 variables (\u201cmarkers\u201d)<\/strong> so that each task can <strong>remember its reference point<\/strong>.<\/p>\n\n\n\n<p>The timer variable type should be the same as the type of the variable counting the system time.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Software Timers variables\nuint32_t Timer_LD4;\nuint32_t Timer_LD5;\nuint32_t Timer_LD6;<\/pre>\n\n\n\n<p>We should <strong>load the current time<\/strong> into these variables. But where do we get it from? We could simply assign the Tick variable from the SysTick Timer, but <strong>THAT\u2019S NOT HOW IT\u2019S DONE<\/strong>!<\/p>\n\n\n\n<p>In the future we will split our code into files, so let\u2019s start preparing for that. <strong>We need a function that returns this time to us. <\/strong>We can\u2019t be thinking each time about how we obtain the global time. Because what if we change the method of obtaining it? Will we rummage through the whole program and change every single line? No. It has to be wrapped in a convenient function.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Tick for System Time\n__IO uint32_t Tick;\n\nuint32_t GetSystemTick(void)\n{\n\treturn Tick; \/\/ Return current System Time\n}<\/pre>\n\n\n\n<p>With such a function returning the system time, it will be much easier and correct.<\/p>\n\n\n\n<p>We can use it to feed the initial state of our timer variables. Let\u2019s do it right after configuring the LEDs.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\t\/\/ Configure LEDs\n\tConfigureLD4();\n\tConfigureLD5();\n\tConfigureLD6();\n\n\t\/\/ Software Timers - first fill\n\tTimer_LD4 = GetSystemTick();\n\tTimer_LD5 = GetSystemTick();\n\tTimer_LD6 = GetSystemTick();<\/pre>\n\n\n\n<p>We have<strong> the first marker placement<\/strong>. Let\u2019s first do one task on the LD4 LED we already know. In a blocking way, using Delay, we changed its state every 500 ms.<strong> Let\u2019s now do it non-blocking.<\/strong><\/p>\n\n\n\n<p>First of all, a convenient definition of this waiting time would be useful.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Constants for Software Timer's actions\n#define LD4_TIMER 500<\/pre>\n\n\n\n<p>Having this time, we can finally write the code for the task triggering algorithm.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>We need to check whether the specified amount of time has passed. We compare the difference between the current time and the \u201cmarked\u201d one. If this difference is greater than the required time between actions, we start calling the action.<\/li>\n\n\n\n<li>We can immediately reload the timer, i.e., mark the next reference point on the timeline from which we want the required time to pass before performing our action again. Placing the reload at this point gives us that the start of the action will always be every specified time regardless of how long the task takes to execute.<br><p>Tasks can be different and take different amounts of time depending on current conditions. Such placement of the reload at the beginning is a very good choice.<\/p><br><br><\/li>\n\n\n\n<li>What to reload with? As I said \u2013 I prefer the current time.<\/li>\n<\/ol>\n\n\n\n<p>Once we have all the matters around the timer operation sorted out, we can finally move on to executing our action. We are blinking an LED, but it can be any action. Refreshing a screen, reading a temperature, polling some chip for a measurement. Basically anything we need to do cyclically.<\/p>\n\n\n\n<p>The code performing these actions might look like this, for example:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\t\t\/\/ LD4\n\t\tif((GetSystemTick() - Timer_LD4) &amp;gt; LD4_TIMER) \/\/ Check if is time to make  action\n\t\t{\n\t\t\tTimer_LD4 = GetSystemTick(); \/\/ Refill action's timer\n\t\t\tLD4_TOGGLE; \/\/ ACTION!\n\t\t}<\/pre>\n\n\n\n<p>Simple, right? This mechanism is incredibly simple, and so useful!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Other LEDs<\/strong><\/h3>\n\n\n\n<p>We do our remaining LED actions analogously, changing only the time between calls.<\/p>\n\n\n\n<p>We can confidently copy the fragments for the first LED. We just have to remember to change the pins and definitions that relate to them. After all, these are different pins and we want to blink at a different frequency.<\/p>\n\n\n\n<p>The complete code of our program will look as follows:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/**\n ******************************************************************************\n * @file           : main.c\n * @author         : Mateusz Salamon\n * @brief          : STM32 na Rejestrach\n ******************************************************************************\n ******************************************************************************\n\n \t \t \t \t https:\/\/msalamon.pl\n \t \t \t \t https:\/\/sklep.msalamon.pl\n \t \t \t \t https:\/\/kursstm32.pl\n \t \t \t \t https:\/\/stm32narejestrach.pl\n\n *\/\n#include \"main.h\"\n\n\/\/ LEDs control macros\n#define LD4_ON GPIOA-&amp;gt;BSRR = GPIO_BSRR_BS5\n#define LD4_OFF GPIOA-&amp;gt;BSRR = GPIO_BSRR_BR5\n#define LD4_TOGGLE GPIOA-&amp;gt;ODR ^= GPIO_ODR_OD5\n\n#define LD5_ON GPIOA-&amp;gt;BSRR = GPIO_BSRR_BS6\n#define LD5_OFF GPIOA-&amp;gt;BSRR = GPIO_BSRR_BR6\n#define LD5_TOGGLE GPIOA-&amp;gt;ODR ^= GPIO_ODR_OD6\n\n#define LD6_ON GPIOA-&amp;gt;BSRR = GPIO_BSRR_BS7\n#define LD6_OFF GPIOA-&amp;gt;BSRR = GPIO_BSRR_BR7\n#define LD6_TOGGLE GPIOA-&amp;gt;ODR ^= GPIO_ODR_OD7\n\n\/\/ Constants for Software Timer's actions\n#define LD4_TIMER 500\n#define LD5_TIMER 222\n#define LD6_TIMER 147\n\n\/\/ Tick for System Time\n__IO uint32_t Tick;\n\n\/\/ LEDs Configuration\nvoid ConfigureLD4(void);\nvoid ConfigureLD5(void);\nvoid ConfigureLD6(void);\n\n\/\/ Get current System Time\nuint32_t GetSystemTick(void);\n\n\/\/ Software Timers variables\nuint32_t Timer_LD4;\nuint32_t Timer_LD5;\nuint32_t Timer_LD6;\n\nint main(void)\n{\n\n\t\/\/ 1s = 12 000 000\n\t\/\/ 0,001 = X\n\tSysTick_Config(12000000 \/ 1000);\n\n\t\/\/ Configure LEDs\n\tConfigureLD4();\n\tConfigureLD5();\n\tConfigureLD6();\n\n\t\/\/ Software Timers - first fill\n\tTimer_LD4 = GetSystemTick();\n\tTimer_LD5 = GetSystemTick();\n\tTimer_LD6 = GetSystemTick();\n\n    \/* Loop forever *\/\n\twhile(1)\n\t{\n\t\t\/\/ LD4\n\t\tif((GetSystemTick() - Timer_LD4) &amp;gt; LD4_TIMER) \/\/ Check if is time to make  action\n\t\t{\n\t\t\tTimer_LD4 = GetSystemTick(); \/\/ Refill action's timer\n\t\t\tLD4_TOGGLE; \/\/ ACTION!\n\t\t}\n\n\t\t\/\/ LD5\n\t\tif((GetSystemTick() - Timer_LD5) &amp;gt; LD5_TIMER)\n\t\t{\n\t\t\tTimer_LD5 = GetSystemTick();\n\t\t\tLD5_TOGGLE;\n\t\t}\n\n\t\t\/\/ LD6\n\t\tif((GetSystemTick() - Timer_LD6) &amp;gt; LD6_TIMER)\n\t\t{\n\t\t\tTimer_LD6 = GetSystemTick();\n\t\t\tLD6_TOGGLE;\n\t\t}\n\n\n\t}\n}\n\nvoid ConfigureLD4(void)\n{\n\t\/\/ Enable Clock for PORTA\n\tRCC-&amp;gt;IOPENR |= RCC_IOPENR_GPIOAEN;\n\n\t\/\/ Configure GPIO Mode - Output\n\tGPIOA-&amp;gt;MODER |= GPIO_MODER_MODE5_0;\n\tGPIOA-&amp;gt;MODER &amp;amp;= ~(GPIO_MODER_MODE5_1);\n\n\t\/\/ Configure Output Mode - Push-pull\n\tGPIOA-&amp;gt;OTYPER &amp;amp;= ~(GPIO_OTYPER_OT5);\n\n\t\/\/ Configure GPIO Speed - Low\n\tGPIOA-&amp;gt;OSPEEDR &amp;amp;= ~(GPIO_OSPEEDR_OSPEED5);\n\n\t\/\/ Configure Pull-up\/Pull-down - no PU\/PD\n\tGPIOA-&amp;gt;PUPDR &amp;amp;= ~(GPIO_PUPDR_PUPD5);\n}\n\nvoid ConfigureLD5(void) \/\/ PA6\n{\n\t\/\/ Enable Clock for PORTA\n\tRCC-&amp;gt;IOPENR |= RCC_IOPENR_GPIOAEN;\n\n\t\/\/ Configure GPIO Mode - Output\n\tGPIOA-&amp;gt;MODER |= GPIO_MODER_MODE6_0;\n\tGPIOA-&amp;gt;MODER &amp;amp;= ~(GPIO_MODER_MODE6_1);\n\n\t\/\/ Configure Output Mode - Push-pull\n\tGPIOA-&amp;gt;OTYPER &amp;amp;= ~(GPIO_OTYPER_OT6);\n\n\t\/\/ Configure GPIO Speed - Low\n\tGPIOA-&amp;gt;OSPEEDR &amp;amp;= ~(GPIO_OSPEEDR_OSPEED6);\n\n\t\/\/ Configure Pull-up\/Pull-down - no PU\/PD\n\tGPIOA-&amp;gt;PUPDR &amp;amp;= ~(GPIO_PUPDR_PUPD6);\n}\n\nvoid ConfigureLD6(void) \/\/ PA7\n{\n\t\/\/ Enable Clock for PORTA\n\tRCC-&amp;gt;IOPENR |= RCC_IOPENR_GPIOAEN;\n\n\t\/\/ Configure GPIO Mode - Output\n\tGPIOA-&amp;gt;MODER |= GPIO_MODER_MODE7_0;\n\tGPIOA-&amp;gt;MODER &amp;amp;= ~(GPIO_MODER_MODE7_1);\n\n\t\/\/ Configure Output Mode - Push-pull\n\tGPIOA-&amp;gt;OTYPER &amp;amp;= ~(GPIO_OTYPER_OT7);\n\n\t\/\/ Configure GPIO Speed - Low\n\tGPIOA-&amp;gt;OSPEEDR &amp;amp;= ~(GPIO_OSPEEDR_OSPEED7);\n\n\t\/\/ Configure Pull-up\/Pull-down - no PU\/PD\n\tGPIOA-&amp;gt;PUPDR &amp;amp;= ~(GPIO_PUPDR_PUPD7);\n}\n\nvoid SysTick_Handler(void)\n{\n\tTick++; \/\/ Increase system timer\n}\n\nuint32_t GetSystemTick(void)\n{\n\treturn Tick; \/\/ Return current System Time\n}\n\n\n\n<\/pre>\n\n\n\n<p>If we have everything copied, we can run the program and see if it works. Of course, you already know how to do that \ud83d\ude42<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<p>A Software Timer is a great way to implement tasks in an embedded system without blocking the processor. It works by checking elapsed time and triggering actions at the right moments. Thanks to this, we can create the illusion of multitasking and ensure smooth operation of many elements of the system.<\/p>\n\n\n\n<p>The basis of operation is the <strong>SysTick Timer<\/strong>, which counts time in milliseconds in the background. It is enough to store a time \u201cmarker\u201d, compare it with the current system time, and trigger an action at the right moments, e.g., blinking an LED. The key is proper reloading of the time marker, which helps avoid errors related to long task execution time.<\/p>\n\n\n\n<p>Thanks to this method, we can independently control multiple LEDs with different blink frequencies, without the need to use blocking <strong>delay<\/strong> functions. This mechanism is universal and can be used to control any cyclic tasks \u2013 sensor readings, communication handling, or display refreshing.<\/p>\n\n\n\n<p>In the next post we will deal with another element of practical register-level programming. It will be the first communication with the outside world. We will touch the UART interface \ud83d\ude42<\/p>\n\n\n\n<p><strong>Let me know in the comments if you liked this post! <\/strong>Maybe you have a suggestion of what to show as part of the STM32 on Registers series? Share this article with your friends.<\/p>\n\n\n\n<p>I also invite you to my store, where you can buy interesting modules for experiments, including <strong><a href=\"https:\/\/sklep.msalamon.pl\/produkt\/stm32-nucleo-c031c6-nucleo-32-z-stm32c031c6t6-arm-cortex-m0\/?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=stm32narejestrach&amp;utm_content=Text\" target=\"_blank\" rel=\"noreferrer noopener\">NUCLEO-C031C6<\/a><\/strong>, which we use in this series:<br>\ud83d\udd17 <a href=\"https:\/\/sklep.msalamon.pl\">https:\/\/sklep.msalamon.pl<\/a><\/p>\n\n\n\n<p>You can find the project from this article at:<br>\ud83d\udcc2 <a href=\"https:\/\/github.com\/lamik\/stm32narejestrach_5\" target=\"_blank\" rel=\"noopener\">https:\/\/github.com\/lamik\/stm32narejestrach_5<\/a><\/p>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;4127&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;0&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;0&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;0&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;0\\\/5 - (0 votes)&quot;,&quot;size&quot;:&quot;24&quot;,&quot;title&quot;:&quot;Doing 3 Things at Once, or How to Implement a Software Timer? | STM32 on Registers #5&quot;,&quot;width&quot;:&quot;0&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} - ({count} {votes})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 0px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 0px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 19.2px;\">\n            <span class=\"kksr-muted\"><\/span>\n    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>Doing 3 Things at Once, or How to Implement a Software Timer? | STM32 on Registers #5 Let\u2019s get to know one of the effective ways not to block the processor\u2019s work by waiting. It will be a Software Timer. This is an absolute foundation for an embedded programmer. A [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3960,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"categories":[160],"tags":[176,174],"class_list":["post-4127","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-stm32","tag-programming","tag-stm32"],"_links":{"self":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4127","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/comments?post=4127"}],"version-history":[{"count":5,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4127\/revisions"}],"predecessor-version":[{"id":4134,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4127\/revisions\/4134"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/media\/3960"}],"wp:attachment":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/media?parent=4127"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/categories?post=4127"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/tags?post=4127"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}