前言
汽車ECU開發,到最后最難的兩類問題一個是硬件相關的偶發問題,一個就是系統相關的偶發問題。硬件相關的偶發問題和ECU工作的溫度,負載,線束等各種外因相關,這里暫不做討論。系統相關的偶發問題一般都和OS相關,能夠通過OS的錯誤處理機制能識別出來。我們在軟件設計階段就應該把能提前預知的錯誤考慮進去,當問題出現的時候能快速的定位問題發生的原因和位置。本文就來介紹下OS的錯誤類型,以及OS錯誤發生后常見的處理辦法。每個感興趣的讀者都可以考慮以下三個問題:
問題1:有哪里常見的OS錯誤 ?
問題2:如何進行OS錯誤處理?
問題3:如何定位OS錯誤發生的原因和位置?

縮略詞
簡寫 | 全稱 |
SCR | Standby Controller |
PMS | Power Management System |
PMSWCR0 | Standby and Wake-up Control Register0 |
STBYRAMSEL | Standby RAM supply in Standby Mode |
DEADD | Data Error Address Register |
參考文檔:
1.TriCoreTM TC1.6.2 core architecture manual .
2.MICROSAR Classic OS Technical Reference.
3.Specification of Operating System AUTROSAR CP Release 4.3.1.
注:本公眾號文章中使用了一些第三方工具和文檔,若有侵權,請聯系作者刪除!
正文
OS的Error類型分為三類,Application Errors, Protection Errors, Kernel Errors, 每種Errors產生的原因及產生Error后OS執行的動作都不相同,詳見下表:
Error Types | Feature |
Application Errors | 1.?如果操作系統無法正確執行應用程序請求的操作系統提供的API服務,則引發Application Erros。典型情況就是操作系統API使用錯誤(例如對象ID無效)。 2.?Application Error不會損壞操作系統內部數據。 ? 3.?如果配置了Error Hook,則OS會調用ErrorHook(),ErrorHook()是一個Callout函數,需要用戶自定義錯誤處理機制。 ? 4.?不會造成OS調用Shutdown/terminate。應用程序可以通過簡單地從ErrorHooks返回來繼續執行。 ? |
Protection Errors | 1.?如果應用程序違反其配置的邊界則會觸發Protection Errors, 典型的就是配置了內存保護或者時間保護后發生內存非法訪問或超時。 ? 2.?Protection Errors不會損壞操作系統內部數據。 ? 3.?在發生未處理的異常和中斷時會觸發Protection Error。 ? 4.?將導致ProtectionHook()的調用,在該調用中可以選擇引發Shutdown或Terminate?handing(ProtectionHook返回值將覺得OS接下來的執行流,無論是否重新啟動)。 ? 5.?如果配置了Shutdownhook,則會調用ShutdownHook(). ? ? 6.?如果配置了ProtectionHook,則會調用ProtectionHook(). ? ? |
Kernel Errors | 1.?如果操作系統無法再確保其內部數據的正確性,則引發Kernel Errors(例如,ProtectionHook()期間內存訪問違規)。 ? ? 2.?發生Kernel Errors后OS會關閉所有中斷且調用Os_PannicHook()通知應用程序。 ? ? 3. 最后操作系統進入無限循環。 |
發生Application Errors后OS會調用ErrorHook(),?ErrorHook()函數是callout函數,函數原型:
(void) ErrorHook(StatusType Error);參數Error標識具體的錯誤碼
發生Protection Errors后OS會調用ProtectionHook(), ProtectionHook函數是callout函數,函數原型:
ProtectionReturnType ProtectionHook(StatusType Fatalerror);參數Fatalerror標識具體的錯誤碼
返回值類型ProtectionReturnType是一個枚舉類型:
typedef enum ProtectionReturnType_e{PRO_IGNORE,PRO_TERMINATETASKISR,PRO_TERMINATEAPPL,PRO_TERMINATEAPPL_RESTART,PRO_SHUTDOWN,PRO_NOTCONFIGURED} ProtectionReturnType;
也就是,我們可以通過自定義ProtectionHook()的返回值來控制發送ProtectionHook后Os的執行流。
每個廠商(Vector, Etas…)Os實現的Os_Types.h文件中都具體定義了每一種Error?Code,這里以Vector的代碼實現為例說明每種Error Type包含的常見的Error Code:
Error?Types | 包含的Error Codes |
Application Errors | E_OS_ACCESS: Illegal access ? E_OS_CALLEVEL:?Invalid calling context. ? E_OS_ID:?Invalid OS object ID. ? E_OS_LIMIT: Maximum task activations reached. ? E_OS_NOFUNC: OS object is currently not in use. ? E_OS_RESOURCE:?Scheduling requested with occupied resource. ? E_OS_STATE: OS object is not in correct state to perform the requested operation. ? E_OS_VALUE:?Given value is out of the configured range. ? E_OS_SERVICEID: Service cannot be called. ? ? ? ? |
Protection Errors | E_OS_PROTECTION_MEMORY:?A memory access violation occurred. ? E_OS_PROTECTION_EXCEPTION: A trap occurred. ? E_OS_SYS_PROTECTION_SYSCALL: An unhandled syscall occurred. ? E_OS_STACKFAULT: A stack fault detected via stack monitoring by the OS. ? E_OS_SYS_API_ERROR: Wrong API usage. ? |
三個Error相關的Hook函數可以在Davinci中配置,如果配置后就需要用戶自定義實現。

?
通過第一節,我們知道了Error的類型及其包含的具體的Error Code,同時,如果我們配置Error發生后Hook函數,那么在Error發生時我們就能被通知到。那么現在,我們在Error發生后應該考慮如何存儲錯誤相關的信息,同時能在事后通過存儲的Error相關信息定位和分析Error。
背景知識1:RAM?Retention。RAMretention是一種技術,用于在斷電后保持隨機存取存儲器(RAM)中的數據。在計算機系統中,RAM是一種易失性存儲器,這意味著在斷電情況下,其中的數據會被清除。這對于一些應用程序來說是不可接受的,因為它們需要在斷電后仍然能夠保持數據。這就是RAMretention技術的用武之地。可以參考博文:https://blog.csdn.net/bjxdbz/article/details/122799397
背景知識2:斷電系統和深度休眠系統。ECU在設計時根據具體需求可以在硬件上添加SBC或無SBC。如果ECU有SBC,ECU就是一個斷電系統。那么ECU在系統下電(Shutdown)流程的最后一步會調用SBC的服務接口斷掉MCU的電,整個MCU在休眠中是處于斷電狀態的。在外部信號(Can Transceiver/Lin Transceiver的INH引腳,Dio喚醒引腳 )喚醒MCU時,SBC重新給MCU供電,MCU重新冷啟動。
如果ECU無SBC,ECU就是一個深度休眠系統。那么ECU在系統下電(Shutdown)流程的最后一步會調用MCU的服務進入到Deep Sleep深度休眠狀態(MCU陷入深度休眠狀態,程序不在運行,但是MCU還有電存在)。在外部信號(Can Transceiver/Lin Transceiver的INH引腳,Dio喚醒引腳 )通過中斷喚醒MCU,MCU被喚醒后,程序可以選擇軟件復位,整個軟件重新運行,也可以選擇從上次停止的地方接著運行。

?
Aurix芯片進入深度休眠后后SCR會接管芯片控制,在進入SCR前可以配置PMS模塊的PMSWCR0.STBYRAMSEL位域,選擇給哪快RAM進行供電。只有休眠后改被供電的RAM才有RAM?Retentions的功能。

?
問題1:為什么要考慮錯誤信息的存儲了?
答:因為Error發生時如果時Protection Error的話,一般就會在OS調用ProtectionHook()后執行Shutdown,在ShutdownHook()中一般執行ECU復位了,如果我們不存儲Error發生時的上下文信息的話,一旦系統復位的話我們就無法再分析Error發生的原因了。
問題2:錯誤信息存儲在那里了,是不是可以存儲在NvM?
答:錯誤信息可以存儲在NvM中,但是因為ProtectionHook()后一般馬上就要進行MCU復位了,來不及調用異步的NvM接口來存儲錯誤信息了,所以只能把錯誤信息存儲到Retention RAM中。復位起來后,錯誤信息處理SWC讀取Retention RAM中的異常信息,此時可選擇是否再次寫入到NvM當中。
Note:
1.如果系統是斷電系統,那么一定要注意OS ShutdownHook()中調用Mcu_PerformReset()進行軟件復位而不是調用SBC的接口給MCU斷電,因為MCU斷電后是冷啟動,Retention RAM中的數據也沒了。
2.如果系統是深度休眠系統且使用Aurix芯片的SCR功能,那么Retention RAM一定要配置在PMSWCR0.STBYRAMSEL配置供電的RAM塊中。
3.無論是深度休眠系統還是斷點系統,MCU復位后在Main函數之前的Startup階段都不能把Retention RAM給清零了(需要修改啟動代碼和連接器腳本)。
參考文檔:
RH850-U2A16芯片--RAM and Flash介紹
AUTOSAR架構下RH850芯片斷電系統配置實踐
AUTOSAR架構下RH850芯片深度休眠配置實踐-Conifig EcuM and BswM
問題1:通過2.1小結我們知道錯誤信息應該存放在Retention RAM當中,那么我們應該存儲哪些異常時的上下文信息了?
答:我們通過一個表格來舉例給出答案。
Error Types | Error Contex |
Application Errors | 如果在使用Spinlock是發生Application Error,可以獲取以下信息: ? 1.?通過Os_GetDetailedError()獲取服務ID及Error Code等信息。 ? 2.?通過OSError_GetSpinlock_SpinlockId()返回錯誤的GetSpinlock調用的參數SpinlockId. ? 使用其他OS服務,比如Alarm, Resource等發生錯誤時同樣可以調用OsError_xxx_xxx()獲取相關錯誤現場信息。 |
Protection Errors | 1.?ProtectionHook()的參數Fataerror. ? 2.?通過GetTaskID獲取Error發生時的正在處理的Task. ? 3.?通過GetISRID()獲取當前執行ISR的標識符。 ? 4.?通過Os_GetExceptionAddress()獲取引發最新異常的指令的地址。 ? 5.?讀取DEADD寄存器獲取發生trap時的地址信息。 ? 6.?通過Os_GetExceptionContext()獲取異常上下文信息,異常結構體為:struct Os_ExceptionContextType_Tag; ? 通過結構體成員Ra和ExceptionSource對應的TIN和Class信息,可以輕松定位MPU保護產生的Error. |
Kernel Errors | 通過GetTaskID獲取Error發生時的正在處理的Task. |
/*!?Set?of?hardware?registers?to?be?able?to?resume?from?an?exception.?*/struct?Os_ExceptionContextType_Tag{??/*?Stored?Address?registers?of?the?thread?(a2-a7,?a12-a15)*/??uint32?AddressRegisters[16];??/*?Stored?Data?registers?of?the?thread?(d0-d15)*/??uint32?DataRegisters[16];??/*!?Stored?return?address?of?the?thread?*/??uint32?Ra;??/*!?Stored?Psw?of?the?thread?*/??uint32?Psw;??/*!?Stored?Exception?source(Exception?class?and?tin?number)?of?the?thread?*/??uint32?ExceptionSource;??/*!?Stored?Pcpn?(Previous?CPU?Priority?number)?from?the?Pcxi?of?the?thread?*/??uint32?Pcpn;??/*!?Stored?Pie?(Previous?Interrupt?Enable)?from?the?Pcxi?of?the?thread?*/??uint32?Pie;??/*!?The?lower?address?of?the?MPU?region?for?stack.?*/??uint32?MpuRegionForStackLow;??/*!?The?upper?address?of?the?MPU?region?for?stack.?*/??uint32?MpuRegionForStackUpper;??/*!?The?raw?PCXI?value?from?the?upper?context;?may?be?used?to?look?up?in?CSAs?prior?to?the?exception?*/??uint32?RawPCXI;};
對于Application Error一般都是錯誤使用OS?API導致的,只要我們記錄好錯誤發生時的ServiceID等就能輕松定位。
對于Kernel Error由于OS內部數據可能被異常打亂了,數據不在可信,可獲取的上下文信息不多,這類錯誤就只能根據具體硬件平臺和OS代碼積累經驗了(開發階段可以通過故障注入提前獲知Kernel Error產生后的表現)。
實際項目中最可能出問題的就是Protection Error了,而這里面也以MPU保護Error為最常見。出現內存保護Error后,通過Ra(A11程序返回寄存器)?查找Map文件可以大概知道那塊代碼(指令所在的地址)發生異常;通過DEADD寄存器可以得知大概是訪問了哪塊Data數據(訪問的數據的地址)發生了異常,比如異常改寫了調用棧內容。示例可以參考文檔:TC3xx芯片的Trap詳解
最后通過回答開頭的三個問題來結束本文。
問題1:有哪里常見的OS錯誤 ?
答:大類有Application Errors, Protection Errors, Kernel Errors三種,每種大類包含的具體Error?Code可以參考1.1章節。
問題2:如何進行OS錯誤處理?
答:通過Retention RAM來存儲OS錯誤信息,通過OS給出的一系列API獲取Error發生時的上下文信息。
問題3:如何定位OS錯誤發生的原因和位置?
答:具體參考2.3章節。
End
「汽車電子嵌入式在CSDN上同步推出AUTOSAR精進之路專欄,本專欄每個模塊完全按實際項目中開發及維護過程來詳細介紹。模塊核心概念介紹、實際需求描述、實際工程配置、特殊需求介紹及背后原理、實際工程使用經驗總結。目的是讓讀者看完每一個章節后能理解原理后根據需求完成一個模塊的配置或者解決一個問題。」
點擊文章最后左下角的閱讀原文可以獲取更多信息
或者復制如下鏈接到瀏覽器獲取更多信息
https://blog.csdn.net/qq_36056498/article/details/132125693
注:本公眾號文章中使用了一些第三方工具和文檔,若有侵權,請聯系作者刪除!
推薦閱讀
汽車電子嵌入式精彩文章匯總第一期:20210530-20230703
AUTOSAR 架構下EcuM喚醒源事件詳解
AUTOSAR架構下NVM Block連續寫及Default Value問題分析
AUTOSAR架構下NvM模塊詳細分析
AUTOSAR架構下報文掉線超時不上報問題分析
Classic Autosar下的以太網通訊架構概覽
通信中間件Someip服務化通信
AUTOSAR架構下Fee詳細分析
TC37x芯片FLASH基本概念介紹
AUTOSAR架構下Fls詳細分析
TC3xx芯片DMU介紹
TC3xx芯片MPU介紹
TC3xx芯片的Trap詳解
End
歡迎點贊,關注,轉發,在看,您的每一次鼓勵,都是我最大的動力!
汽車電子嵌入式
微信掃描二維碼,關注我的公眾號