Bare metal C Ch16 IWDG - Hongjayeong-02/Basic_SoC_implementation GitHub Wiki
ํ ์ค ์์ฝ: ์ ์ ๋์ ์ค IWDG๋ฅผ ์ฃผ๊ธฐ์ ์ผ๋ก reloadํ๊ณ , B1์ ๋๋ฅด๋ฉด reload๋ฅผ ์ค๋จํด ์ฝ 4์ด ๋ค hardware reset์ ์ ๋ํ๋ค.
Watchdog Timer๋ software๊ฐ ์ ์์ ์ผ๋ก ๋์ํ๊ณ ์์์ ์ฃผ๊ธฐ์ ์ธ reload๋ก ํ์ธํ๊ณ , ์ผ์ ์๊ฐ ๋์ reload๋์ง ์์ผ๋ฉด system reset์ ๋ฐ์์ํค๋ ์์ ์ฅ์น๋ค.
IWDG๋ LSI๋ฅผ ์ฌ์ฉํ๋ฏ๋ก main clock๊ณผ ๋ ๋ฆฝ์ ์ผ๋ก ๋์ํ๋ค.
Key | ์๋ฏธ -- | -- 0xCCCC | IWDG ์์ 0xAAAA | Counter reload 0x5555 | PR/RLR write access enableNotion ๊ธฐ๋ก์ ์ต์ข ์ค์ :
Prescaler = /32
RLR = 0xFFF
LSI โ 32 kHz
Timeout โ (32 ร 4096) / 32000
โ 4.1 s
IWDG reset ์ดํ:
RCC->CSR & RCC_CSR_IWDGRSTF
๋ก ์ง์ reset ์์ธ์ ํ์ธํ๊ณ RMVF๋ก flag๋ฅผ clearํ๋ค.
iwdg_init()
โ
โโ 0xCCCC โ start
โโ 0x5555 โ unlock
โโ PR=/32
โโ RLR=0xFFF
โโ PVU/RVU wait
โโ 0xAAAA โ reload
โ
โผ
main loop
โ
B1 not pressed?
โ โ
Yes No
โ โ
โผ โผ
reload reload ์ค๋จ
LED toggle โ
โผ
timeout โ4 s
โ
โผ
Hardware Reset
โ
โผ
IWDGRSTF ํ์ธ
Ch16_iwdg/
โโโ Inc/gpio.h
โโโ Src/gpio.c
โโโ Inc/gpio_exti.h
โโโ Src/gpio_exti.c
โโโ Inc/iwdg.h
โโโ Src/iwdg.c
โโโ Inc/uart.h
โโโ Src/uart.c
โโโ Src/main.c
syscalls.c,sysmem.c, startup file, linker script, CubeIDE metadata/build output์ Ch04์์ ๋ค๋ฃฌ ๊ณตํต ๊ธฐ๋ฐ์ด๋ฏ๋ก ์ด ํ์ด์ง์์๋ ๋ฐ๋ณตํ์ง ์๋๋ค. ์๋์๋ ์ด chapter ๊ธฐ๋ฅ ๊ตฌํ์ ์ง์ ์ฌ์ฉํ source/header๋ฅผ ์ ๋ถ ๊ธฐ๋กํ๋ค.
#ifndef GPIO_H
#define GPIO_H
#include <stdbool.h>
/* ---- LED (PB0, LD1 ๋
น์) ---- */
void led_init(void);
void led_on(void);
void led_off(void);
/* ---- Push Button (PC13, B1) ---- */
void button_init(void);
bool get_btn_state(void);
void led_toggle(void); /* Ch08์์ ์ถ๊ฐ */
#endif /* GPIO_H */
#include "stm32f4xx.h"
#include "gpio.h"
#define LED_PIN 0U /* PB0 = LD1 (๋
น์) /
#define BTN_PIN 13U / PC13 = B1 */
void led_init(void)
{
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;
GPIOB->MODER &= ~(0x3UL << (LED_PIN * 2));
GPIOB->MODER |= (0x1UL << (LED_PIN * 2));
}
void led_on(void)
{
GPIOB->BSRR = (1UL << LED_PIN); /* Set */
}
void led_off(void)
{
GPIOB->BSRR = (1UL << (LED_PIN + 16)); /* Reset */
}
void button_init(void)
{
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;
GPIOC->MODER &= ~(0x3UL << (BTN_PIN * 2)); /* Input */
GPIOC->PUPDR &= ~(0x3UL << (BTN_PIN * 2)); /* No pull (๋ณด๋๊ฐ ์์ฒด ์ฒ๋ฆฌ) */
}
bool get_btn_state(void)
{
return (GPIOC->IDR & (1UL << BTN_PIN)) != 0U; /* active-HIGH */
}
void led_toggle(void)
{
GPIOB->ODR ^= (1UL << 0); /* PB0 = LD1 */
}
#ifndef GPIO_EXTI_H__
#define GPIO_EXTI_H__
#include <stdint.h>
#include "stm32f4xx.h"
#define LINE13 (1U << 13)
void pc13_exti_init(void);
#endif
#include "gpio_exti.h"
#define GPIOCEN (1U << 2)
#define SYSCFGEN (1U << 14)
void pc13_exti_init(void)
{
__disable_irq();
RCC->AHB1ENR |= GPIOCEN;
GPIOC->MODER &= ~(1U << 26);
GPIOC->MODER &= ~(1U << 27);
RCC->APB2ENR |= SYSCFGEN;
/* EXTI13 -> PORTC */
SYSCFG->EXTICR[3] |= (1U << 5);
EXTI->IMR |= (1U << 13);
/* ์ด ๋ณด๋๋ B1์ด active-HIGH๋ผ Rising-edge (์์๋ FTSR/active-LOW) */
EXTI->RTSR |= (1U << 13);
NVIC_EnableIRQ(EXTI15_10_IRQn);
__enable_irq();
}
#ifndef IWDG_H__
#define IWDG_H__
#include <stdint.h>
#include "stm32f4xx.h"
#define IWDG_KEY_RELOAD 0x0000AAAAU
void iwdg_init(void);
#endif
#include "iwdg.h"
#define IWDG_KEY_ENABLE 0x0000CCCCU
#define IWDG_KEY_WR_ACCESS_ENABLE 0x00005555U
#define IWDG_PRESCALER_32 0x00000003U /* /256(0x6) -> /32๋ก ๋ณ๊ฒฝ */
#define IWDG_RELOAD_VAL 0xFFFU
static uint8_t isIwdg_ready(void);
void iwdg_init(void)
{
IWDG->KR = IWDG_KEY_ENABLE;
IWDG->KR = IWDG_KEY_WR_ACCESS_ENABLE;
IWDG->PR = IWDG_PRESCALER_32; /* /4 -> /32๋ก ๋ณ๊ฒฝ, ํ์์์ โ 4์ด */
IWDG->RLR = IWDG_RELOAD_VAL;
while (isIwdg_ready() != 1U) {}
IWDG->KR = IWDG_KEY_RELOAD;
}
static uint8_t isIwdg_ready(void)
{
return (uint8_t)((READ_BIT(IWDG->SR, IWDG_SR_PVU | IWDG_SR_RVU) == 0U) ? 1U : 0U);
}
#ifndef UART_H
#define UART_H
#include "stm32f4xx.h"
void uart_init(void);
void uart_write_string(const char *s);
int __io_putchar(int ch);
#endif
#include <stdint.h>
#include "uart.h"
#define GPIODEN (1U << 3)
#define USART3EN (1U << 18)
#define DBG_UART_BAUDRATE 115200U
#define SYS_FREQ 16000000U
#define APB1_CLK SYS_FREQ
#define CR1_TE (1U << 3)
#define CR1_UE (1U << 13)
#define SR_TXE (1U << 7)
static void uart_write(int ch);
static uint16_t compute_uart_bd(uint32_t periph_clk, uint32_t baudrate);
static void uart_set_baudrate(uint32_t periph_clk, uint32_t baudrate);
int __io_putchar(int ch)
{
uart_write(ch);
return ch;
}
void uart_init(void)
{
RCC->AHB1ENR |= GPIODEN;
GPIOD->MODER &= ~(0x3UL << (8 * 2));
GPIOD->MODER |= (0x2UL << (8 * 2));
GPIOD->MODER &= ~(0x3UL << (9 * 2));
GPIOD->MODER |= (0x2UL << (9 * 2));
GPIOD->AFR[1] &= ~(0xFUL << 0);
GPIOD->AFR[1] |= (0x7UL << 0); /* PD8 -> AF7 (USART3_TX) */
GPIOD->AFR[1] &= ~(0xFUL << 4);
GPIOD->AFR[1] |= (0x7UL << 4); /* PD9 -> AF7 (USART3_RX) */
RCC->APB1ENR |= USART3EN;
uart_set_baudrate(APB1_CLK, DBG_UART_BAUDRATE);
USART3->CR1 = CR1_TE;
USART3->CR1 |= CR1_UE;
}
static void uart_write(int ch)
{
while (!(USART3->SR & SR_TXE)) { }
USART3->DR = (ch & 0xFF);
}
void uart_write_string(const char *s)
{
while (*s) uart_write((int)*s++);
}
static uint16_t compute_uart_bd(uint32_t periph_clk, uint32_t baudrate)
{
return (uint16_t)((periph_clk + (baudrate / 2U)) / baudrate);
}
static void uart_set_baudrate(uint32_t periph_clk, uint32_t baudrate)
{
USART3->BRR = compute_uart_bd(periph_clk, baudrate);
}
#include <stdio.h>
#include "gpio.h"
#include "gpio_exti.h"
#include "iwdg.h"
extern void uart_init(void);
uint8_t g_btn_press;
static void check_reset_source(void);
int main(void)
{
uart_init();
led_init();
pc13_exti_init();
check_reset_source();
iwdg_init();
while (1)
{
if (g_btn_press != 1U)
{
IWDG->KR = IWDG_KEY_RELOAD;
led_toggle();
for (volatile int i = 0; i < 90000; i++) {}
}
}
}
static void check_reset_source(void)
{
if ((RCC->CSR & RCC_CSR_IWDGRSTF) == RCC_CSR_IWDGRSTF)
{
RCC->CSR = RCC_CSR_RMVF;
led_on();
printf("RESET was caused by IWDG.....\r\n");
while (g_btn_press != 1U) {}
g_btn_press = 0U;
}
}
static void exti_callback(void)
{
g_btn_press = 1U;
}
void EXTI15_10_IRQHandler(void)
{
if ((EXTI->PR & LINE13) != 0)
{
EXTI->PR |= LINE13;
exti_callback();
}
}
Notion์๋ ์ด chapter์์ ์ค์ ๋ก ๋ง๋ ๋ฌดํ ์ฌ๋ฆฌ์ ๋ฌธ์ ๊ฐ ๊ธฐ๋ก๋์ด ์๋ค.
์ด๊ธฐ ์์ ์ค์ /4์์๋ timeout์ด ์ฝ 0.5์ด๋ผ, IWDG reset ์งํ ๋ฉ์์ง๋ฅผ ํ์ธํ๊ณ button์ ๋ค์ ๋๋ฅด๊ธฐ ์ ์ watchdog๊ฐ ๋ค์ timeout๋์ด reset์ด ๋ฐ๋ณต๋์๋ค.
์กฐ์ ๊ณผ์ :
/4 โ ์ฝ 0.5 s : ๋๋ฌด ์งง์, ์ฌ๋ฆฌ์
๋ฐ๋ณต
/256 โ ์ฝ 33 s : ๋๋ฌด ๊น
/32 โ ์ฝ 4.1 s : ์ต์ข
์ฌ์ฉ
์ต์ข ์ค์ ๋ณด๋ ๊ฒ์ฆ:
์ ์ ์ํ์์ LD1 toggle
B1 ๋๋ฆ โ reload ์ค๋จ
์ฝ 4์ด ํ hardware reset
UART์
RESET was caused by IWDG.....1ํ ์ถ๋ ฅbutton ์ ๋ ฅ ํ ๋ค์ cycle ์งํ
text = 1536 bytes
data = 0 bytes
bss = 2568 bytes
warning ์์
ํ์ฌ ์ฒจ๋ถ ZIP์ g_btn_press๋ ISR๊ณผ main()์ด ๊ณต์ ํ์ง๋ง volatile ์์ด uint8_t๋ก ์ ์ธ๋์ด ์๋ค. ์ด Wiki์์๋ ์ค์ ์์ค๋ฅผ ๊ทธ๋๋ก ๊ธฐ๋กํ๋ค.
IWDG๋ LSI ๊ธฐ๋ฐ ๋ ๋ฆฝ watchdog์ด๋ค.
์ ์ ์คํ ์ 0xAAAA reload๋ฅผ ๋ฐ๋ณตํ๊ณ ์ค๋จ๋๋ฉด timeout reset์ด ๋ฐ์ํ๋ค.
์ค๊ธฐ์์ timeout์ /32 ์ฝ 4.1์ด๋ก ์กฐ์ ํด ์ฌ๋ฆฌ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ค.