千錯萬(wàn)錯,都是中斷和堆棧惹的禍!
四月的重慶已然百花盛開(kāi),春回大地,大自然又恢復了勃勃的生機,燕子揮舞著(zhù)銀光閃閃的翅膀,在湛藍而悠遠的天空中無(wú)拘無(wú)束地飛翔著(zhù),時(shí)而快速扇動(dòng)著(zhù)翅膀沖上天空,時(shí)而展開(kāi)雙翼低低滑翔。在吸飽了四月新雨的潮氣的濕潤空氣中,小草顯得格外清新,綠油油地,就像一汪春水,在春風(fēng)的吹拂下,蕩起粼粼的水波。草地不遠處的停車(chē)場(chǎng)上,兩位面容憔悴、因睡眠不足而眼角發(fā)黑的工程師緊張而激烈地討論著(zhù),在空曠而幽靜的試驗場(chǎng)里,他們的聲音格外引人注目。
本文引用地址:http://dyxdggzs.com/article/201809/391649.htm“是不是因為汽車(chē)行駛過(guò)程中,電磁環(huán)境的干擾造成CAN總線(xiàn)數據中某些位發(fā)生了變化,所以才造成無(wú)緣無(wú)故解鎖車(chē)門(mén)的情況?”同事抬起腫脹的眼皮,帶著(zhù)詢(xún)問(wèn)的神情,小心翼翼地問(wèn)我。
“不會(huì )的,CAN總線(xiàn)的協(xié)議里本身就有CRC校驗,如果數據位出錯,CAN報文中的CRC校驗是通不過(guò)的,這時(shí)CAN控制器會(huì )提示錯誤的?!边@次故障發(fā)生在產(chǎn)品功能驗證已經(jīng)通過(guò),量產(chǎn)前的實(shí)車(chē)路試過(guò)程中,如果問(wèn)題解決地慢,可能需要重新路試,第二次路試的所有費用都得我們來(lái)掏,所以我的心情怎么也好不起來(lái),于是我口氣生硬地回答他。
我們做的產(chǎn)品是車(chē)身控制器,俗稱(chēng)BCM,這次路試出現的故障現象極其明了,就是在開(kāi)車(chē)過(guò)程中,沒(méi)有任何操作的情況下,突然解鎖或者突然閉鎖,或者突然后背門(mén)解鎖了,來(lái)了兩天,一直沒(méi)有找到引發(fā)故障的原因,弄得我茶飯不思,苦悶到了極點(diǎn)。
“找車(chē)廠(chǎng)路試人員,我再跟他上車(chē)跑一下,觀(guān)察一下現象吧!”做為這次產(chǎn)品代碼的開(kāi)發(fā)主力人員,我的任務(wù)是解決問(wèn)題,同事的任務(wù)是和車(chē)廠(chǎng)人員打交道,給我做好服務(wù),所以我不客氣地支使起這位同事來(lái)。
雨后新晴的空氣顯得格外清新,微風(fēng)拂面,帶來(lái)一絲絲涼意,停產(chǎn)場(chǎng)的坑洼處還有一些沒(méi)有吹干的水窩,倒映著(zhù)碎成一片片金箔的陽(yáng)光。盡管倍感煎熬,目前仍處在水深火熱之中,但是我堅信,正如冬去春來(lái)大地回春一樣,我也會(huì )柳暗花明峰回路轉的。
故障再現
路試人員是個(gè)年輕小伙兒,看著(zhù)很精神,也頗為健談,上車(chē)不久,便主動(dòng)搭話(huà)和我談了起來(lái)。
“前些天一直下雨,你們過(guò)來(lái)這兩天才放晴?!彼治罩?zhù)方向盤(pán),腦袋稍稍轉向我這邊,笑意隨著(zhù)他那年輕而又清脆的聲音一起傳了過(guò)來(lái)。
“你們發(fā)現故障的時(shí)候是在下雨天?”心思仍然撲在故障原因上的我,突然警覺(jué)起來(lái)?!笆遣皇翘烨绲臅r(shí)候不發(fā)生這種故障?”
“大概是吧,記不太清了?!彼鼗貞?。
‘是不是因為下雨,天氣比較潮濕,機械鎖那塊密封性做得不好,造成機械解閉鎖開(kāi)關(guān)那里會(huì )出現解閉鎖信號呢?’我的腦袋飛速運轉著(zhù),默默在心里盤(pán)算著(zhù)?!畱摬粫?huì ),即便路試車(chē)的機械鎖密封不好,也是只會(huì )誤解鎖,怎么會(huì )誤閉鎖呢?再說(shuō),后背門(mén)解鎖信號來(lái)自于PEPS從CAN總線(xiàn)上發(fā)過(guò)來(lái)的指令,和天氣也沒(méi)啥關(guān)系?!译S即否決了這種判斷。
前方路口紅燈,路試小伙兒嫻熟地減速、停車(chē),按下了電子手剎,我看了看這輛車(chē),隨口問(wèn)起這輛車(chē)的配置來(lái),EPS、自動(dòng)擋、電子手剎、PEPS、陽(yáng)光雨量傳感器、自動(dòng)天窗、車(chē)窗防夾,‘比我們當時(shí)測試BCM時(shí)的試驗車(chē)配置高?!也唤蛋迪氲?。
‘咯噔’,一聲清脆的解鎖聲,劃破空氣直沖我的耳膜,“你按中控那里的解鎖鍵了?還是按遙控鑰匙上的解鎖鍵了?”一股熱血沖上了我的胸膛,爬上了我的臉龐,我帶著(zhù)緊張的神情,急切地問(wèn)道。
“沒(méi)有啊,我什么都沒(méi)動(dòng),”路試小伙兒臉上掛著(zhù)意味深長(cháng)的微笑,“之前就是這樣子的,莫名其妙就解鎖了,有時(shí)是莫名其妙閉鎖,有時(shí)開(kāi)著(zhù)開(kāi)著(zhù)車(chē),就聽(tīng)到后背門(mén)打開(kāi)了,當時(shí)嚇了我一跳!”他盯著(zhù)我的眼睛,加重語(yǔ)氣說(shuō)道。
問(wèn)題復現了!我的心砰砰跳著(zhù),現在可是個(gè)大晴天,艷陽(yáng)高照,這下怪不到下雨天氣頭上了吧。驕傲的太陽(yáng)高高在上,透過(guò)前擋風(fēng)玻璃,慷慨地將金線(xiàn)似的陽(yáng)光灑滿(mǎn)在我的身上。
車(chē)輛又緩緩開(kāi)動(dòng)了,路試小伙兒顯然知道我在沉思,所以沒(méi)有打擾我。宜人的春風(fēng)透過(guò)車(chē)窗,撫摸著(zhù)我的頭發(fā),我茫然地望著(zhù)窗外,恍惚間,竟似不知身在何處。
‘為什么之前測試那么多次,都沒(méi)有出現這種偶發(fā)的故障呢?’我煩惱地思考著(zhù)?!暗臏y試還是很充分的,我測完讓同事測,同事測完又讓測試人員測,最后又找車(chē)廠(chǎng)的技術(shù)人員來(lái)測,測的次數夠多了吧,我每次都在現場(chǎng)觀(guān)察,也沒(méi)出現過(guò)這種摸不著(zhù)頭腦的現象??!’
‘要說(shuō)測試條件有什么區別的話(huà),那就是之前車(chē)停在那里,而現在是開(kāi)了起來(lái)??墒?,這款BCM的功能和車(chē)開(kāi)還是車(chē)?;緵](méi)關(guān)系,難道車(chē)開(kāi)起來(lái)和停在那里真有什么區別嗎?’想到這里,我不禁有些著(zhù)急起來(lái)。
“把車(chē)靠邊停一下,接上OBD,我看看總線(xiàn)數據吧。因為之前測試BCM時(shí),車(chē)廠(chǎng)不讓我們自己開(kāi)車(chē),我們基本上都是停著(zhù)車(chē)測試的。我突然想到,是不是開(kāi)起來(lái)總線(xiàn)上報文數據比停車(chē)狀態(tài)要多?”我給路試小伙兒解釋道,同時(shí)又因為和無(wú)關(guān)人員解釋而感到懊惱。
故障定位
車(chē)輛打著(zhù)右轉向,緩緩地停在了路邊,我在方向盤(pán)下面摸索著(zhù)找到OBD口,接上OBD線(xiàn),另一邊接上我的筆記本,打開(kāi)監控軟件,把兩路CAN總線(xiàn)和一路LIN總線(xiàn)都監控起來(lái)。
‘恩,比之前的報文好像是多了一些!’我模模糊糊地想到,‘也難怪,這輛車(chē)的配置全,CAN節點(diǎn)多,之前那輛車(chē)沒(méi)有ESP,是手動(dòng)擋,也沒(méi)有TCU,而且不帶天窗?!彝蝗桓杏X(jué),被詭異故障塵封的大門(mén)正在緩緩開(kāi)啟。
“開(kāi)起來(lái)吧,小伙兒,”我的心情突然明朗起來(lái),帶著(zhù)輕松而明快的語(yǔ)氣對他說(shuō)?!拔铱纯纯偩€(xiàn)報文?!?/p>
路邊的景色迅速向后退去,汽車(chē)已經(jīng)駛上了高速,我的大腦也開(kāi)始高速運轉起來(lái)。
‘之前的測試車(chē)配置低,CAN/LIN節點(diǎn)少,在固定的時(shí)間內觸發(fā)中斷的次數也少,現在這個(gè)路試車(chē),CAN/LIN節點(diǎn)多,觸發(fā)中斷次數多,這就是測試條件的真正區別!’由于勝利在望,我的心開(kāi)始安定下來(lái),有條不紊地分析著(zhù)問(wèn)題?!畣挝粫r(shí)間內中斷次數越多,對CPU而言負荷就越重,中斷服務(wù)例程的執行時(shí)間是一定的,中斷次數越多,就越可能出現中斷嵌套的問(wèn)題,而中斷嵌套時(shí)會(huì )消耗堆棧,嵌套層級越深,堆棧消耗越大,由于堆棧大小是固定的,而且堆??臻g和變量空間都是在RAM的線(xiàn)性空間里,一旦堆棧越界,就會(huì )改變它所臨近的變量空間中的內容!這些內容發(fā)生了不應該發(fā)生的變化,當然會(huì )導致詭異的故障,也許這次無(wú)故解鎖和閉鎖只是表現比較明顯的故障,還有一些隱患已經(jīng)埋下,只是沒(méi)有暴露出來(lái)而已!’
‘問(wèn)題就在這里,’我繼續欣喜地思考著(zhù),越來(lái)越感覺(jué)到喜悅在內心激蕩不已?!吩囓?chē)中斷次數多,造成了堆棧越界,堆棧越界,造成了無(wú)故解鎖閉鎖的故障!Perfect,這邏輯鏈條,完美!’
故障解決
回到停車(chē)場(chǎng),同事正端著(zhù)平板電腦等在那里,帶著(zhù)耳機,笑意盈盈,顯然正在沉浸在電影的世界里??吹轿一貋?lái)了,他迎上來(lái),張口就問(wèn):“測到故障了嗎?你感覺(jué)可能是什么原因?”
“嗯,故障復現了,而且已經(jīng)找到原因了?!?/p>
“哦?什么原因?”他兩眼放光,不自然地笑著(zhù)。
“以后再說(shuō)吧,我先把問(wèn)題解決了再說(shuō)?!蔽矣行┌脨涝趺窗堰@個(gè)同事也帶來(lái)了,還得浪費我的時(shí)間和他解釋這些事情,全然忘記了住宿、吃飯、找車(chē)廠(chǎng)人員都是這位老兄干的。
我打開(kāi)源碼,仔細閱讀了各個(gè)中斷的服務(wù)程序,卻覺(jué)得無(wú)從下手,因為每個(gè)中斷服務(wù)程序里都沒(méi)有冗余代碼,沒(méi)辦法進(jìn)行精簡(jiǎn),所以,降低中斷服務(wù)程序的執行時(shí)間這條路是走不通了。
此路不通,我迅速轉向,仔細分析了各個(gè)中斷的優(yōu)先級,這些中斷的優(yōu)先級都是在之前寫(xiě)代碼的過(guò)程中按照添加代碼的順序隨手設定的,由于之前測試沒(méi)出過(guò)岔子,所以盡管是“隨手設定”,也沒(méi)爆過(guò)雷?,F在回頭一看,問(wèn)題就出在這里。
我這款BCM里用了不少中斷,像定時(shí)中斷、CAN中斷、LIN中斷都是經(jīng)常發(fā)生的,而且CAN中斷的頻率最為頻繁,但是我之前卻把它的中斷優(yōu)先級設置得很低,結果就導致CAN中斷被各個(gè)優(yōu)先級更高的中斷隨意搶占,由于它頻繁發(fā)生且被隨意搶占,導致CPU大量時(shí)間都用在中斷服務(wù)程序的切換導致的堆棧入棧和出棧上,不僅實(shí)際效率降低,而且會(huì )導致堆棧越界問(wèn)題。如果把CAN中斷優(yōu)先級調高,這個(gè)頻繁發(fā)生的中斷就不會(huì )被搶占,不僅提高了CPU的執行效率,而且避免了堆棧越界。
按照這個(gè)思路,我調整了CAN中斷的優(yōu)先級,再次上車(chē)測試了兩天,故障消失了。。。
由于問(wèn)題解決地還算及時(shí),描述故障原因和解決方案的文檔寫(xiě)得也清晰明確,因此這次路試繼續進(jìn)行,不用再里程清零重新路試了。在回程的途中,筆者百感交集,在這些復雜難名的情感中,竟有一種寂寞感在心底滋生,我突然想起《美人魚(yú)》中鄧超唱的那句歌詞:“無(wú)敵是多么,多么寂寞~”
評論