1. 程式人生 > >uc/os程式設計點滴記錄

uc/os程式設計點滴記錄

任務有切換,但切換到某個任務,總是出現hardfault錯誤?

【現象:給出錯的任務換一個大小一樣但名字不一樣的堆疊就可以,使用原來名字的堆疊就是出錯】
解決:

  1. 檢視hardfault暫存器,找到出錯的原因–>提示是fault上報導致
  2. 檢視其它的fault暫存器,發現是用法fault–>具體為異常返回時試圖非法載入EXC_RETURN到PC…
  3. 明確中斷髮生時使用的堆疊是PSP還是MSP;檢視MSP或PSP暫存器的值;根據中斷的入棧序列找到hardfault發生時的PC值,即中斷現場找到了。其實到步驟3一般很難查找出問題。
  4. 直接在應用層除錯,呼叫OSTaskStkChk()檢視任務的堆疊.
    所以在uC/OS程式設計中,如果出現上述分析的用法fault錯誤,非法載入EXC_RETURN到PC,很可能就是堆疊溢位後,被其他程式修改導致,加大堆疊試一下。

一個任務的堆疊大小怎麼估算?

在uC/OS II中,建立任務,至少要考慮到被切換,任務切換至少使用17個暫存器(68個位元組),這時再加上任務的區域性變數、引數傳遞、函式呼叫等還要使用堆疊,所以至少要大於 68多 的位元組。【68位元組的堆疊只能符合空函式之類很簡單的函式,因為在任務函式中,函式內各個私有變數以及函式呼叫時引數的傳遞基本都是使用CPU暫存器或堆疊配合來實現,這樣棧肯定要大於68,如果這時棧太小,那麼程式執行到需要一些開銷很大的數值等時,很可能因為溢位造成hardfault錯誤】

  1. 方法1
    可以先分配大的堆疊,再使用堆疊檢驗功能,帶任務執行一段時間,估計堆疊使用最多的時候已經過了,再通過堆疊檢驗函式OSTaskStkChk()檢視具體的堆疊使用了多少,再可以修改程式碼或者動態分配記憶體在建立任務。

  2. 方法2
    來自網上自己還沒有驗證:
    這個不是這樣滴,微扣死吐 有個高階選擇,CreateTaskPrxx 裡面可以選擇一個類似於debug模式,然後裡面有個類似於stackDepth的東西,Run起來就可以知道這個Task大概用了多少ram了。當然了,前提是必須把Task的所有路徑執行完畢。
    PS:一般人我不告訴他的,看你是原子鍋的粉絲就額外給你的建議。

任務劃分

在uC/OS II工程中,可能會包含多種外設,可能會有很多種功能,比如鍵盤,顯示等等, 其實任務劃分時最好將各功能 任務化, 比如顯示就單獨成立一個顯示任務,鍵盤就單獨成立一個鍵盤掃描任務,任務之間通訊通過各種通訊機制進行; 不能在各個任務之間,將各種的功能太過交叉化,比如顯示功能,該功能模組可能會有多個顯示函式介面,那麼如果不單獨將顯示做出一個獨立的任務,那麼在很多工中就要交叉使用這個顯示函式介面,如果某一個顯示函式介面在函式可重入性方面做的不好,就會引發程式錯誤;那如果將顯示獨立做成一個任務【也就是將函式都變成該任務的私有函式】,那其他的任務想要顯示時,可以通過郵箱或訊息佇列與顯示任務通訊,這樣程式就會安全很多。
目前,各功能單獨成立為一個任務,比如顯示功能成為顯示任務,檔案系統通過一個任務來管理,這樣檔案系統任務要顯示時,就向顯示任務的訊息佇列裡面傳送顯示訊息,而不是直接在本任務中呼叫顯示函式。

資源同步

取樣任務將AD的取樣結果轉換並存儲到陣列data[]中,顯示任務從data[]中讀取資料並顯示。 兩個任務需要訪問同一個資源:data[],那麼時就可以先定義一個互斥訊號量,任務一個任務需先獲取該互斥訊號量再進行操作,最後釋放訊號量。
用簡單的二值訊號來解決資源訪問衝突,因為沒有優先順序的反轉,容易鎖住(為什麼?或者不是這樣,待求證),比如低優先順序的任務在獲取了二值訊號量還沒有釋放時就被高優先順序的任務搶佔

1、什麼是共享資源?
共享資源就是被兩個或以上的併發程式單元(如:ISR與任務、任務與任務)訪問的資源,共享資源一定是全域性資源,但是全域性資源不一定是共享資源,如字型陣列,是全域性的數值,但只被單個任務使用(顯示任務),就不是共享資源;

2、什麼是資源同步?訪問共享資源的程式碼段位臨界區(關鍵段落),各個臨界區訪問共享資源時,一定要保住互斥訪問,要做到這點,就需要使用相關的措施,這些措施就是資源同步。

3、為什麼要使用資源同步?
因為可讀可寫的共享資源的訪問一定要在互斥條件下進行,只有這樣才能保證共享資源的可靠性與完整性;如當前的A臨界區要用到共享資源,且這時的共享資源對A有效,那如果不適用資源同步,就很有可能在A使用對於自己有效的共享資源時,共享資源被修改,造成錯誤。

是不是所有的共享資源都是需要進行資源同步?不一定,如一些共享資源的屬性是隻讀,不能被寫,所有使用它的程式碼段,只能讀取它,不能修改它,所以不需要資源同步;對於那些可讀可寫的共享資源,一定要進行資源同步。

4、如何分析一個共享資源,存在的安全隱患?
【只要是全域性的資源(不是某個程式碼段私有的,且不是隻讀),就一定考慮:使用資源的過程被其他的程式碼段打斷,資源被修改的情況,從這點出發再去做防範】

  1. 由於系統存在各種突發事件(如中斷、時間片輪轉),可讀可寫的共享資源在沒有使用資源同步措施情況下一定存在不可靠性與不完整性。

  2. 從訪問共享資源出錯的排程去分析:在使用共享資源的地方(要有一種意識:使用資源的地方即使只用一句話,這個使用的過程也是需要CPU多步走,即使用共享資源,就存在使用過程被打斷的情況),假設出錯(可能原因是中斷修改資源、中斷觸發高優先任務執行修改資源、時間片輪轉後其他任務修改),這時再去分析,具體的程式碼會怎麼樣,應該做如何的修改。

5、資源同步的措施有哪些?
1. 關中斷
2. 關排程
3. 使用互斥訊號量
4. 使用計數訊號量

關中斷方法
應使關中斷的時間儘可能的短(可以聯想到linux中處理中斷時的方法)

上下文法
讓需要實時性很高的程式碼在關閉中斷下處理(上文),對於一些耗時的操作,可以放在中斷外面去作為一個執行緒去執行(下文)),有這個思路,我們也可以借鑑,如在一個臨界區關了中斷,要訪問共享資源,我們可以先只讀取資料到一個臨時的地方(所謂對資料拍照),然後立馬開中斷,對資料的處理(較耗時)放在中斷外面進行。
例如:RTC,RTC中斷服務程式中設定全域性陣列中的時分秒,我們在任務中讀取這個全域性陣列時就可以先關中斷,再拍照,再開中斷,再處理資料(如顯示等等),這樣系統對中斷的實時性響應就很好。
【併發程式包含ISR時,只能通過關中斷措施來訪問共享資源,關中斷直接影響系統的實時性,因此只能用於對簡單共享資源的短暫訪問,故關中斷常用於對全域性變數或小規模全域性資料結構的訪問,且需要使用拍照的方法】

關排程方法
當臨界區程式碼不包含ISR時(即全部是任務級程式碼),可以通過關排程的方法,訪問共享資源;關排程的方法會影響與共享資源無關的任務的執行。【直接關排程的方法優點不多,缺點不少,儘可能不要使用】

使用互斥訊號量
(ISR中不包含臨界區程式碼的情況)互斥訊號量也是二值的,專門用於資源同步的訊號量,與用於行為同步的二值訊號量(二值[計數]訊號量也可用作資源同步)不同,互斥訊號量還可以進行優先順序翻轉[臨時調高優先順序]。使用互斥訊號量訪問共享資源,對中斷和任務排程都沒有限制,系統可以照常響應各種非同步事件,且其他與共享資源無關的高優先順序任務也可以執行。【使用互斥訊號量進行資源訪問對系統的實時性影響最小】
1. 選取互斥訊號量:OSMutexPend(sem,0,&err)
2. 訪問共享資源
3. 釋放互斥訊號量:OSMutexPost(sem)

使用計數訊號量
與用於行為同步的計數訊號量不一樣,用於資源同步的計數訊號量的初始值為共享資源的實體總數【如記憶體:同類型的記憶體分配了好幾塊,那麼此時計數訊號量的值就是這個總數,計數訊號量減1,表示這型別的記憶體塊就有一塊被佔用,直到用完,其他的任務再要使用就需要等待,這對於有多個實體的共享資源比較好,其實這裡還要管理具體的那個任務佔用了具體的那個實體資源】