Chapter 16 - Hongjayeong-02/Basic_SoC_implementation GitHub Wiki

16. Independent Watchdog (IWDG)

Goal

STM32F439ZI의 Independent Watchdog Timer(IWDG) λ₯Ό 직접 μ„€μ •ν•˜κ³ , softwareκ°€ μ •μƒμ μœΌλ‘œ λ™μž‘ν•˜λŠ” λ™μ•ˆμ—λŠ” watchdog counterλ₯Ό 주기적으둜 reloadν•œλ‹€.

B1을 λˆ„λ₯΄λ©΄ μ˜λ„μ μœΌλ‘œ reloadλ₯Ό μ€‘λ‹¨ν•˜μ—¬ μ•½ 4초 ν›„ hardware reset이 λ°œμƒν•˜λ„λ‘ λ§Œλ“ λ‹€.

Normal Operation

main() ↓ IWDG Reload ↓ IWDG Reload ↓ IWDG Reload ↓ System keeps running

B1을 λˆ„λ₯΄λ©΄:

B1 Press
↓
g_btn_press = 1
↓
Stop IWDG Reload
↓
Counter ↓↓↓
↓
0
↓
Hardware Reset
↓
main() Restart
↓
RCC->CSR.IWDGRSTF
↓
"IWDG reset" 확인

1. What is a Watchdog?

Embedded softwareκ°€ λ‹€μŒκ³Ό 같은 μƒνƒœμ— 빠질 수 μžˆλ‹€.

Infinite Loop
Deadlock
Bus Hang
Unexpected Software Fault

μ΄λ•Œ software μžμ²΄κ°€ 이미 λ©ˆμ·„λ‹€λ©΄ softwareκ°€ 자기 μžμ‹ μ„ λ³΅κ΅¬μ‹œν‚€κΈ° μ–΄λ ΅λ‹€.

Watchdog은 λ³„λ„μ˜ hardware counterλ₯Ό 계속 κ°μ†Œμ‹œν‚€κ³ :

정상 software
β†’ timeout 전에 counter reload

software failure β†’ reload μ—†μŒ β†’ counter = 0 β†’ system reset

ν•˜λ„λ‘ λ§Œλ“ λ‹€.


2. Why Independent Watchdog?

IWDGλŠ” STM32의 main system clock이 μ•„λ‹ˆλΌ LSI 저속 λ‚΄λΆ€ oscillatorλ₯Ό μ‚¬μš©ν•œλ‹€.

Main CPU Clock
X

LSI ↓ IWDG ↓ Independent Counter

λ”°λΌμ„œ main clock μͺ½μ— λ¬Έμ œκ°€ 생겨도 watchdog은 λ…λ¦½μ μœΌλ‘œ λ™μž‘ν•  수 μžˆλ‹€.


3. Important Registers

Register μ—­ν• 
IWDG->KR Watchdog key command
IWDG->PR Prescaler
IWDG->RLR Reload value
IWDG->SR Prescaler / reload update status
RCC->CSR Reset cause 확인

4. IWDG Key Register

IWDGλŠ” 일반적인 control bit λŒ€μ‹  νŠΉλ³„ν•œ key 값을 KR에 writeν•΄μ„œ μ œμ–΄ν•œλ‹€.

0xCCCC
β†’ IWDG Start

0x5555 β†’ PR / RLR Write Access Enable

0xAAAA β†’ Counter Reload

즉:

START
0xCCCC

CONFIG UNLOCK 0x5555

FEED / RELOAD 0xAAAA

둜 κΈ°μ–΅ν•˜λ©΄ λœλ‹€.


5. Timeout Calculation

곡식:

Timeout
β‰ˆ
Prescaler Γ— (RLR + 1)
─────────────────────
LSI Clock

이번 μ‹€μŠ΅:

LSI β‰ˆ 32 kHz

Prescaler = /32

RLR = 0xFFF = 4095

λ”°λΌμ„œ:

32 Γ— (4095 + 1)
────────────────
32000

= 32 Γ— 4096 ───────── 32000

β‰ˆ 4.096 sec

즉 μ•½:

4.1 seconds

λ™μ•ˆ reloadκ°€ μ—†μœΌλ©΄ reset이 λ°œμƒν•œλ‹€.


6. Why /32?

처음 μ›μ„œ 섀정은:

Prescaler = /4

μ˜€λ‹€.

계산:

4 Γ— 4096
────────
32000

β‰ˆ 0.512 sec

즉 μ•½ 0.5μ΄ˆλ‹€.

μ‹€κΈ°μ—μ„œλŠ” 이 값이 λ„ˆλ¬΄ μ§§μ•„μ„œ IWDG reset 직후 μ‚¬μš©μžκ°€ λ²„νŠΌμ„ λˆ„λ₯΄κΈ°λ„ 전에 λ‹€μ‹œ timeout이 λ°œμƒν•΄ 재reset loopκ°€ λ°œμƒν–ˆλ‹€.

쀑간에:

/256
β†’ μ•½ 33초

도 μ‹œν—˜ν–ˆμ§€λ§Œ λ„ˆλ¬΄ κΈΈμ—ˆλ‹€.

μ΅œμ’…:

/32
β†’ μ•½ 4.1초

둜 κ²°μ •ν–ˆλ‹€.


7. Practice Code

Project:

Inc/
β”œβ”€β”€ gpio.h
β”œβ”€β”€ gpio_exti.h
β”œβ”€β”€ iwdg.h
└── uart.h

Src/ β”œβ”€β”€ gpio.c β”œβ”€β”€ gpio_exti.c β”œβ”€β”€ iwdg.c β”œβ”€β”€ uart.c └── main.c

Ch07 GPIO, Ch10 UART, Ch14 EXTI μ½”λ“œλ₯Ό μž¬μ‚¬μš©ν•œλ‹€.


8. iwdg.h

#ifndef IWDG_H__
#define IWDG_H__

#include <stdint.h> #include "stm32f4xx.h"

/*

  • ============================================================
  • IWDG Reload Key
  • ============================================================
  • Writing 0xAAAA to IWDG->KR reloads the watchdog
  • counter from IWDG->RLR.
  • Application code uses this periodically to tell
  • the watchdog:
  • "software is still alive"
    

*/ #define IWDG_KEY_RELOAD 0x0000AAAAU

/*

  • Initialize and start Independent Watchdog. */ void iwdg_init(void);

#endif /* IWDG_H__ */


9. iwdg.c

#include "iwdg.h"

/*

  • ============================================================
  • IWDG Key Values
  • ============================================================ */

/*

  • Start Independent Watchdog.
  • After this value is written,
  • the watchdog begins counting down. */ #define IWDG_KEY_ENABLE 0x0000CCCCU

/*

  • Unlock write access to:
  • IWDG-&gt;PR
    
  • IWDG-&gt;RLR
    

*/ #define IWDG_KEY_WR_ACCESS_ENABLE 0x00005555U

/*

  • ============================================================
  • Timeout Configuration
  • ============================================================ */

/*

  • PR = 0x3
  • Prescaler:
  • LSI / 32
    
  • Original book example used /4.
  • Final board test uses /32 because /4 produced
  • an approximately 0.5-second watchdog timeout,
  • which was too short for the reset test flow. */ #define IWDG_PRESCALER_32 0x00000003U

/*

  • Maximum 12-bit reload value.
  • 0xFFF
  • =
  • 4095 */ #define IWDG_RELOAD_VAL 0x00000FFFU

/*

  • Private helper.
  • Returns 1 when both prescaler and reload-value
  • updates have completed. */ static uint8_t isIwdg_ready(void);

/*

  • ============================================================
  • IWDG Initialization
  • ============================================================ */

void iwdg_init(void) { /* * -------------------------------------------------------- * Step 1. Start IWDG * -------------------------------------------------------- * * KR = 0xCCCC * * Once started, IWDG begins counting down. */ IWDG->KR = IWDG_KEY_ENABLE;

/*
 * --------------------------------------------------------
 * Step 2. Unlock PR / RLR Write Access
 * --------------------------------------------------------
 *
 * KR = 0x5555
 *
 * The prescaler and reload registers are protected
 * against accidental modification.
 */
IWDG-&gt;KR = IWDG_KEY_WR_ACCESS_ENABLE;


/*
 * --------------------------------------------------------
 * Step 3. Configure Prescaler
 * --------------------------------------------------------
 *
 * PR = 0x3
 *
 * LSI clock division:
 *
 *     /32
 */
IWDG-&gt;PR = IWDG_PRESCALER_32;


/*
 * --------------------------------------------------------
 * Step 4. Configure Reload Value
 * --------------------------------------------------------
 *
 * RLR = 0xFFF
 *
 * Timeout estimate:
 *
 *     (32 Γ— 4096) / 32000
 *
 *     β‰ˆ 4.096 seconds
 */
IWDG-&gt;RLR = IWDG_RELOAD_VAL;


/*
 * --------------------------------------------------------
 * Step 5. Wait Until PR / RLR Update Completes
 * --------------------------------------------------------
 *
 * IWDG-&gt;SR contains:
 *
 *     PVU
 *     RVU
 *
 * These flags are set while new values
 * are being transferred internally.
 *
 * Continue only when BOTH become zero.
 */
while (isIwdg_ready() != 1U)
{
}


/*
 * --------------------------------------------------------
 * Step 6. Reload Counter
 * --------------------------------------------------------
 *
 * KR = 0xAAAA
 *
 * Load the new RLR value into the internal
 * watchdog down-counter.
 *
 * From here the approximately 4.1-second
 * timeout is active.
 */
IWDG-&gt;KR = IWDG_KEY_RELOAD;

}

/*

  • ============================================================
  • Check IWDG Configuration Update Status
  • ============================================================ */

static uint8_t isIwdg_ready(void) { /* * IWDG_SR_PVU * * Prescaler Value Update * * IWDG_SR_RVU * * Reload Value Update * * If either bit is still set: * * configuration update is still in progress. * * If both are zero: * * PR / RLR configuration is ready. */ if (READ_BIT( IWDG->SR, IWDG_SR_PVU | IWDG_SR_RVU ) == 0U) { return 1U; }

return 0U;

}

원본 ν•œ 쀄 ν˜•νƒœ:

return (uint8_t)(
(READ_BIT(IWDG->SR,
IWDG_SR_PVU | IWDG_SR_RVU) == 0U)
? 1U
: 0U
);

와 λ™μΌν•˜λ‹€.


10. Why Wait for PVU / RVU?

λ‹€μŒ μ½”λ“œλ₯Ό 썼닀고 ν•΄μ„œ:

IWDG->PR  = IWDG_PRESCALER_32;
IWDG->RLR = IWDG_RELOAD_VAL;

IWDG λ‚΄λΆ€ counter logic에 μ¦‰μ‹œ λ°˜μ˜λλ‹€κ³  κ°€μ •ν•˜λ©΄ μ•ˆ λœλ‹€.

Hardware λ‚΄λΆ€μ—μ„œλŠ”:

CPU Register Write
↓
Update in progress
↓
PVU / RVU = 1
↓
Internal configuration updated
↓
PVU / RVU = 0

과정이 μžˆμ„ 수 μžˆλ‹€.

κ·Έλž˜μ„œ:

while (isIwdg_ready() != 1U)
{
}

λ₯Ό μ‚¬μš©ν•œλ‹€.


11. main.c

Wiki correction 1

κΈ°μ‘΄ μ‹€μŠ΅ μ½”λ“œμ—λŠ” uint8_t g_btn_press;둜 κΈ°λ‘λ˜μ–΄ μžˆμ—ˆλ‹€.

이 λ³€μˆ˜λŠ” ISRμ—μ„œ writeν•˜κ³  mainμ—μ„œ readν•˜λ―€λ‘œ μ΅œμ’… Wikiμ—μ„œλŠ” compilerμ—κ²Œ 비동기 λ³€κ²½ κ°€λŠ₯성을 λͺ…ν™•νžˆ μ•Œλ¦¬κΈ° μœ„ν•΄ volatile을 μ‚¬μš©ν•œλ‹€.

#include <stdint.h>

#include "gpio.h" #include "gpio_exti.h" #include "iwdg.h" #include "uart.h"

/*

  • ============================================================
  • Button Event Flag
  • ============================================================
  • Modified by:
  • EXTI15_10_IRQHandler()
    
  • Read by:
  • main()
    
  • Because ISR and normal code share this variable,
  • volatile is used. */ volatile uint8_t g_btn_press = 0U;

/*

  • Check whether the previous reset
  • was caused by the IWDG. */ static void check_reset_source(void);

/*

  • Set the button-event flag.
  • Keep ISR-side processing short. */ static void exti_callback(void);

int main(void) { /* * -------------------------------------------------------- * Step 1. Initialize UART * -------------------------------------------------------- * * Used to report watchdog reset cause. */ uart_init();

/*
 * --------------------------------------------------------
 * Step 2. Initialize LD1
 * --------------------------------------------------------
 *
 * LD1 β†’ PB0
 */
led_init();


/*
 * --------------------------------------------------------
 * Step 3. Initialize B1 EXTI
 * --------------------------------------------------------
 *
 * B1 β†’ PC13
 *
 * Button press generates EXTI interrupt.
 */
pc13_exti_init();


/*
 * --------------------------------------------------------
 * Step 4. Check Previous Reset Cause
 * --------------------------------------------------------
 *
 * RCC-&gt;CSR retains information that tells us
 * why the MCU was reset.
 *
 * If IWDGRSTF is set:
 *
 *     previous reset was caused by watchdog.
 */
check_reset_source();


/*
 * --------------------------------------------------------
 * Step 5. Start IWDG
 * --------------------------------------------------------
 *
 * Final configuration:
 *
 *     Prescaler = /32
 *     RLR       = 0xFFF
 *     Timeout   β‰ˆ 4.1 sec
 */
iwdg_init();


while (1)
{
    /*
     * ----------------------------------------------------
     * Normal Case
     * ----------------------------------------------------
     *
     * If B1 has NOT been pressed:
     *
     *     g_btn_press = 0
     *
     * continue feeding the watchdog.
     */
    if (g_btn_press != 1U)
    {
        /*
         * -----------------------------------------------
         * Feed the Watchdog
         * -----------------------------------------------
         *
         * KR = 0xAAAA
         *
         * Reload internal counter from RLR.
         *
         * This prevents the watchdog from reaching zero.
         */
        IWDG-&gt;KR = IWDG_KEY_RELOAD;


        /*
         * Toggle LED as a visible indication
         * that main() is still running normally.
         */
        led_toggle();


        /*
         * Intentional busy-wait delay.
         *
         * This delay must remain much shorter than
         * the approximately 4.1-second watchdog timeout.
         *
         * volatile prevents the compiler from simply
         * deleting an empty loop during optimization.
         */
        for (volatile int i = 0;
             i &lt; 90000;
             i++)
        {
        }
    }


    /*
     * ----------------------------------------------------
     * Failure Simulation
     * ----------------------------------------------------
     *
     * If B1 is pressed:
     *
     *     g_btn_press = 1
     *
     * The if block above is skipped.
     *
     * Therefore:
     *
     *     NO KR = 0xAAAA
     *
     * is written.
     *
     * The watchdog counter keeps decreasing:
     *
     *     ... β†’ 3 β†’ 2 β†’ 1 β†’ 0
     *
     * At zero:
     *
     *     Hardware Reset
     *
     * No software reset instruction is executed.
     */
}

}


12. check_reset_source()

static void check_reset_source(void)
{
/*
* --------------------------------------------------------
* Check IWDG Reset Flag
* --------------------------------------------------------
*
* RCC_CSR_IWDGRSTF:
*
*     1
*
* means the previous system reset was
* generated by the Independent Watchdog.
/
if ((RCC->CSR & RCC_CSR_IWDGRSTF)
== RCC_CSR_IWDGRSTF)
{
/
* ----------------------------------------------------
* Clear Reset Flags
* ----------------------------------------------------
*
* RMVF:
*
*     Remove Reset Flags
*
* If this is not cleared, a later reset could
* incorrectly appear to have been caused by IWDG.
*/
RCC->CSR = RCC_CSR_RMVF;
    /*
     * Turn LD1 ON so the watchdog-reset state
     * is visually obvious.
     */
    led_on();


    /*
     * Report reset cause through UART.
     */
    uart_write_string(
        "RESET was caused by IWDG.....\r\n"
    );


    /*
     * ----------------------------------------------------
     * Wait for User Confirmation
     * ----------------------------------------------------
     *
     * After an IWDG reset, wait until B1 is
     * pressed again before proceeding.
     *
     * This allows the reset message to be observed.
     *
     * IMPORTANT:
     *
     * The practical experiment showed that the
     * watchdog remains relevant through this sequence,
     * which is why an excessively short timeout such as
     * approximately 0.5 seconds caused repeated resets.
     */
    while (g_btn_press != 1U)
    {
    }


    /*
     * Consume the button event before
     * entering the next watchdog cycle.
     */
    g_btn_press = 0U;
}

}


13. EXTI Callback

static void exti_callback(void)
{
/*
* Do only the minimum work inside the ISR path.
*
* The main loop decides what action to take
* after seeing this flag.
/
g_btn_press = 1U;
}

14. EXTI Handler

Wiki correction 2

κΈ°μ‘΄ μ‹€μŠ΅ 기둝:

EXTI->PR |= LINE13;

Ch14μ—μ„œ μ •λ¦¬ν–ˆλ“― EXTI->PR은 W1C registerμ΄λ―€λ‘œ μ΅œμ’… Wikiμ—μ„œλŠ” 직접 assignmentλ₯Ό μ‚¬μš©ν•œλ‹€.

void EXTI15_10_IRQHandler(void)
{
/
* EXTI10 ~ EXTI15 share one IRQ handler.
*
* Confirm that EXTI13 caused this interrupt.
/
if ((EXTI->PR & LINE13) != 0U)
{
/
* Clear EXTI13 pending bit.
*
* PR is W1C:
*
*     Write 1 β†’ Clear
*/
EXTI->PR = LINE13;
    /*
     * Set button event flag.
     */
    exti_callback();
}

}


15. Normal Runtime Flow

Power On
↓
UART Init
↓
LED Init
↓
EXTI Init
↓
Check Reset Cause
↓
IWDG Init
↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ g_btn_press == 0      β”‚
β”‚                       β”‚
β”‚ KR = 0xAAAA           β”‚
β”‚ LED Toggle            β”‚
β”‚ Delay                 β”‚
β”‚                       β”‚
β”‚ Repeat                β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Watchdog counterλŠ” λ§€ loopλ§ˆλ‹€:

Reload
↓
0xFFF
↓
Counting...
↓
Reload
↓
0xFFF

κ°€ λ°˜λ³΅λœλ‹€.

λ”°λΌμ„œ resetλ˜μ§€ μ•ŠλŠ”λ‹€.


16. Failure Simulation Flow

B1:

B1 Press
↓
PC13 Rising Edge
↓
EXTI13
↓
ISR
↓
g_btn_press = 1

main:

g_btn_press == 1
↓
Skip Reload
↓
No 0xAAAA
↓
IWDG Counter
↓
0
↓
SYSTEM RESET

17. Reset Cause Detection

Reset이 λ°œμƒν•˜λ©΄ CPUλŠ” λ‹€μ‹œ:

Reset_Handler
↓
Startup
↓
main()

λΆ€ν„° μ‹€ν–‰ν•œλ‹€.

κ·ΈλŸ¬λ‚˜ RCC->CSRμ—λŠ” reset cause flagκ°€ 남아 μžˆμ–΄μ„œ:

RCC->CSR & RCC_CSR_IWDGRSTF

둜 직전 reset 원인을 확인할 수 μžˆλ‹€.

흐름:

IWDG Timeout
↓
Reset
↓
main()
↓
check_reset_source()
↓
IWDGRSTF == 1
↓
UART:
RESET was caused by IWDG.....

18. Why Clear Reset Flags?

λ§Œμ•½:

RCC->CSR = RCC_CSR_RMVF;

λ₯Ό ν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄ κ³Όκ±° reset 정보가 남을 수 μžˆλ‹€.

그러면 λ‚˜μ€‘μ— λ‹€λ₯Έ 이유둜 resetλ˜μ–΄λ„:

Previous IWDG Flag
still present

λ•Œλ¬Έμ— 잘λͺ»λœ reset causeλ₯Ό νŒλ‹¨ν•  수 μžˆλ‹€.

λ”°λΌμ„œ:

Read Cause
↓
Handle Cause
↓
Clear Cause Flags

μˆœμ„œλ₯Ό μ‚¬μš©ν•œλ‹€.


19. μ‹€κΈ°μ—μ„œ λ°œκ²¬ν•œ 문제

초기 μ„€μ •:

Prescaler = /4
Timeout β‰ˆ 0.5 sec

μ΄μ—ˆλ‹€.

B1을 눌러 watchdog reset을 λ°œμƒμ‹œμΌ°λ”λ‹ˆ terminalμ—μ„œ:

RESET was caused by IWDG.....
RESET was caused by IWDG.....
RESET was caused by IWDG.....
...

처럼 λΉ λ₯΄κ²Œ λ°˜λ³΅λ˜λŠ” ν˜„μƒμ΄ λ°œμƒν–ˆλ‹€.

즉:

IWDG Reset
↓
main Restart
↓
Reset Cause Message
↓
Wait for User
↓
Before User Can Respond
↓
IWDG Timeout Again
↓
Reset

이 λ°˜λ³΅λλ‹€.


20. Timeout Tuning

First

/4
β‰ˆ 0.5 sec

문제:

Too Short
β†’ repeated reset

Second

/256
β‰ˆ 33 sec

문제:

Too Long
β†’ test takes too long

Final

/32
β‰ˆ 4.1 sec

κ²°κ³Ό:

Long enough for user interaction
+
Short enough for practical test

둜 μ‚¬μš©ν–ˆλ‹€.


21. Why ISR Only Sets a Flag?

Button interruptκ°€ λ°œμƒν–ˆλ‹€κ³  ISR μ•ˆμ—μ„œ:

UART
Delay
Complex Logic

을 λͺ¨λ‘ μˆ˜ν–‰ν•˜μ§€ μ•ŠλŠ”λ‹€.

ν˜„μž¬ ꡬ쑰:

ISR
↓
g_btn_press = 1
↓
Return

main:

Check flag
↓
Change application behavior

이 방식은 ISR을 짧게 μœ μ§€ν•  수 μžˆλ‹€.

Ch14μ—μ„œ λ°”λ‘œ callback μ•ˆμ—μ„œ UARTλ₯Ό μ‹€ν–‰ν–ˆλ˜ λ‹¨μˆœ ꡬ쑰보닀 ν•œ 단계 더 싀무적인 pattern이닀.


22. Build Result

μ‹€μ œ μ‹€μŠ΅:

Build    : PASS
Download : PASS
Run      : PASS

Program size:

text = 1536 bytes
data = 0 bytes
bss  = 2568 bytes

κ²½κ³  없이 build μ™„λ£Œ.


23. Board Verification

정상 λ™μž‘:

LD1 Toggle
LD1 Toggle
LD1 Toggle
...

β†’ watchdog이 계속 reload되고 있음.

B1 press:

B1 Press
↓
LED normal activity stops
↓
approximately 4 sec
↓
System Reset

Reset ν›„:

LD1 ON

UART:

RESET was caused by IWDG.....

κ°€ ν•œ 번 좜λ ₯λ˜λŠ” κ²ƒκΉŒμ§€ ν™•μΈν–ˆλ‹€.

λ‹€μ‹œ B1을 λˆ„λ₯΄λ©΄ λ‹€μŒ cycle둜 μ§„ν–‰ν–ˆλ‹€.


24. Debugger Verification

IWDG Prescaler

확인:

IWDG->PR

Expected:

0x3
β†’ /32

Reload Value

확인:

IWDG->RLR

Expected:

0xFFF

Status

확인:

IWDG->SR

configuration μ™„λ£Œ ν›„:

PVU = 0
RVU = 0

이어야 ν•œλ‹€.


Reset Cause

watchdog reset ν›„:

RCC->CSR

μ—μ„œ:

IWDGRSTF = 1

을 ν™•μΈν•œλ‹€.

check_reset_source()κ°€ μ²˜λ¦¬ν•œ λ’€ reset flagκ°€ clearλ˜λŠ”μ§€λ„ ν™•μΈν•œλ‹€.


25. Screenshots to Add

images/ch16_build.png
images/ch16_iwdg_registers.png
images/ch16_normal_led.gif
images/ch16_before_timeout.png
images/ch16_reset_uart.png
images/ch16_reset_flag.png

κ°€μž₯ μ€‘μš”ν•œ evidence:

B1 Press
↓
~4 sec wait
↓
System Reset
↓
RCC IWDGRSTF
↓
"RESET was caused by IWDG....."

이닀.


26. Key Points

LSI
↓
IWDG Prescaler /32
↓
12-bit Counter
↓
RLR = 0xFFF
↓
β‰ˆ 4.1 sec timeout

정상 μƒνƒœ:

0xAAAA
↓
Reload
↓
System Alive

였λ₯˜ μƒνƒœ:

No Reload
↓
Counter = 0
↓
Hardware Reset
  • IWDGλŠ” LSIλ₯Ό μ‚¬μš©ν•˜λŠ” 독립 watchdog이닀.

  • 0xCCCCλŠ” IWDG start keyλ‹€.

  • 0x5555λŠ” PR/RLR write access enable keyλ‹€.

  • 0xAAAAλŠ” watchdog reload keyλ‹€.

  • 이번 μ‹€μŠ΅μ€ /32, RLR=0xFFFλ₯Ό μ‚¬μš©ν•΄ μ•½ 4.1초 timeout을 κ΅¬μ„±ν–ˆλ‹€.

  • PR/RLR μ„€μ • ν›„ PVU/RVUκ°€ clear될 λ•ŒκΉŒμ§€ κΈ°λ‹€λ¦°λ‹€.

  • 정상 softwareλŠ” timeout 전에 주기적으둜 0xAAAAλ₯Ό writeν•œλ‹€.

  • B1을 λˆ„λ₯΄λ©΄ reloadλ₯Ό 쀑지해 μ˜λ„μ μœΌλ‘œ watchdog reset을 λ°œμƒμ‹œν‚¨λ‹€.

  • RCC->CSR.IWDGRSTF둜 직전 reset 원인을 ν™•μΈν•œλ‹€.

  • 확인 ν›„ RMVF둜 reset cause flagsλ₯Ό clearν•œλ‹€.

  • μ‹€μ œ boardμ—μ„œ watchdog timeout β†’ hardware reset β†’ reset cause UART 좜λ ₯κΉŒμ§€ 검증 μ™„λ£Œν–ˆλ‹€.

  • μ΅œμ’… Wikiμ—μ„œλŠ” ISR 곡유 λ³€μˆ˜μ— volatile, EXTI W1C clear에 direct assignmentλ₯Ό μ‚¬μš©ν•œλ‹€.

⚠️ **GitHub.com Fallback** ⚠️