應(yīng)用方案設(shè)計(jì)中,開(kāi)發(fā)者經(jīng)常會(huì)碰到某個(gè)子函數(shù)需要多次多級(jí)調(diào)用的情況。程序執(zhí)行過(guò)程中有可能打斷本該順序執(zhí)行的指令轉(zhuǎn)而跨層執(zhí)行其他層級(jí)指令的情況,為了說(shuō)明方便,將主循環(huán)程序作為一層,不同的中斷服務(wù)程序各自為一層。
一、現(xiàn)象描述
keil編譯器編譯code后,經(jīng)常會(huì)遇到如下warning:[*** WARNING L15:MULTIPLE CALL TO SEGMENT ],碰到此warning就是編譯器提醒開(kāi)發(fā)者,不同層級(jí)出現(xiàn)調(diào)用同一子函數(shù)的情況,或者主循環(huán)與中斷服務(wù)中都有調(diào)用,或者不同中斷服務(wù)程序中都有調(diào)用。
二、注意事項(xiàng)分析
1)全局變量有可能被非可控篡改。
同一子函數(shù)在不同層同時(shí)調(diào)用,那如果在當(dāng)前層執(zhí)行此函數(shù)時(shí)被臨時(shí)打斷跨層后同樣執(zhí)行此函數(shù),那此子函數(shù)中的變了就有可能出現(xiàn)主循環(huán)中此子函數(shù)調(diào)用的變了出現(xiàn)非需求改變。
出錯(cuò)舉例:鍵盤應(yīng)用中,主循環(huán)和中斷中都調(diào)用USB上報(bào)鍵值的子函數(shù),如下:
當(dāng)主循環(huán)剛好在執(zhí)行這個(gè)子函數(shù)時(shí),出現(xiàn)中斷,轉(zhuǎn)而去執(zhí)行中斷服務(wù)程序,而中斷服務(wù)程序中也執(zhí)行這個(gè)子函數(shù)的時(shí)候。buffer_addr(xdata全局指針變量)的數(shù)據(jù)就將被填充成非正常的狀態(tài),整程序運(yùn)行就會(huì)出錯(cuò)。
2)局部變量和全局變量全被非可控篡改。
KEIL編譯器在順序分配局部變量地址時(shí),不同層級(jí)臨時(shí)變量分配地址不會(huì)復(fù)用,但同層級(jí)調(diào)用的子函數(shù)分配局部變量的地址時(shí)可能是相同的,舉個(gè)簡(jiǎn)單的例子
如上:
delay_us()和pwm_control_led_mode1()在主循環(huán)中調(diào)用,KEIL編譯器可能將兩個(gè)函數(shù)中的臨時(shí)變量i(不局限同名)分配到同一個(gè)RAM地址中,如果子函數(shù)同層級(jí)調(diào)用時(shí)不會(huì)有問(wèn)題的,因?yàn)楹瘮?shù)都是順序執(zhí)行的。
同樣是上述兩個(gè)函數(shù),delay_us()在timer0中斷服務(wù)程序中調(diào)用, pwm_control_led_mode1()在主循環(huán)和timer0中斷服務(wù)程序中都有調(diào)用,那編譯器有可能將delay_us()和pwm_control_led_mode1()判定為同層級(jí)(中斷服務(wù)),那臨時(shí)變量i就有可能分配為同一RAM地址。
此時(shí)如果主循環(huán)在pwm_control_led_mode1()函數(shù)中執(zhí)行到i=10時(shí)timer中斷發(fā)生,程序被打斷進(jìn)入中斷服務(wù)程序,中斷執(zhí)行delay_us()函數(shù)后i=500后回到主循環(huán),因?yàn)閮蓚€(gè)子函數(shù)中臨時(shí)變量i在RAM中的地址是公用的,所以回到主循環(huán)pwm_control_led_mode1()繼續(xù)執(zhí)行時(shí),其臨時(shí)變量i的值已經(jīng)是500了,變量led_status_temp[i]可能會(huì)因?yàn)閕值溢出導(dǎo)致賦值的數(shù)據(jù)被賦值到非led_status_temp變量存儲(chǔ)驅(qū)導(dǎo)致程序中變量出錯(cuò)。
三、解決辦法建議
出現(xiàn)[*** WARNING L15:MULTIPLE CALL TO SEGMENT ]warning的時(shí)候,程序都是存在潛在風(fēng)險(xiǎn)的,最徹底的改善就是從程序架構(gòu)上避免出現(xiàn)不同層級(jí)重復(fù)調(diào)用的情況。當(dāng)然正式應(yīng)用方案中可能會(huì)因?yàn)榭臻g大小或者其他原因不得不重復(fù)調(diào)用同一子函數(shù)的情況,針對(duì)此種情況,推薦幾種規(guī)避方式,僅供讀者參考
1)執(zhí)行子函數(shù)關(guān)中斷法
程序開(kāi)發(fā)中,出現(xiàn)多層調(diào)用的情況一般就是兩種情況,一是主循環(huán)跟中斷服務(wù)程序中重復(fù)調(diào)用,另外就是不同中斷服務(wù)程序中同時(shí)調(diào)用,經(jīng)過(guò)上面分析,但凡出問(wèn)題時(shí),都是在執(zhí)行被重復(fù)調(diào)用的子函數(shù)時(shí)打斷去執(zhí)行其他層指令,要徹底解決出問(wèn)題的可能,只需在執(zhí)行低優(yōu)先級(jí)層(比如主循環(huán))同一子函數(shù)之前關(guān)中斷,執(zhí)行完此子函數(shù)后再開(kāi)中斷就可解決所以可能存在的問(wèn)題。
說(shuō)明:有一種情況雖然會(huì)這個(gè)warning,但不會(huì)出問(wèn)題,比如在不同的中斷服務(wù)程序中掉用同一個(gè)子函數(shù),但是中斷的優(yōu)先級(jí)同級(jí),也就是不存在嵌套的情況。
優(yōu)點(diǎn):簡(jiǎn)單便捷,徹底解決問(wèn)題。
缺點(diǎn):有些應(yīng)用中因?yàn)闀r(shí)序的問(wèn)題,不允許臨時(shí)關(guān)中斷。
2)子函數(shù)copy改名法
就是重復(fù)調(diào)用的子函數(shù),copy一份改一下函數(shù)名稱,分別給不同層級(jí)調(diào)用,這樣waring也會(huì)消失。
優(yōu)點(diǎn):簡(jiǎn)單,不存在臨時(shí)變量被改的情況
缺點(diǎn):仍然存在全局變量同時(shí)操作并被修改的情況,需要設(shè)計(jì)者注意是否會(huì)存在執(zhí)行此子函數(shù)時(shí)臨時(shí)中斷換層又執(zhí)行到此子函數(shù)的情況。
3)臨時(shí)變量不復(fù)用法
在開(kāi)發(fā)者確定不會(huì)存在執(zhí)行此子函數(shù)時(shí)臨時(shí)中斷換層又執(zhí)行到此子函數(shù)的情況(全局變量篡改)下,可配置KEIL編譯器,使編譯器給臨時(shí)變量分配地址時(shí),每個(gè)臨時(shí)變量占用一個(gè)地址,不復(fù)用。配置方式如下:
編譯器中嵌入這個(gè)NOOVERLAY命令,意思是臨時(shí)變量不復(fù)用RAM地址
優(yōu)點(diǎn):可簡(jiǎn)單方便解決臨時(shí)變量篡改導(dǎo)致的問(wèn)題。
缺點(diǎn):增加RAM的使用量。
說(shuō)明:如果重復(fù)調(diào)用的子函數(shù)臨時(shí)變量很少,不妨就將子函數(shù)中的臨時(shí)變量直接定義成全局變量,這樣不至于增加太多的RAM空間。
結(jié)束語(yǔ):
上述推薦的方法只是一點(diǎn)建議,必定還有很多辦法可以解決這類問(wèn)題,個(gè)人認(rèn)為最重要的是慎重處理此warning,并明確其存在的風(fēng)險(xiǎn)和內(nèi)在邏輯,至于如何解除應(yīng)用風(fēng)險(xiǎn),每個(gè)人每個(gè)方案的做法可以根據(jù)實(shí)際情況處理。
審核編輯:劉清
-
RAM
+關(guān)注
關(guān)注
8文章
1368瀏覽量
114701 -
變量
+關(guān)注
關(guān)注
0文章
613瀏覽量
28371
原文標(biāo)題:子函數(shù)多層調(diào)用主要事項(xiàng)
文章出處:【微信號(hào):SINO_25181447,微信公眾號(hào):中穎電子】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論