Chapter 16 - Hongjayeong-02/Basic_SoC_implementation GitHub Wiki
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" νμΈ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
νλλ‘ λ§λ λ€.
IWDGλ STM32μ main system clockμ΄ μλλΌ LSI μ μ λ΄λΆ oscillatorλ₯Ό μ¬μ©νλ€.
Main CPU Clock
X
LSI
β
IWDG
β
Independent Counter
λ°λΌμ main clock μͺ½μ λ¬Έμ κ° μ겨λ watchdogμ λ 립μ μΌλ‘ λμν μ μλ€.
| Register | μν |
|---|---|
| IWDG->KR | Watchdog key command |
| IWDG->PR | Prescaler |
| IWDG->RLR | Reload value |
| IWDG->SR | Prescaler / reload update status |
| RCC->CSR | Reset cause νμΈ |
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
λ‘ κΈ°μ΅νλ©΄ λλ€.
곡μ:
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μ΄ λ°μνλ€.
μ²μ μμ μ€μ μ:
Prescaler = /4μλ€.
κ³μ°:
4 Γ 4096
ββββββββ
32000
β 0.512 sec
μ¦ μ½ 0.5μ΄λ€.
μ€κΈ°μμλ μ΄ κ°μ΄ λ무 μ§§μμ IWDG reset μ§ν μ¬μ©μκ° λ²νΌμ λλ₯΄κΈ°λ μ μ λ€μ timeoutμ΄ λ°μν΄ μ¬reset loopκ° λ°μνλ€.
μ€κ°μ:
/256
β μ½ 33μ΄λ μννμ§λ§ λ무 κΈΈμλ€.
μ΅μ’ :
/32
β μ½ 4.1μ΄λ‘ κ²°μ νλ€.
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 μ½λλ₯Ό μ¬μ¬μ©νλ€.
#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__ */
#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->PR
-
IWDG->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->KR = IWDG_KEY_WR_ACCESS_ENABLE;
/*
* --------------------------------------------------------
* Step 3. Configure Prescaler
* --------------------------------------------------------
*
* PR = 0x3
*
* LSI clock division:
*
* /32
*/
IWDG->PR = IWDG_PRESCALER_32;
/*
* --------------------------------------------------------
* Step 4. Configure Reload Value
* --------------------------------------------------------
*
* RLR = 0xFFF
*
* Timeout estimate:
*
* (32 Γ 4096) / 32000
*
* β 4.096 seconds
*/
IWDG->RLR = IWDG_RELOAD_VAL;
/*
* --------------------------------------------------------
* Step 5. Wait Until PR / RLR Update Completes
* --------------------------------------------------------
*
* IWDG->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->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
);μ λμΌνλ€.
λ€μ μ½λλ₯Ό μΌλ€κ³ ν΄μ:
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)
{
}λ₯Ό μ¬μ©νλ€.
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->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->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 < 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.
*/
}
}
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;
}
}
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;
}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();
}
}
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λμ§ μλλ€.
B1:
B1 Press
β
PC13 Rising Edge
β
EXTI13
β
ISR
β
g_btn_press = 1main:
g_btn_press == 1
β
Skip Reload
β
No 0xAAAA
β
IWDG Counter
β
0
β
SYSTEM RESETResetμ΄ λ°μνλ©΄ 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.....λ§μ½:
RCC->CSR = RCC_CSR_RMVF;λ₯Ό νμ§ μλλ€λ©΄ κ³Όκ±° reset μ λ³΄κ° λ¨μ μ μλ€.
κ·Έλ¬λ©΄ λμ€μ λ€λ₯Έ μ΄μ λ‘ resetλμ΄λ:
Previous IWDG Flag
still presentλλ¬Έμ μλͺ»λ reset causeλ₯Ό νλ¨ν μ μλ€.
λ°λΌμ:
Read Cause
β
Handle Cause
β
Clear Cause Flagsμμλ₯Ό μ¬μ©νλ€.
μ΄κΈ° μ€μ :
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μ΄ λ°λ³΅λλ€.
/4
β 0.5 secλ¬Έμ :
Too Short
β repeated reset/256
β 33 secλ¬Έμ :
Too Long
β test takes too long/32
β 4.1 secκ²°κ³Ό:
Long enough for user interaction
+
Short enough for practical testλ‘ μ¬μ©νλ€.
Button interruptκ° λ°μνλ€κ³ ISR μμμ:
UART
Delay
Complex Logicμ λͺ¨λ μννμ§ μλλ€.
νμ¬ κ΅¬μ‘°:
ISR
β
g_btn_press = 1
β
Returnmain:
Check flag
β
Change application behaviorμ΄ λ°©μμ ISRμ μ§§κ² μ μ§ν μ μλ€.
Ch14μμ λ°λ‘ callback μμμ UARTλ₯Ό μ€ννλ λ¨μ κ΅¬μ‘°λ³΄λ€ ν λ¨κ³ λ μ€λ¬΄μ μΈ patternμ΄λ€.
μ€μ μ€μ΅:
Build : PASS
Download : PASS
Run : PASSProgram size:
text = 1536 bytes
data = 0 bytes
bss = 2568 bytesκ²½κ³ μμ΄ build μλ£.
μ μ λμ:
LD1 Toggle
LD1 Toggle
LD1 Toggle
...β watchdogμ΄ κ³μ reloadλκ³ μμ.
B1 press:
B1 Press
β
LED normal activity stops
β
approximately 4 sec
β
System ResetReset ν:
LD1 ONUART:
RESET was caused by IWDG.....κ° ν λ² μΆλ ₯λλ κ²κΉμ§ νμΈνλ€.
λ€μ B1μ λλ₯΄λ©΄ λ€μ cycleλ‘ μ§ννλ€.
νμΈ:
IWDG->PRExpected:
0x3
β /32νμΈ:
IWDG->RLRExpected:
0xFFFνμΈ:
IWDG->SRconfiguration μλ£ ν:
PVU = 0
RVU = 0μ΄μ΄μΌ νλ€.
watchdog reset ν:
RCC->CSRμμ:
IWDGRSTF = 1μ νμΈνλ€.
check_reset_source()κ° μ²λ¦¬ν λ€ reset flagκ° clearλλμ§λ νμΈνλ€.
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....."μ΄λ€.
LSI
β
IWDG Prescaler /32
β
12-bit Counter
β
RLR = 0xFFF
β
β 4.1 sec timeoutμ μ μν:
0xAAAA
β
Reload
β
System Aliveμ€λ₯ μν:
No Reload
β
Counter = 0
β
Hardware ResetIWDGλ 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λ₯Ό μ¬μ©νλ€.