天天看點

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,表示這類型的記憶體塊就有一塊被占用,直到用完,其他的任務再要使用就需要等待,這對于有多個實體的共享資源比較好,其實這裡還要管理具體的那個任務占用了具體的那個實體資源】