開發(fā)環(huán)境:
MDK:Keil 5.30
開發(fā)板:GD32F207I-EVAL
MCU:GD32F207IK
1 GD32電源管理
GD32的工作電壓(VDD)為2.0~3.6V。通過內(nèi)置的電壓調(diào)節(jié)器提供所需的1.8V電源。當(dāng)主電源VDD掉電后,通過VBAT腳為實(shí)時(shí)時(shí)鐘(RTC)和備份寄存器提供電源。
使用電池或其他電源連接到VBAT腳上,當(dāng)VDD斷電時(shí),可以保存?zhèn)浞菁拇嫫鞯膬?nèi)容和維持RTC的功能。
VBAT腳為RTC、 LSE振蕩器和PC13至PC15端口供電,可以保證當(dāng)主電源被切斷時(shí)RTC能繼續(xù)工作。切換到VBAT供電的開關(guān),由復(fù)位模塊中的掉電復(fù)位功能控制。
當(dāng)備份域由VDD供電(VBAK連接至VDD)時(shí),以下功能可用:
● PC13可以作為通用I/O口或RTC功能引腳;
● PC14和PC15可以作為通用I/O口或LXTAL晶振引腳。
● PI8可以作為通用I/O口或RTC功能引腳
當(dāng)備份域由VBAT電源供電時(shí)(VBAK連接至VBAT),以下功能可用:
● PC13僅可以作為RTC功能引腳;
● PC14和PC15僅可作為LXTAL晶振引腳。
● PI8僅可以作為RTC功能引腳
注意:由于PC13至PC15引腳是通過電源切換器供電的,電源切換器僅可通過小電流,因此當(dāng)PC13至PC15的GPIO口在輸出模式時(shí),其工作的速度不能超過2MHz(最大負(fù)載為30pF)。
2 GD32低功耗模式
在系統(tǒng)或電源復(fù)位以后,微控制器處于運(yùn)行狀態(tài)。當(dāng)CPU不需繼續(xù)運(yùn)行時(shí),可以利用多種低功耗模式來節(jié)省功耗,例如等待某個(gè)外部事件時(shí)。用戶需要根據(jù)最低電源消耗、最快速啟動(dòng)時(shí)間和可用的喚醒源等條件,選定一個(gè)最佳的低功耗模式。
GD32F207有三種低功耗模式:
● 深度睡眠/停止模式(所有的時(shí)鐘都已停止)
● 待機(jī)模式(1.8V電源關(guān)閉)
此外,在運(yùn)行模式下,可以通過以下方式中的一種降低功耗:
● 降低系統(tǒng)時(shí)鐘
● 關(guān)閉APB和AHB總線上未被使用的外設(shè)時(shí)鐘。
從表中可以看到,這三種低功耗模式層層遞進(jìn),運(yùn)行的時(shí)鐘或芯片功能越來越少,因而功耗越來越低。
在睡眠模式中,僅關(guān)閉了 CPU 時(shí)鐘, CPU 停止運(yùn)行 ,但其片上外設(shè),CM3 核心外設(shè)全都還照常運(yùn)行。有兩種方式進(jìn)入睡眠模式,它的進(jìn)入方式?jīng)Q定了從睡眠喚醒的方式,分別是 WFI(wait for interrupt)和 WFE(wait for event),即由等待“中斷”喚醒和由“事件”喚醒。
在深度睡眠模式中, 進(jìn)一步關(guān)閉了其它所有的時(shí)鐘 ,于是所有的外設(shè)都停止了工作,但由于其 1.8V 區(qū)域的電源沒有關(guān)閉,還保留了 CPU 的寄存器、內(nèi)存的信息,所以深度睡眠模式喚醒,并重新開啟時(shí)鐘后,還可以從上次深度睡眠處繼續(xù)執(zhí)行代碼。深度睡眠模式可以由任意一個(gè)外部中斷(EXTI)喚醒。在深度睡眠模式中可以選擇電壓調(diào)節(jié)器為開模式或低功耗模式,若選擇低功耗模式,在喚醒時(shí)會(huì)加上電壓調(diào)節(jié)器的喚醒延遲。
待機(jī)模式,這與我們平時(shí)印象中的手機(jī)關(guān)機(jī)模式相似,它除了關(guān)閉所有的時(shí)鐘,還把1.8V 區(qū)域的電源也關(guān)閉了,也就是說,從待機(jī)模式喚醒后,由于沒有之前代碼的運(yùn)行記錄,只能對(duì)芯片復(fù)位,重新檢測(cè) boot 條件,從頭開始執(zhí)行程序。它有四種喚醒方式,分別是 WKUP(PA0)引腳的上升沿,RTC 鬧鐘事件,NRST 引腳的復(fù)位和FWDGT復(fù)位。
在運(yùn)行模式下,任何時(shí)候都可以通過停止為外設(shè)和內(nèi)存提供時(shí)鐘來減少功耗。為了在睡眠模式下更多地減少功耗,可在執(zhí)行WFI或WFE指令前關(guān)閉所有外設(shè)的時(shí)鐘。
通過設(shè)置AHB外設(shè)時(shí)鐘使能寄存器、APB2外設(shè)時(shí)鐘使能寄存器和APB1外設(shè)時(shí)鐘使能寄存器來開關(guān)各個(gè)外設(shè)模塊的時(shí)鐘。
2.1睡眠模式
- 進(jìn)入睡眠模式
通過執(zhí)行WFI或WFE指令進(jìn)入睡眠狀態(tài)。根據(jù)Cortex?-M3中SCR(系統(tǒng)控制寄存器)的SLEEPONEXIT位,有兩種睡眠進(jìn)入機(jī)制選項(xiàng):
● Sleep-now:如果SLEEPONEXIT位被清零,一旦執(zhí)行WFI或WFE指令, MCU立即進(jìn)入睡眠模式;
● Sleep-on-exit:如果SLEEPONEXIT位被置位,當(dāng)系統(tǒng)從最低優(yōu)先級(jí)的中斷處理程序離開后, MCU立即進(jìn)入睡眠模式。
在睡眠模式下,所有的I/O引腳都保持它們?cè)谶\(yùn)行模式時(shí)的狀態(tài)。
- 退出睡眠模式
如果執(zhí)行WFI指令進(jìn)入睡眠模式,任意一個(gè)被嵌套向量中斷控制器響應(yīng)的外設(shè)中斷都能將系統(tǒng)從睡眠模式喚醒。
如果執(zhí)行WFE指令進(jìn)入睡眠模式,則一旦發(fā)生喚醒事件時(shí),微處理器都將從睡眠模式退出。喚醒事件可以通過下述方式產(chǎn)生:
● 在外設(shè)控制寄存器中使能一個(gè)中斷,而不是在NVIC(嵌套向量中斷控制器)中使能,并且在Cortex-M3系統(tǒng)控制寄存器中使能SEVONPEND位。當(dāng)MCU從WFE中喚醒后,外設(shè)的中斷掛起位和外設(shè)的NVIC中斷通道掛起位(在NVIC中斷清除掛起寄存器中)必須被清除。
● 配置一個(gè)外部或內(nèi)部的EXIT線為事件模式。當(dāng)MCU從WFE中喚醒后,因?yàn)榕c事件線對(duì)應(yīng)的掛起位未被設(shè)置,不必清除外設(shè)的中斷掛起位或外設(shè)的NVIC中斷通道掛起位。
該模式喚醒所需的時(shí)間最短,因?yàn)闆]有時(shí)間損失在中斷的進(jìn)入或退出上。
SLEEP-NOW****模式 | 說明 |
---|---|
進(jìn)入 | 在以下條件下執(zhí)行WFI(等待中斷)或WFE(等待事件)指令: –SLEEPDEEP = 0和–SLEEPONEXIT = 0參考Cortex-M3系統(tǒng)控制寄存器。 |
退出 | 如果執(zhí)行WFI進(jìn)入睡眠模式:中斷。 如果執(zhí)行WFE進(jìn)入睡眠模式:喚醒事件。 |
喚醒延時(shí) | 無 |
SLEEP-ON_EXIT****模式 | 說明 |
---|---|
進(jìn)入 | 在以下條件下執(zhí)行WFI指令:–SLEEPDEEP = 0和–SLEEPONEXIT = 1參考Cortex?-M3系統(tǒng)控制寄存器 |
退出 | 中斷:參考中斷向量表 |
喚醒延時(shí) | 無 |
2.2 深度睡眠模式
深度睡眠模式是在Cortex?-M3的深睡眠模式基礎(chǔ)上結(jié)合了外設(shè)的時(shí)鐘控制機(jī)制,深度睡眠模式與 Cortex?-M3 的 SLEEPDEEP 模式相對(duì)應(yīng)。在深度睡眠模式下,1.2V 域中的所有時(shí)鐘全部關(guān)閉,IRC8M、HXTAL及PLLs 也全部被禁用。SRAM和寄存器中的內(nèi)容被保留。
在停止模式下,所有的I/O引腳都保持它們?cè)谶\(yùn)行模式時(shí)的狀態(tài)。
- 進(jìn)入深度睡眠模式
在深度睡眠模式下,通過設(shè)置電源控制寄存器PMU_CTL的LDOLP位使內(nèi)部調(diào)節(jié)器進(jìn)入低功耗模式,能夠降低更多的功耗。
如果正在進(jìn)行閃存編程,直到對(duì)內(nèi)存訪問完成,系統(tǒng)才進(jìn)入深度睡眠模式。
如果正在進(jìn)行對(duì)APB的訪問,直到對(duì)APB訪問完成,系統(tǒng)才進(jìn)入深度睡眠模式??梢酝ㄟ^對(duì)獨(dú)立的控制位進(jìn)行編程。
在深度睡眠模式下,如果在進(jìn)入該模式前ADC和DAC沒有被關(guān)閉,那么這些外設(shè)仍然消耗電流。
- 退出深度睡眠模式
當(dāng)一個(gè)中斷或喚醒事件導(dǎo)致退出深度睡眠模式時(shí),IRC8M、IRC40K振蕩器被選為系統(tǒng)時(shí)鐘。
當(dāng)電壓調(diào)節(jié)器處于低功耗模式下,當(dāng)系統(tǒng)從深度睡眠模式退出時(shí),將會(huì)有一段額外的啟動(dòng)延時(shí)。如果在深度睡眠模式期間保持內(nèi)部調(diào)節(jié)器開啟,則退出啟動(dòng)時(shí)間會(huì)縮短,但相應(yīng)的功耗會(huì)增加。
深度睡眠模式 | 說明 |
---|---|
進(jìn)入 | 在以下條件下執(zhí)行WFI(等待中斷)或WFE(等待事件)指令: –設(shè)置Cortex-M3系統(tǒng)控制寄存器中的SLEEPDEEP位 –清除電源控制寄存器(PMU_CTL)中的STBMOD位 –通過設(shè)置PMU_CTL中LDOLP位選擇電壓調(diào)節(jié)器的模式 注:為了進(jìn)入停止模式,所有的外部中斷的請(qǐng)求位(掛起寄存器)和RTC的鬧鐘標(biāo)志都必須被清除,否則停止模式的進(jìn)入流程將會(huì)被跳過,程序繼續(xù)運(yùn)行。 |
退出 | 如果執(zhí)行WFI進(jìn)入停止模式: 設(shè)置任一外部中斷線為中斷模式(在NVIC中必須使能相應(yīng)的外部中斷向量)。參見中斷向量。 如果執(zhí)行WFE進(jìn)入停止模式: 設(shè)置任一外部中斷線為事件模式。參見喚醒事件管理。 |
喚醒延時(shí) | IRC8M、IRC40K喚醒時(shí)間+電壓調(diào)節(jié)器從低功耗喚醒的時(shí)間。 |
2.3待機(jī)模式
待機(jī)模式可實(shí)現(xiàn)系統(tǒng)的最低功耗。該模式是在Cortex-M3深睡眠模式時(shí)關(guān)閉電壓調(diào)節(jié)器。整個(gè)1.8V供電區(qū)域被斷電。IRC8M、HXTAL 和 PLL振蕩器也被斷電。SRAM和寄存器內(nèi)容丟失。只有備份的寄存器和待機(jī)電路維持供電。
- 進(jìn)入待機(jī)模式
進(jìn)入待機(jī)模式前,先將Cortex?-M3 系統(tǒng)控制寄存器的 SLEEPDEEP 位置 1,再將 PMU_CTL 寄存器的 STBMOD 位置 1,再清除 PMU_CS 寄存器的 WUF 位,然后執(zhí)行 WFI 或 WFE 指令,系統(tǒng)進(jìn)入待機(jī)模式,PMU_CS 寄存器的 STBF 位狀態(tài)表示 MCU 是否已進(jìn)入待機(jī)模式。
- 退出待機(jī)模式
當(dāng)一個(gè)外部復(fù)位(NRST引腳)、 FWDGT復(fù)位、 WKUP引腳上的上升沿或RTC鬧鐘事件的上升沿發(fā)生時(shí),微控制器從待機(jī)模式退出。從待機(jī)喚醒后,除了電源控制/狀態(tài)寄存器(PWR_CS),所有寄存器被復(fù)位。
從待機(jī)模式喚醒后的代碼執(zhí)行等同于復(fù)位后的執(zhí)行(采樣啟動(dòng)模式引腳、讀取復(fù)位向量等)。 電源控制/狀態(tài)寄存器(PWR_CS)將會(huì)指示內(nèi)核由待機(jī)狀態(tài)退出。
待機(jī)模式可實(shí)現(xiàn)系統(tǒng)的最低功耗。該模式是在Cortex-M3深睡眠模式時(shí)關(guān)閉電壓調(diào)節(jié)器。整個(gè)1.8V供電區(qū)域被斷電。IRC8M、HXTAL 和 PLL振蕩器也被斷電。SRAM和寄存器內(nèi)容丟失。只有備份的寄存器和待機(jī)電路維持供電。
待機(jī)模式 | 說明 |
---|---|
進(jìn)入 | 在以下條件下執(zhí)行WFI(等待中斷)或WFE(等待事件)指令: –設(shè)置Cortex?-M3系統(tǒng)控制寄存器中的SLEEPDEEP位 –設(shè)置電源控制寄存器(PWR_CTL)中的STBMOD位 –清除電源控制/狀態(tài)寄存器(PWR_CS)中的WUF位 |
退出 | WKUP引腳的上升沿、RTC鬧鐘事件的上升沿、NRST引腳上外部復(fù)位、FWDGT復(fù)位。 |
喚醒延時(shí) | 復(fù)位階段時(shí)電壓調(diào)節(jié)器的啟動(dòng) |
3 低功耗的寄存器描述
電源控制寄存器(PWR_CTL),該寄存器的各位描述如下圖所示:
我們通過設(shè)置 PWR_CTL的 STBMOD位,使 CPU 進(jìn)入深度睡眠時(shí)進(jìn)入待機(jī)模式。
電源控制/狀態(tài)寄存器( PWR_CS)的各位描述如圖所示。
通過設(shè)置 PWR_CS的 WUPEN 位,來使能 WKUP 引腳用于待機(jī)模式喚醒。我們還可以從 WUF 來檢查是否發(fā)生了喚醒事件。
4 低功耗具體代碼實(shí)現(xiàn)
通過以上介紹,我們了解了進(jìn)入低功耗模式的三種方法,在者三種模式中待機(jī)模式功耗最低。筆者這里使用的是按鍵喚醒,其電路如下:
4.1睡眠模式
睡眠模式很簡單,就是通過以下指令進(jìn)入睡眠:
__WFI();
__WFE();
那么以上兩條指令又是啥意思呢?WFI(Wait for interrupt)和WFE(Wait for event)是兩個(gè)讓ARM核進(jìn)入low-power standby模式的指令,由ARM architecture定義,由ARM core實(shí)現(xiàn)。我們可以在core_cmx3.h(筆者使用的是GD32F207,對(duì)應(yīng)的就是core_cmx3.h,其他內(nèi)核類似),中找到以上指令的定義。
static __INLINE void __WFI() { __ASM volatile ("wfi"); }
static __INLINE void __WFE() { __ASM volatile ("wfe"); }
以上就是把匯編指令都封裝成了諸如__Commnad()的函數(shù)形式,并且預(yù)編譯為二進(jìn)制包。那么以上指令都能讓ARM進(jìn)入睡眠模式,又有啥區(qū)別呢?
對(duì)WFI來說,執(zhí)行WFI指令后,ARM core會(huì)立即進(jìn)入low-power standby state,直到有WFI Wakeup events發(fā)生。
而WFE則稍微不同,執(zhí)行WFE指令后,根據(jù)Event Register(一個(gè)單bit的寄存器,每個(gè)PE一個(gè))的狀態(tài),有兩種情況:如果Event Register為1,該指令會(huì)把它清零,然后執(zhí)行完成(不會(huì)standby);如果Event Register為0,和WFI類似,進(jìn)入low-power standby state,直到有WFE Wakeup events發(fā)生。
總結(jié)一下,這兩條指令的作用都是令MCU進(jìn)入休眠/待機(jī)狀態(tài)以便降低功耗,但是略有區(qū)別:
WFI: wait for Interrupt 等待中斷,即下一次中斷發(fā)生前都在此hold住不干活
WFE: wait for Events 等待事件,即下一次事件發(fā)生前都在此hold住不干活
因此我們要項(xiàng)喚醒MCU,最簡單的就是通過中斷喚醒。
睡眠模式時(shí)通過按鍵中斷喚醒,代碼如下:
/*
brief main function
param[in] none
param[out] none
retval none
*/
int main(void)
{
//usart init 115200 8-N-1
com_init(COM1, USART_MODE_GPIO, 115200, 0, 1);
/* configure LED1 GPIO port */
led_init(LED1);
/* configure LED2 GPIO port */
led_init(LED2);
/* configure LED3 GPIO port */
led_init(LED3);
/* configure LED4 GPIO port */
led_init(LED4);
//key init
key_init(KEY_WAKEUP, KEY_MODE_EXTI);
printf("\\r\\n Sleep Test \\r\\n");
while(1)
{
led_toggle(LED1);
Delay(0xFFFFF);
led_toggle(LED2);
Delay(0xFFFFF);
led_toggle(LED3);
Delay(0xFFFFF);
led_toggle(LED4);
//__WFI(); //進(jìn)入睡眠模式,等待中斷喚醒 方式一
__WFE(); //方式二
}
}
進(jìn)入睡眠模式也可調(diào)用庫函數(shù)。
void pmu_to_sleepmode(uint8_t sleepmodecmd)
值得注意的是,這里不能用滴答定時(shí)器來延時(shí),因?yàn)檫@里使用的是中斷方式實(shí)現(xiàn)的。
WFI和WFE兩條指令讓MCU進(jìn)入睡眠模式,均可通過按鍵中斷喚醒,但是他們的喚醒本質(zhì)是有區(qū)別的。
如上圖所示,圖中的藍(lán)色虛線箭頭標(biāo)出了中斷信號(hào)的傳輸路徑,而紅色箭頭標(biāo)出了事件的傳輸路徑。雖然中斷和事件的產(chǎn)生源都是一樣的,都是通過按鍵產(chǎn)生,但是路徑卻有不同,中斷是需要CPU參與的,需要軟件的中斷服務(wù)函數(shù)才能完成中斷后產(chǎn)生的結(jié)果;事件是靠脈沖發(fā)生器產(chǎn)生一個(gè)脈沖,進(jìn)而由硬件自動(dòng)完成這個(gè)事件產(chǎn)生的結(jié)果,當(dāng)然相應(yīng)的聯(lián)動(dòng)部件需要先設(shè)置好,比如引起DMA操作,AD轉(zhuǎn)換等。
4.2 深度睡眠模式
進(jìn)入深度睡眠模式之后,任何外部中斷都可以喚醒低功耗,但是需要重新配置時(shí)鐘,不然系統(tǒng)將以默認(rèn)時(shí)鐘(沒有經(jīng)過倍頻)運(yùn)行。筆者這里還是使用外部中斷喚醒。我們先看看主函數(shù)。
/*
brief main function
param[in] none
param[out] none
retval none
*/
int main(void)
{
//usart init 115200 8-N-1
com_init(COM1, USART_MODE_GPIO, 115200, 0, 1);
/* configure LED1 GPIO port */
led_init(LED1);
/* configure LED2 GPIO port */
led_init(LED2);
/* configure LED3 GPIO port */
led_init(LED3);
/* configure LED4 GPIO port */
led_init(LED4);
//key init
key_init(KEY_WAKEUP, KEY_MODE_EXTI);
/* 使能電源管理單元的時(shí)鐘 */
rcu_periph_clock_enable(RCU_PMU);
printf("\\r\\n Enter stop mode \\r\\n");
/* 進(jìn)入深度睡眠模式,設(shè)置電壓調(diào)節(jié)器為低功耗模式,等待中斷喚醒*/
pmu_to_deepsleepmode(PMU_LDO_LOWPOWER,WFI_CMD);
while(1)
{
led_toggle(LED1);
Delay(0xFFFFF);
led_toggle(LED2);
Delay(0xFFFFF);
led_toggle(LED3);
Delay(0xFFFFF);
led_toggle(LED4);
}
}
以上最重要的就一句:
pmu_to_deepsleepmode(PMU_LDO_LOWPOWER,WFI_CMD);
這是MCU進(jìn)入低功耗模式的庫函數(shù),在gd32f20x_pmu.c中實(shí)現(xiàn),原型如下:
/*!
\\brief PMU work in deepsleep mode
\\param[in] ldo:
only one parameter can be selected which is shown as below:
\\arg PMU_LDO_NORMAL: LDO work at normal power mode when pmu enter deepsleep mode
\\arg PMU_LDO_LOWPOWER: LDO work at low power mode when pmu enter deepsleep mode
\\param[in] deepsleepmodecmd:
only one parameter can be selected which is shown as below:
\\arg WFI_CMD: use WFI command
\\arg WFE_CMD: use WFE command
\\param[out] none
\\retval none
*/
void pmu_to_deepsleepmode(uint32_t ldo, uint8_t deepsleepmodecmd)
{
static uint32_t reg_snap[4];
/* clear stbmod and ldolp bits */
PMU_CTL &= ~((uint32_t)(PMU_CTL_STBMOD | PMU_CTL_LDOLP));
/* set ldolp bit according to pmu_ldo */
PMU_CTL |= ldo;
/* set sleepdeep bit of Cortex-M3 system control register */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
reg_snap[0] = REG32(0xE000E010U);
reg_snap[1] = REG32(0xE000E100U);
reg_snap[2] = REG32(0xE000E104U);
reg_snap[3] = REG32(0xE000E108U);
REG32(0xE000E010U) &= 0x00010004U;
REG32(0xE000E180U) = 0XFF7FF83DU;
REG32(0xE000E184U) = 0XBFFFF8FFU;
REG32(0xE000E188U) = 0xFFFFFFFFU;
/* select WFI or WFE command to enter deepsleep mode */
if(WFI_CMD == deepsleepmodecmd) {
__WFI();
} else {
__SEV();
__WFE();
__WFE();
}
REG32(0xE000E010U) = reg_snap[0] ;
REG32(0xE000E100U) = reg_snap[1] ;
REG32(0xE000E104U) = reg_snap[2] ;
REG32(0xE000E108U) = reg_snap[3] ;
/* reset sleepdeep bit of Cortex-M3 system control register */
SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
}
上述函數(shù)主要節(jié)做了四件事:
1.設(shè)置Cortex-M3系統(tǒng)控制寄存器中的SLEEPDEEP位(SCB_SCR參考Cortex-M3權(quán)威指南182頁)。
2.清除電源控制寄存器(PWR_CTL)中的STBMOD位。
3.通過設(shè)置PWR_CR中LDOLP位選擇電壓調(diào)節(jié)器的模式。
4.執(zhí)行WFI或者WFE匯編指令。
我們可以選擇事件和中斷喚醒兩種方式,選擇哪種方式是根據(jù)庫函數(shù)的第二個(gè)參數(shù)決定的,筆者這里使用的中斷喚醒。
深度睡眠模式下MCU喚醒之后,時(shí)鐘和頻率是沒有經(jīng)過倍頻的,在GD32F207上,低功耗喚醒之后,是8M頻率運(yùn)行,而正常運(yùn)行是120M。所以,在喚醒停機(jī)模式之后,需要重新配置時(shí)鐘。最簡單就是直接調(diào)用庫函數(shù):
SystemInit();
當(dāng)然也可以自己重寫時(shí)鐘初始化函數(shù)。
好了,我們最后再看看中斷喚醒的函數(shù):
/*!
\\brief this function handles external lines 0 interrupt request
\\param[in] none
\\param[out] none
\\retval none
*/
void EXTI0_IRQHandler(void)
{
if(RESET != exti_interrupt_flag_get(EXTI_0))
{
printf("\\r\\n Enter interrupt \\r\\n");
SystemInit();
printf("\\r\\n Quit interrupt \\r\\n");
exti_interrupt_flag_clear(EXTI_0);
}
}
進(jìn)入中斷后主要是重啟時(shí)鐘,然后就會(huì)接著運(yùn)行程序。
4.3 待機(jī)模式
待機(jī)模式的功耗最低。待機(jī)模式的具體步驟如下:
1) 使能電源時(shí)鐘。
因?yàn)橐渲秒娫纯刂萍拇嫫?,所以必須先使能電源時(shí)鐘。在庫函數(shù)中,使能電源時(shí)鐘的方法是:
rcu_periph_clock_enable(RCU_PMU); //使能 PWR 外設(shè)時(shí)鐘
- 設(shè)置 WK_UP 引腳作為喚醒源。
使能時(shí)鐘之后再設(shè)置 PWR_CS 的WUPEN位,使能WUPEN用于將 CPU 從待機(jī)模式喚醒。在庫函數(shù)中,設(shè)置使能WUPEN用于喚醒 CPU 待機(jī)模式的函數(shù)是:
pmu_wakeup_pin_enable (); //使能喚醒管腳功能
3) 設(shè)置 SLEEPDEEP 位,設(shè)置 STBMOD位,執(zhí)行 WFI 指令,進(jìn)入待機(jī)模式。
進(jìn)入待機(jī)模式, 首先要設(shè)置 SLEEPDEEP 位( 該位在系統(tǒng)控制寄存器( SCB_SCR)的第二位,詳見《 CM3 權(quán)威指南》), 接著我們通過 PWR_CTL設(shè)置 STBMOD位,使得 CPU 進(jìn)入深度睡眠時(shí)進(jìn)入待機(jī)模式,最后執(zhí)行 WFI 指令開始進(jìn)入待機(jī)模式,并等待 WK_UP中斷的到來。在庫函數(shù)中,進(jìn)行上面三個(gè)功能進(jìn)入待機(jī)模式是在函數(shù)pmu_to_standbymode中實(shí)現(xiàn)的:
void pmu_to_standbymode(uint8_t standbymodecmd);
pmu_to_standbymode ()函數(shù)原型如下所示:
/*!
\\brief pmu work in standby mode
\\param[in] standbymodecmd:
only one parameter can be selected which is shown as below:
\\arg WFI_CMD: use WFI command
\\arg WFE_CMD: use WFE command
\\param[out] none
\\retval none
*/
void pmu_to_standbymode(uint8_t standbymodecmd)
{
/* set sleepdeep bit of Cortex-M3 system control register */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
/* set stbmod bit */
PMU_CTL |= PMU_CTL_STBMOD;
/* reset wakeup flag */
PMU_CTL |= PMU_CTL_WURST;
/* select WFI or WFE command to enter standby mode */
if(WFI_CMD == standbymodecmd) {
__WFI();
} else {
__WFE();
}
}
該函數(shù)中先配置了STBMOD寄存器位及 SLEEPDEEP 寄存器位,接著調(diào)用__force_stores函數(shù)確保存儲(chǔ)操作完畢后再調(diào)用 WFI 指令,從而進(jìn)入待機(jī)模式。這里值得注意的是,待機(jī)模式也可以使用 WFE 指令進(jìn)入的。
在進(jìn)入待機(jī)模式后,除了被使能了的用于喚醒的 I/O,其余 I/O 都進(jìn)入高阻態(tài),而待機(jī)模式喚醒后,相當(dāng)于復(fù)位 GD32 芯片,程序重新從頭開始執(zhí)行。
4) 最后編寫 WK_UP 中斷/事件函數(shù)。
因?yàn)槲覀兺ㄟ^ WK_UP 中斷/事件( PA0 中斷/事件)來喚醒MCU,所以我們有必要設(shè)置一下該中斷函數(shù),同時(shí)我們也通過該函數(shù)里面進(jìn)入待機(jī)模式。
/**
* @brief 用于檢測(cè)按鍵是否被長時(shí)間按下
* @param 無
* @retval 1 :按鍵被長時(shí)間按下 0 :按鍵沒有被長時(shí)間按下
*/
uint8_t pwr_check_standby(void)
{
uint8_t downCnt = 0; //記錄按下的次數(shù)
uint8_t upCnt = 0; //記錄松開的次數(shù)
while(1) //死循環(huán),由return結(jié)束
{
if(RESET == gpio_input_bit_get(GPIOA, GPIO_PIN_0))//檢測(cè)到按下按鍵
{
led_on(LED1);led_on(LED2);led_on(LED3);led_on(LED4); //點(diǎn)亮所有LED燈
downCnt++; //記錄按下次數(shù)
upCnt=0; //清除按鍵釋放記錄
Delay(0xFFFF);
if(downCnt>=100) //按下時(shí)間足夠
{
led_off(LED1);led_off(LED2);led_off(LED3);led_off(LED4);
return 1; //檢測(cè)到按鍵被時(shí)間長按下
}
}
else
{
upCnt++; //記錄釋放次數(shù)
if(upCnt>5) //連續(xù)檢測(cè)到釋放超過5次
{
led_off(LED1);led_off(LED2);led_off(LED3);led_off(LED4); //關(guān)閉所有LED燈
return 0; //按下時(shí)間太短,不是按鍵長按操作
}
}
}
}
通過以上幾個(gè)步驟的設(shè)置,我們就可以使用 GD32 的待機(jī)模式了,并且可以通過 WK_UP來喚醒 MCU。
主函數(shù)如下:
/*
brief main function
param[in] none
param[out] none
retval none
*/
int main(void)
{
//usart init 115200 8-N-1
com_init(COM1, USART_MODE_GPIO, 115200, 0, 1);
/* configure LED1 GPIO port */
led_init(LED1);
/* configure LED2 GPIO port */
led_init(LED2);
/* configure LED3 GPIO port */
led_init(LED3);
/* configure LED4 GPIO port */
led_init(LED4);
//key init
key_init(KEY_WAKEUP, KEY_MODE_GPIO);
/* 使能電源管理單元的時(shí)鐘 */
rcu_periph_clock_enable(RCU_PMU);
if(pmu_flag_get(PMU_FLAG_WAKEUP) == SET)
{
printf("\\r\\n Standby wake-up reset \\r\\n");
}
else
{
printf("\\r\\n Power-on reset\\r\\n");
}
while(1)
{
led_toggle(LED1);
Delay(0xFFFFF);
led_toggle(LED2);
Delay(0xFFFFF);
led_toggle(LED3);
Delay(0xFFFFF);
led_toggle(LED4);
if(pwr_check_standby())
{
printf("\\r\\n Enter standby mode\\r\\n");
/*清除 WU 狀態(tài)位*/
pmu_flag_clear (PMU_FLAG_RESET_WAKEUP);
/* 使能WKUP引腳的喚醒功能 */
pmu_wakeup_pin_enable ();
/* 進(jìn)入待機(jī)模式,等待喚醒*/
pmu_to_standbymode(WFI_CMD);
}
}
}
在循環(huán)體外使用庫函數(shù) pmu_flag_get檢測(cè) PMU_FLAG_WAKEUP標(biāo)志位,當(dāng)這個(gè)標(biāo)志位為SET 狀態(tài)的時(shí)候,表示本次系統(tǒng)是從待機(jī)模式喚醒的復(fù)位,否則可能是上電復(fù)位。其中PMU_FLAG_WAKEUP的標(biāo)志位在gd32f20x_pmu.h中定義。
pwr_check_standby()函數(shù)用于檢測(cè)漸漸是否長按,當(dāng)長按后就進(jìn)入待機(jī)模式。
5 低功耗實(shí)驗(yàn)現(xiàn)象
5.1睡眠模式
將程序編譯好后下載到板子上,可以看到4個(gè)LED依次閃爍,然后熄滅。按下KEY1按鍵,3個(gè)LED再次依次閃爍。
圖6
5.2 深度睡眠模式
將程序編譯好后下載到板子上。按下KEY1按鍵,4個(gè)LED依次閃爍。串口依次打印信息如下:
當(dāng)程序運(yùn)行后會(huì)首先深度睡眠模式,當(dāng)按鍵按下后,退出深度睡眠模式,則程序又會(huì)繼續(xù)運(yùn)行。
5.3待機(jī)模式
將程序編譯好后下載到板子上。按下按鍵,4個(gè)LED依次閃爍。長按KEY1按鍵,MCU進(jìn)入待機(jī)模式,LED熄滅,再次按下KEY1按鍵,LED會(huì)同時(shí)點(diǎn)亮,直到同時(shí)熄滅,松開KEY1按鍵,KEY1按下會(huì)使 PA0 引腳產(chǎn)生一個(gè)上升沿,從而喚醒系統(tǒng)。
系統(tǒng)喚醒后會(huì)進(jìn)行復(fù)位,從頭開始執(zhí)行上述過程,與第一次上電時(shí)不同的是,這樣的復(fù)位會(huì)使 PWR_FLAG_WU 標(biāo)志位改為 SET 狀態(tài),LED再次依次閃爍。串口打印信息如下。
-
mcu
+關(guān)注
關(guān)注
146文章
17123瀏覽量
350975 -
電源管理
+關(guān)注
關(guān)注
115文章
6177瀏覽量
144440 -
低功耗
+關(guān)注
關(guān)注
10文章
2396瀏覽量
103670 -
開發(fā)板
+關(guān)注
關(guān)注
25文章
5032瀏覽量
97371 -
GD32
+關(guān)注
關(guān)注
7文章
403瀏覽量
24326
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論