新的一年開(kāi)始了!上班后的第一周不太忙,處理了一個(gè)年前遺留的問(wèn)題。
某工程師移植了一個(gè)FreeRTOS操作系統(tǒng),運(yùn)行了3個(gè)任務(wù)
MainTask: 間隔10秒(不是非常精確,大概9秒左右) LCD數(shù)值加一。
JcqTask: 間隔1秒翻轉(zhuǎn)LED指示燈
ModbusTask:等待信號(hào)量(按鍵中斷),刷新LCD的數(shù)據(jù)。
該工程師反饋跑了一夜后,第2個(gè)任務(wù)的LED燈不閃爍了,出現(xiàn)異常后,其它兩個(gè)任務(wù)都還正常,就LED燈閃爍的任務(wù)不正常。

這個(gè)問(wèn)題聽(tīng)起來(lái)挺詭異,我在年前也復(fù)現(xiàn)出來(lái)了,確實(shí)需要好幾個(gè)小時(shí)才能復(fù)現(xiàn)出來(lái)。
起初懷疑是棧溢出,后來(lái)通過(guò)增加調(diào)試信息,發(fā)現(xiàn)并沒(méi)有。
另外這個(gè)出問(wèn)題的任務(wù)優(yōu)先級(jí)還是最高,排除是優(yōu)先級(jí)引起的問(wèn)題。
后來(lái)看了看他移植的代碼,他用到了FreeRTOS的低功耗tickless模式,它的核心邏輯是:讓系統(tǒng)在沒(méi)有任務(wù)需要處理時(shí),直接進(jìn)入深度睡眠,而不是靠“定時(shí)器中斷”來(lái)維持心跳。
這樣的好處是省電,避免了無(wú)意義的定時(shí)器中斷,讓CPU在需要時(shí)才運(yùn)行工作。
在 FreeRTOS中,Tickless模式通常通過(guò)配置宏 configUSE_TICKLESS_IDLE來(lái)開(kāi)啟。
#define configUSE_TICKLESS_IDLE 2
當(dāng)系統(tǒng)進(jìn)入idle 狀態(tài)下,調(diào)用portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime )這個(gè)函數(shù)。
這是由移植者根據(jù)MCU平臺(tái)要實(shí)現(xiàn)的一個(gè)關(guān)鍵底層函數(shù)。它的核心功能是計(jì)算休眠時(shí)間、關(guān)閉系統(tǒng)節(jié)拍定時(shí)器、讓CPU進(jìn)入低功耗模式,并在正確的時(shí)間喚醒系統(tǒng)。喚醒系統(tǒng)要靠一個(gè)低功耗定時(shí)器來(lái)實(shí)現(xiàn)。
想來(lái)想去,大概率問(wèn)題會(huì)出在這里。
后來(lái)咨詢了一下VsCode Copilot AI,它快速幫我定位到了問(wèn)題,問(wèn)題出在下面這個(gè)代碼

將其修改為如下代碼就沒(méi)問(wèn)題了。

原因是當(dāng) LPTIM 是一個(gè)16位的計(jì)數(shù)器,如果不加 & 0xFFFFUL 掩碼,當(dāng)溢出時(shí)會(huì)導(dǎo)致計(jì)算出的差值為一個(gè)很大的負(fù)數(shù)(當(dāng)做 uint32_t 時(shí)就是個(gè)巨大的正數(shù)),傳給 vTaskStepTick()函數(shù)就會(huì)引起異常現(xiàn)象。
關(guān)注我們:
掃碼加入嵌入式交流群:
