Bare metal C Ch18 StandbyMode - Hongjayeong-02/Basic_SoC_implementation GitHub Wiki

Ch18. Power Management โ€” Standby + PA0 Wakeup

ํ•œ ์ค„ ์š”์•ฝ: B1 interrupt๋กœ Standby์— ์ง„์ž…ํ•˜๊ณ  PA0(WKUP)์„ wakeup source๋กœ ๊ตฌ์„ฑํ•œ๋‹ค. Standby ์ง„์ž…์€ ๊ฒ€์ฆํ–ˆ์ง€๋งŒ PA0 wakeup์€ ํ˜„์žฌ ๋ฏธ๊ฒ€์ฆ ์ƒํƒœ๋‹ค.

1. ํ•ต์‹ฌ ์ด๋ก 

Notion์—์„œ๋Š” STM32 low-power mode๋ฅผ Sleep / Stop / Standby์˜ ์„ธ ๋‹จ๊ณ„๋กœ ์ •๋ฆฌํ–ˆ๋‹ค.

Mode | ํŠน์ง• -- | -- Sleep | Core ์ค‘์‹ฌ์œผ๋กœ ์ •์ง€ Stop | ๋” ๊นŠ์€ ์ €์ „๋ ฅ Standby | ๊ฐ€์žฅ ๊นŠ์€ ์ €์ „๋ ฅ, wakeup ์‹œ reset ํ๋ฆ„

์ด๋ฒˆ ์‹ค์Šต์€ Standby๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

Cortex-M๊ณผ STM32 ์„ค์ •์˜ ๊ฒฐํ•ฉ

Standby ์ง„์ž…์—๋Š” ์„œ๋กœ ๋‹ค๋ฅธ ๊ณ„์ธต์˜ ์„ค์ •์ด ํ•จ๊ป˜ ํ•„์š”ํ•˜๋‹ค.

SCB->SCR.SLEEPDEEP
= Cortex-M core์—๊ฒŒ deep sleep ์š”์ฒญ

PWR->CR.PDDS = STM32์—๊ฒŒ deep sleep ์ค‘ Standby ์„ ํƒ

๊ทธ ํ›„:

__WFI();

๋กœ sleep ์ง„์ž…์„ ์š”์ฒญํ•œ๋‹ค.

Standby wakeup ์ดํ›„

Notion ๊ธฐ๋ก์—์„œ๋Š” Standby์—์„œ ๊นจ์–ด๋‚˜๋ฉด ์ด์ „ ์ฝ”๋“œ ์œ„์น˜๋กœ ์ด์–ด์„œ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ reset๊ณผ ๊ฐ™์€ ํ๋ฆ„์œผ๋กœ main()๋ถ€ํ„ฐ ๋‹ค์‹œ ์‹œ์ž‘ํ•œ๋‹ค๊ณ  ์ •๋ฆฌํ–ˆ๋‹ค.

๋”ฐ๋ผ์„œ PWR->CSR์˜:

  • SBF

  • WUF

flag๋ฅผ ์ด์šฉํ•ด reset/wakeup ์›์ธ์„ ํ™•์ธํ•œ๋‹ค.

Wakeup pin

PA0์„ WKUP input์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค. ๋ณ„๋„ pull-up/down ์—†์ด ์™ธ๋ถ€ wiring์œผ๋กœ input state๋ฅผ ๋งŒ๋“ ๋‹ค.

2. ๋™์ž‘ ํ๋ฆ„

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()

3. ์‹ค์ œ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ


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๋ฅผ ์ „๋ถ€ ๊ธฐ๋กํ•œ๋‹ค.

4. ์ „์ฒด ์ฝ”๋“œ

Inc/gpio.h

#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 */

Src/gpio.c

#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-&gt;MODER &amp;= ~(0x3UL &lt;&lt; (LED_PIN * 2));
GPIOB-&gt;MODER |=  (0x1UL &lt;&lt; (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-&gt;MODER &amp;= ~(0x3UL &lt;&lt; (BTN_PIN * 2));  /* Input */
GPIOC-&gt;PUPDR &amp;= ~(0x3UL &lt;&lt; (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 */ }

Inc/gpio_exti.h

#ifndef GPIO_EXTI_H__
#define GPIO_EXTI_H__

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

#define LINE13 (1U << 13)

void pc13_exti_init(void);

#endif

Src/gpio_exti.c

#include "gpio_exti.h"

#define GPIOCEN (1U << 2) #define SYSCFGEN (1U << 14)

void pc13_exti_init(void) { __disable_irq();

RCC-&gt;AHB1ENR |= GPIOCEN;

GPIOC-&gt;MODER &amp;= ~(1U &lt;&lt; 26);
GPIOC-&gt;MODER &amp;= ~(1U &lt;&lt; 27);

RCC-&gt;APB2ENR |= SYSCFGEN;

/* EXTI13 -&gt; PORTC */
SYSCFG-&gt;EXTICR[3] |= (1U &lt;&lt; 5);

EXTI-&gt;IMR |= (1U &lt;&lt; 13);

/* ์ด ๋ณด๋“œ๋Š” B1์ด active-HIGH๋ผ Rising-edge (์›์„œ๋Š” FTSR/active-LOW) */
EXTI-&gt;RTSR |= (1U &lt;&lt; 13);

NVIC_EnableIRQ(EXTI15_10_IRQn);

__enable_irq();

}

Inc/standby_mode.h

#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__ */

Src/standby_mode.c

#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-&gt;MODER &amp;= ~(1U &lt;&lt; 0);
GPIOA-&gt;MODER &amp;= ~(1U &lt;&lt; 1);

GPIOA-&gt;PUPDR &amp;= ~(1U &lt;&lt; 0);
GPIOA-&gt;PUPDR &amp;= ~(1U &lt;&lt; 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-&gt;CSR &amp;= ~(1U &lt;&lt; 8);
PWR-&gt;CR  |= (1U &lt;&lt; 2);
PWR-&gt;CSR |= (1U &lt;&lt; 8);

set_power_mode(PWR_MODE_STANDBY);

SCB-&gt;SCR |= (1U &lt;&lt; 2);

__WFI();

}

Inc/uart.h

#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

Src/uart.c

#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-&gt;MODER &amp;= ~(0x3UL &lt;&lt; (8 * 2));
GPIOD-&gt;MODER |=  (0x2UL &lt;&lt; (8 * 2));
GPIOD-&gt;MODER &amp;= ~(0x3UL &lt;&lt; (9 * 2));
GPIOD-&gt;MODER |=  (0x2UL &lt;&lt; (9 * 2));

GPIOD-&gt;AFR[1] &amp;= ~(0xFUL &lt;&lt; 0);
GPIOD-&gt;AFR[1] |=  (0x7UL &lt;&lt; 0);   /* PD8 -&gt; AF7 (USART3_TX) */
GPIOD-&gt;AFR[1] &amp;= ~(0xFUL &lt;&lt; 4);
GPIOD-&gt;AFR[1] |=  (0x7UL &lt;&lt; 4);   /* PD9 -&gt; AF7 (USART3_RX) */

RCC-&gt;APB1ENR |= USART3EN;

uart_set_baudrate(APB1_CLK, DBG_UART_BAUDRATE);

USART3-&gt;CR1 = CR1_TE;
USART3-&gt;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); }

Src/main.c

/*
  • 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 -&gt; Standby ์ง„์ž…, WKUP -&gt; ๋ฆฌ์…‹)๋กœ๋งŒ ์ด๋ค„์ง */
}

}

static void check_reset_source(void) { RCC->APB1ENR |= RCC_APB1ENR_PWREN;

if ((PWR-&gt;CSR &amp; PWR_CSR_SBF) == PWR_CSR_SBF)
{
    PWR-&gt;CR |= PWR_CR_CSBF;
    uart_write_string("System resume from Standby.....\r\n");

    while (get_wakeup_pin_state() == 0) {}
}

if ((PWR-&gt;CSR &amp; PWR_CSR_WUF) == PWR_CSR_WUF)
{
    PWR-&gt;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(); } }

5. ์‹ค์Šต ๊ฒฐ๊ณผ

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์—์„œ๋Š” ํ˜„์žฌ ์†Œ์Šค๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ  ๊ทธ๋Œ€๋กœ ๊ธฐ๋กํ•œ๋‹ค.

6. ํ•ต์‹ฌ ์ •๋ฆฌ

  • Standby๋Š” SLEEPDEEP + PDDS + WFI ํ๋ฆ„์œผ๋กœ ์ง„์ž…ํ•œ๋‹ค.

  • Standby wakeup ์ดํ›„ reset ํ๋ฆ„์œผ๋กœ main์ด ๋‹ค์‹œ ์‹œ์ž‘๋œ๋‹ค.

  • Standby ์ง„์ž…์€ ๊ฒ€์ฆํ–ˆ๊ณ  PA0 ์‹ค์ œ wakeup์€ ๋ฏธ๊ฒ€์ฆ์ด๋‹ค.

โš ๏ธ **GitHub.com Fallback** โš ๏ธ