创建第一个任务
系统主函数如下:
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 )