實(shí)時(shí)斷言開始
我們討論了為嵌入式應(yīng)用程序設(shè)置斷言通常需要的內(nèi)容。我們還看到,根據(jù)所使用的工具鏈,它可能會(huì)略有不同。盡管存在這些較小的差異,但仍將斷言用于相同的目的:檢測(cè)開發(fā)人員對(duì)應(yīng)用程序的假設(shè)何時(shí)在應(yīng)用程序中的特定點(diǎn)不正確。
當(dāng)適當(dāng)使用時(shí),斷言可以提高代碼質(zhì)量。但是,存在一些關(guān)鍵情況,即斷言要么無(wú)效或可能引起意外問題。
在今天的帖子中,我們將研究主張可能失敗的地方以及為什么要失敗,我將分享一些在實(shí)時(shí)系統(tǒng)中安全實(shí)施斷言的實(shí)用技巧。
斷言會(huì)引起問題的地方
在您查看實(shí)時(shí)斷言之前,您需要了解主張可能使您失敗的地方。在三種情況下,您可能會(huì)發(fā)現(xiàn)標(biāo)準(zhǔn)斷言實(shí)現(xiàn)將使您失敗。
1。在系統(tǒng)初始化期間
當(dāng)微控制器啟動(dòng)時(shí),它會(huì)執(zhí)行供應(yīng)商供應(yīng)的代碼,該代碼初始化系統(tǒng)時(shí)鐘,執(zhí)行內(nèi)存設(shè)置并準(zhǔn)備運(yùn)行時(shí)環(huán)境。這似乎是斷言的邏輯場(chǎng)所,但事實(shí)并非如此。為什么:
· 振蕩器才剛剛啟動(dòng),外圍設(shè)備可能需要充分時(shí)鐘。
· 仍然需要映射諸如printf之類的函數(shù),因此即使斷言失敗,輸出也將無(wú)處可去。
· 如果您嘗試停止處理器或打印消息,則可能會(huì)觸發(fā)一個(gè)例外,以阻止系統(tǒng)啟動(dòng)。
除非必要,否則避免在啟動(dòng)代碼中斷言,并且僅使用直接I/O切換(例如LED )等低級(jí)機(jī)制進(jìn)行診斷。
2。在微控制器驅(qū)動(dòng)程序中
駕駛員是使用斷言的非常有用的地方,但是再次,我們需要小心我們使用哪些驅(qū)動(dòng)程序??紤]一下我們通過(guò)啟動(dòng)代碼獲得的情況。許多開發(fā)人員要做的第一件事是初始化GPIO引腳。我經(jīng)常使用傳遞到gpio_init函數(shù)的配置表。例如,如果您有GPIO的配置表:
斷言(config!= null);
如果我有斷言檢查這種結(jié)構(gòu)并且不正確的事物,我將發(fā)出斷言,但是該斷言的結(jié)果將無(wú)處可尋! GPIO引腳不僅沒有初始化,而且尚未映射printf和關(guān)聯(lián)的輸出。在這一點(diǎn)上,我將得到一個(gè)默默失敗的斷言。
沉默的斷言不一定是一件壞事。我們?nèi)匀猾@得失敗的斷言的行號(hào)和有關(guān)原因的信息。問題是,我們沒有意識(shí)到,主張已經(jīng)發(fā)射了,并且在我們的系統(tǒng)中看起來(lái)很混亂,以了解為什么它不運(yùn)行。
正如我們上次討論的那樣,我們可以設(shè)置自動(dòng)斷點(diǎn)或使用匯編指令使我們顯而易見。我最喜歡的技巧之一是將LED作為主張LED獻(xiàn)上,該主張?jiān)跀嘌蚤_火時(shí)會(huì)鎖定。我們將很快談?wù)摳唷?
3。實(shí)時(shí)硬件組件
這是可能變得危險(xiǎn)的地方。想象一個(gè)嵌入式系統(tǒng)驅(qū)動(dòng)電動(dòng)機(jī)。如果斷言發(fā)射并停止電動(dòng)機(jī):
· 重載有效載荷可能會(huì)突然讓位,并造成身體傷害。
· 渦輪機(jī),火箭發(fā)動(dòng)機(jī)或其他實(shí)時(shí)機(jī)制可能會(huì)災(zāi)難性地失效。
在這一點(diǎn)上,斷言不僅會(huì)導(dǎo)致軟件錯(cuò)誤,還會(huì)損害安全性。在這些情況下,停止系統(tǒng)不是一個(gè)選擇。
我們不能允許這些類型的情況發(fā)生。對(duì)于可能處于實(shí)時(shí)或生產(chǎn)操作中間的系統(tǒng),我們的斷言需要具備更多的技巧,而不僅僅是停止執(zhí)行我們的代碼。斷言需要能夠記錄他們可以的任何數(shù)據(jù),然后通知應(yīng)用程序代碼出現(xiàn)問題。然后,應(yīng)用程序可以決定是否應(yīng)安全地關(guān)閉系統(tǒng),或終止該系統(tǒng),或者該應(yīng)用程序是否應(yīng)繼續(xù)進(jìn)行(甚至可能嘗試恢復(fù))。現(xiàn)在,讓我們看一下如何實(shí)施主張,以便可以在實(shí)時(shí)系統(tǒng)中使用它們的提示。
實(shí)時(shí)斷言的提示
實(shí)時(shí)斷言是旨在驗(yàn)證具有實(shí)時(shí)限制的系統(tǒng)執(zhí)行過(guò)程中開發(fā)人員假設(shè)的程序檢查。與傳統(tǒng)的斷言在失敗時(shí)停止系統(tǒng),實(shí)時(shí)斷言對(duì)關(guān)鍵診斷信息進(jìn)行記錄,向應(yīng)用程序或開發(fā)人員發(fā)出信號(hào),并允許系統(tǒng)執(zhí)行或過(guò)渡到安全狀態(tài),而不會(huì)破壞關(guān)鍵的實(shí)時(shí)操作。
以下是在使用實(shí)時(shí)斷言時(shí)需要考慮的一些技巧:
提示#1 - 使用視覺輔助
在不停止CPU的情況下通知開發(fā)人員失敗斷言的最簡(jiǎn)單方法是使用視覺指示器。對(duì)于大多數(shù)系統(tǒng),這意味著要切換LED:
void __aeabi_assert(const char *expr,const char *file,int line){
//使用LED
dio_channelwrite信號(hào)故障(assert_led,low);
而(1); //停止執(zhí)行
}
LED閂鎖表明發(fā)生了斷言,終端上的消息告訴您確切的發(fā)生在哪里。
提示#2 - 創(chuàng)建斷言日志
正如我們?cè)谶@些博客中所看到的那樣,斷言通常會(huì)停止CPU,但是如果我們有電動(dòng)機(jī)旋轉(zhuǎn)或其他原因,為什么我們不想停止執(zhí)行代碼,我們可以改為將終端信息重定向到日志。日志可以用于開發(fā)中,但它們也是記錄沒有與之連接的終端的生產(chǎn)系統(tǒng)中的斷言信息的最佳方法之一。
我們可以將幾個(gè)不同的位置重定向到主張日志。我們應(yīng)該考慮的第一個(gè)位置,無(wú)論將主張數(shù)據(jù)記錄到RAM是什么。我通常會(huì)使用一個(gè)可以容納最大長(zhǎng)度的字符串然后將信息寫入緩沖區(qū)的圓形緩沖區(qū)。我通常會(huì)包含文件,行號(hào),然后包括我認(rèn)為可能很重要的任何其他信息。有時(shí),我什至?xí)薷臄嘌允〉墓δ埽垣@取一個(gè)自定義字符串,該字符串可以在發(fā)出斷言之前立即提供有關(guān)條件的更多信息。我們可能會(huì)記錄執(zhí)行以下操作的數(shù)據(jù):
void __aeabi_assert(const char *expr,const char *file,int line){
#if assert_uart == true
uart_printf(uart1,“ ostertion ostertion in lin s in line s in line%d \ n”,file,line);
#elif
log_append(assert,assert_string,file,line);
#endif
//視覺指示器
dio_channelwrite(assert_led,low);
}
圓形緩沖區(qū)可以在RAM中暫時(shí)固定斷言日志。然后,背景任務(wù)可以將這些日志沖洗到非易失性內(nèi)存(例如,閃存或SD卡)。
提示#3 - 通知應(yīng)用程序
主張并非被設(shè)計(jì)為故障處理程序,而是實(shí)時(shí)斷言不能僅僅阻止嵌入式系統(tǒng)。我們可能仍然想停止系統(tǒng),但是要這樣做,我們需要讓主應(yīng)用程序知道已經(jīng)檢測(cè)到缺陷,并且我們需要盡快進(jìn)入安全模式。我們可以通過(guò)在主張庫(kù)和主要應(yīng)用程序之間創(chuàng)建信號(hào)機(jī)制來(lái)做到這一點(diǎn)。
例如,我們可能會(huì)認(rèn)為我們的實(shí)時(shí)系統(tǒng)中有三種不同類型的斷言:
1. 關(guān)鍵主張要求系統(tǒng)立即進(jìn)入安全狀態(tài)。
2. 中等主張不需要系統(tǒng)停止,但是開發(fā)人員立即通知存在問題,以便開發(fā)人員可以決定如何進(jìn)行。
3. 次要斷言不需要停止系統(tǒng),甚至可能不需要通知申請(qǐng)。
我們可能會(huì)將這些斷言的嚴(yán)重性水平添加到一個(gè)枚舉中,然后我們可以在代碼中使用。例如,枚舉可能是:
typedef enum
{
assert_severity_minor,
assert_severity_moderate,
assert_severity_critical,
assert_severity_max_count
} assertseertseverity_t
然后,我們斷言失敗的功能可能會(huì)成為完全自定義的實(shí)現(xiàn),不是來(lái)自C庫(kù)斷言。H模塊,而是來(lái)自myAssert.h或某種效果。一個(gè)示例可能看起來(lái)像以下內(nèi)容:
void assert_failed(const char expr,const char *file,int line,assertSeverity_t嚴(yán)重性)
{
#if assert_uart == true
uart_printf(uart1,“斷言在line s in line s in line%d \ n”中失敗,file,file,line);
#elif
log_append(assert,assert_string,file,line);
#endif
#將I/O線拉低以打開LED并發(fā)出斷言。
dio_channelwrite(LED_ASSERT,低);
app_notify(嚴(yán)重性);
}
此示例只是將調(diào)用添加到app_notify,然后通過(guò)嚴(yán)重性,但是這種簡(jiǎn)單性非常強(qiáng)大。 app_notify將使應(yīng)用程序知道已經(jīng)檢測(cè)到缺陷,然后可以決定該系統(tǒng)應(yīng)放入哪種狀態(tài)。
提示#4 - 有條件配置斷言
斷言是檢測(cè)缺陷的簡(jiǎn)單機(jī)制,但是開發(fā)人員可以在確定適合其應(yīng)用的情況下以復(fù)雜的機(jī)制創(chuàng)建。如果您打算在開發(fā)和生產(chǎn)中使用斷言,則創(chuàng)建一系列條件來(lái)確定您的斷言的運(yùn)作方式可能很有用。例如,您可能會(huì)創(chuàng)建允許輸出映射到的條件:
· uart
· 調(diào)試控制臺(tái)
· 日志
也可以有一些條件可以完全禁用斷言功能或?qū)⑹占⑻峁┙o日志的信息。開發(fā)人員在開發(fā)過(guò)程中可能會(huì)有不同的功能,而他們?cè)谏a(chǎn)中想要的功能可能會(huì)有不同的功能。重要的是要從主張能力中獲得什么來(lái)思考,并設(shè)計(jì)最簡(jiǎn)單的功能。您做的越復(fù)雜,出現(xiàn)問題的機(jī)會(huì)就越大。
采取您的下一步
斷言是捕獲錯(cuò)誤的強(qiáng)大工具,但是在實(shí)時(shí)系統(tǒng)中,濫用它們可能會(huì)引起嚴(yán)重的問題。安全地使用斷言:
1. 避免將主張放在啟動(dòng)代碼中。
2. 使用視覺指示燈(例如LED)向早期失敗發(fā)出信號(hào)。
3. log未能用于診斷或非易失性內(nèi)存。
4. 通知申請(qǐng),以便可以適當(dāng)處理失敗。
5. 有條件地為開發(fā)與生產(chǎn)構(gòu)建配置斷言。
通過(guò)這些提示,您可以實(shí)現(xiàn)實(shí)時(shí)斷言,以幫助您檢測(cè)缺陷,而不會(huì)損害系統(tǒng)的安全性或穩(wěn)定性。