{"id":9662,"date":"2014-12-20T03:59:22","date_gmt":"2014-12-20T08:59:22","guid":{"rendered":"http:\/\/embedded-lab.com\/blog\/?p=9662"},"modified":"2023-04-20T23:04:22","modified_gmt":"2023-04-21T03:04:22","slug":"stm32-internals","status":"publish","type":"post","link":"https:\/\/embedded-lab.com\/blog\/stm32-internals\/","title":{"rendered":"STM32 Internals"},"content":{"rendered":"<p>STM32 micros as we know are high-end micros and this high-end tag is not only due to its memory, speed and hardware richness. An advanced micro like this also needs advanced internal supporting hardware. Most of us know about watchdog timers from previous experiences with common 8 bit MCUs like AVR and PIC. However when it comes to STM32 the idea of watchdog circuitry is elaborated. The options available for clock are also enhanced in the STM32 micros. In this post, we will see some of these supporting internal hardware. We will examine the use and operation of two different watchdog timers \u2013 <b><i>Independent Watchdog (IWDG)<\/i><\/b> and <b><i>Window Watchdog (WWDG)<\/i><\/b>, and the clock options usually found in common STM32 micros.<\/p>\n<h3>Clock Options<\/h3>\n<p>In a robust microcontroller like the STM32 there are several options for clock. At first the whole stuff may look a bit complex. Indeed it is complicated but not too difficult to understand. The simplified block diagram below shows the common clock arrangement inside a STM32F103 series MCU.<\/p>\n<div id=\"attachment_9695\" style=\"width: 870px\" class=\"wp-caption alignleft\"><a href=\"http:\/\/embedded-lab.com\/blog\/stm32-internals\/clock-internal\/\" rel=\"attachment wp-att-9695\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-9695\" class=\" wp-image-9695\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2014\/11\/Clock-Internal-1024x366.png\" alt=\"Clock Internal\" width=\"860\" height=\"307\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2014\/11\/Clock-Internal-1024x366.png 1024w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2014\/11\/Clock-Internal-550x197.png 550w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2014\/11\/Clock-Internal.png 1030w\" sizes=\"auto, (max-width: 860px) 100vw, 860px\" \/><\/a><p id=\"caption-attachment-9695\" class=\"wp-caption-text\">STM32F103 Internal Clock Arrangement (Source: <strong>The Insiders Guide to the STM32 ARM based Microcontroller<\/strong> from HITEX, http:\/\/www.hitex.com\/fileadmin\/pdf\/insiders-guides\/stm32\/isg-stm32-v18d-scr.pdf)<\/p><\/div>\n<p><!--more--><\/p>\n<p>This view give a straight forward insight of the clock hardware. When it comes to software, it is very easy to configure this vast array of hardware. The good stuff about MikroC PRO for ARM and the good news for us is the fact that its IDE already ported an easy-to-use clock configuration tool just as MikroElektronika added fuse configuration tools for its PIC and AVR compilers.<\/p>\n<p><a href=\"http:\/\/embedded-lab.com\/blog\/stm32-internals\/clock-configuration-tool\/\" rel=\"attachment wp-att-9664\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-9664\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2014\/11\/Clock-Configuration-Tool.png\" alt=\"Clock Configuration Tool\" width=\"500\" height=\"320\" \/><\/a><\/p>\n<p>This clock configuration option pops up whenever we start a new project. Alternatively we can go to the <b><i>Project<\/i><\/b> tab in the MikroC IDE and select <b><i>Edit Project<\/i><\/b>. If configured properly then it is not needed to manually code clock settings by accessing <b><i>Reset Clock Control<\/i><\/b> (<b><i>RCC<\/i><\/b>) registers. In fact we won\u2019t be needing to add the generated values of the RCC registers anywhere in the code. These values are automatically integrated with the user code. However this feature doesn\u2019t limit us to code RCC registers on our own.<\/p>\n<p>Now let\u2019s check out what clock sources are there in a STM32 micro. There are two basic types of clock and they are themselves divided into two speed categories. These are as follows:<\/p>\n<ul>\n<li><strong><span style=\"color: #ff0000\" data-darkreader-inline-color=\"\">External Sources<\/span><\/strong>\n<ul>\n<li><span style=\"color: #339966\" data-darkreader-inline-color=\"\"><b><i>High Speed External (HSE)<\/i><\/b> <\/span>clock sources can be crystal oscillators, resonators or clock signal generating circuits. When using clock generator circuits, the waveform from such circuits do not necessarily always need to be square waves. HSE accepts sine and triangular waves but whatever waveform is used it must be symmetrical, i.e. 50% on and 50% off and only <b><i>OSC_IN<\/i><\/b> pin is used to feed the clock signal, leaving <b><i>OSC_OUT<\/i><\/b> pin open. Typically the HSE of STM32 MCUs accepts clock frequencies from 4 \u2013 25MHz. If external clock circuitry is used then HSE oscillator should be bypassed. This will ensure no conflict.<\/li>\n<\/ul>\n<ul>\n<li><span style=\"color: #339966\" data-darkreader-inline-color=\"\"><b><i>Low Speed External (LSE)<\/i><\/b> <\/span>clock sources share properties similar to HSE sources but usually very accurate <i>32.768 kHz<\/i> clock crystals are used to feed the LSE. This is the most profound use of LSE as LSE feeds STM32\u2019s internal <b><i>Real Time Clock (RTC)<\/i><\/b> module.<\/li>\n<\/ul>\n<\/li>\n<li><strong><span style=\"color: #ff0000\" data-darkreader-inline-color=\"\">Internal Sources<\/span><\/strong>\n<ul>\n<li><span style=\"color: #339966\" data-darkreader-inline-color=\"\"><b><i>High Speed Internal (HSI)<\/i><\/b> <\/span>clock source is an internal fixed 8MHz clock source. It is factory calibrated and has 1% tolerance.<\/li>\n<li><span style=\"color: #339966\" data-darkreader-inline-color=\"\"><b><i>Low Speed Internal (LSI)<\/i><\/b><\/span> clock source is similar to LSE but it is not very accurate. Typically its frequency is somewhat between 30 \u2013 60 kHz. For most common uses it is considered to have a mean frequency of 45 kHz. Due to such high deviations I strongly recommend not to use it for the internal RTC.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>There are prescalars at various points and these can be used to configure individual clocks of various parts of the STM32 MCU. This feature not only ensures energy saving but also aid in running various components of the micro at optimum speeds. An optional clock security unit is also available for use that can switch to HSI should HSE fail for some reason. Apart from different clock sources there is a Phase-Lock-Loop (PLL) module that can multiply either HSE or HSI to generate yet larger values of clock. In fact an 8MHz HSI or HSE clock is passed through the PLL with 9 as multiplying factor to generate full speed 72MHz clock. This also why most ready-made STM32 development boards like the ones I use for demos come with an 8MHz crystal oscillator.<\/p>\n<div id=\"attachment_9683\" style=\"width: 510px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/embedded-lab.com\/blog\/stm32-internals\/open103r-standard_l\/\" rel=\"attachment wp-att-9683\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-9683\" class=\"size-full wp-image-9683\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2014\/11\/Open103R-Standard_l.jpg\" alt=\"Open103R-Standard_l\" width=\"500\" height=\"362\" \/><\/a><p id=\"caption-attachment-9683\" class=\"wp-caption-text\">Waveshare&#8217;s STM32 development board<\/p><\/div>\n<p>Though out this post I have used a Waveshare\u2019s Open103R STM32F103RC delevopment board &#8211; <a href=\"http:\/\/www.wvshare.com\/product\/Open103R-Standard.htm\">http:\/\/www.wvshare.com\/product\/Open103R-Standard.htm<\/a>. Like I said about development board and crystal oscillators in them this board also comes with an 8MHz and a 32.768 kHz clock crystal. As much as I have used Waveshare STM32 goods I have come across basically three categories of STM32 ARM development boards. Firstly they have <i>Open<\/i> series development boards that pack all of the features one might expect in a microcontroller development board and these boards come with easy to interface headers for connecting to external hardware like CAN communication modules, RTC modules, LCDs, etc. Secondly they also have a plug-in-module (PIM) based Open series boards that have minimum hardware and they can used either separately or with an extension motherboard. Thirdly they have <i>Port <\/i>series boards that are lighter versions of Open series boards.<\/p>\n<p>When dealing with STM32\u2019s clock, there are a few things that need well understanding. The ARM Cortex M3 is a network of instruction\/data buses. Fore important buses of the Cortex are the <b><i>Core System Clock<\/i><\/b>, <b><i>Advanced High Speed Bus (AHB)<\/i><\/b>, <b><i>Advanced Peripheral Bus 1 (APB1)<\/i><\/b> and <b><i>Advanced Peripheral Bus 2 (APB2)<\/i><\/b>. These buses are connected as such that they are connected to the Direct Memory Access (DMA) module, SRAM, peripherals like GPIOs, ADC, timers, etc. and Cortex core. At present we need just to know about APB buses and they are of the highest importance to us. This is because we are currently dealing with the peripheral hardware of the STM32 micro and certainly not other stuffs like the DMA, Cortex core, etc. It is well known from previous posts that APB1 has a maximum operating frequency of 36MHz while APB2 can run as fast as the AHB bus \u2013 72MHz. You can now understand why GPIOs are connected to APB2 bus instead of APB1 or any other bus and how STM32 GPIOs can achieve 50MHz switching speed. APB1 bus mostly serves communication and timer modules of the STM32. APB1 frequency is not automatically scaled to have half the speed of AHB and so we need to make sure it is not overclocked by mistake. Overclocking is not a good practice and is also not recommended by any manufacturer. To avoid overclocking the APB1 bus always use at least a prescaler of 2 whenever driving the STM32 beyond 36MHz.<\/p>\n<p>Lastly we can also get clock output from a special pin called <b><i>Microcontroller Clock Output (MCO)<\/i><\/b>. The MCO pin is usually located at PA8 pin. However to use the MCO we need to set PA8 as an <b><i>Alternate Function (AFIO)<\/i><\/b> output. The MCO pin can be used to clock another micro or as a time-base for another circuit or device.<\/p>\n<h6>Code Example:<\/h6>\n<p>The code example for configuring STM32\u2019s clock and its MCO pin is literally no code at all. Everything is done by the IDE\u2019s clock configuration tool. We\u2019ll just need to configure the MCO pin. In all of the codes in this post, I used MikroC\u2019s GPIO library as it easy to use and saves a lot of time.<\/p>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">void main()<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">{<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 GPIO_Clk_Enable(&amp;GPIOA_BASE);\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Enable clock for\u00a0 GPIOA<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 GPIO_Config(&amp;GPIOA_BASE, _GPIO_PINMASK_8, (_GPIO_CFG_MODE_ALT_FUNCTION | _GPIO_CFG_SPEED_50MHZ | _GPIO_CFG_OTYPE_PP)); \u00a0<em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Set PA8 as a high speed digital output<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 while(1)<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 {<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<em> <span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/To do stuffs here<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 };<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">}<\/span><\/pre>\n<p><a href=\"http:\/\/embedded-lab.com\/blog\/stm32-internals\/rcc-1\/\" rel=\"attachment wp-att-9674\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-9674\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2014\/11\/RCC-1.png\" alt=\"RCC 1\" width=\"500\" height=\"318\" \/><\/a> <a href=\"http:\/\/embedded-lab.com\/blog\/stm32-internals\/rcc-2\/\" rel=\"attachment wp-att-9675\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-9675\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2014\/11\/RCC-2.png\" alt=\"RCC 2\" width=\"500\" height=\"318\" \/><\/a><\/p>\n<p>Notice how the clocks are configured. I used the HSI and didn\u2019t use the HSE. I use HSI just to show its accuracy. I used PLL as such that the 8MHz HSI is first divided by 2 before entering the PLL stage. Thus the PLL gets 4MHz input and it then multiplies this value with 2 to generate 8MHz clock. Finally The MCO outputs a clock signal of half the value of the PLL output, i.e. 4MHz. The STM32 core however runs using HSI instead of the PLL. An oscilloscope hooked with the MCO pin registers that the clock out has a frequency of 3.99MHz. It is close enough for most applications. This is the simplest demo I could imagine.<\/p>\n<p><a href=\"http:\/\/embedded-lab.com\/blog\/stm32-internals\/dsc_0296\/\" rel=\"attachment wp-att-9666\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-9666\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2014\/11\/DSC_0296.jpg\" alt=\"DSC_0296\" width=\"500\" height=\"427\" \/><\/a> <a href=\"http:\/\/embedded-lab.com\/blog\/stm32-internals\/dsc_0310\/\" rel=\"attachment wp-att-9667\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-9667\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2014\/11\/DSC_0310.jpg\" alt=\"DSC_0310\" width=\"500\" height=\"358\" \/><\/a><\/p>\n<p>Video link: <a href=\"https:\/\/www.youtube.com\/watch?v=Fgbju2Qznkw\">https:\/\/www.youtube.com\/watch?v=Fgbju2Qznkw<\/a><\/p>\n<p><span style=\"color: #222222;font-size: 1.5em;font-weight: bold;line-height: 1em\" data-darkreader-inline-color=\"\">Independent Watchdog<\/span><\/p>\n<p>As the name suggests the Independent Watchdog (hereinafter referred as IWDG) is a completely independent watchdog timer. It has separate dedicated clock and it remains operational even if the main clock of a STM32 micro fails. Thus IWDG is suited especially for those applications where it is needed just to reset a STM32 MCU on failure or due to a hang up. This is just like the regular watchdog timer use in common 8 bit MCUs. There is nothing complex about it.<\/p>\n<p>The dedicated separate clock of the IWDG hardware comes from Low Speed Internal (LSI) clock. It is not an accurate one as one might expect. This inaccuracy is due to the fact that the LSI is a RC oscillator. It has an oscillation frequency of somewhat between 30 \u2013 60 kHz. For most applications it is assumed to have a mean frequency of 45 kHz though it is supposed to be around 32 kHz. This assumption makes it simple although there will be some deviation. Shown below is the internal block diagram of IWDG hardware:<\/p>\n<p><a href=\"http:\/\/embedded-lab.com\/blog\/stm32-internals\/iwdg-internal\/\" rel=\"attachment wp-att-9672\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-9672\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2014\/11\/IWDG-Internal-.png\" alt=\"IWDG Internal\" width=\"500\" height=\"222\" \/><\/a><\/p>\n<p>There are a few registers associated with IWDG and the register map for IWDG is shown below:<\/p>\n<p><a href=\"http:\/\/embedded-lab.com\/blog\/stm32-internals\/iwdg-register-map\/\" rel=\"attachment wp-att-9673\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-9673\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2014\/11\/IWDG-Register-Map.png\" alt=\"IWDG Register Map\" width=\"500\" height=\"179\" \/><\/a><\/p>\n<p>Activating the IWDG is straight. All we need to do is to load the <b><i>Key Register IWDG_KR<\/i><\/b> with a predefined constant <i>0xCCCC<\/i>. Once loaded with this value the IWDG hardware is initiated and its counter will down count from a reset value 0xFFF or a preloaded value to 0x000. When the counter counts to 0x000 count, a reset signal is issued. This is normally what we will not be wanting and so to avoid the reset we need to rewrite <b><i>IWDG_KR<\/i><\/b> with <i>0xAAAA<\/i>. This will reload the counter and thus reset is avoided. At this point it is pretty much clear that we will periodically need to write <i>0xAAAA<\/i> to the <b><i>IWDG_KR<\/i><\/b> register in the software. Should the software get stuck it will not be doing so and when time or count runs out, the IWDG will restart the MCU right from the initialization stage.<\/p>\n<p>Before we activate the IWDG it should be configured according to our timeout need. The <b><i>IWDG_PR<\/i><\/b> and <b><i>IWDG_RLR<\/i><\/b> registers hold prescalar or divisor factor and reload values respectively. These values decide the required timeout before reset. These registers are by default write protected and so to alter their values we need to follow a sequence or otherwise write protection will not be removed. To configure the IWDG, we need to follow according to the steps below:<\/p>\n<ol>\n<li>Load IWDG_KR register with <i>0x5555<\/i>. This will remove write protection for <b><i>IWDG_PR<\/i><\/b> and <b><i>IWDG_RLR<\/i><\/b> registers, allowing us to edit their values.<\/li>\n<li>Edit values for <b><i>IWDG_PR<\/i><\/b> and <b><i>IWDG_RLR<\/i><\/b> registers.<\/li>\n<li>Enable write protection by issuing reload command, i.e. writing <i>0xAAAA<\/i> to <b><i>IWDG_PR<\/i><\/b> register.<\/li>\n<li>Start the IDWG by loading <b><i>IWDG_PR<\/i><\/b> with <i>0xCCCC<\/i>.<\/li>\n<\/ol>\n<p>The formula for IWDG timeout is as follows:<a href=\"http:\/\/embedded-lab.com\/blog\/stm32-internals\/iwdg-formula\/\" rel=\"attachment wp-att-9685\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-9685\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2014\/11\/IWDG-Formula.png\" alt=\"IWDG Formula\" width=\"395\" height=\"111\" \/><\/a><\/p>\n<p>If, for example, <b><i>RLR <\/i><\/b>equals 180, <b><i>PR<\/i><\/b> equals 6 and the LSI has a frequency of 45 kHz then we roughly get a timeout of about 1000ms or 1s.<\/p>\n<h6>Code Example:<\/h6>\n<p>The code example for IWDG and the setup for it is very simple. A LED connected to PC 9 remains off until a push button connected to PA9 is pressed. This indicates initialization stage. Once pressed and held, the LED starts blinking, indicating normal operation. When the button is released, the LED stays on and then goes to reset after about one second. We, then, know for sure that the STM32 went to reset by seeing that the LED is turned off as it was during start up. <i><br \/>\n<\/i><\/p>\n<pre><em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/* Function prototypes *\/<\/span><\/em><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">void setup();<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">void setup_GPIO();<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">void setup_IWDG();<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">void main()<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">{<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 setup();<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 while(1)<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 {<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if(GPIOA_IDRbits.IDR9 == 0)\u00a0\u00a0 <em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/If the switch is pressed<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 GPIOC_BRRbits.BR9 = 1;\u00a0\u00a0 \u00a0<em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Turn off LED<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 delay_ms(90);\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0<em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Wait for 90ms<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 GPIOC_BSRRbits.BS9 = 1;\u00a0  <em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Turn on LED<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 delay_ms(90);\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0  <em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Wait for 90ms<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 IWDG_KR = 0xAAAA;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <em>\u00a0<span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Reload IWDG<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 };<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">}<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">void setup()<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">{<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 setup_GPIO();<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 setup_IWDG();<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 while(GPIOA_IDRbits.IDR9 == 1);      <em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Wait till the switch is pressed<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">}<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">void setup_GPIO()<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">{<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 GPIO_Clk_Enable(&amp;GPIOA_BASE);\u00a0\u00a0 <em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Enable clock for GPIOA<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 GPIO_Clk_Enable(&amp;GPIOC_BASE);\u00a0\u00a0\u00a0<em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Enable clock for GPIOC<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 GPIO_Config(&amp;GPIOA_BASE, _GPIO_PINMASK_9, (_GPIO_CFG_MODE_INPUT | _GPIO_CFG_PULL_UP));                             <em> <span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Set PA9 as a digital input with pull-up<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 GPIO_Config(&amp;GPIOC_BASE, _GPIO_PINMASK_9, (_GPIO_CFG_MODE_OUTPUT | _GPIO_CFG_OTYPE_PP | _GPIO_CFG_SPEED_2MHZ));    <em> <span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Set PC9 as a digital output<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 GPIOC_BSRRbits.BS9 = 0;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Turn off LED<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">}<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">void setup_IWDG()<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">{<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 IWDG_KR = 0x5555;    <em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Disable write protection of IWDG registers<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 IWDG_PR = 0x06;\u00a0\u00a0\u00a0\u00a0 \u00a0<em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Set PR value<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 IWDG_RLR = 0xB4;\u00a0\u00a0\u00a0 \u00a0<em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Set RLR value<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 IWDG_KR = 0xAAAA;\u00a0\u00a0 \u00a0<em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Reload IWDG<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 IWDG_KR = 0xCCCC;\u00a0\u00a0\u00a0 <em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Start IWDG<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">}\n<\/span><\/pre>\n<p><a href=\"http:\/\/embedded-lab.com\/blog\/stm32-internals\/iwdg-2\/\" rel=\"attachment wp-att-9669\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-9669\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2014\/11\/IWDG-2.jpg\" alt=\"IWDG (2)\" width=\"500\" height=\"335\" \/><\/a> <a href=\"http:\/\/embedded-lab.com\/blog\/stm32-internals\/iwdg-4\/\" rel=\"attachment wp-att-9671\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-9671\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2014\/11\/IWDG-4.jpg\" alt=\"IWDG (4)\" width=\"500\" height=\"351\" \/><\/a> <a href=\"http:\/\/embedded-lab.com\/blog\/stm32-internals\/iwdg-3\/\" rel=\"attachment wp-att-9670\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-9670\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2014\/11\/IWDG-3.jpg\" alt=\"IWDG (3)\" width=\"500\" height=\"353\" \/><\/a><\/p>\n<p>Video link: <a href=\"https:\/\/www.youtube.com\/watch?v=_6VAUcnRPVM\">https:\/\/www.youtube.com\/watch?v=_6VAUcnRPVM<\/a>.<\/p>\n<p><span style=\"color: #222222;font-size: 1.5em;font-weight: bold;line-height: 1em\" data-darkreader-inline-color=\"\">Window Watchdog<\/span><\/p>\n<p>The Window Watchdog (WWDG) is an advanced watchdog timer concept. It can detect if a program is executing earlier or later than a predefined time window. Using this info it can understand if things are working perfectly or not and reset a STM32 micro if things are not okay. Unlike the IWDG or the usual watchdog timerconcept where just a counter is monitored and reloaded periodically, the WWDG is reloaded or refreshed within the predefined time window (referred just as window from now on), reloading it earlier or later than what was defined as time frame will result in a reset. Thus the WWDG is helpful in debugging software bugs apart from other uses.<\/p>\n<div id=\"attachment_9679\" style=\"width: 510px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/embedded-lab.com\/blog\/stm32-internals\/wwdg-internal\/\" rel=\"attachment wp-att-9679\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-9679\" class=\"size-full wp-image-9679\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2014\/11\/WWDG-Internal-.png\" alt=\"WWDG Internal\" width=\"500\" height=\"150\" \/><\/a><p id=\"caption-attachment-9679\" class=\"wp-caption-text\">Windowed Watchdog (Source: <strong>The Insiders Guide to the STM32 ARM based Microcontroller<\/strong> from HITEX, http:\/\/www.hitex.com\/fileadmin\/pdf\/insiders-guides\/stm32\/isg-stm32-v18d-scr.pdf)<\/p><\/div>\n<p>The WWDG will start its counter after setup and will down-count from a preset top value to the window value and so forth. A reset will occur when its counter counts from 0x40 to 0x3F, i.e. when the T6 bit of WWDG_CR is cleared. A programmer can only set the upper value of the window and that is because the lower value is 0x40. At 0x40 count, the WWDG will give an early wakeup call in the form of an interrupt because after this at 0x3F count it will reset the STM32 CPU. As shown in the block diagram above, window (<b><i>W<\/i><\/b>) bits are compared with counter (<b><i>T<\/i><\/b>) bits. The W bits are unaltered after setting them during initialization because these bits hold the value of the count after which we are allowed to reload the down counter or T bits. ST recommends that <b><i>WWDG_CR<\/i><\/b> is either configured as 0xFF or 0xCC. Doing so will ensure that the counter starts counting well above what\u2019s stored as window. I suggest that<b><i> <\/i><\/b> \u00a0are set as 0x7F as it is the maximum possible value. I recommend so to avoid unnecessary minor overlooking and head-scratching mistakes.<\/p>\n<p>Like the IWDG, the WWDG also has few registers to configure. Here\u2019s the register map for WWDG:<\/p>\n<p><a href=\"http:\/\/embedded-lab.com\/blog\/stm32-internals\/wwdg-register-map\/\" rel=\"attachment wp-att-9681\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-9681\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2014\/11\/WWDG-Register-Map.png\" alt=\"WWDG Register Map\" width=\"500\" height=\"181\" \/><\/a><br \/>\nTo use the use the WWDG, we need to follow the following steps as given in the order below:<\/p>\n<ol>\n<li>Unlike the IWDG which has its separate clock, the WWDG\u2019s clock input comes from APB1 bus and so just like enabling clocks for GPIO \u00a0ports or any other bus-driven hardware we need to enable the clock for WWDG. This is done by setting the 11<sup>th<\/sup> bit (<b><i>WWDGEN <\/i><\/b>bit) of the <b><i>RCC_APB1ENR<\/i><\/b> register.<\/li>\n<li>After enabling clock for the WWDG, we need to configure the <b><i>WWDG_CR<\/i><\/b> and <b><i>WWDG_CFG<\/i><\/b> registers along with clearing interrupt flag. Configuring these registers will configure the timing parameters like the window, prescalar, initial counter value and of course enable the WWDG. One thing to note at this point is the fact that after the WWDG is enabled in the software, it cannot be disabled without a reset.<\/li>\n<li>Finally if we need to use the WWDG early wakeup interrupt (EWI), we\u2019ll need to configure the NVIC for that. I strongly suggest using this interrupt as it will run in the background and thereby needing no attention during coding. Should there be some problem with the software execution, it will automatically the reset the CPU, requiring no user intervention.<\/li>\n<li>In the interrupt we need to clear the interrupt flag but clearing <b><i>WWDG_SR<\/i><\/b> register\u2019s <b><i>EWIF <\/i><\/b>bit. We will also need to reload the counter.<\/li>\n<\/ol>\n<p>Before going further there are some certain points I must clear first because ST\u2019s documentation is somewhat a bit confusing. The window value and the counter values are both 7 bits wide. However please notice the formula below for obtaining WWDG timeout:<\/p>\n<p align=\"center\"><a href=\"http:\/\/embedded-lab.com\/blog\/stm32-internals\/wwdg-formula\/\" rel=\"attachment wp-att-9684\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-9684\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2014\/11\/WWDG-Formula.png\" alt=\"WWDG Formula\" width=\"479\" height=\"125\" \/><\/a><\/p>\n<p><span style=\"font-size: 0.95em;line-height: 1.6em\">Notice that the counter value<\/span><b style=\"font-size: 0.95em;line-height: 1.6em\"><i> t<\/i><\/b><span style=\"font-size: 0.95em;line-height: 1.6em\"> is shown to be 6 bits wide instead of 7 bits. To make things clear, first consider that \u00a0 to be 0, the window value to be 95 (0x5F) and the counter\u2019s initial value to be 127 (0x7F). From 127 to 95 counts we cannot refresh the WWDG counter as doing so will cause a reset. Between 94 to 64 counts we can reload the WWDG counter. If, for example, is 36MHz and \u00a0is 3 then \u00a0is 910\u00b5s. Thus each count takes this much time. Hence the refresh window is between \u00a0to . Reloading the counter before 29.13ms or reloading it after 58.25ms will result in reset.<\/span><\/p>\n<h6>Code Example:<\/h6>\n<p>In this demo example for the WWDG, I used a pair of LEDs designated <i>WWDG LED<\/i> and <i>main LED<\/i>. The WWDG LED is connected to PC9 and main LED is connected to PC12. There is also a button connected to PA9. What happens in the code is pretty simple. The entire working of the WWDG is handled by its ISR. When the code starts the main LED turns on and the WWDG LED is held off at the same time. This indicates the starting of the code. After this the main LED toggles every 300ms while the WWDG LED also toggles but at a much faster rate than the main LED. The WWDG LED\u2019s toggling suggests that it has reached early wakeup count by down counting from initial value and the WWDG counter is being reloaded. The main LED toggles as to show that normal operation are going on okay. If however the button is pressed, the counter is forced to zero, causing a WWDG reset. The process repeats once the button is released and the whole thing starts over again.<\/p>\n<pre><em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/* Function prototypes *\/<\/span><\/em><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">void setup();<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">void setup_GPIO();<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">void setup_WWDG();<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">void WWDG_ISR()<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">iv IVT_INT_WWDG ics ICS_AUTO\u00a0\u00a0\u00a0\u00a0 <em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/WWDG early wakeup interrupt function<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">{<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0 unsigned char cnt = 0;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Temporary variables for counter and window values<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0 unsigned char wdt = 0;<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0 wdt = (WWDG_CFR &amp; 0x7F);\u00a0\u00a0\u00a0\u00a0\u00a0<em> <span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Read window value<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0 cnt = (WWDG_CR &amp; 0x7F);\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Read counter value<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0 if(cnt &lt; wdt)\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/If counter is less than window value<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0 {<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 WWDG_CR |= 0x7F;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Reload the counter<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 WWDG_SR = 0x00;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Clear interrupt flag<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 GPIOC_ODRbits.ODR9 ^= 1;\u00a0<span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\u00a0<em>\/\/Toggle WWDG LED<\/em><\/span><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0 }<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">}<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">void main()<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">{<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 setup();<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 while(1)<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 {<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 GPIOC_ODRbits.ODR12 ^= 1;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Toggle main LED<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 delay_ms(300);\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Wait for 300ms<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if(GPIOA_IDRbits.IDR9 == 0)\u00a0\u00a0\u00a0\u00a0<em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/If button is pressed<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 WWDG_CR = 0x80;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Force the counter to zero<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 while(1);\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Get stuck into an infinity loop<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 };<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">}<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">void setup()<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">{<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 setup_GPIO();<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 setup_WWDG();<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">}<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">void setup_GPIO()<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">{<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 GPIO_Clk_Enable(&amp;GPIOA_BASE);\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Enable clock for GPIOA<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 GPIO_Clk_Enable(&amp;GPIOC_BASE);\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<em>\u00a0<span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Enable clock for GPIOC<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 GPIO_Config(&amp;GPIOA_BASE, _GPIO_PINMASK_9, (_GPIO_CFG_MODE_INPUT | _GPIO_CFG_PULL_UP));\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0                    <\/span><em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Set PA9 as a digital input with pull-up<\/span><\/em><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 GPIO_Config(&amp;GPIOC_BASE, (_GPIO_PINMASK_9 | _GPIO_PINMASK_12), (_GPIO_CFG_MODE_OUTPUT | _GPIO_CFG_OTYPE_PP | _GPIO_CFG_SPEED_2MHZ));    \n                                          <em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Set PC9 and PC12 as digital outputs<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 GPIOC_ODRbits.ODR9 = 0;              <em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Turn off WWDG LED at first<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 GPIOC_ODRbits.ODR12 = 1;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Turn on main LED at first<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 delay_ms(1000);\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Wait for a second<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">}<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">void setup_WWDG()<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">{<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 RCC_APB1ENRbits.WWDGEN = 1;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Enable clock for WWDG module<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 WWDG_CFR = 0x3DF;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Set WWDG_CFR register<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 WWDG_SR = 0x00;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Clear interrupt flag<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 WWDG_CR = 0xFF;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Turn on WWDG and load the counter<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 NVIC_IntEnable(IVT_INT_WWDG);\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <em><span style=\"color: #ff6600\" data-darkreader-inline-color=\"\">\/\/Enable NVIC for WWDG interrupt<\/span><\/em><\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">\u00a0\u00a0\u00a0\u00a0 EnableInterrupts();<\/span><\/pre>\n<pre><span style=\"color: #0000ff\" data-darkreader-inline-color=\"\">}<\/span><\/pre>\n<p><a href=\"http:\/\/embedded-lab.com\/blog\/stm32-internals\/wwdg-2\/\" rel=\"attachment wp-att-9676\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-9676\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2014\/11\/WWDG-2.jpg\" alt=\"WWDG (2)\" width=\"500\" height=\"324\" \/><\/a> <a href=\"http:\/\/embedded-lab.com\/blog\/stm32-internals\/wwdg-4\/\" rel=\"attachment wp-att-9678\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-9678\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2014\/11\/WWDG-4.jpg\" alt=\"WWDG (4)\" width=\"500\" height=\"339\" \/><\/a> <a href=\"http:\/\/embedded-lab.com\/blog\/stm32-internals\/wwdg-3\/\" rel=\"attachment wp-att-9677\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-9677\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2014\/11\/WWDG-3.jpg\" alt=\"WWDG (3)\" width=\"500\" height=\"331\" \/><\/a><br \/>\nVideo link: <a href=\"https:\/\/www.youtube.com\/watch?v=E8_S2qKagDM\">https:\/\/www.youtube.com\/watch?v=E8_S2qKagDM<\/a>.<br \/>\nIt is also possible to halt both the IWDG and WWDG to halt during STM32 debugging session using the STM32\u2019s MCUDBG register. With this feature unnecessary resets during a debug session can be avoided when STM32 core is halted.<br \/>\n<span style=\"font-size: 0.95em;line-height: 1.6em\"><br \/>\nFor making things easy, I have designed a GUI that can calculate parameters and generate code for both the IWDG and the WWDG. Here is a screenshot of the GUI in action.<br \/>\n<a href=\"http:\/\/embedded-lab.com\/blog\/stm32-internals\/gui-3\/\" rel=\"attachment wp-att-9668\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-9668\" src=\"http:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2014\/11\/GUI.png\" alt=\"GUI\" width=\"500\" height=\"455\" \/><\/a><\/span><\/p>\n<p>To summarize:<\/p>\n<ul>\n<li>STM32\u2019s clock options are agile and flexible. There are various ways to achieve optimum clocking. Please refer to the RCC section of the STM32 reference manual for details.<\/li>\n<li>Without fully realizing the STM32 clock peripheral it is pointless to go any further.<\/li>\n<li>I personally recommend using the HSE for accurate timing although HSI is good enough for most applications. 1% deviation of frequency due to tolerance of the HSI is not a big deal.<\/li>\n<li>I don\u2019t recommend using LSI anywhere other than for the IWDG hardware. A very accurate 32.768 kHz clock crystal should be used for the LSE if it is to be used for the internal RTC.<\/li>\n<li>It is not always necessary to run any MCU at max oscillator frequency as a higher operating frequency needs higher energy. This is what we should avoid if we are to design battery-operated or energy efficient devices.<\/li>\n<li>IWDG and WWDG are different types of watchdog and should be deployed according to specific requirement. IWDG and WWDG are not interchangeable by any means.<\/li>\n<\/ul>\n<p>Files:\u00a0<a href=\"http:\/\/embedded-lab.com\/blog\/stm32-internals\/stm32-internals\/\" rel=\"attachment wp-att-9663\">STM32 Internals<\/a>.<\/p>\n<p><strong>References:<\/strong><\/p>\n<p><strong>The Insiders Guide to the STM32 ARM based Microcontroller<\/strong>\u00a0from HITEX, http:\/\/www.hitex.com\/fileadmin\/pdf\/insiders-guides\/stm32\/isg-stm32-v18d-scr.pdf<\/p>\n<p>I wish readers a useful STM32 experience. Happy coding.<br \/>\n<i><\/i><\/p>\n<p>Repository: <a href=\"https:\/\/github.com\/sshahryiar\/STM32-Tutorials\">https:\/\/github.com\/sshahryiar\/STM32-Tutorials<\/a><\/p>\n<p><i>Author: Shawon M. Shahryiar<br \/>\n<\/i><\/p>\n<p><a href=\"https:\/\/www.youtube.com\/c\/sshahryiar\">https:\/\/www.youtube.com\/c\/sshahryiar<\/a><\/p>\n<p><a href=\"https:\/\/github.com\/sshahryiar\">https:\/\/github.com\/sshahryiar<\/a><\/p>\n<p><a href=\"mailto:sshahryiar@gmail.com\"><i>sshahryiar@gmail.com<\/i><\/a><i><\/i><i>\u00a0 \u00a0 \u00a0 \u00a0 <\/i><\/p>\n<p><i>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0\u00a0<\/i><\/p>\n","protected":false},"excerpt":{"rendered":"<p>STM32 micros as we know are high-end micros and this high-end tag is not only due to its memory, speed and hardware richness. An advanced micro like this also needs advanced internal supporting hardware. Most of us know about watchdog timers from previous experiences with common 8 bit MCUs like AVR and PIC. However when it comes to STM32 the idea of watchdog circuitry is elaborated. The options available for clock are also enhanced in the STM32 micros. In this post, we will see some of these supporting internal hardware. We will examine the use and operation of two different<\/p>\n","protected":false},"author":5,"featured_media":9664,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[733,1474,1466],"tags":[803,804,1319,1035,850,886],"class_list":["post-9662","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-stm32","category-stm32-tutorials","category-tutorials","tag-arm-microcontrollers","tag-mikroc-pro-for-arm","tag-stm32","tag-stm32f103rc","tag-stmicroelectronics","tag-waveshare-electronics"],"_links":{"self":[{"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/posts\/9662","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/comments?post=9662"}],"version-history":[{"count":12,"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/posts\/9662\/revisions"}],"predecessor-version":[{"id":15157,"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/posts\/9662\/revisions\/15157"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/media\/9664"}],"wp:attachment":[{"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/media?parent=9662"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/categories?post=9662"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/tags?post=9662"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}