創建第一個任務
系統主函數如下:
void main()
{
/** initialize the hardware */
PE_low_level_init();
/** disable write buffering end enable ARM exceptions */
HEXIWEAR_EnableExceptions();
/** initialize the startup task */
HEXIWEAR_Init();
/** start RTOS scheduler */
HEXIWEAR_Start();
while (1) {}
}
函數HEXIWEAR_Init初始化啓動任務HEXIWEAR_startup。
任務創建完成後,靜態變量指針pxCurrentTCB(見《FreeRTOS高級篇2—FreeRTOS任務創建分析》第7節內容)指向優先級最高的就緒任務。但此時任務並不能運行,因爲接下來還有關鍵的一步:啓動FreeRTOS調度器。
開啓內核運行,調度便由此開始
調度器是FreeRTOS操作系統的核心,主要負責任務切換,即找出最高優先級的就緒任務,並使之獲得CPU運行權。調度器並非自動運行的,需要人爲啓動它。
API函數vTaskStartScheduler()用於啓動調度器,它會:
- 創建一個空閒任務;
- 初始化一些靜態變量;
- 最主要的,它會初始化系統節拍定時器並設置好相應的中斷;
- 然後啓動第一個任務。
http://blog.csdn.net/zhzht19861011/article/details/51331638
執行第一個任務,也就是啓動任務HEXIWEAR_startup
code/HEXIWEAR/src/HEXIWEAR_driver.c
HEXIWEAR_startup分析:
- output GPIO configuration
- input GPIO configuration
- intern flash initialization
- create basic tasks
Notification_Init – HostInterface_Init(HostInterface_TxInit,HostInterface_RxInit) – sensor_Init – GuiDriver_Init - check for settings in flash at startup
- CLOCK_SYS_Init POWER_SYS_Init
- turn on regular battery readings
搜索OSA_TaskCreate
分析上圖可知,啓動任務HEXIWEAR_startup,開啓了
power_Task
sensor_GetData
HostInterface_TxTask
HostInterface_RxTask
watch_TimeUpdateTask
watch_GetPacketsTask
watch_GuiUpdateTask
七個任務,執行完成後自動Destroy自己。
注:上圖註釋有誤,其實不止四個Tasks,加上Watch的三個,應該是七個。
watch_TimeUpdateTask
watch_GetPacketsTask
watch_GuiUpdateTask
這三個任務,HEXIWEAR_startup—>GuiDriver_Init—>進入開機畫面—>進入watch畫面,後創建的。
power_Task
功耗管理任務,主要是負責HEXIWEAR的自動睡眠
HostInterface_TxTask
HostInterface_RxTask
與K40 的MCU接口接受任務,主要負責處理接受到的數據包
sensor_GetData
Sensor數據讀取任務,負責循環讀取各個sensor的數據
從上圖中可以看出,除了上面的後四個任務,其餘任務基本上都和GUI的各個界面一一對應。那這些其餘的任務,肯定是跟着界面的跳動動態創建和銷燬。參考我博客的GUI 篇,你可以知道界面如何跳轉的。
開機默認界面Watch
也就是找watch_CreateTasks這個任務何時被創建。
HEXIWEAR_startup—>
GuiDriver_Init—>
GuiDriver_Navigation( GUI_NAVIGATION_SPLASH, NULL ); (直接開機畫面)
GuiDriver_Navigation( GUI_NAVIGATION_WATCH, NULL ); (進入Watch界面)
—>
gui_status_t GuiDriver_Navigation(guiNavigationDir_t navigationDir, void *param)
{
const guiScreen_t* ptrNewScreen;
oled_transition_t transition;
void *destroyParam = NULL;
void *initParam = NULL;
void *createParam = NULL;
const guiNavigation_t* navigation = &guiDriver_display.guiItem->navigation;
switch(navigationDir)
{
/**
* splash screen (啓動畫面)
*/
case GUI_NAVIGATION_SPLASH:
{
ptrNewScreen = &splashScreen;
transition = OLED_TRANSITION_NONE;
break;
}
/**
* goto watch directly(直接進入watch 界面)
*/
case GUI_NAVIGATION_WATCH:
{
ptrNewScreen = &watchScreen;
transition = OLED_TRANSITION_NONE;
break;
}
......
// update the current gui item
guiDriver_display.guiItem = (guiScreen_t*)ptrNewScreen;
// starting action for the new screen
if( NULL != ptrNewScreen->initFunction )
{
ptrNewScreen->initFunction(initParam);
}
while (1)
{
statusOLED = OLED_DrawScreen(
guiDriver_display.image,
xCrd,
yCrd,
width,
height,
transition
);
if ( OLED_STATUS_SUCCESS == statusOLED )
{
break;
}
}
if(haptic_CurrentStateGet() == hapticState_enable)
{
//OSA_TimeDelay(50);
haptic_MutexUnlock();
}
if( OLED_STATUS_SUCCESS == statusOLED )
{
// post-load action for the new screen (就在這裏創建了Watch的任務)
if( NULL != ptrNewScreen->createTaskFunction )
{
ptrNewScreen->createTaskFunction(createParam);
}
return GUI_STATUS_SUCCESS;
}
else
{
return GUI_STATUS_ERROR;
}
......
ptrNewScreen = &watchScreen;
// update the current gui item
guiDriver_display.guiItem = (guiScreen_t*)ptrNewScreen;
ptrNewScreen->initFunction(initParam);
ptrNewScreen->createTaskFunction(createParam);
如何快速的知道一個系統到底會創建多少個任務?
其實,每個任務的創建我們都會給其定義一個優先級,作爲參數傳進去。所以,只要找一下各個任務的的優先級的宏定義就好了。
HEXIWEAR的任務優先級定義在HEXIWEAR_info.h中。
/** tasks' priorities */
#define HEXIWEAR_STARTUP_PRIO ( 1 )
#define HEXIWEAR_KW40_INTF_TASK_OK_PRIO ( gHostInterfaceOkPriority_c )
#define HEXIWEAR_KW40_INTF_TASK_Tx_PRIO ( gHostInterfaceTxPriority_c )
#define HEXIWEAR_KW40_INTF_TASK_Rx_PRIO ( gHostInterfaceRxPriority_c )
#define HEXIWEAR_GUI_PRIO ( 5 )
#define HEXIWEAR_APP_PRIO ( 6 )
#define HEXIWEAR_SENSOR_PRIO ( 7 )
#define HEXIWEAR_USB_TASK ( USB_PRIO )
#define HEXIWEAR_TASK_SENSOR_TAG_PRIO ( SENSOR_GET_DATA_PRIO )
#define HEXIWEAR_APP_WATCH_DATA_PRIO ( WATCH_PRIO )