6.1 實(shí)驗(yàn)內(nèi)容
通過(guò)本實(shí)驗(yàn)主要學(xué)習(xí)以下內(nèi)容:
? PMU原理;
? 低功耗的進(jìn)入以及退出操作;
6.2 實(shí)驗(yàn)原理
6.2.1 PMU結(jié)構(gòu)原理
PMU即電源管理單元,其內(nèi)部結(jié)構(gòu)下圖所示,由該圖可知,GD32F303系列MCU具有三個(gè)電源域,包括VDD/VDDA電源域、1.2V電源域以及電池備份域,其中,VDD /VDDA域由電源直接供電。在VDD/VDDA域中嵌入了一個(gè)LDO,用來(lái)為1.2V域供電。在備份域中有一個(gè)電源切換器,當(dāng)VDD/VDDA電源關(guān)閉時(shí),電源切換器可以將備份域的電源切換到VBAT引腳,此時(shí)備份域由VBAT引腳(電池)供電。
VDD 域?yàn)閿?shù)字電源域包括 HXTAL(高速外部晶體振蕩器)、 LDO(電壓調(diào)節(jié)器)、 POR / PDR(上電/掉電復(fù)位)、 FWDGT(獨(dú)立看門狗定時(shí)器)和除 PC13、PC14 和 PC15 之外的所有 PAD 等等。另外,上圖中與PMU控制器連接的PA0、NRST、FWDGT以及RTC表示待機(jī)模式下的喚醒源。VDDA域?yàn)槟M電源域包括 ADC / DAC(AD / DA 轉(zhuǎn)換器)、 IRC8M(內(nèi)部 8M RC 振蕩器)、 IRC48M(內(nèi)部 48M RC 振蕩器)、 IRC40K(內(nèi)部 40KHz RC振蕩器) PLLs(鎖相環(huán))和 LVD(低電壓檢測(cè)器)等等。
POR / PDR(上電/掉電復(fù)位) 電路檢測(cè)VDD / VDDA并在電壓低于特定閾值時(shí)產(chǎn)生電源復(fù)位信號(hào)復(fù)位除備份域之外的整個(gè)芯片。 下圖顯示了供電電壓和電源復(fù)位信號(hào)之間的關(guān)系。 VPOR 表示上電復(fù)位的閾值電壓,典型值約為 2.40V, VPDR 表示掉電復(fù)位的閾值電壓,典型值約為1.8V。遲滯電壓Vhyst值約為600mV。
? 注意:當(dāng)電源電壓高于VPOR后,MCU內(nèi)部會(huì)延遲2ms后再拉高NRST,MCU才會(huì)正式啟動(dòng),此時(shí)可確保MCU啟動(dòng)時(shí)刻VDD電壓已高于VPOR。
GD32F303系列MCU具有LVD低電壓檢測(cè)功能,如下圖所示,LVD 的功能是檢測(cè) VDD / VDDA 供電電壓是否低于低電壓檢測(cè)閾值,該閾值由電源控制寄存器(PMU_CTL) 中的 LVDT[2:0]位進(jìn)行配置。 LVD 通過(guò) LVDEN 置位使能,位于電源狀態(tài)寄存器(PMU_CS) 中的 LVDF 位表示低電壓事件是否出現(xiàn),該事件連接至 EXTI 的第 16 線,用戶可以通過(guò)配置 EXTI 的第16 線產(chǎn)生相應(yīng)的中斷。 LVD 中斷信號(hào)依賴于 EXTI 第 16 線的上升或下降沿配置。遲滯電壓 Vhyst值為 100mV。
? 注意:LVD一般可用于欠壓異常處理或者用于掉電檢測(cè)。
1.2V 電源域?yàn)?Cortex?-M4 內(nèi)核邏輯、 AHB / APB 外設(shè)、備份域和 VDD / VDDA域的 APB 接口等供電。若系統(tǒng)系統(tǒng)工作在高頻狀態(tài)建議使能高驅(qū)模式。
電池備份域由內(nèi)部電源切換器來(lái)選擇VDD供電或VBAT(電池)供電,然后由VBAK為備份域供電,該備份域包含RTC(實(shí)時(shí)時(shí)鐘)、 LXTAL(低速外部晶體振蕩器)、 BPOR(備份域上電復(fù)位)、BREG(備份寄存器),以及PC13至PC15共3個(gè)BKPPAD。為了確保備份域中寄存器的內(nèi)容及RTC正常工作,當(dāng)VDD關(guān)閉時(shí), VBAT引腳可以連接至電池或其他等備份源供電。電源切換器是由VDD / VDDA域掉電復(fù)位電路控制的。對(duì)于沒(méi)有外部電池的應(yīng)用,建議將VBAT引腳通過(guò)100nF的外部陶瓷去耦電容連接到VDD引腳上。
? 注意: 由于PC13至PC15引腳是通過(guò)電源切換器供電的,電源切換器僅可通過(guò)小電流,因此當(dāng)PC13至PC15的GPIO口在輸出模式時(shí),其工作的速度不能超過(guò)2MHz(最大負(fù)載為30Pf)。
電池備份域中具有84字節(jié)備份數(shù)據(jù)寄存器,該備份數(shù)據(jù)寄存器可用于存儲(chǔ)用戶數(shù)據(jù),且在掉電復(fù)位以及系統(tǒng)復(fù)位情況下數(shù)據(jù)不丟失,僅在發(fā)生侵入事件時(shí)數(shù)據(jù)會(huì)被擦除。
若讀者有在VDD掉電情況下RTC繼續(xù)工作的應(yīng)用需求,需要VBAT引腳外接電池并使用LXTAL外部低頻晶振,這樣在VDD掉電的情況下,VBAT供電將會(huì)由VDD切換到VBAT,LXTAL和RTC均可正常工作,后續(xù)VDD上電后同步RTC寄存器即可獲取正確的RTC時(shí)間。
6.2.2 低功耗模式
GD32F303系列MCU具有三種低功耗模式,分別為睡眠模式、深度睡眠模式和待機(jī)模式。
睡眠模式與 Cortex?-M4 的 SLEEPING 模式相對(duì)應(yīng)。在睡眠模式下,僅關(guān)閉 Cortex?-M4的時(shí)鐘,如需進(jìn)入睡眠模式,只要清除 Cortex?-M4 系統(tǒng)控制寄存器中的 SLEEPDEEP 位,并執(zhí)行一條 WFI 或 WFE 指令即可。
深度睡眠模式與 Cortex?-M4 的 SLEEPDEEP 模式相對(duì)應(yīng),在深度睡眠模式下, 1.2V 域中的所有時(shí)鐘全部關(guān)閉, IRC8M、 HXTAL 及 PLLs 也全部被禁用,SRAM 和寄存器中的內(nèi)容被保留,根據(jù) PMU_CTL 寄存器的 LDOLP 位的配置,可控制 LDO 工作在正常模式或低功耗模式。進(jìn)入深度睡眠模式之前,先將 Cortex?-M4 系統(tǒng)控制寄存器的 SLEEPDEEP 位置 1,再清除PMU_CTL 寄存器的 STBMOD 位,然后執(zhí)行WFI 或 WFE 指令即可進(jìn)入深度睡眠模式。
待機(jī)模式是基于 Cortex?-M4 的 SLEEPDEEP 模式實(shí)現(xiàn)的。在待機(jī)模式下,整個(gè) 1.2V 域全部停止供電,同時(shí) LDO 和包括 IRC8M、 HXTAL 和 PLL 也會(huì)被關(guān)閉。進(jìn)入待機(jī)模式前,先將Cortex?-M4 系統(tǒng)控制寄存器的 SLEEPDEEP 位置 1,再將 PMU_CTL 寄存器的 STBMOD位置 1,再清除 PMU_CS 寄存器的 WUF位,然后執(zhí)行WFI 或 WFE 指令,系統(tǒng)進(jìn)入待機(jī)模式。
低功耗模式相關(guān)數(shù)據(jù)可參考下表,不同的低功耗模式是通過(guò)關(guān)閉不同時(shí)鐘以及電源來(lái)實(shí)現(xiàn)的,關(guān)閉的時(shí)鐘和電源越多,MCU所進(jìn)入的睡眠模式將會(huì)越深,功耗也會(huì)越低,帶來(lái)的喚醒時(shí)間也會(huì)越長(zhǎng),其喚醒源也會(huì)越少。睡眠模式是最淺的低功耗模式,僅關(guān)閉了CPU,代碼不再運(yùn)行,所有的中斷或事件均可喚醒,喚醒時(shí)間也最快;深度睡眠模式時(shí)中間的低功耗模式,關(guān)閉了1.2V電源域時(shí)鐘以及IRC8M/HXTAL/PLL,僅可通過(guò)EXTI中斷或事件喚醒,喚醒后需要重新配置系統(tǒng)時(shí)鐘;待機(jī)模式是功耗最低的低功耗模式,關(guān)閉了1.2V電源域電源以及IRC8M/HXTAL/PLL,僅可通過(guò)NRST/看門狗/RTC鬧鐘/WKUP引腳喚醒,喚醒后MCU將會(huì)復(fù)位重啟。
各種睡眠模式下的功耗可以參考數(shù)據(jù)手冊(cè)描述,睡眠模式下相較于同主頻模式下的運(yùn)行模式功耗減少約50%,深度睡眠和待機(jī)模式功耗更低,如下表所示,深度睡眠模式下功耗常溫典型值為133ua-189ua,待機(jī)模式下功耗常溫典型值為5uA。
? 注意:由于深度睡眠模式具有較低的功耗,喚醒后繼續(xù)從斷點(diǎn)處執(zhí)行,因而具有更廣泛的應(yīng)用場(chǎng)景,但需注意若需達(dá)到較一致的MCU深度睡眠功耗,需要將系統(tǒng)中未使用的MCU引腳均配置為模擬輸入狀態(tài),包括芯片內(nèi)部未引出的pad。
Note:左側(cè)是常溫下的典型數(shù)值,中間為85度下的典型數(shù)值,右側(cè)為常溫下的最大數(shù)值。
6.3 硬件設(shè)計(jì)
本例程stanby的喚醒使用到了PA0喚醒引腳,其電路如下所示。
6.4 代碼解析
本例程實(shí)現(xiàn)deepsleep以及standby的進(jìn)入以及喚醒測(cè)試,首先我們來(lái)看下主函數(shù),如下所示。該主函數(shù)首先配置了系統(tǒng)主時(shí)鐘、延遲、打印和LED函數(shù),并打印Example of Low Power Test Demo。之后查詢是否進(jìn)入過(guò)Standby模式,如果進(jìn)入過(guò)Standby模式,表示當(dāng)前狀態(tài)為standby喚醒后的復(fù)位,則打印A reset event from Standby mode has occurred,并翻轉(zhuǎn)LED0,因而驗(yàn)證standby喚醒的時(shí)候,其現(xiàn)象可觀察到LED0的翻轉(zhuǎn)。之后使能wakeup引腳的喚醒以及按鍵的初始化,此時(shí)將KEY0配置為中斷模式。在while(1)中,查詢KEY1是否按下,如果按下則打印Entering Standby Mode.并進(jìn)入standby模式,如果key2按下,則打印Enter Deepsleep mode.并進(jìn)入Deepsleep模式,從deepsleep模式喚醒后需要重新配置時(shí)鐘,打印Exit Deepsleep mode.并翻轉(zhuǎn)LED1。Standby的喚醒使用PA0 wakeup引腳,deepsleep的喚醒可使用任何EXTI中斷,本實(shí)例中使用PE2的KEY0按鍵中斷喚醒。
C
int main(void)
{
rcu_periph_clock_enable(RCU_PMU);
rcu_system_clk_config_120M();
driver_init();
bsp_uart_init(&BOARD_UART); ??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????/* 板載UART初始化 */
printf("Example of Low Power Test Demo.\r\n");
delay_ms(2000);
bsp_led_group_init();
if(pmu_flag_get(PMU_FLAG_RESET_STANDBY)==SET)
{
printf("A reset event from Standby mode has occurred.\r\n");
bsp_led_toggle(&LED0);
pmu_flag_clear(PMU_FLAG_RESET_STANDBY);
}
rcu_all_reset_flag_clear();
pmu_wakeup_pin_enable();
KEY0.key_gpio->gpio_mode = INT_HIGH;
KEY0.key_gpio->int_callback = key0_IRQ_callback;
bsp_key_group_init();
nvic_irq_enable(EXTI2_IRQn,0,0);
while (1)
{
if(bsp_key_state_get(&KEY1)!=RESET)
{
printf("Entering Standby Mode.\r\n");
bsp_led_toggle(&LED0);
pmu_to_standbymode(WFI_CMD);
}
if(bsp_key_state_get(&KEY2)!=RESET)
{
printf("Enter Deepsleep mode.\r\n");
bsp_led_toggle(&LED1);
config_allgpio_into_analog();
bsp_key_group_init();
pmu_to_deepsleepmode(PMU_LDO_NORMAL, PMU_LOWDRIVER_DISABLE, WFI_CMD);
bsp_led_group_init();
bsp_uart_init(&BOARD_UART); ??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????/* 板載UART初始化 */
printf("Exit Deepsleep mode.\r\n");
bsp_led_toggle(&LED1);
}
}
}
需要注意,進(jìn)入deepsleep之前需要將不用的GPIO全部配置為模擬輸入的模式,為了得到更為一致且較低的功耗,其配置函數(shù)如下。
在配置所有IO為模擬輸入之后,如果有需要保持GPIO狀態(tài)的引腳,需要配置后再進(jìn)入deepsleep,如例程中的按鍵引腳,因?yàn)樾枰存I喚醒deep sleep。
C
void config_allgpio_into_analog(void)
{
rcu_periph_clock_enable( RCU_GPIOA );
rcu_periph_clock_enable( RCU_GPIOB );
rcu_periph_clock_enable( RCU_GPIOC );
rcu_periph_clock_enable( RCU_GPIOD );
rcu_periph_clock_enable( RCU_GPIOE );
rcu_periph_clock_enable( RCU_GPIOF );
rcu_periph_clock_enable( RCU_GPIOG );
rcu_periph_clock_enable( RCU_AF );
GPIO_CTL0( GPIOA ) = 0x0 ;
GPIO_CTL1( GPIOA ) &= 0xFFF00000 ;
GPIO_CTL0( GPIOB ) &= 0x000FF000 ;
GPIO_CTL1( GPIOB ) = 0x0 ;
GPIO_CTL0( GPIOC ) = 0x0 ;
GPIO_CTL1( GPIOC ) = 0x0 ;
GPIO_CTL0( GPIOD ) = 0x0 ;
GPIO_CTL1( GPIOD ) = 0x0 ;
GPIO_CTL0( GPIOE ) = 0x0 ;
GPIO_CTL1( GPIOE ) = 0x0;
GPIO_CTL0( GPIOF ) = 0x0 ;
GPIO_CTL1( GPIOF ) = 0x0;
GPIO_CTL0( GPIOG ) = 0x0 ;
GPIO_CTL1( GPIOG ) = 0x0 ;
RCU_AHBEN = 0;
RCU_APB2EN = 0;
RCU_APB1EN = 0;
rcu_periph_clock_disable( RCU_GPIOA );
rcu_periph_clock_disable( RCU_GPIOB );
rcu_periph_clock_disable( RCU_GPIOC );
rcu_periph_clock_disable( RCU_GPIOD );
rcu_periph_clock_disable( RCU_GPIOE );
rcu_periph_clock_disable( RCU_GPIOF );
rcu_periph_clock_disable( RCU_GPIOG );
rcu_periph_clock_disable( RCU_AF );
}
6.5 實(shí)驗(yàn)結(jié)果
將本實(shí)驗(yàn)歷程燒錄到紅楓派實(shí)驗(yàn)板中,按下KEY1按鍵將進(jìn)入standby模式,并打印Entering Standby Mode.,然后按下wakeup按鍵,將從stanby模式喚醒,打印A reset event from Standby mode has occurred.并翻轉(zhuǎn)LED0,之后按下KEY2按鍵將打印Enter Deepsleep mode.進(jìn)入deepsleep模式,然后按下KEY0按鍵將從deepsleep模式下喚醒,喚醒后重新配置時(shí)鐘,打印Exit Deepsleep mode.并將LED1翻轉(zhuǎn)。
具體現(xiàn)象如下所示。
紅楓派開(kāi)發(fā)板使用手冊(cè):??????????????????????????????????????????????????GD32F303紅楓派使用手冊(cè) - 飛書(shū)云文檔 (feishu.cn)