Bare metal C Ch18 StandbyMode - Hongjayeong-02/Basic_SoC_implementation GitHub Wiki
ํ ์ค ์์ฝ: B1 interrupt๋ก Standby์ ์ง์ ํ๊ณ PA0(WKUP)์ wakeup source๋ก ๊ตฌ์ฑํ๋ค. Standby ์ง์ ์ ๊ฒ์ฆํ์ง๋ง PA0 wakeup์ ํ์ฌ ๋ฏธ๊ฒ์ฆ ์ํ๋ค.
Notion์์๋ STM32 low-power mode๋ฅผ Sleep / Stop / Standby์ ์ธ ๋จ๊ณ๋ก ์ ๋ฆฌํ๋ค.
Mode | ํน์ง -- | -- Sleep | Core ์ค์ฌ์ผ๋ก ์ ์ง Stop | ๋ ๊น์ ์ ์ ๋ ฅ Standby | ๊ฐ์ฅ ๊น์ ์ ์ ๋ ฅ, wakeup ์ reset ํ๋ฆ์ด๋ฒ ์ค์ต์ Standby๋ฅผ ์ฌ์ฉํ๋ค.
Standby ์ง์ ์๋ ์๋ก ๋ค๋ฅธ ๊ณ์ธต์ ์ค์ ์ด ํจ๊ป ํ์ํ๋ค.
SCB->SCR.SLEEPDEEP
= Cortex-M core์๊ฒ deep sleep ์์ฒญ
PWR->CR.PDDS
= STM32์๊ฒ deep sleep ์ค Standby ์ ํ
๊ทธ ํ:
__WFI();
๋ก sleep ์ง์ ์ ์์ฒญํ๋ค.
Notion ๊ธฐ๋ก์์๋ Standby์์ ๊นจ์ด๋๋ฉด ์ด์ ์ฝ๋ ์์น๋ก ์ด์ด์ ์คํํ๋ ๊ฒ์ด ์๋๋ผ reset๊ณผ ๊ฐ์ ํ๋ฆ์ผ๋ก main()๋ถํฐ ๋ค์ ์์ํ๋ค๊ณ ์ ๋ฆฌํ๋ค.
๋ฐ๋ผ์ PWR->CSR์:
SBFWUF
flag๋ฅผ ์ด์ฉํด reset/wakeup ์์ธ์ ํ์ธํ๋ค.
PA0์ WKUP input์ผ๋ก ์ฌ์ฉํ๋ค. ๋ณ๋ pull-up/down ์์ด ์ธ๋ถ wiring์ผ๋ก input state๋ฅผ ๋ง๋ ๋ค.
Normal boot
โ
โโ UART init
โโ LED init
โโ PA0 wakeup pin init
โโ reset source ํ์ธ
โ
โผ
B1 / EXTI13
โ
โผ
LED OFF
โ
โผ
Standby setup
โ
โโ WUF clear
โโ WKUP enable
โโ PDDS
โโ SLEEPDEEP
โโ __WFI()
โ
โผ
Standby
โ
PA0 wakeup
โ
โผ
Reset
โ
โผ
main()
Ch18_pm/
โโโ Inc/gpio.h
โโโ Src/gpio.c
โโโ Inc/gpio_exti.h
โโโ Src/gpio_exti.c
โโโ Inc/standby_mode.h
โโโ Src/standby_mode.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 STANDBY_MODE_H__
#define STANDBY_MODE_H__
#include <stdint.h>
#include "stm32f4xx.h"
uint32_t get_wakeup_pin_state(void);
void wakeup_pin_init(void);
void standby_wakeup_pin_setup(void);
#endif /* STANDBY_MODE_H__ */
#include "standby_mode.h"
#define PWR_MODE_STANDBY (PWR_CR_PDDS)
#define WK_PIN (1U << 0)
static void set_power_mode(uint32_t pwr_mode);
void wakeup_pin_init(void)
{
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
GPIOA->MODER &= ~(1U << 0);
GPIOA->MODER &= ~(1U << 1);
GPIOA->PUPDR &= ~(1U << 0);
GPIOA->PUPDR &= ~(1U << 1);
}
uint32_t get_wakeup_pin_state(void)
{
return ((GPIOA->IDR & WK_PIN) == WK_PIN);
}
static void set_power_mode(uint32_t pwr_mode)
{
MODIFY_REG(PWR->CR,
(PWR_CR_PDDS | PWR_CR_LPDS | PWR_CR_FPDS | PWR_CR_LPLVDS | PWR_CR_MRLVDS),
pwr_mode);
}
void standby_wakeup_pin_setup(void)
{
while (get_wakeup_pin_state() == 0) {}
PWR->CSR &= ~(1U << 8);
PWR->CR |= (1U << 2);
PWR->CSR |= (1U << 8);
set_power_mode(PWR_MODE_STANDBY);
SCB->SCR |= (1U << 2);
__WFI();
}
#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);
}
/*
- Ch18 - Power Management: Standby ๋ชจ๋ + PA0(WKUP) ์จ์ดํฌ์
-
- B1(PC13)์ ๋๋ฅด๋ฉด EXTI ์ธํฐ๋ฝํธ๋ก standby_wakeup_pin_setup()์ด
- ํธ์ถ๋์ด ๋ณด๋๊ฐ Standby ๋ชจ๋(๊ฐ์ฅ ๊น์ ์ ์ ๋ ฅ ๋ชจ๋)๋ก ๋ค์ด๊ฐ๋ค.
- PA0(WKUP)์ ๋ฐฐ์ ๋ ์ ํธ๊ฐ Low->High๋ก ๋ฐ๋๋ฉด ๋ณด๋๊ฐ ๊นจ์ด๋๋๋ฐ,
- Standby์์ ๊นจ์ด๋๋ ๊ฑด ์์ ํ ๋ฆฌ์
๊ณผ ๋์ผํด์ main()์ด ์ฒ์๋ถํฐ
- ๋ค์ ์คํ๋๋ค โ ๊ทธ๋์ check_reset_source()๊ฐ PWR->CSR์ SBF
- ๋นํธ๋ก "๋ฐฉ๊ธ Standby์์ ๊นจ์ด๋ฌ๋ค"๋ฅผ ํ๋ณํ๋ค.
-
- LD1(PB0)์ ๋ฐฐ์ ๋ถํ์. ์ ์ ๋์ ์ค์ ์ผ์ ธ ์๋ค๊ฐ Standby ์ง์
- ์ง์ ์ ๊บผ์ง๊ณ , ์จ์ดํฌ์
(๋ฆฌ์
) ํ ๋ค์ ์ผ์ง๋ค.
*/
#include "gpio.h"
#include "gpio_exti.h"
#include "standby_mode.h"
#include "uart.h"
uint8_t g_btn_press;
static void check_reset_source(void);
int main(void)
{
uart_init();
led_init();
wakeup_pin_init();
/* ๋ฆฌ์
์์ธ ํ์ธ (Standby์์ ๊นจ์ด๋ ๊ฒ์ธ์ง ์๋์ง) */
check_reset_source();
/* ์ ์ ๋์ ์ค์์ LED๋ก ํ์ */
led_on();
/* B1 ๋ฒํผ์ผ๋ก Standby ์ง์
์ ํธ๋ฆฌ๊ฑฐํ๊ธฐ ์ํ EXTI ์ค์ */
pc13_exti_init();
while (1)
{
/* ๋ชจ๋ ๋์์ ์ธํฐ๋ฝํธ(B1 -> Standby ์ง์
, WKUP -> ๋ฆฌ์
)๋ก๋ง ์ด๋ค์ง */
}
}
static void check_reset_source(void)
{
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
if ((PWR->CSR & PWR_CSR_SBF) == PWR_CSR_SBF)
{
PWR->CR |= PWR_CR_CSBF;
uart_write_string("System resume from Standby.....\r\n");
while (get_wakeup_pin_state() == 0) {}
}
if ((PWR->CSR & PWR_CSR_WUF) == PWR_CSR_WUF)
{
PWR->CR |= PWR_CR_CWUF;
}
}
static void exti_callback(void)
{
led_off();
standby_wakeup_pin_setup();
}
void EXTI15_10_IRQHandler(void)
{
if ((EXTI->PR & LINE13) != 0)
{
EXTI->PR |= LINE13;
exti_callback();
}
}
Notion ๊ธฐ๋ก ๊ธฐ์ค:
B1 โ EXTI interrupt ํ์ธ
LED off ํ Standby ์ง์ ํ์ธ
Standby ์ง์ ์ดํ UART๊ฐ ์๋ตํ์ง ์๋ ์ํ ํ์ธ
PA0(WKUP) ์ค์ wakeup์ jumper wire๊ฐ ์์ด ๋ฏธ๊ฒ์ฆ
text = 1660 bytes
data = 0 bytes
bss = 2560 bytes
warning ์์
Notion ์ค๋ช
์๋ standby_wakeup_pin_setup() ์์ ๋ถ๋ถ์ "PA0์ด Low๋ก ์์ ๋ ๋๊น์ง ๋๊ธฐ"๋ผ๊ณ ์ ์ด๋์์ง๋ง, ํ์ฌ ZIP์ ์ค์ ์ฝ๋๋:
while (get_wakeup_pin_state() == 0) {}
์ด๋ค. ์ด ์กฐ๊ฑด์ PA0์ด 0์ธ ๋์ ๊ณ์ ๋๊ธฐํ๊ณ 1์ด ๋๋ฉด ๋น ์ ธ๋์จ๋ค.
PA0 wakeup ์์ฒด๊ฐ ์์ง ๋ฏธ๊ฒ์ฆ ์ํ์ด๋ฏ๋ก, ์ค์ jumper test๋ฅผ ํ ๋ ์ด๊ธฐ pin ์ํ์ ์ด polling ์กฐ๊ฑด์ ํจ๊ป ์ฌํ์ธํ ํ์๊ฐ ์๋ค. ์ด Wiki์์๋ ํ์ฌ ์์ค๋ฅผ ์์ ํ์ง ์๊ณ ๊ทธ๋๋ก ๊ธฐ๋กํ๋ค.
Standby๋
SLEEPDEEP + PDDS + WFIํ๋ฆ์ผ๋ก ์ง์ ํ๋ค.Standby wakeup ์ดํ reset ํ๋ฆ์ผ๋ก main์ด ๋ค์ ์์๋๋ค.
Standby ์ง์ ์ ๊ฒ์ฆํ๊ณ PA0 ์ค์ wakeup์ ๋ฏธ๊ฒ์ฆ์ด๋ค.