SYS/BIOS實例分析


SYS/BIOS簡介

SYS/BIOS是一個可擴展的實時內核(或者說是操作系統),其提供了許多模塊化的APIs(應用程序接口),支持搶占式多線程,硬件抽象,實時分析和配置工具,其設計目的是為了最大限度地減少對內存和CPU的要求。其擁有很多實時嵌入式操作系統的功能,如任務的調度,任務間的同步和通信,內存管理,實時時鍾管理,中斷服務管理等。有了它,用戶可以編寫復雜的多線程程序,並且會占用更少的CPU和內存資源。
SYS/BIOS的早期版本是DSP/BIOS,更名的原因,是因為SYS/BIOS不僅可以用於DSP,而且也可以嵌入到ARM等其他SoC中去。SYS/BIOS是一個可用於實時調度、同步,主機和目標機通信,以及實時分析系統上的一個可裁減實時內核,它提供了搶占式的多任務調度,對硬件的及時反應,實時分析和配置工具等。同時也提供標准的API接口,易於使用。它是TI的eXpressDSP實時軟件技術的的一個關鍵部分。
CCS中集成安裝了SYS/BIOS,能夠大大方便用戶編寫多任務應用程序。另一方面,SYS/BIOS可以在XDCtools中使用配置技術,極大地方便了SYS/BIOS的開發流程。

創建一個SYS/BIOS項目

在項目模板中選擇SYS/BIOS項目中的Hello Example模板,點擊Next:

在RTSC(XDCtools的別稱)配置頁中選中需要的SYS/BIOS,XDCtools及其他組件的版本,Target保持默認,不需修改,如果Platform沒有自動填充,選擇與設備適用的平台。Build-profile決定程序鏈接的庫,推薦使用release,即使仍然處於創建和調試階段,點擊Finish完成創建項目。

點擊編譯;導入target文件后,點擊調試,運行得到結果:

 SYS/BIOS的模塊與配置

SYS/BIOS可以用文本編輯器或者是圖像配置編輯器XGCONF來編輯,雙擊打開.cfg文件:

單擊System Overview,可以顯示程序當前使用的主模塊(帶綠色小箭頭的):

各種APIs模塊的添加這里有兩種方法,一種是直接雙擊主模板進入,然后勾選Add:

各個API模塊的作用

CLK:片內定時器模塊,主要控制片內定時器並提供高精度的32位實時邏輯時鍾,它能控制中斷的速度,使之最快達到單指令周期時間。
HST:主機輸入/輸出模塊,管理主機通過對象,它允許應用程序在目標系統和主機之間交流數據,主機通道通過靜態配置為輸入或輸出。
HWI:硬件中斷模塊,提供對硬件中斷服務例程的支持,可在配置文件中指定當硬件中斷發生時需要啟動的函數
IDL:休眠功能模塊,管理休眠函數在目標系統程序沒有更高優先權的函數運行時啟動
LOG:日志模塊,管理LOG對象,LOG對象在目標系統程序執行時實時捕捉事件,開發者可以使用系統日志或定義自己的日志,並在CCS中利用它實時瀏覽信息。
MEM:存儲器模塊允許指定存放目標程序的代碼和數據所需的存儲器段
PIP:數據通道模塊管理數據通道,它用來緩存輸入和輸出數據流,這此數據通道提供一致性的軟件數據結構,可以使用它們驅動DSP和其他實時外圍設備之間的I/O通道
PRD:周期函數模塊,管理周期對象,它觸發應用程序的周期性執行。
RTDX:實時數據交換允許數據在主機和目標系統之間實時交換,在主機上使用自動OLE的客戶都可對數據進行實時顯示和分析。
STS:統計模塊,管理統計累積器,在程序運行時,它存儲關鍵統計數據並能通過CCS瀏覽這此統計數據
SWI:軟件中斷模塊管理軟件中斷。
TRC:跟蹤模塊,管理一套跟蹤控制比特,它們通過事件日志和統計累積器控制程序信息的實時捕捉。

在項目中導入LOG模塊

 LOG模塊實際上是一個實現打印信息的API。

添加LOG模塊,默認是自動添加的。

LOG模塊定義了許多比如Log_error、Log_info、Log_warning、Log_print等之類函數,這些函數的用法同printf函數的用法很相似,這些函數都可以在<xdc/runtime/Log.h>找到,其實際上是將printf的有用法分成許多不同的類(如錯誤信息、提示信息、警告信息等),LOG模塊打印的內容查看:

右下角會出現面板:

LOG中定義了許多如下的函數,比如Log_info1函數后面的數字代表函數接的變量數目,如:

Log_info1("%d",s1); Log_info2("%d, %d", s1, s2)

在項目中導入TSK任務模塊

TSK任務模塊是操作系統中最基本的模塊,其實際上反映了多線程搶占,每個任務單獨是一個線程,各個線程(任務)具有各自的優先級。

創建新任務,我們創建兩個任務task0、task1,分別對應其函數func_tsk0、func_tsk1。其優先級都為1:

編寫任務函數:

/* * ======== hello.c ======== * The hello example serves as a basic sanity check program for SYS/BIOS. It * demonstrates how to print the string "hello world" to stdout. */ #include <xdc/std.h> #include <xdc/runtime/System.h> #include <ti/sysbios/BIOS.h> #include <xdc/runtime/Log.h> #include <ti/sysbios/knl/Task.h>



/* * ======== main ======== */

void fun_task0(void); void fun_task1(void); Void main() { System_printf("hello world\n"); BIOS_start(); } void fun_task0(void) { Int count = 0; while(count<10) { Log_info1("Task0 is doing %d\n",count); Task_yield(); count++; } BIOS_exit(0); } void fun_task1(void) { Int count = 0; while(count<10) { Log_info1("Task1 is doing %d\n",count); Task_yield(); count++; } BIOS_exit(0); }
說明:
這里我們在主函數中BIOS_start()函數,說明任務開始執行了
任務執行完后調用BIOS_exit(0)退出
Task_yield()是個優先級調度函數,其作用就是如果有相同優先級的任務,則調度到同優先級的其它任務執行!
Log_info1()的作用是打印日志信息
while和count循環的目標是讓任務執行較長的時間,而不是只執行一次就退出了。
編譯調試,運行查看結果(這里我們只需要選擇單核運行就可以了)

我們可以看到兩個任務是相互依次運行的,每個任務運行一次后,其優先級就會降低,此時就切換到下一個任務。

在項目中導入Swi軟件中斷模塊

 不同任務有不同優先級,而軟件中斷具有比任何任務都高的優先級,而其中硬件中斷(HWI)又比軟件中斷(SWI)優先級更高。

添加軟件中斷Swi:

代碼:

/* * ======== hello.c ======== * The hello example serves as a basic sanity check program for SYS/BIOS. It * demonstrates how to print the string "hello world" to stdout. */ #include <xdc/std.h> #include <xdc/runtime/System.h> #include <ti/sysbios/BIOS.h> #include <xdc/runtime/Log.h> #include <ti/sysbios/knl/Task.h> #include <ti/sysbios/knl/Swi.h>



/* * ======== main ======== */

void fun_task0(void); void fun_task1(void); void func_swi0(void); Swi_Handle swi0; //聲明一個全局的SWI句柄
 Void main() { System_printf("hello world\n"); //初始化SWI參數
 Swi_Params swiParams; Swi_Params_init(&swiParams); swiParams.priority = 2;  //軟件中斷優先級設置為2
    swiParams.trigger = 2;   //設置軟件中斷計數器
    swi0 = Swi_create(func_swi0, &swiParams, NULL); //創建軟件中斷swi0,func_swi0為軟件中斷函數
 BIOS_start(); } void func_swi0(void) { static Int count = 0; Log_info1("Swi0 is doing %d\n",count); count++; } /*更改軟件中斷計數器trigger,要觸發軟件中斷,首先需要讓trigger的計數為0, 這里我們可以在任務函數內增加一個trigger自減的函數,任務函數執行兩次后,將會觸發軟件中斷*/
void fun_task0(void) { Int count = 0; while(count<10) { Log_info1("Task0 is doing %d\n",count); Swi_dec(swi0); Task_yield(); count++; } BIOS_exit(0); } void fun_task1(void) { Int count = 0; while(count<10) { Log_info1("Task1 is doing %d\n",count); Swi_dec(swi0); Task_yield(); count++; } BIOS_exit(0); }

編譯調試,運行查看結果(這里我們只需要選擇單核運行就可以了):

可以看到兩個任務的每次都會使得軟件中斷計數trigger減1(通過Swi_dec函數),直到trigger的值減少到0時,執行軟件中斷,中斷后,trigger恢復到原來的值,這里的trigger初始值為2,所以執行兩次任務后就會觸發一次軟件中斷。

在項目中導入信號量Semaphore模塊

信號量是在多線程環境下使用的一種設施,是可以用來保證兩個或多個關鍵代碼段不被並發調用,對於多個任務來說,使用信號量可以防止多個任務同時執行。
信號量可分互斥信號量和計數信號量,互斥信號量只有兩種狀態:1和0,為1時說明可用,否則不可用。而計數信號量通過設置一個計數值,如果計數值大於0,則任務請求該信號量時是可用。
這里例子是我們給task0任務中增加一個互斥信號量,當信號量狀態為1時,task0才能繼續執行。通過軟件中斷來達到信號量歸1。
添加信號量:
 

代碼:

/* * ======== hello.c ======== * The hello example serves as a basic sanity check program for SYS/BIOS. It * demonstrates how to print the string "hello world" to stdout. */ #include <xdc/std.h> #include <xdc/runtime/System.h> #include <ti/sysbios/BIOS.h> #include <xdc/runtime/Log.h> #include <ti/sysbios/knl/Task.h> #include <ti/sysbios/knl/Swi.h> #include <ti/sysbios/knl/Semaphore.h>


/* * ======== main ======== */

void fun_task0(void); void fun_task1(void); void func_swi0(void); Swi_Handle swi0; Semaphore_Handle sem0; //添加全局的信號量句柄
 Void main() { System_printf("hello world\n"); Swi_Params swiParams; Swi_Params_init(&swiParams); swiParams.priority = 2; swiParams.trigger = 2; swi0 = Swi_create(func_swi0, &swiParams, NULL); sem0 = Semaphore_create(0, NULL, NULL);//創建信號量
 BIOS_start(); } void func_swi0(void) { static Int count = 0; Log_info1("Swi0 is doing %d\n",count); count++; //增加一個解鎖信號量的函數
 Semaphore_post(sem0); } void fun_task0(void) { Int count = 0; while(count<10) { Semaphore_pend(sem0, BIOS_WAIT_FOREVER);//在增加互斥信號量的任務函數中增加一個等待信號量為1的函數
        Log_info1("Task0 is doing %d\n",count); Swi_dec(swi0); Task_yield(); count++; } BIOS_exit(0); } void fun_task1(void) { Int count = 0; while(count<10) { Log_info1("Task1 is doing %d\n",count); Swi_dec(swi0); Task_yield(); count++; } BIOS_exit(0); }

編譯調試,運行查看結果(這里我們只需要選擇單核運行就可以了):

可以看到只有當軟件中斷執行后,此時信號量才解鎖,task0才能執行,而任務執行兩次,才能觸發一次軟件中斷。

在項目中導入時鍾Clock模塊

Clocks模塊主要提供周期性執行函數,我們這里新建一個周期性執行函數,其每四個周期執行一次.

添加時鍾:

代碼:

/* * ======== hello.c ======== * The hello example serves as a basic sanity check program for SYS/BIOS. It * demonstrates how to print the string "hello world" to stdout. */ #include <xdc/std.h> #include <xdc/runtime/System.h> #include <ti/sysbios/BIOS.h> #include <xdc/runtime/Log.h> #include <ti/sysbios/knl/Task.h> #include <ti/sysbios/knl/Swi.h> #include <ti/sysbios/knl/Semaphore.h> #include <ti/sysbios/knl/Clock.h>

/* * ======== main ======== */

void fun_task0(void); void fun_task1(void); void func_swi0(void); void func_clk(UArg arg0); Swi_Handle swi0; Semaphore_Handle sem0; Void main() { System_printf("hello world\n"); Swi_Params swiParams; Swi_Params_init(&swiParams); swiParams.priority = 2; swiParams.trigger = 2; swi0 = Swi_create(func_swi0, &swiParams, NULL); Clock_Params clkParams; Clock_Params_init(&clkParams); clkParams.period = 5; // 函數執行周期
    clkParams.startFlag = TRUE; // True說明時鍾立即開始計時
    Clock_create(func_clk, 5, &clkParams, NULL); //創建時鍾,func_clk是周期執行的函數,這里5是開始執行的延時。
 sem0 = Semaphore_create(0, NULL, NULL); BIOS_start(); } void func_swi0(void) { static Int count = 0; Log_info1("Swi0 is doing %d\n",count); count++; Semaphore_post(sem0); } void func_clk(UArg arg0) { UInt32 time; time = Clock_getTicks(); // 這里是定時器的節拍器
    System_printf("System time in clk0Fxn = %lu\n", (ULong)time); if(time>20) BIOS_exit(0); } /* 因為任務的執行時間非常快,所以需要先把任務內的退出BIOS命令先刪除下,否則當任務完成后,時鍾函數還沒執行 */
void fun_task0(void) { Int count = 0; while(1) { Semaphore_pend(sem0, BIOS_WAIT_FOREVER); Log_info1("Task0 is doing %d\n",count); Swi_dec(swi0); Task_yield(); count++; } } void fun_task1(void) { Int count = 0; while(1) { Log_info1("Task1 is doing %d\n",count); Swi_dec(swi0); Task_yield(); count++; } }

編譯調試,運行查看結果(這里我們只需要選擇單核運行就可以了):

可以看到只有當周期函數func_clk每隔5個周期開始執行,開始執行時間為5。 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM