Chapter 18 - Hongjayeong-02/Basic_SoC_implementation GitHub Wiki
Verification Status
Build / Link : PASS B1 โ Standby Entry : PASS PA0 WKUP โ Wakeup : NOT VERIFIEDStandby ์ง์ ๊น์ง๋ ์ค์ NUCLEO-F439ZI์์ ํ์ธํ๋ค.
PA0(WKUP)์ ์ด์ฉํ wake-up์ ์ ํผ์ ์ด ์์ด ์์ง ๊ฒ์ฆํ์ง ๋ชปํ๋ค.
NUCLEO-F439ZI์ B1 ๋ฒํผ์ ๋๋ฌ STM32F439ZI๋ฅผ Standby Mode๋ก ์ง์ ์ํจ๋ค.
์ดํ PA0์ WKUP ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ฌ ๋ค์ system์ ๊นจ์ฐ๋ ๊ตฌ์กฐ๋ฅผ ์ดํดํ๋ค.
Normal Operation
โ
B1 Press
โ
PC13 EXTI
โ
LED OFF
โ
Configure Standby
โ
SLEEPDEEP = 1
โ
__WFI()
โ
STANDBYWake-up ๋ชฉํ:
PA0 WKUP
LOW โ HIGH
โ
Wakeup Event
โ
System Reset
โ
main() from beginning
โ
SBF Check
โ
"System resume from Standby....."STM32F4์ ๋ํ์ ์ธ low-power mode:
Mode | ์ ์ ์์ค | Wake-up | ํน์ง -- | -- | -- | -- Sleep | ๋ฎ์ | ๋น ๋ฆ | CPU core ์ค์ฌ์ผ๋ก ์ ์ง Stop | ์ค๊ฐ | ๋ณดํต | ์ฃผ์ system clock ์ ์ง Standby | ๊ฐ์ฅ ๋์ | ๊ฐ์ฅ ๋๋ฆผ | ๋๋ถ๋ถ์ ํ๋ก์ SRAM ์ํ ์์ค์ด๋ฒ ์ค์ต:
B1
โ PC13
โ EXTI13
โ Standby ์ง์
Wake-up target:
PA0
โ WKUP pinLED:
LD1
โ PB0LED ์ํ๋ฅผ ์ด์ฉํด:
ON
โ Normal Operation
OFF
โ Entering Standby
๋ฅผ ํ์ํ๋ค.
Project:
Inc/
โโโ gpio.h
โโโ gpio_exti.h
โโโ standby_mode.h
โโโ uart.h
Src/
โโโ gpio.c
โโโ gpio_exti.c
โโโ standby_mode.c
โโโ uart.c
โโโ main.c
Ch07:
GPIOCh10:
UARTCh14:
EXTIdriver๋ฅผ ์ฌ์ฌ์ฉํ๋ค.
#ifndef STANDBY_MODE_H__
#define STANDBY_MODE_H__
#include <stdint.h>
#include "stm32f4xx.h"
/*
- Configure PA0 as the external WKUP input.
*/
void wakeup_pin_init(void);
/*
- Configure Standby mode and enter low-power state.
*/
void standby_wakeup_pin_setup(void);
/*
- Return the current PA0 input state.
-
- Complete archived function body was not preserved
- in the current Notion source.
*/
uint8_t get_wakeup_pin_state(void);
#endif
void wakeup_pin_init(void)
{
/*
* --------------------------------------------------------
* Step 1. Enable GPIOA Clock
* --------------------------------------------------------
*
* PA0 is used as the WKUP input pin.
*/
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
/*
* --------------------------------------------------------
* Step 2. Configure PA0 as Input
* --------------------------------------------------------
*
* MODER<span>[1:0]</span>:
*
* 00 = Input
*
* Clear both bits.
*/
GPIOA->MODER &= ~(1U << 0);
GPIOA->MODER &= ~(1U << 1);
/*
* --------------------------------------------------------
* Step 3. Disable Internal Pull-up / Pull-down
* --------------------------------------------------------
*
* PUPDR<span>[1:0]</span>:
*
* 00 = No Pull
*
* External wiring directly determines
* whether PA0 is LOW or HIGH.
*/
GPIOA->PUPDR &= ~(1U << 0);
GPIOA->PUPDR &= ~(1U << 1);
}
์๋๋ ๊ธฐ์กด ์ค์ต์ ๋ณด์กด๋ ํต์ฌ ์ฝ๋๋ค.
void standby_wakeup_pin_setup(void)
{
/*
* --------------------------------------------------------
* Step 1. Check Wakeup Pin State
* --------------------------------------------------------
*
* ORIGINAL PRACTICE CODE:
*/
while (get_wakeup_pin_state() == 0U)
{
}
/*
* IMPORTANT โ RE-TEST REQUIRED
*
* Existing notes described the code above as:
*
* "wait until PA0 is stably LOW"
*
* However the actual C condition means:
*
* while PA0 == 0
* keep waiting
*
* Therefore this loop exits only when:
*
* PA0 != 0
* โ HIGH
*
* The code and archived explanation do not agree.
*
* Because PA0 wake-up was NOT hardware-tested,
* do not silently change this condition.
*
* Verify the intended PA0 sequence during re-test.
*/
/*
* --------------------------------------------------------
* Step 2. Temporarily Disable Wakeup Pin
* --------------------------------------------------------
*
* PWR->CSR bit8 controls the wakeup pin.
*
* Disable it before clearing the old
* wakeup condition.
*/
PWR->CSR &= ~(1U << 8);
/*
* --------------------------------------------------------
* Step 3. Clear Wakeup Flag
* --------------------------------------------------------
*
* PWR->CR bit2:
*
* CWUF
*
* Clears a previously latched wakeup event.
*/
PWR->CR |= (1U << 2);
/*
* --------------------------------------------------------
* Step 4. Enable Wakeup Pin Again
* --------------------------------------------------------
*
* PA0 WKUP detection becomes active.
*/
PWR->CSR |= (1U << 8);
/*
* --------------------------------------------------------
* Step 5. Select Standby Mode
* --------------------------------------------------------
*
* set_power_mode(PWR_MODE_STANDBY)
*
* configures PWR->CR.PDDS.
*
* Full helper implementation is not preserved
* in the archived chapter source.
*/
set_power_mode(PWR_MODE_STANDBY);
/*
* --------------------------------------------------------
* Step 6. Enable Deep Sleep at Cortex-M4 Level
* --------------------------------------------------------
*
* SCB SCR bit2:
*
* SLEEPDEEP = 1
*
* Tells the Cortex-M core that WFI should
* enter a deep low-power mode.
*/
SCB->SCR |= (1U << 2);
/*
* --------------------------------------------------------
* Step 7. Wait For Interrupt
* --------------------------------------------------------
*
* __WFI()
*
* WFI = Wait For Interrupt
*
* With:
*
* PDDS = 1
* SLEEPDEEP = 1
*
* this instruction causes the MCU
* to enter Standby.
*
* After this point normal code execution stops.
*/
__WFI();
/*
* In Standby mode, successful wake-up causes
* a reset-like restart.
*
* Therefore normal execution is not expected
* to continue here.
*/
}
์ด chapter์์ ๊ฐ์ฅ ์ค์ํ ๋ฏธํ์ธ ๋ถ๋ถ์ด๋ค.
ํ์ฌ ์ฝ๋:
while (get_wakeup_pin_state() == 0U)
{
}logic:
PA0 = 0
โ
Stay in while()
PA0 = 1
โ
Exit while()
์ฆ ์ฝ๋๋ง ํด์ํ๋ฉด:
Wait until PA0 becomes HIGH์ด๋ค.
ํ์ง๋ง ๊ธฐ์กด ์ค๋ช ์:
PA0์ด LOW๋ก ์์ ๋ ๋๊น์ง ๋๊ธฐ๋ผ๊ณ ๊ธฐ๋ก๋์ด ์์๋ค.
๋์ ๊ฐ์ ์๋ฏธ๊ฐ ์๋๋ค.
๋ฐ๋ผ์ ์ฌ์ค์ต์์๋ debugger๋ UART๋ฅผ ์ฌ์ฉํด์ ๋ฐ๋์:
PA0 LOW์ผ ๋ ํจ์ ์งํ ์ฌ๋ถ
PA0 HIGH์ผ ๋ ํจ์ ์งํ ์ฌ๋ถ๋ฅผ ๋จผ์ ํ์ธํ๋ค.
์ด ๋ถ๋ถ์ PA0 wake-up ์์ฒด๊ฐ ์์ง ๋ฏธ๊ฒ์ฆ์ด๋ฏ๋ก ํ์ฌ ์์๋ก ์์ ํ์ง ์๋๋ค.
#include "gpio.h"
#include "gpio_exti.h"
#include "standby_mode.h"
#include "uart.h"
/*
- Check whether this boot occurred
- after leaving Standby mode.
*/
static void check_reset_source(void);
/*
- Called from EXTI interrupt path.
*/
static void exti_callback(void);
int main(void)
{
/*
* --------------------------------------------------------
* Step 1. Initialize UART
* --------------------------------------------------------
*
* Used to report wakeup status.
*/
uart_init();
/*
* --------------------------------------------------------
* Step 2. Initialize LD1
* --------------------------------------------------------
*
* PB0 โ LD1
*/
led_init();
/*
* --------------------------------------------------------
* Step 3. Initialize PA0 Wakeup Input
* --------------------------------------------------------
*/
wakeup_pin_init();
/*
* --------------------------------------------------------
* Step 4. Check Previous Reset Source
* --------------------------------------------------------
*
* Standby wake-up causes main() to restart.
*
* Therefore check SBF early during boot.
*/
check_reset_source();
/*
* --------------------------------------------------------
* Step 5. Indicate Normal Operation
* --------------------------------------------------------
*
* LED ON:
*
* board is awake
*/
led_on();
/*
* --------------------------------------------------------
* Step 6. Configure B1 EXTI
* --------------------------------------------------------
*
* B1:
*
* PC13
* โ
* EXTI13
* โ
* Standby entry
*/
pc13_exti_init();
while (1)
{
/*
* Main loop has no polling task.
*
* B1 interrupt triggers Standby entry.
*/
}
}
static void check_reset_source(void)
{
/*
* --------------------------------------------------------
* Step 1. Enable Power Controller Clock
* --------------------------------------------------------
*
* PWR peripheral belongs to APB1.
*/
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
/*
* --------------------------------------------------------
* Step 2. Check Standby Flag
* --------------------------------------------------------
*
* SBF:
*
* Standby Flag
*
* If set:
*
* this boot followed Standby mode.
*/
if ((PWR->CSR & PWR_CSR_SBF)
== PWR_CSR_SBF)
{
/*
* -----------------------------------------------
* Clear Standby Flag
* -----------------------------------------------
*
* CSBF:
*
* Clear Standby Flag
*/
PWR->CR |= PWR_CR_CSBF;
/*
* Inform the user that this boot occurred
* after Standby wake-up.
*
* NOTE:
*
* This exact message is the EXPECTED output.
*
* Actual PA0 wake-up has not yet been verified.
*/
uart_write_string(
"System resume from Standby.....\r\n"
);
/*
* ORIGINAL PRACTICE CODE
*
* Same PA0 condition appears here.
*
* Again:
*
* while state == 0
*
* means the function waits while LOW
* and exits when HIGH.
*
* Re-test required.
*/
while (get_wakeup_pin_state() == 0U)
{
}
}
/*
* --------------------------------------------------------
* Step 3. Check Wakeup Flag
* --------------------------------------------------------
*
* WUF:
*
* Wakeup Flag
*/
if ((PWR->CSR & PWR_CSR_WUF)
== PWR_CSR_WUF)
{
/*
* Clear WUF for the next low-power cycle.
*/
PWR->CR |= PWR_CR_CWUF;
}
}
static void exti_callback(void)
{
/*
* --------------------------------------------------------
* Step 1. Turn LED OFF
* --------------------------------------------------------
*
* This is the last visible indication
* before entering Standby.
*
* It must happen BEFORE __WFI().
*/
led_off();
/*
* --------------------------------------------------------
* Step 2. Enter Standby
* --------------------------------------------------------
*/
standby_wakeup_pin_setup();
/*
* Once __WFI() enters Standby,
* normal execution stops.
*/
}
Consider:
standby_wakeup_pin_setup();
led_off();If standby_wakeup_pin_setup() reaches:
__WFI();and Standby is successfully entered:
CPU execution stopsso:
led_off();is never executed.
Therefore correct ordering:
led_off();
standby_wakeup_pin_setup();
์ด๋ค.
์ฆ:
LED OFF
โ
WFI
โ
Standby์ด๋ค.
B1 press:
B1
โ
PC13 Rising Edge
โ
EXTI13
โ
EXTI15_10_IRQHandler
โ
exti_callback()
โ
LED OFF
โ
Wakeup Flag Clear
โ
Wakeup Pin Enable
โ
PDDS = 1
โ
SLEEPDEEP = 1
โ
__WFI()
โ
STANDBY์ด ๋ถ๋ถ์ ์ค์ board์์ ํ์ธํ๋ค.
๋์ ์ญํ ์ด ๋ค๋ฅด๋ค.
ARM Cortex-M4 core setting:
SCB->SCR |= (1U << 2);์๋ฏธ:
WFI
โ
Deep SleepSTM32-specific power setting:
PWR->CR.PDDS = 1์๋ฏธ:
Deep Sleep Mode
์ค์์๋
Standby ์ ํ๋ฐ๋ผ์:
SLEEPDEEP only
โ Deep Sleep category
PDDS + SLEEPDEEP
โ Standby
๋ก ์ดํดํ๋ค.
__WFI();๋ ARM instruction:
Wait For Interrupt์ด๋ค.
์ผ๋ฐ ์ํฉ์์๋ CPU๊ฐ interrupt/event๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ฉฐ sleepํ ๋ ์ฌ์ฉํ๋ค.
์ด๋ฒ์๋ ๋ฏธ๋ฆฌ:
SLEEPDEEP = 1
PDDS = 1์ ์ค์ ํ๊ธฐ ๋๋ฌธ์:
__WFI()
โ
Standby๋ก ์ด์ด์ง๋ค.
Standby์์๋ SRAM ์ํ๊ฐ ์ ์ง๋์ง ์๋๋ค.
์:
uint32_t counter = 1234;Standby ์ง์ ์ :
counter = 1234๋ผ๊ณ ํด๋ wake-up ํ:
์ด ๋ณ์ ๊ฐ์์ ๊ณ์ ์คํํ๋ ๊ตฌ์กฐ๊ฐ ์๋๋ค.
Wake-up:
Reset
โ
Startup
โ
.data initialize
โ
.bss clear
โ
main()๊ณผ์ ์ ๋ค์ ๊ฑฐ์น๋ค.
๋ฐ๋ผ์ Standby๋:
Pause / Resume๊ฐ ์๋๋ผ:
Power Down
+
Reboot์ ๊ฐ๊น๋ค.
Wake-up ํ CPU๋ ๋ค์ main()๋ถํฐ ์์ํ๊ธฐ ๋๋ฌธ์ software ์
์ฅ์์๋:
Power-on reset?
NRST?
Standby wake?๋ฅผ ๊ตฌ๋ถํด์ผ ํ๋ค.
์ฌ๊ธฐ์:
PWR->CSR & PWR_CSR_SBF๋ฅผ ํ์ธํ๋ค.
SBF = 1
โ
Previous state was Standby๋ฐ๋ผ์:
uart_write_string(
"System resume from Standby.....\r\n"
);๊ณผ ๊ฐ์ ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํ๋ค.
Wakeup event๊ฐ ๋ฐ์ํ๋ฉด:
WUF = 1์ด ๋ ์ ์๋ค.
๋ค์ low-power cycle์ ์ํด ์ด์ flag๋ฅผ ๋จ๊ฒจ๋๋ฉด ์ ๋๋ค.
๋ฐ๋ผ์:
PWR->CR |= PWR_CR_CWUF;๋ก clearํ๋ค.
ํจํด:
Check Event
โ
Handle Event
โ
Clear Flag
โ
Prepare Next Event์ด๋ค.
์ด ๋ถ๋ถ์ ์์ง ์ค์ ๊ฒ์ฆ ์ ์ด๋ค.
์ ํผ์ ์ ์ค๋นํ ํ:
PA0
โ GND
โ LOWB1 Press
โ
LED OFF
โ
StandbyPA0์:
LOW
โ
HIGH์ผ๋ก ๋ณ๊ฒฝํ๋ค.
์:
GND
โ
3.3 VExpected:
Wakeup Event
โ
System Reset
โ
main()
โ
SBF detected
โ
UART:
System resume from Standby.....
โ
LD1 ON์ค๊ธฐ ์ฌ๊ฒ์ฆ ๋ ์์๋ ๋ค์์ด ์ข๋ค.
1. PA0 IDR ํ์ธ
2. get_wakeup_pin_state() return ํ์ธ
3. while ์กฐ๊ฑด ํ์ธ
4. WUF clear ํ์ธ
5. EWUP enable ํ์ธ
6. PDDS ํ์ธ
7. SLEEPDEEP ํ์ธ
8. WFI
9. PA0 LOW โ HIGH
10. SBF ํ์ธํนํ ๊ฐ์ฅ ๋จผ์ :
while (get_wakeup_pin_state() == 0U)
{
}๊ฐ ์๋ ์๋ํ sequence์ ๋ง๋์ง ํ์ธํด์ผ ํ๋ค.
ํ์ฌ ์ค์ ํ์ธํ ๋ถ๋ถ:
Build
PASS
Download
PASS
B1 EXTI
PASS
LED OFF before Standby
PASS
Standby Entry
PASS
์ค์ ํ์:
Normal
โ LD1 ON
B1 Press
โ LD1 OFF
Standby
โ UART communication stops
Standby ์ง์ ์์ฒด๋ ํ์ธํ๋ค.
์์ง ํ์ธํ์ง ๋ชปํ ๋ถ๋ถ:
PA0 WKUP
โ
Standby Exit
โ
System Reset
โ
SBF = 1
โ
UART Resume Message์ด์ :
PA0 wake-up test์ฉ jumper wire ์์๋ฐ๋ผ์ ํ์ฌ:
Standby Entry
Verified
Wakeup
Pending
์ผ๋ก ๊ธฐ๋กํ๋ค.
๊ธฐ์กด ์ค์ต ๊ธฐ๋ก:
text = 1660 bytes
data = 0 bytes
bss = 2560 bytesWarnings = 0ํ์ธ:
RCC->APB1ENRExpected:
PWREN = 1ํ์ธ:
PWR->CSRPA0 wakeup function enable bit ํ์ธ.
ํ์ธ:
PWR->CRExpected before WFI:
PDDS = 1ํ์ธ:
SCB->SCRExpected:
SLEEPDEEP = 1PA0 wake ์ฑ๊ณต ํ:
PWR->CSR์์:
SBF
WUF์ํ๋ฅผ ํ์ธํ๋ค.
ํ์ฌ ์ถ๊ฐ ๊ฐ๋ฅ:
images/ch18_build.png
images/ch18_before_standby.png
images/ch18_standby_led_off.png
images/ch18_power_registers.png์ฌ์ค์ต ํ ์ถ๊ฐ:
images/ch18_pa0_low.png
images/ch18_pa0_high.png
images/ch18_wakeup_flags.png
images/ch18_resume_uart.png
images/ch18_wakeup.gif๊ฐ์ฅ ์ค์ํ ์ต์ข evidence:
LD1 ON
โ
B1 Press
โ
LD1 OFF
โ
Standby
โ
PA0 LOW โ HIGH
โ
Reset
โ
UART:
System resume from Standby.....
โ
LD1 ON์ด๋ค.
B1
โ
EXTI
โ
LED OFF
โ
PWR.PDDS
+
SCB.SLEEPDEEP
โ
__WFI()
โ
STANDBYWake-up:
PA0 WKUP
โ
Reset
โ
main()
โ
SBF
โ
Wakeup DetectionStandby๋ STM32F4์ ๊ฐ์ฅ ๊น์ ์ ์ ๋ ฅ mode ์ค ํ๋๋ค.
Standby์์๋ SRAM๊ณผ ์ผ๋ฐ execution context๊ฐ ์ ์ง๋์ง ์๋๋ค.
Standby wake-up ํ์๋
main()๋ถํฐ ๋ค์ ์คํ๋๋ค.SCB->SCR.SLEEPDEEP์ Cortex-M core ์ฐจ์์ deep-sleep ์ค์ ์ด๋ค.PWR->CR.PDDS๋ STM32์์ Standby mode๋ฅผ ์ ํํ๋ค.__WFI()๊ฐ ์ค์ low-power mode ์ง์ trigger๊ฐ ๋๋ค.PA0์ WKUP input์ผ๋ก ์ฌ์ฉํ๋ค.
SBF๋ฅผ ํตํด Standby์์ ๊นจ์ด๋ boot์ธ์ง ํ์ธํ๋ค.WUF๋ wakeup event flag๋ค.B1 โ EXTI โ Standby ์ง์ ๊น์ง๋ ์ค์ ๋ณด๋์์ ๊ฒ์ฆํ๋ค.
PA0 wake-up์ ์์ง hardware ๋ฏธ๊ฒ์ฆ์ด๋ค.
๊ธฐ์กด
while (get_wakeup_pin_state() == 0)์ฝ๋์ โLOW ์์ ๋๊ธฐโ ์ค๋ช ์ด ์ผ์นํ์ง ์์ผ๋ฏ๋ก ์ฌ์ค์ต์์ ๋ฐ๋์ ํ์ธํ๋ค.