{"id":4151,"date":"2023-08-02T17:23:25","date_gmt":"2023-08-02T15:23:25","guid":{"rendered":"https:\/\/msalamon.pl\/?p=4151"},"modified":"2025-12-27T15:34:45","modified_gmt":"2025-12-27T14:34:45","slug":"blinking-an-led-on-the-stm32-gpio-output-stm32-using-registers-2","status":"publish","type":"post","link":"https:\/\/msalamon.pl\/en\/blinking-an-led-on-the-stm32-gpio-output-stm32-using-registers-2\/","title":{"rendered":"Blinking an LED on the STM32, GPIO Output | STM32 Using Registers #2"},"content":{"rendered":"\n<h1 class=\"wp-block-heading\">Blinking an LED on STM32, GPIO Output<\/h1>\n\n\n\n<p>Recently, we learned how to set up an STM32 project for register-level programming. This time I\u2019ll show you <strong>how to blink an LED<\/strong> \ud83d\ude0e<\/p>\n\n\n\n<p>In today\u2019s post we\u2019ll go through configuring GPIO Output and <strong>learn how to control the output<\/strong> of a single GPIO pin. For the exercises we\u2019ll use the built-in LD4 LED located on the <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>.<\/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<h2 class=\"wp-block-heading\">STM32 on Registers series on YouTube<\/h2>\n\n\n\n<p>These posts are created in parallel with the series <strong>on my YouTube<\/strong> on the same topic. If you prefer the video version, I invite you there. These articles are a condensed version 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=\"Miganie diod\u0105 na STM32 - GPIO Output | STM32 na Rejestrach #2\" width=\"750\" height=\"422\" src=\"https:\/\/www.youtube.com\/embed\/Hd8t2sx5dew?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 nofollow\"><strong>Link to the YouTube Playlist<\/strong><\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Configuring GPIO Output on STM32<\/h2>\n\n\n\n<p>I start the work from an empty project that I created in the previous article. First, <strong>we need to find out which pin<\/strong> of the microcontroller the LED on the <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> board is connected to. The easiest way here will be to use the schematic. You can find the schematic on the Nucleo page in the <em>CAD Resources<\/em> tab. <a href=\"https:\/\/www.st.com\/resource\/en\/schematic_pack\/mb1717-c031c6-b02_schematic.pdf\" target=\"_blank\" rel=\"noopener\">Link to our schematic<\/a>.<\/p>\n\n\n\n<p>What we care about is on page 4 and looks as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"630\" src=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/08\/NUCLEO-C031-LD4-1024x630.jpg\" alt=\"\" class=\"wp-image-2379\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/08\/NUCLEO-C031-LD4-1024x630.jpg 1024w, https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/08\/NUCLEO-C031-LD4-300x184.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/08\/NUCLEO-C031-LD4-768x472.jpg 768w, https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/08\/NUCLEO-C031-LD4.jpg 1088w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><\/figure>\n<\/div>\n\n\n\n<p><strong>The LD4 LED is connected through an N-MOSFET to pin PA5 on GPIOA.<\/strong> This means that turning the LED on will force a high state on the transistor gate, and turning it off \u2013 a low state.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Peripheral clocks<\/h3>\n\n\n\n<p>STM32s are built in such a way that each peripheral needs its own clock. Each GPIO port, in turn, has separate clocking.<\/p>\n\n\n\n<p>Clock control is handled by the <strong>RCC block<\/strong> (Reset and Clock Control), and it is there that <strong>we must enable the clock<\/strong>. In our case, for GPIOA. I show the detailed way of working with the documentation on YouTube. Here in the article I will paste ready-made code that you need to type in to get the effect.<\/p>\n\n\n\n<p>To <strong>enable the clock<\/strong> for GPIOA in the STM32C031C6T6 you need to write<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Enable Clock for PORTA\nRCC->IOPENR |= RCC_IOPENR_GPIOAEN;<\/pre>\n\n\n\n<p><strong>WARNING!<\/strong> Other STM32s may have the GPIO clock enable bits in different RCC registers. You have to confirm it every time in the Reference Manual!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Pin configuration<\/h3>\n\n\n\n<p>Once we have clocking on GPIOA, we can move on to its configuration. Previously this peripheral was inactive and we wouldn\u2019t be able to do anything. What do we need to set?<\/p>\n\n\n\n<p>We are interested in a few registers:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>MODER <\/strong>\u2013 here we set the mode in which specific GPIO pins operate. Here we decide whether a given pin is Input \/ Output \/ Alternate Function \/ Analog Input<\/li>\n\n\n\n<li><strong>OTYPER <\/strong>\u2013 Output type. Here we indicate whether we want push-pull output or open-drain<\/li>\n\n\n\n<li><strong>OSPEEDR <\/strong>\u2013 Output edge rise speed. This parameter says how steep the edge should be when changing state. Useful when minimizing and optimizing various kinds of interference<\/li>\n\n\n\n<li><strong>PUPDR <\/strong>\u2013 the register where we enable (or not) the built-in pull-up and pull-down resistors. Register values differ between families and you must verify this in the Datasheet.<\/li>\n<\/ul>\n\n\n\n<p>Our LED is on PA5. So we\u2019re interested in the set of these registers for GPIOA and the settings for number 5. Sometimes these will be single bits, sometimes a couple. What do we need to set?<\/p>\n\n\n\n<p>Pay attention to one thing that is in the Reference Manual for each register.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"789\" height=\"191\" src=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/08\/NUCLEO-C031-reset-value.jpg\" alt=\"\" class=\"wp-image-2381\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/08\/NUCLEO-C031-reset-value.jpg 789w, https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/08\/NUCLEO-C031-reset-value-300x73.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/08\/NUCLEO-C031-reset-value-768x186.jpg 768w\" sizes=\"auto, (max-width: 789px) 100vw, 789px\" \/><\/figure>\n\n\n\n<p><strong>All microcontroller registers after reset have a specific, predefined value. <\/strong>This means that you won\u2019t have to configure all registers during the initial setup right after the microcontroller starts.<\/p>\n\n\n\n<p>For now we\u2019ll set everything. So that I can show you the full configuration and leave no ambiguity.<\/p>\n\n\n\n<p><strong>MODER <\/strong>\u2013 here we set GPIO Output, i.e. value 0b01.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"745\" height=\"164\" src=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/08\/NUCLEO-C031-MODER.jpg\" alt=\"\" class=\"wp-image-2382\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/08\/NUCLEO-C031-MODER.jpg 745w, https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/08\/NUCLEO-C031-MODER-300x66.jpg 300w\" sizes=\"auto, (max-width: 745px) 100vw, 745px\" \/><\/figure>\n\n\n\n<pre class=\"EnlighterJSRAW EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Configure GPIO Mode - Output\nGPIOA->MODER |= GPIO_MODER_MODE5_0;\nGPIOA->MODER &amp;= ~(GPIO_MODER_MODE5_1);<\/pre>\n\n\n\n<p><strong>OTYPER <\/strong>\u2013 LEDs whose cathode is directly connected to a GPIO pin should be driven in push-pull mode. Here we have a MOSFET, which additionally has some pull-up that eliminates floating states and charges the gate. Let\u2019s use push-pull here. It doesn\u2019t matter that much what we choose, because the built-in pull-up resistor would outweigh the hardware one anyway.<\/p>\n\n\n\n<p>Push-pull is already set after reset, so this setting is redundant.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"660\" height=\"158\" src=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/08\/NUCLEO-C031-OTYPER.jpg\" alt=\"\" class=\"wp-image-2383\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/08\/NUCLEO-C031-OTYPER.jpg 660w, https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/08\/NUCLEO-C031-OTYPER-300x72.jpg 300w\" sizes=\"auto, (max-width: 660px) 100vw, 660px\" \/><\/figure>\n\n\n\n<pre class=\"EnlighterJSRAW EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Configure Output Mode - Push-pull\nGPIOA->OTYPER &amp;= ~(GPIO_OTYPER_OT5);<\/pre>\n\n\n\n<p><strong>OSPEEDR <\/strong>\u2013 It\u2019s worth keeping the rise speed as low as possible. Sometimes you can\u2019t, because you need to implement a fast custom interface on GPIO. Blinking an LED is slow, so we can set the lowest possible, i.e. <em>Low<\/em>. It is set by default after reset.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"643\" height=\"157\" src=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/08\/NUCLEO-C031-OSPEEDR.jpg\" alt=\"\" class=\"wp-image-2384\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/08\/NUCLEO-C031-OSPEEDR.jpg 643w, https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/08\/NUCLEO-C031-OSPEEDR-300x73.jpg 300w\" sizes=\"auto, (max-width: 643px) 100vw, 643px\" \/><\/figure>\n\n\n\n<pre class=\"EnlighterJSRAW EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Configure GPIO Speed - Low\nGPIOA->OSPEEDR &amp;= ~(GPIO_OSPEEDR_OSPEED5);<\/pre>\n\n\n\n<p><strong>PUPDR <\/strong>\u2013 We\u2019re using push-pull output. Enabling built-in pull-ups doesn\u2019t make much sense. We must disable them, which is basically the default state after reset.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"710\" height=\"152\" src=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/08\/NUCLEO-C031-PUPDR.jpg\" alt=\"\" class=\"wp-image-2385\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/08\/NUCLEO-C031-PUPDR.jpg 710w, https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/08\/NUCLEO-C031-PUPDR-300x64.jpg 300w\" sizes=\"auto, (max-width: 710px) 100vw, 710px\" \/><\/figure>\n\n\n\n<pre class=\"EnlighterJSRAW EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Configure Pull-up\/Pull-down - no PU\/PD\nGPIOA->PUPDR &amp;= ~(GPIO_PUPDR_PUPD5);<\/pre>\n\n\n\n<p>Finally, it\u2019s worth wrapping the entire LED configuration in a convenient function whose name says what it\u2019s for.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">void ConfigureLD4(void)\n{\n\t\/\/ Enable Clock for PORTA\n\tRCC->IOPENR |= RCC_IOPENR_GPIOAEN;\n\n\t\/\/ Configure GPIO Mode - Output\n\tGPIOA->MODER |= GPIO_MODER_MODE5_0; \/\/ It's default reset state. Not necessary.\n\tGPIOA->MODER &amp;= ~(GPIO_MODER_MODE5_1);\n\n\t\/\/ Configure Output Mode - Push-pull\n\tGPIOA->OTYPER &amp;= ~(GPIO_OTYPER_OT5); \/\/ It's default reset state. Not necessary.\n\n\t\/\/ Configure GPIO Speed - Low\n\tGPIOA->OSPEEDR &amp;= ~(GPIO_OSPEEDR_OSPEED5); \/\/ Two bits together. It's default reset state. Not necessary.\n\n\t\/\/ Configure Pull-up\/Pull-down - no PU\/PD\n\tGPIOA->PUPDR &amp;= ~(GPIO_PUPDR_PUPD5); \/\/ It's default reset state. Not necessary.\n}<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Controlling the GPIO output<\/h2>\n\n\n\n<p>To control what is present on the GPIO Output pin, we have two (or even three!) methods.<\/p>\n\n\n\n<p><strong>The first is the \u201cregular\u201d one via the ODR register<\/strong> (Output Data Register). We write the state we want to the position of our pin. Here we have to remember not to change the state of the other outputs. Because of that it has a <strong>drawback in the form of complexity.<\/strong> We must perform <strong>several operations<\/strong> (read the register, change one bit, write it back) to change a single bit.<\/p>\n\n\n\n<p><strong>The second method is atomic access<\/strong>, i.e. performed in a single operation (the write itself). This method is based on a special <strong>BSRR register<\/strong>. <strong>It only reacts to writing a one, so bits that are zero remain without effect.<\/strong><\/p>\n\n\n\n<p>BSRR is 32-bit and is split in half. The upper half corresponds to resetting the appropriate pin, the lower half to setting it. So with the upper 16 bits we set 0 on the indicated pin, and with the lower bits we set 1. These actions are reflected in the ODR register.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"932\" height=\"497\" src=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/08\/NUCLEO-C031-BSRR.jpg\" alt=\"\" class=\"wp-image-2386\" srcset=\"https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/08\/NUCLEO-C031-BSRR.jpg 932w, https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/08\/NUCLEO-C031-BSRR-300x160.jpg 300w, https:\/\/msalamon.pl\/wp-content\/uploads\/2023\/08\/NUCLEO-C031-BSRR-768x410.jpg 768w\" sizes=\"auto, (max-width: 932px) 100vw, 932px\" \/><\/figure>\n\n\n\n<p>We\u2019ll use atomic access. It is much more efficient and effective. To set<strong> a high state<\/strong> on pin <strong>PA5 <\/strong>we must write a one to the <strong>BSRR <\/strong>register on the bit marked as <strong>BS5 <\/strong>(Bit Set).<\/p>\n\n\n\n<p><strong>NOTE.<\/strong> On YouTube I made a mistake\u2026 we only need to write a one to the pin we care about. The other ones don\u2019t matter to us, and writing a zero does not change the output state. That\u2019s why we do a direct assignment, without any logical operation. That guarantees atomic access \ud83d\udc4d<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">GPIOA->BSRR = GPIO_BSRR_BS5<\/pre>\n\n\n\n<p>To <strong>get a low state <\/strong>on PA5, we write a one to BSRR at bit position <strong>BR5<\/strong> (Bit Reset), i.e. bit 21 of this register.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">GPIOA->BSRR = GPIO_BSRR_BR5<\/pre>\n\n\n\n<p>And this is how we can control the LED. It would be nice to also create convenient macros that immediately tell us what they do.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#define LD4_ON GPIOA->BSRR = GPIO_BSRR_BS5\n#define LD4_OFF GPIOA->BSRR = GPIO_BSRR_BR5<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Blinking the LED \u2013 delay<\/h2>\n\n\n\n<p>Blinking an LED consists of cyclically turning the LED on and off. A microcontroller is a very fast beast. For us to see the blinking at all, <strong>we must delay<\/strong> these two cyclic operations.<\/p>\n\n\n\n<p>We\u2019ll deal with proper delaying in the next lessons, but today we\u2019ll use a dumb delay based on for loops.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">void Delay(void)\n{\n\tuint32_t i;\n\n\tfor(i = 0; i &lt; 99999; i++)\n\t{\n\n\t}\n}<\/pre>\n\n\n\n<p>It has many drawbacks, such as not controlling the delay time easily, and the fact that this loop can be optimized away when compiler optimization is enabled. For today, however, it will be enough \ud83d\ude0e<\/p>\n\n\n\n<p>In main, we now need to first call the function that configures the LD4 LED pin, and in the infinite loop put turning the LED on and off, separated by our dumb delay. It will look like this:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">int main(void)\n{\n\n\tConfigureLD4();\n\n    \/* Loop forever *\/\n\twhile(1)\n\t{\n\t\t\/\/ Set LED on PA5\n\t\tLD4_ON;\n\t\tDelay();\n\n\t\t\/\/ Reset LED on PA5\n\t\tLD4_OFF;\n\t\tDelay();\n\t}\n}<\/pre>\n\n\n\n<p><strong>After compiling and flashing to our <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<\/a>, you\u2019ll see a blinking LED!<\/strong><\/p>\n\n\n\n<p>The complete code for convenient viewing:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include \"main.h\"\n\n#define LD4_ON GPIOA->BSRR = GPIO_BSRR_BS5\n#define LD4_OFF GPIOA->BSRR = GPIO_BSRR_BR5\n\n\/\/ PA5 - LD4\n\nvoid ConfigureLD4(void);\nvoid Delay(void);\n\nint main(void)\n{\n\n\tConfigureLD4();\n\n    \/* Loop forever *\/\n\twhile(1)\n\t{\n\t\t\/\/ Set LED on PA5\n\t\tLD4_ON;\n\t\tDelay();\n\n\t\t\/\/ Reset LED on PA5\n\t\tLD4_OFF;\n\t\tDelay();\n\t}\n}\n\nvoid ConfigureLD4(void)\n{\n\t\/\/ Enable Clock for PORTD\n\tRCC->IOPENR |= RCC_IOPENR_GPIOAEN;\n\n\t\/\/ Configure GPIO Mode - Output\n\tGPIOA->MODER |= GPIO_MODER_MODE5_0; \/\/ It's default reset state. Not necessary.\n\tGPIOA->MODER &amp;= ~(GPIO_MODER_MODE5_1);\n\n\t\/\/ Configure Output Mode - Push-pull\n\tGPIOA->OTYPER &amp;= ~(GPIO_OTYPER_OT5); \/\/ It's default reset state. Not necessary.\n\n\t\/\/ Configure GPIO Speed - Low\n\tGPIOA->OSPEEDR &amp;= ~(GPIO_OSPEEDR_OSPEED5); \/\/ Two bits together. It's default reset state. Not necessary.\n\n\t\/\/ Configure Pull-up\/Pull-down - no PU\/PD\n\tGPIOA->PUPDR &amp;= ~(GPIO_PUPDR_PUPD5); \/\/ It's default reset state. Not necessary.\n}\n\nvoid Delay(void)\n{\n\tuint32_t i;\n\n\tfor(i = 0; i &lt; 99999; i++)\n\t{\n\n\t}\n}<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<p>Configuring and using GPIO isn\u2019t as difficult as it might initially seem. It becomes problematic if we don\u2019t know what to do. That\u2019s why this series is being created \ud83d\ude42 Now you\u2019ll have no problem dealing with other GPIO pins, also on other ports.<\/p>\n\n\n\n<p>In the next post we\u2019ll take care of that ugly delay. We\u2019ll replace it with a controlled one using the SysTick Timer. It still won\u2019t be the prettiest delay, but at least it will be controllable.<\/p>\n\n\n\n<p>Let me know in the comments if you liked this post! Maybe you have a suggestion of what to show as part of the STM32 on Registers cycle? Share this article with your friends.<\/p>\n\n\n\n<p>I also invite you to my shop, where you can buy interesting electronics for programming such as the <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> that we use in this series: <a href=\"https:\/\/sklep.msalamon.pl\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/sklep.msalamon.pl<\/a><\/p>\n\n\n\n<p>You can find the project from this article at: <a href=\"https:\/\/github.com\/lamik\/stm32narejestrach_2\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/github.com\/lamik\/stm32narejestrach_2<\/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;4151&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;Blinking an LED on the STM32, GPIO Output | STM32 Using Registers #2&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>Blinking an LED on STM32, GPIO Output Recently, we learned how to set up an STM32 project for register-level programming. This time I\u2019ll show you how to blink an LED \ud83d\ude0e In today\u2019s post we\u2019ll go through configuring GPIO Output and learn how to control the output of a single [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3828,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"categories":[160],"tags":[176,174,177],"class_list":["post-4151","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-stm32","tag-programming","tag-stm32","tag-stm32cubemx"],"_links":{"self":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4151","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=4151"}],"version-history":[{"count":3,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4151\/revisions"}],"predecessor-version":[{"id":4156,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/posts\/4151\/revisions\/4156"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/media\/3828"}],"wp:attachment":[{"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/media?parent=4151"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/categories?post=4151"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/msalamon.pl\/en\/wp-json\/wp\/v2\/tags?post=4151"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}