OSAL概述


OSAL概述

OSALOperating System Abstraction Layer,即操作系統抽象層,支持多任務運行,其中BLE協議棧、配置文件以及所有的應用程序(app)都在其上運行,它並不是一個傳統意義上的操作系統,但是實現了部分類似操作系統的功能,為了方便,下面簡稱OSAL系統。

 

 

1、OSAL簡要流程

 

 

 

初始化完成后,在appinit最后一般會啟動一個定時器或者直接set一個任務事件START_DEVICE_EVT,超時后進入app回調函數START_DEVICE_EVT事件分支處理,在該分支中啟動具體的信息采集、數據處理、數據顯示或發送等定時任務。

OSAL系統工作,判斷當前是否存在待處理的任務事件,有,則調用對應的回調函數進行處理,並在結束后重新設定定時器等待超時,若沒有任務事件,則進入休眠狀態,等待喚醒。

 

 

2OSALmain函數

 

任何一個程序都由main函數起,單片機程序中,一般順序為:

時鍾初始化——>相應外設初始化——>系統關鍵參數初始化——>進入死循環處理;

OSALmain函數中,同樣也是這些流程:

 1  
 2 
 3 /**************************************************************************************************
 4 
 5  * @fn          main
 6 
 7  *
 8 
 9  * @brief       Start of application.
10 
11  *
12 
13  * @param       none
14 
15  *
16 
17  * @return      none
18 
19  **************************************************************************************************
20 
21  */
22 
23 int main(void)
24 
25 {
26 
27   /* Initialize hardware */
28   HAL_BOARD_INIT();
29 
30   // Initialize board I/O
31   InitBoard( OB_COLD );
32 
33   /* Initialze the HAL driver */
34   HalDriverInit();
35 
36   /* Initialize NV system */
37   osal_snv_init();
38 
39   /* Initialize LL */
40 
41   /* Initialize the operating system */
42   osal_init_system();
43 
44   /* Enable interrupts */
45   HAL_ENABLE_INTERRUPTS(); 
46 
47   // Final board initialization
48   InitBoard( OB_READY );
49 
50   #if defined ( POWER_SAVING )
51 
52     osal_pwrmgr_device( PWRMGR_BATTERY );
53 
54   #endif
55 
56   /* Start OSAL */
57   osal_start_system(); // No Return from here
58 
59   return 0;
60 
61 }
62 
63  
64 
65  

 

 

解析:

 HAL_BOARD_INIT(); //初始化晶振及預讀取程序 

 

 InitBoard( OB_COLD ); //main函數中有兩處InitBoard();此為第一次初始化,此時OSAL   還未啟動,初始化IO及一些系統級寄存器,類似電腦上的BIOS   為系統的啟動做准備,個人認識,歡迎指正。

 

 HalDriverInit(); //此處進行硬件初始化,定時器、AD轉換、LCDLEDKEY

 

 osal_snv_init(); //初始化存儲區域

 

 osal_init_system(); //初始化OSAL,此處系統初始化,內存初始化、消息隊列初始  化、定時器初始化、電源管理初始化及應用程序初始化均在該  函數中進行,在OSAL上編程,我們的任務app的初始化程序  在此處的應用程序初始化中進行,每一個應用程序在OSAL  有且只有一個全局唯一標識,即本任務的taskID,在這里進行  分配,在之后的主循環中進行任務分配與事件處理時,使用的

 即為這里分配的taskID

 

 InitBoard( OB_READY ); //第二次調用該函數初始化,此時系統已啟動,在此處可將硬件

  回調函數注冊至系統~~

 

 osal_pwrmgr_device( PWRMGR_BATTERY ); //如果定義了 POWER_SAVING,電源管理啟動

 

 osal_start_system(); //進入系統主循環

 

以上,各種初始化與設置,然后進入loop,,,,,,,,,,

for( ; ; )

{

//loop

}

 

 

 

3OSAL的主循環

 

osal_start_system() 中調用函數osal_run_system()

 1 /*********************************************************************
 2  * @fn      osal_run_system
 3  *
 4  * @brief
 5  *
 6  *   This function will make one pass through the OSAL taskEvents table
 7  *   and call the task_event_processor() function for the first task that
 8  *   is found with at least one event pending. If there are no pending
 9  *   events (all tasks), this function puts the processor into Sleep.
10  *
11  * @param   void
12  *
13  * @return  none
14  */
15 void osal_run_system( void )
16 {
17   uint8 idx = 0;
18 
19 #ifndef HAL_BOARD_CC2538
20   osalTimeUpdate();
21 #endif
22 
23   Hal_ProcessPoll();
24 
25   do {
26     if (tasksEvents[idx])  // Task is highest priority that is ready.
27     {
28       break;
29     }
30   } while (++idx < tasksCnt);
31 
32   if (idx < tasksCnt)
33   {
34     uint16 events;
35     halIntState_t intState;
36 
37     HAL_ENTER_CRITICAL_SECTION(intState);
38     events = tasksEvents[idx];
39     tasksEvents[idx] = 0;  // Clear the Events for this task.
40     HAL_EXIT_CRITICAL_SECTION(intState);
41 
42     activeTaskID = idx;
43     events = (tasksArr[idx])( idx, events );
44     activeTaskID = TASK_NO_TASK;
45 
46     HAL_ENTER_CRITICAL_SECTION(intState);
47     tasksEvents[idx] |= events;  // Add back unprocessed events to the current task.
48     HAL_EXIT_CRITICAL_SECTION(intState);
49   }
50 #if defined( POWER_SAVING )
51   else  // Complete pass through all task events with no activity?
52   {
53     osal_pwrmgr_powerconserve();  // Put the processor/system into sleep
54   }
55 #endif
56 
57   /* Yield in case cooperative scheduling is being used. */
58 #if defined (configUSE_PREEMPTION) && (configUSE_PREEMPTION == 0)
59   {
60     osal_task_yield();
61   }
62 #endif
63 }

 

 

分析這個函數之前先搞明白幾個主要的變量,

uint16 *tasksEvents;

 

typedef unsigned short (*pTaskEventHandlerFn)( unsigned char task_id, unsigned short event );

const pTaskEventHandlerFn tasksArr[] = 

{

//........

};

 

uint8 tasksCnt = sizeof( tasksArr ) / sizeof( tasksArr[0] );

 

(1) tasksCnt,即OSAL內任務個數; 

(2) tasksEvents,從定義上看,short類型指針,值域0x0000 ~ 0xFFFF,事實上,每個task只允許存在16個事件類型,在使用宏定義事件類型時,采用bit map方式進行定義,如0x00010x00020x0004……這樣做可以使 存在多個數據同時需要處理時,在處理完某一事件后,返回主循環,判斷繼續處理下一事件。每一個任務都包含一個系統事件SYS_EVENT_MSG,因此每個任務最多可以有15個自有事件,其在init時初始化為0

(3) tasksArr[],函數指針數組,該指針數組元素為函數指針,具體為各模塊事件回調函數,編寫完本模塊事件回調函數之后,按照本模塊ID,將回調注冊至此處,在主循環中准備調用。

 

在本函數中,do{...}while();循環判斷是否存在待處理的任務事件,即tasksEvents[idx]是否為空,若存在則break,並進入后續if語句,先保存當前事件,並清空事件標志,調用(tasksArr[idx])( idx, events );處理任務事件並返回,此時event使用位圖方法定義的好處就體現了一點,一般在回調函數返回時,會return event ^ currntEVENT; 異或操作只處理當前位,表明當前事件處理完畢,若其他位不為0,則表示該任務還有其他事件待處理;回調函數返回后,保存事件標志位,進入下一次輪詢。


免責聲明!

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



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