TI-RTOS多任務編程

最近在做一些關於一些驅動向TI板子的移植集成的事情,在這裏簡單的記錄一下。本文主要敘述如何進行多任務的編程,以及我在編程中遇到的一些不解。

  1. Task組成部分:任務函數,任務參數(屬性),任務堆棧.
實際上Task是sys/bios提供的一種併發編程手段,和我們常見到的線程是一個道理。
  1. Task類型:硬中斷HWI,軟中斷SWI,任務Task,空閒任務IDLE.
  2. 優先級排列:硬中斷HWI>軟中斷SWI>任務Task>空閒任務IDLE.
  3. 四種類型任務釋義:
硬中斷:實時環境中,它是響應外部觸發的異步事件(中斷)-----優先級不由sys/bios管理,由cpu的特性決定。
雖然優先級最高,當然也可以被中斷。

軟中斷:軟件中斷服務例程 ------優先級可以達到 32 級,默認只有 16 級。
SWI 可以被更高優先級的 SWI 和 HWI 搶佔,但是 SWI 是不會阻塞的。

任務:用戶任務,運行過程中,可以被阻塞直到必要的資源可用;
TASK 要求每個任務要有自己獨立的棧空間。
SYS/BIOS 提供了一些機制用於 TASK 間的同步和通信,它們有信號量(Semphore),事件(Events),隊列(Queue)和郵箱(Mailboxes)。
優先級也可以達到 32 級,默認是 16 級。
Task 優先級數值越大,其優先級就越高,0 是優先級最低的。Task_setPri 函數動態的更改。新的優先級必須在 1 到 TnumPriorities – 1 之間。當新優先級數低於當前優先級時,可能會發生任務的切換。

空閒任務:優先級最低的任務。
當 SYS/BIOS 沒有比空閒任務更高的任務運行時,SYS/BIOS 就會執行空閒任務,並且是連續執行,直到有更高的任務進入就緒狀態。
其運行在Task任務 0 優先級上。
  1. 創建一個task過程:
#include <app.h>
#include <utils/console_io/include/app_log.h>
#include <xdc/runtime/Error.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>
#include <app_ipc_rsctable.h>

static Void appMain(UArg arg0, UArg arg1){   //任務函數
	//do something
	printf("this is thread function\n");
} 

void StartupEmulatorWaitFxn (void){
    volatile uint32_t enableDebug = 0;
    do{
    }while (enableDebug);
}

static uint8_t gTskStackMain[4*1024]                 //任務使用的棧空間
__attribute__ ((section(".bss:taskStackSection")))
__attribute__ ((aligned(4096)))
;

int main(void)
{
    Task_Params tskParams;
    Error_Block eb;
    Task_Handle task;
    /* This is for debug purpose - see the description of function header */
    StartupEmulatorWaitFxn();
    Error_init(&eb);
    Task_Params_init(&tskParams);

    tskParams.arg0 = (UArg) NULL;
    tskParams.arg1 = (UArg) NULL;
    tskParams.priority = 10u;                //指定任務優先級
    tskParams.stack = gTskStackMain;         //指定任務使用的堆棧
    tskParams.stackSize = 4096;              //指定堆棧的大小
    task = Task_create(appMain, &tskParams, &eb); //動態創建一個task
    /*
		You can continue to create other tasks from here......
	*/
    if(NULL == task){
        BIOS_exit(0);
    }
    BIOS_start();                  //運行到這裏程序不會退出,相當於是個死循環,操作系統將會調度執行任務
    return 0;
}

  1. SDK版本以及引用路徑
/psdk_rtos_auto_j7_06_01_00_15/bios_6_76_03_01/packages/ti/sysbios/knl
  1. 如何在程序中獲取任務的信息以及狀態
// bios_6_76_03_01/packages/ti/sysbios/knl/Task.h:105:struct  ti_sysbios_knl_Task_Stat ; 任務信息聲明處
//解釋幾個我用到的成員:
struct ti_sysbios_knl_Task_Stat {
      xdc_Int priority;    //優先級
      xdc_Ptr stack;        //使用的堆棧地址
      xdc_SizeT stackSize;  //使用的堆棧的大小
      xdc_runtime_IHeap_Handle stackHeap;
      xdc_Ptr env;
      ti_sysbios_knl_Task_Mode mode;//狀態:阻塞 就緒 運行 不活躍的
      xdc_Ptr sp;
      xdc_SizeT used;               //已經使用了的堆棧空間大小
 };

如何在一個任務中動態獲取當前任務的狀態信息:

    Task_Stat statbuf;
    Task_stat(Task_self(),&statbuf);
    printf("In appMain task,stack buff used = %d\n",statbuf.used);//查看當前任務已經使用的
    printf("In appMain task,stack total size = %d\n",statbuf.stackSize);//查看當前任務分配的總stack
    printf("In appMain task,task priority =%d\n",statbuf.priority); //查看當前任務的優先級
  1. 關於任務堆棧
    大小:
    儘量使用自定義數組來充當任務執行時的堆棧,不要依靠於系統的堆棧,如果內存不足,將發生致命錯誤;
    關於給任務分配多大內存爲合適,我查看了一些資料,有說到一個任務最少需要分配512個字節,這是理論值,或者說這個任務的函數是一個空函數,啥都不幹,這512是用來滿足上下文的保存的,不符合實際開發,如果條件允許,簡單的函數給予2k,稍微複雜的給予4k.(具體值還請各位嘗試,這裏作爲參考)
    注意:我這裏是跑在R5F mcu2_0上的,和使用的SDK版本也有關係。

對齊方式:(不添加對齊應該也可以運行)
我理解cpu爲了提高取指速率,需要進行內存對齊。
一般而言,選擇對齊數num * n = stackSize,其中n%2 == 0,num可能更滿足要求,如
static uint8_t TskStackMain[4*1024]
attribute ((section(".bss:taskStackSection")))
attribute ((aligned(4096)));

這個我並沒有找到官方的文檔的來解釋說明,僅僅作爲一種猜測,當然不是憑空猜測,是經過實驗的。

  1. 任務阻塞方式:

Task_sleep():使用:Task_sleep(5300 / Clock_tickPeriod);// 延時5.3ms Clock_tickPeriod定義在ti/sysbios/knl/Clock.h

Task_yield():使得任務主動讓出自己的時間片

Semaphore_pend():信號量,獲取臨界資源

  1. 同步方式
    信號量、郵箱、事件等,如需要可以參考官方文檔。

最後說一下我的遇到幾個很奇怪的現象:

1.替換固件,板子斷電重啓,系統運行的結果是前一次,爲什麼上一次數據沒有被擦除?
2.相同優先級的任務存在某一個任務一直運行,不釋放cpu的現象,只好通過一些接口
讓他主動釋放,並沒有像一些文檔中描述的,類似於時間片輪轉?

這裏猜測可能是SDK版本的原因,也可能是板子還是不夠成熟吧
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章