做嵌入式開(kāi)發(fā)的同行,幾乎都繞不開(kāi)低功耗設(shè)計(jì)。
尤其是帶 RTOS 的項(xiàng)目,明明照著芯片手冊(cè)把 MCU 扔進(jìn)了深度睡眠模式,Tickless 也開(kāi)了,結(jié)果待機(jī)電流下不來(lái)、喚醒就死機(jī)、任務(wù)延時(shí)全亂套、外設(shè)數(shù)據(jù)瘋狂丟包。
很多時(shí)候,你踩的坑,不是硬件電路的問(wèn)題,也不是芯片本身的問(wèn)題,而是 RTOS 的低功耗機(jī)制,和你的業(yè)務(wù)代碼、外設(shè)配置、內(nèi)核移植之間,那些看不見(jiàn)的隱性陷阱。
本文基于主流 RTOS(FreeRTOS/RT-Thread/uC/OS 等)的通用低功耗架構(gòu),從內(nèi)核底層到硬件協(xié)同,深挖低功耗設(shè)計(jì)全鏈路的核心坑點(diǎn),講透現(xiàn)象、根因,以及可直接落地的避坑方案,幫你徹底搞定 RTOS 低功耗難題。
1
Tickless 機(jī)制的底層陷阱
RTOS 低功耗的核心,就是 Tickless 無(wú)節(jié)拍模式。
其核心邏輯是:當(dāng)系統(tǒng)僅剩余空閑任務(wù)時(shí),停止周期性的 SysTick 節(jié)拍中斷,計(jì)算未來(lái)最長(zhǎng)可睡眠時(shí)長(zhǎng),讓 MCU 進(jìn)入深度低功耗模式,僅保留喚醒源;喚醒后,再根據(jù)實(shí)際睡眠時(shí)間補(bǔ)償系統(tǒng)節(jié)拍,恢復(fù)任務(wù)調(diào)度。
這套機(jī)制看似成熟,卻是整個(gè)低功耗設(shè)計(jì)中坑最密集的地方,稍有不慎就會(huì)滿盤(pán)皆輸。
坑 1:Tick 補(bǔ)償計(jì)算錯(cuò)誤,導(dǎo)致系統(tǒng)時(shí)間漂移、業(yè)務(wù)邏輯全亂
開(kāi)啟 Tickless 后,系統(tǒng)計(jì)時(shí)嚴(yán)重不準(zhǔn),周期性任務(wù)執(zhí)行周期偏差極大,軟件定時(shí)器超時(shí)觸發(fā)異常,甚至出現(xiàn)任務(wù)餓死、通信時(shí)序完全錯(cuò)亂。
Tickless 的核心是睡眠停 Tick,喚醒補(bǔ) Tick,補(bǔ)償?shù)木戎苯記Q定了系統(tǒng)的時(shí)間準(zhǔn)確性,而 90% 的補(bǔ)償錯(cuò)誤,都來(lái)自這幾個(gè)底層盲區(qū)。
避坑方案
坑 2:最小睡眠時(shí)長(zhǎng)判斷失誤,功耗越優(yōu)化越高
開(kāi)啟 Tickless 后,待機(jī)電流反而比不開(kāi)還大,用示波器抓電流波形,發(fā)現(xiàn)系統(tǒng)頻繁進(jìn)出低功耗,內(nèi)核調(diào)度開(kāi)銷拉滿,電源域反復(fù)啟停帶來(lái)大量額外功耗。
進(jìn)入和退出低功耗是有成本的,不僅有 CPU 執(zhí)行睡眠 / 喚醒代碼的時(shí)間開(kāi)銷,還有主頻啟停、外設(shè)上下電、電源域穩(wěn)壓器切換帶來(lái)的功耗開(kāi)銷。很多工程師直接沿用 RTOS 的默認(rèn)配置,把最小睡眠時(shí)長(zhǎng)設(shè)為 2 個(gè) Tick。
比如系統(tǒng) Tick 是 1ms,最小睡眠時(shí)長(zhǎng)就是 2ms,但如果你的芯片進(jìn)出深度睡眠的總耗時(shí)就有 500us,睡眠 2ms 節(jié)省的電量,還不夠覆蓋進(jìn)出低功耗的開(kāi)銷,最終導(dǎo)致功耗不降反升。
更嚴(yán)重的是,頻繁的睡眠 - 喚醒循環(huán),會(huì)把系統(tǒng)的空閑時(shí)間切成碎片,不僅省不了電,還會(huì)導(dǎo)致內(nèi)核調(diào)度頻繁、外設(shè)時(shí)序異常。
避坑方案
坑 3:Tick 停止后,外設(shè)驅(qū)動(dòng)的超時(shí)機(jī)制集體失效
進(jìn)入低功耗后,串口、SPI、I2C 等外設(shè)通信異常,喚醒后驅(qū)動(dòng)直接卡死,甚至觸發(fā)系統(tǒng) hardfault。
90% 的嵌入式外設(shè)驅(qū)動(dòng),超時(shí)判斷都是基于 RTOS 的系統(tǒng) Tick 計(jì)數(shù),比如:
uint32_t start = xTaskGetTickCount();while(!periph_get_flag()){if(xTaskGetTickCount() - start > TIMEOUT_TICKS){return TIMEOUT_ERROR; // 超時(shí)退出}}
但在 Tickless 模式下,系統(tǒng)進(jìn)入深度睡眠時(shí),SysTick 會(huì)完全停止,xTaskGetTickCount()的值會(huì)被凍結(jié),哪怕硬件上已經(jīng)過(guò)了幾十毫秒,這個(gè)計(jì)數(shù)值依然不會(huì)變化。
這就導(dǎo)致,睡眠前如果驅(qū)動(dòng)正在執(zhí)行帶超時(shí)的循環(huán),進(jìn)入睡眠后,超時(shí)判斷永遠(yuǎn)不會(huì)觸發(fā);喚醒后,哪怕外設(shè)已經(jīng)異常,驅(qū)動(dòng)依然卡死在死循環(huán)里,最終導(dǎo)致任務(wù)阻塞、看門(mén)狗復(fù)位。
避坑方案
2
任務(wù)調(diào)度與優(yōu)先級(jí)設(shè)計(jì)的低功耗陷阱
很多時(shí)候,你的功耗降不下來(lái),根本不是 Tickless 的問(wèn)題,而是任務(wù)設(shè)計(jì)出了問(wèn)題,系統(tǒng)連空閑任務(wù)都進(jìn)不去,談何低功耗?
坑 1:空閑任務(wù)被永久搶占,系統(tǒng)永遠(yuǎn)無(wú)法進(jìn)入低功耗
待機(jī)電流居高不下,測(cè)量發(fā)現(xiàn) CPU 占用率幾乎 100%,哪怕沒(méi)有任何業(yè)務(wù)操作,系統(tǒng)也從來(lái)不會(huì)進(jìn)入低功耗模式。
幾乎所有 RTOS 的低功耗入口,都在空閑任務(wù)里(FreeRTOS 的空閑鉤子、RT-Thread 的空閑線程、uC/OS 的空閑任務(wù)),而空閑任務(wù)的優(yōu)先級(jí),是系統(tǒng)最低的。
只要有一個(gè)優(yōu)先級(jí)比空閑任務(wù)高的任務(wù),一直處于就緒態(tài),不阻塞、不延時(shí)、不掛起,哪怕里面是空循環(huán),空閑任務(wù)也永遠(yuǎn)得不到執(zhí)行,系統(tǒng)的低功耗邏輯永遠(yuǎn)不會(huì)被觸發(fā)。
最常見(jiàn)的踩坑場(chǎng)景,寫(xiě)了一個(gè) while (1) 的業(yè)務(wù)任務(wù),里面沒(méi)有任何阻塞調(diào)用(vTaskDelay、信號(hào)量等待、隊(duì)列等待等),哪怕優(yōu)先級(jí)只比空閑高 1 級(jí),也會(huì)永久霸占 CPU。
中斷服務(wù)函數(shù)里頻繁觸發(fā)任務(wù)喚醒,導(dǎo)致任務(wù)剛進(jìn)入阻塞態(tài),就被拉回就緒態(tài),CPU 永遠(yuǎn)沒(méi)有空閑時(shí)間。
在滴答鉤子、中斷鉤子函數(shù)里,放了耗時(shí)操作,甚至死循環(huán),擠占了空閑任務(wù)的執(zhí)行時(shí)間。
避坑方案
坑 2:任務(wù)喚醒的驚群效應(yīng),導(dǎo)致睡眠碎片化、功耗飆升
一個(gè)中斷觸發(fā),系統(tǒng)電流突然拉高,持續(xù)很長(zhǎng)時(shí)間才回落,頻繁出現(xiàn)短時(shí)間的喚醒,深度睡眠的占比極低,平均功耗遠(yuǎn)超預(yù)期。
驚群效應(yīng),指的是多個(gè)任務(wù)同時(shí)等待同一個(gè)內(nèi)核對(duì)象(信號(hào)量、隊(duì)列、事件組),當(dāng)中斷觸發(fā)給這個(gè)內(nèi)核對(duì)象發(fā)送通知時(shí),所有等待的任務(wù),都會(huì)被從阻塞態(tài)拉到就緒態(tài)。
但最終只有一個(gè)任務(wù)能拿到資源,其他任務(wù)會(huì)馬上再次進(jìn)入阻塞態(tài),這個(gè)過(guò)程會(huì)觸發(fā)多次內(nèi)核調(diào)度,不僅帶來(lái)了大量的 CPU 開(kāi)銷,還會(huì)讓系統(tǒng)遲遲無(wú)法再次進(jìn)入低功耗,甚至剛進(jìn)入睡眠就被再次喚醒。
另一個(gè)類似的坑,是任務(wù)喚醒時(shí)間點(diǎn)過(guò)于分散:比如 A 任務(wù)延時(shí) 10ms,B 任務(wù)延時(shí) 11ms,C 任務(wù)延時(shí) 12ms,導(dǎo)致系統(tǒng)每隔 1ms 就被喚醒一次,每次喚醒只執(zhí)行幾十微秒的代碼,空閑時(shí)間完全被切碎,根本達(dá)不到深度睡眠的最小閾值。
避坑方案
坑 3:高優(yōu)先級(jí)短周期任務(wù),切碎空閑時(shí)間,深度睡眠無(wú)法進(jìn)入
系統(tǒng)整體空閑率超過(guò) 90%,但就是無(wú)法進(jìn)入深度低功耗模式,只能進(jìn)入淺度睡眠,功耗始終降不下來(lái)。
這是很多工程師容易忽略的隱性坑,比如你有一個(gè)高優(yōu)先級(jí)的傳感器采集任務(wù),周期 1ms,每次執(zhí)行只需要 100us,執(zhí)行完就阻塞。
從數(shù)據(jù)上看,這個(gè)任務(wù)的 CPU 占用率只有 10%,系統(tǒng)有 90% 的空閑時(shí)間,但這些空閑時(shí)間,被切成了每 1ms 一個(gè)、時(shí)長(zhǎng) 900us 的碎片。如果你的深度睡眠最小閾值是 1ms,那系統(tǒng)永遠(yuǎn)都沒(méi)法進(jìn)入深度睡眠,只能在每個(gè)碎片里執(zhí)行 WFI 淺度睡眠,功耗節(jié)省極其有限。更常見(jiàn)的場(chǎng)景是,多個(gè)中高優(yōu)先級(jí)的短周期任務(wù),把系統(tǒng)的空閑時(shí)間切成了大量無(wú)法利用的碎片,深度睡眠的觸發(fā)概率幾乎為 0。
避坑方案
3
中斷與臨界區(qū)的低功耗坑
低功耗的核心是睡眠與喚醒,而喚醒的核心是中斷,臨界區(qū)則直接影響中斷和內(nèi)核調(diào)度的邏輯。這個(gè)模塊的坑,輕則功耗異常,重則直接導(dǎo)致系統(tǒng)死機(jī)、喚不醒,是必須死守的底線。
坑 1:中斷喚醒配置錯(cuò)誤,要么喚不醒,要么功耗爆炸
兩個(gè)極端,要么進(jìn)入深度低功耗后,按鍵、串口等外設(shè)完全沒(méi)法喚醒系統(tǒng),直接睡死;要么系統(tǒng)根本沒(méi)法進(jìn)入睡眠,待機(jī)電流居高不下,頻繁被中斷喚醒。
喚不醒的核心原因,現(xiàn)在的 MCU 大多是分電源域設(shè)計(jì),不同的低功耗模式下,會(huì)關(guān)閉不同的外設(shè)時(shí)鐘和電源域。
很多工程師不看芯片手冊(cè),把喚醒源配置到了會(huì)被關(guān)閉的電源域里。
比如把普通 USART 的接收中斷作為喚醒源,但深度睡眠模式下,USART 的時(shí)鐘和電源都被關(guān)閉了,哪怕引腳有數(shù)據(jù),也根本觸發(fā)不了中斷。
外部中斷配置成了電平觸發(fā),而深度睡眠下,引腳電平被拉死,中斷無(wú)法觸發(fā);或者中斷引腳沒(méi)有配置到喚醒電源域,睡眠后引腳檢測(cè)功能直接失效。
進(jìn)入低功耗前,錯(cuò)誤地關(guān)閉了全局中斷,導(dǎo)致喚醒中斷無(wú)法被 CPU 響應(yīng),哪怕硬件觸發(fā)了中斷,系統(tǒng)也依然沉睡。
頻繁喚醒的核心原因,中斷標(biāo)志位沒(méi)有清除,進(jìn)入睡眠前,外設(shè)的中斷標(biāo)志位處于掛起狀態(tài),導(dǎo)致系統(tǒng)剛要進(jìn)入睡眠,就被中斷喚醒,循環(huán)往復(fù)。
外部中斷配置成了電平觸發(fā),睡眠時(shí)引腳處于浮空狀態(tài),受到干擾后頻繁觸發(fā)中斷,系統(tǒng)根本沒(méi)法進(jìn)入睡眠。
保留了大量非必要的中斷開(kāi)啟,比如 ADC、DMA、定時(shí)器的中斷,哪怕沒(méi)有業(yè)務(wù)操作,也會(huì)偶爾觸發(fā),導(dǎo)致系統(tǒng)頻繁被喚醒。
避坑方案
坑 2:WFI/WFE 指令的競(jìng)態(tài)條件,導(dǎo)致系統(tǒng)睡死、中斷丟失
低功耗運(yùn)行時(shí),偶爾出現(xiàn)系統(tǒng)無(wú)響應(yīng),任務(wù)不執(zhí)行,必須硬復(fù)位才能恢復(fù),復(fù)現(xiàn)概率隨機(jī),極難排查。
RTOS 的低功耗,最終都會(huì)落到 CPU 的 WFI(等待中斷)、WFE(等待事件)指令上,而 90% 的工程師自己寫(xiě)低功耗代碼時(shí),都會(huì)踩中這個(gè)經(jīng)典的競(jìng)態(tài)條件坑。
先看一段幾乎人人都寫(xiě)過(guò)的錯(cuò)誤代碼:
// 錯(cuò)誤示例:存在致命的競(jìng)態(tài)條件if(xTaskGetNumberOfTasks() == 1){ // 判斷只有空閑任務(wù),可進(jìn)入睡眠__WFI(); // 進(jìn)入睡眠,等待中斷喚醒}
這段代碼的致命問(wèn)題在于:if 條件判斷完成后,__WFI () 指令執(zhí)行前,系統(tǒng)可以被中斷打斷。
如果在這個(gè)間隙,來(lái)了一個(gè)外部中斷,中斷服務(wù)函數(shù)里喚醒了一個(gè)業(yè)務(wù)任務(wù),此時(shí)系統(tǒng)的任務(wù)數(shù)已經(jīng)大于 1,不滿足睡眠條件了。
但中斷返回后,CPU 還是會(huì)執(zhí)行__WFI () 指令,讓系統(tǒng)進(jìn)入睡眠。這就導(dǎo)致,明明有就緒的業(yè)務(wù)任務(wù),系統(tǒng)卻進(jìn)入了睡眠,內(nèi)核不會(huì)調(diào)度任務(wù)執(zhí)行,只有等到下一個(gè)中斷到來(lái),才能喚醒系統(tǒng),表現(xiàn)出來(lái)就是系統(tǒng)卡死、任務(wù)延遲、實(shí)時(shí)性完全失效。
避坑方案
// 正確示例:解決競(jìng)態(tài)條件__disable_irq(); // 關(guān)中斷,確保判斷和WFI之間不會(huì)被打斷if(可以進(jìn)入睡眠的條件){__WFI(); // 關(guān)中斷下,WFI依然能被硬件喚醒}__enable_irq(); // 開(kāi)中斷,執(zhí)行喚醒后的中斷服務(wù)函數(shù)和任務(wù)調(diào)度
區(qū)分 WFI 和 WFE 的使用場(chǎng)景,WFI 依賴中斷喚醒,適合絕大多數(shù)低功耗場(chǎng)景;WFE 依賴事件喚醒,需要配合 SEV 指令使用,必須注意清除事件標(biāo)志,避免虛假喚醒。
不要重復(fù)造輪子,盡量使用 RTOS 官方提供的、經(jīng)過(guò)驗(yàn)證的 Tickless port 層實(shí)現(xiàn),不要自己隨意改寫(xiě)睡眠入口函數(shù),避免引入底層邏輯漏洞。
坑 3:臨界區(qū)與鎖的濫用,導(dǎo)致低功耗失效、系統(tǒng)死鎖
系統(tǒng)經(jīng)常無(wú)法進(jìn)入低功耗,偶爾喚醒后直接死鎖,任務(wù)調(diào)度完全不執(zhí)行,甚至觸發(fā) hardfault。
臨界區(qū)(關(guān)中斷、調(diào)度鎖)、互斥鎖、信號(hào)量,是 RTOS 里保護(hù)共享資源的核心手段,但在低功耗場(chǎng)景下,濫用這些機(jī)制,會(huì)帶來(lái)致命的問(wèn)題。
避坑方案
4
外設(shè)與電源域協(xié)同的坑
很多低功耗問(wèn)題,根本不是 RTOS 內(nèi)核的問(wèn)題,而是軟件的低功耗邏輯,和硬件的外設(shè)、電源域配置完全脫節(jié),導(dǎo)致功耗降不下來(lái),甚至喚醒后外設(shè)直接報(bào)廢。
坑 1:外設(shè)與 GPIO 處理不當(dāng),漏電流超標(biāo),功耗降不下來(lái)
系統(tǒng)已經(jīng)進(jìn)入深度睡眠,CPU 也停了,但是待機(jī)電流比芯片手冊(cè)的典型值大了幾十倍甚至上百倍,排查半天發(fā)現(xiàn)是外設(shè)和 GPIO 的問(wèn)題。
MCU 的功耗,不僅來(lái)自 CPU 內(nèi)核,更多來(lái)自外設(shè)和 GPIO 的漏電流。很多工程師只關(guān)注 CPU 的睡眠,卻忽略了外設(shè)和 GPIO 的處理,最終導(dǎo)致功耗完全不達(dá)標(biāo)。
避坑方案
第一步:等待所有非喚醒外設(shè)的操作完成,停止 ADC、DAC、PWM、DMA 等外設(shè)的工作;
第二步:關(guān)閉所有非必要外設(shè)的時(shí)鐘,只保留喚醒源外設(shè)的時(shí)鐘;
第三步:配置 GPIO 狀態(tài),所有不用的引腳、睡眠時(shí)不需要的引腳,統(tǒng)一配置成上拉 / 下拉輸出,或者模擬輸入模式,絕對(duì)不能保留浮空輸入;
第四步:關(guān)閉非必要的電源域,只保留喚醒源所在的電源域和備份域。退出低功耗后,按相反的順序,恢復(fù)電源域、時(shí)鐘、外設(shè)、GPIO 的配置,確保喚醒后外設(shè)正常工作。
坑 2:外設(shè)喚醒與系統(tǒng)調(diào)度時(shí)序不匹配,導(dǎo)致數(shù)據(jù)丟失、系統(tǒng)錯(cuò)亂
從低功耗喚醒后,LPUART、SPI 等外設(shè)的數(shù)據(jù)丟包、校驗(yàn)錯(cuò)誤,甚至 DMA 傳輸異常,觸發(fā)內(nèi)存越界和 hardfault。
MCU 從深度睡眠模式喚醒,不是瞬間完成的,需要經(jīng)歷一系列的穩(wěn)定過(guò)程:?jiǎn)拘阎袛嘤|發(fā)→內(nèi)核退出睡眠模式→LDO 穩(wěn)壓器切換→主頻晶振起振并穩(wěn)定→Flash 控制器喚醒→外設(shè)時(shí)鐘恢復(fù)。
這個(gè)過(guò)程,短則幾微秒,長(zhǎng)則上百微秒。很多工程師的代碼,喚醒后立刻就去操作外設(shè)、處理數(shù)據(jù),但是此時(shí)系統(tǒng)主頻、外設(shè)時(shí)鐘、Flash 還沒(méi)有穩(wěn)定,讀寫(xiě)外設(shè)寄存器會(huì)失敗,訪問(wèn)內(nèi)存會(huì)出錯(cuò),最終導(dǎo)致數(shù)據(jù)丟失、程序跑飛。
常見(jiàn)的踩坑場(chǎng)景,LPUART 在睡眠時(shí)收到了數(shù)據(jù),喚醒后立刻去讀接收 FIFO,但是此時(shí)外設(shè)時(shí)鐘還沒(méi)穩(wěn)定,波特率采樣異常,讀出來(lái)的數(shù)據(jù)全是錯(cuò)的。
喚醒后,中斷服務(wù)函數(shù)立刻啟動(dòng) DMA 傳輸,但是此時(shí) DMA 的時(shí)鐘和電源還沒(méi)恢復(fù),導(dǎo)致傳輸目標(biāo)地址錯(cuò)誤,改寫(xiě)了系統(tǒng)內(nèi)存,觸發(fā) hardfault。
喚醒后,RTOS 立刻調(diào)度任務(wù)執(zhí)行,任務(wù)里訪問(wèn) Flash 里的常量 / 代碼,但是 Flash 還沒(méi)喚醒,導(dǎo)致指令預(yù)取錯(cuò)誤,系統(tǒng)直接崩潰。
避坑方案
5
RTOS 內(nèi)核配置與移植的坑
很多低功耗問(wèn)題,從一開(kāi)始移植 RTOS、配置內(nèi)核的時(shí)候,就已經(jīng)埋下了隱患,后面再怎么調(diào)應(yīng)用代碼,都沒(méi)法徹底解決。
坑 1:Tick 定時(shí)器的時(shí)鐘源選錯(cuò),深度睡眠下系統(tǒng)直接停擺
進(jìn)入深度低功耗后,系統(tǒng)直接睡死,只有復(fù)位才能喚醒,哪怕設(shè)置了定時(shí)喚醒,也完全不生效。
絕大多數(shù) RTOS 的默認(rèn)移植,系統(tǒng) Tick 節(jié)拍定時(shí)器,用的都是 Cortex-M 內(nèi)核自帶的 SysTick 定時(shí)器。
而 SysTick 的時(shí)鐘源,是內(nèi)核的系統(tǒng)主頻,一旦進(jìn)入深度低功耗模式,內(nèi)核主頻會(huì)被關(guān)閉,SysTick 定時(shí)器會(huì)直接停止工作,既沒(méi)法計(jì)時(shí),也沒(méi)法喚醒系統(tǒng)。
很多工程師不知道這個(gè)底層特性,直接開(kāi)了 Tickless,用默認(rèn)的 SysTick 配置,結(jié)果進(jìn)入深度睡眠后,Tick 完全停了,喚醒后也沒(méi)法做時(shí)間補(bǔ)償,系統(tǒng)時(shí)間直接錯(cuò)亂,甚至調(diào)度器完全不工作。
避坑方案
坑 2:內(nèi)核低功耗配置不完整,Tickless 完全不生效
明明在配置文件里開(kāi)了 Tickless 的宏開(kāi)關(guān),但是系統(tǒng)根本不進(jìn)入 Tickless 模式,低功耗邏輯完全不執(zhí)行。
RTOS 的 Tickless 功能,不是開(kāi)一個(gè)宏就能生效的,有大量的配套配置和依賴項(xiàng),很多工程師只改了總開(kāi)關(guān),其他配置完全沒(méi)動(dòng),導(dǎo)致功能不生效。以最常用的 FreeRTOS 為例,常見(jiàn)的配置錯(cuò)誤。
只開(kāi)了configUSE_TICKLESS_IDLE = 1,但是沒(méi)有實(shí)現(xiàn)對(duì)應(yīng)的vPortSuppressTicksAndSleep函數(shù),內(nèi)核沒(méi)有地方執(zhí)行睡眠邏輯。
configEXPECTED_IDLE_TIME_BEFORE_SLEEP
配置不合理,導(dǎo)致系統(tǒng)很難滿足最小睡眠時(shí)長(zhǎng)的條件,Tickless 邏輯永遠(yuǎn)不觸發(fā)。
重寫(xiě)了vApplicationIdleHook空閑鉤子函數(shù),在里面加了阻塞操作或者耗時(shí)循環(huán),導(dǎo)致空閑任務(wù)永遠(yuǎn)走不到 Tickless 的執(zhí)行入口。
開(kāi)了configUSE_TICKLESS_IDLE,但是同時(shí)開(kāi)了內(nèi)核的調(diào)試功能、Trace 功能,這些功能會(huì)強(qiáng)制系統(tǒng)保持 Tick 運(yùn)行,禁止進(jìn)入低功耗模式。
避坑方案
RTOS 的低功耗設(shè)計(jì),從來(lái)不是簡(jiǎn)單開(kāi)個(gè) Tickless、調(diào)用個(gè)睡眠指令就能搞定的,它是一個(gè)貫穿內(nèi)核機(jī)制、任務(wù)設(shè)計(jì)、中斷管理、外設(shè)配置、硬件協(xié)同、測(cè)試驗(yàn)證的全鏈路系統(tǒng)工程。
很多時(shí)候,你踩的坑,本質(zhì)上是對(duì)RTOS 內(nèi)核調(diào)度原理和MCU 低功耗硬件機(jī)制的理解不到位,把 RTOS 的低功耗功能當(dāng)成了黑盒來(lái)用,自然會(huì)被各種隱性陷阱絆倒。
嵌入式開(kāi)發(fā)的核心競(jìng)爭(zhēng)力,從來(lái)不是能把功能跑起來(lái),而是能把底層的細(xì)節(jié)吃透,在資源受限的場(chǎng)景里,把性能、功耗、穩(wěn)定性做到極致。
與各位同行共勉。
