ZigBee协议栈任务处理分析笔记
----(转载请注明出处 774910349@qq.com)Everhuai写于 2011-11-17
弄了这么久ZigBee协议栈,今天终于有一点头绪了,基本上知道了整个系统任务怎么被添加,又是怎么被切换的一个过程。下面就简单讲一讲这部分内容。
首先看的当然是main()函数,不过这个函数不是今天的重点,里面有我添加的注释,先就一笔带过吧。
int main( void ) {
// Turn off interrupts
osal_int_disable( INTS_ALL );//关闭全局中断EA=0,初始化过程不响应任何中断
// Initialization for board related stuff such as LEDs HAL_BOARD_INIT();//配置了时钟、LED、串口
// Make sure supply voltage is high enough to run zmain_vdd_check();//检查电源电压
// Initialize stack memory zmain_ram_init();//初始化堆内存
// Initialize board I/O /初始化板子用到的IO口 InitBoard( OB_COLD );
// Initialze HAL drivers HalDriverInit();//初始化外设
// Initialize NV System //系统初始化 osal_nv_init( NULL );
// Initialize basic NV items//任务初始化 zgInit();
// Initialize the MAC ZMacInit();
// Determine the extended address //确定长地址 zmain_ext_addr(); #ifndef NONWK
// Since the AF isn't a task, call it's initialization routine afInit(); #endif
// Initialize the operating system osal_init_system();
//系统初始化
// Allow interrupts
osal_int_enable( INTS_ALL );//使能中断 // Final board initialization
//后期初始化
InitBoard( OB_READY ); //sd rest // Display information about this device zmain_dev_info();
/* Display the device info on the LCD */ #ifdef LCD_SUPPORTED zmain_lcd_init(); #endif
//显示信息
//显示设备信息
#ifdef WDT_IN_PM1
/* If WDT is used, this is a good place to enable it. */ WatchDogEnable( WDTIMX ); #endif
osal_start_system(); // No Return from here//正常情况下不返回
// Shouldn't get here return ( 0 ); } // main()
//使用看门狗
其中含有osal的都是与操作系统相关的。这里主要提一下这些函数:
// Initialze HAL drivers HalDriverInit();//初始化外设
片内外设与片外外设基本上在这个函数中初始化,像Timer、DMA、LCD等。该函数调用后设备即可使用。
// Initialize basic NV items zgInit();
这个函数通过调用
// Initialize the items table zgInitItems( setDefault );
初始化了zgItemTable[]//ZGlobal Item Table
我反正没搞懂这个数组干嘛用的,至少跟我们今天讨论的任务没有关系。我们讨论的任务在
// Initialize the operating system osal_init_system();
函数中调用osalInitTasks()进行初始化,在该函数中为每一个任务分配了一个ID号,这个ID号在任务切换的时候将用到。该函数中的初始化函数的顺序与函数指针数组
const pTaskEventHandlerFn tasksArr[] 中对应的任务的顺序是一致的,这一点不难理解,就是为了保证任务与ID号的对应。
该函数中还有这么两天语句值得注意:
tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);//申请空间,用于存放任务 osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));
//用0初始化申请到的空间
tasksEvents是一个指针,C语言好的不用看它的定义都看得出来。任务切换的时候就是通过tasksEvents来查找需要处理
的任务。tasksEvents指向的对象保存的是对应任务的掩码。
最后通过调用函数osal_start_system(); /* No Return from here*/启动操作系统,该函数正常情况下是不返回的。 #if !defined ( ZBIT ) && !defined ( UBIT ) for(;;) // Forever Loop #endif
然后所有的任务都在这个for循环中被处理:
{
uint8 idx = 0;
osalTimeUpdate();//定时器任务更新
//轮询处理
Hal_ProcessPoll(); // This replaces MT_SerialPoll() and osal_check_timer(). do {
if (tasksEvents[idx]) // Task is highest priority that is ready.//查找优先级最高的任务 { break; }
} while (++idx < tasksCnt);//tasksCnt为总的任务数
if (idx < tasksCnt)//任务数检查 {
uint16 events; halIntState_t intState;
HAL_ENTER_CRITICAL_SECTION(intState);//保存中断状态 events = tasksEvents[idx];//取出任务后立即清除 tasksEvents[idx] = 0; // Clear the Events for this task. HAL_EXIT_CRITICAL_SECTION(intState);//恢复中断状态
events = (tasksArr[idx])( idx, events );//执行任务,返回值是未处理的事件的掩码
HAL_ENTER_CRITICAL_SECTION(intState);
tasksEvents[idx] |= events; // Add back unprocessed events to the current task.//添加未被处理的任务 HAL_EXIT_CRITICAL_SECTION(intState); }
#if defined( POWER_SAVING )
else // Complete pass through all task events with no activity? {
//当任务ID号出错时进入睡眠
osal_pwrmgr_powerconserve(); // Put the processor/system into sleep } #endif
}
当有任务需要处理时便调用函数osal_set_event()添加任务:
/********************************************************************* * @fn osal_set_event * * @brief *
* This function is called to set the event flags for a task. The * event passed in is OR'd into the task's event variable. **设置事件标志,这些事件保存到变量task * @param uint8 task_id - receiving tasks ID * @param uint8 event_flag - what event to set *
* @return SUCCESS, INVALID_TASK */
uint8 osal_set_event( uint8 task_id, uint16 event_flag ) {
if ( task_id < tasksCnt )//正确的ID {
halIntState_t intState;
HAL_ENTER_CRITICAL_SECTION(intState); // Hold off interrupts
tasksEvents[task_id] |= event_flag; // Stuff the event bit(s)/添加需要处理的事件的掩码 HAL_EXIT_CRITICAL_SECTION(intState); // Release interrupts } else
return ( INVALID_TASK );
return ( SUCCESS ); }
再看函数osal_start_system()对于tasksEvents就比较清楚了。
在所有调用osal_set_event()的函数中比较值得关注的是void osalTimerUpdate( uint16 updateTime )
先来看看函数体:
/********************************************************************* * @fn osalTimerUpdate *
* @brief Update the timer structures for a timer tick. *
* @param none *
* @return none **更新定时器任务
*********************************************************************/ void osalTimerUpdate( uint16 updateTime ) {
halIntState_t intState; osalTimerRec_t *srchTimer; osalTimerRec_t *prevTimer;
HAL_ENTER_CRITICAL_SECTION( intState ); // Hold off interrupts./保存中断状态 // Update the system time/更新系统时间 osal_systemClock += updateTime;
HAL_EXIT_CRITICAL_SECTION( intState ); // Re-enable interrupts./恢复中断状态
// Look for open timer slot if ( timerHead != NULL ) {
// Add it to the end of the timer list/添加到定时器列表 srchTimer = timerHead; prevTimer = (void *)NULL;
// Look for open timer slot/遍历链表 while ( srchTimer ) {
osalTimerRec_t *freeTimer = NULL;
HAL_ENTER_CRITICAL_SECTION( intState ); // Hold off interrupts.
if (srchTimer->timeout <= updateTime)//超时检查 {
srchTimer->timeout = 0; } else {
srchTimer->timeout = srchTimer->timeout - updateTime; }
// When timeout or delete (event_flag == 0)/需要处理的事件 if ( srchTimer->timeout == 0 || srchTimer->event_flag == 0 ) {
// Take out of list if ( prevTimer == NULL ) timerHead = srchTimer->next; else
prevTimer->next = srchTimer->next;
// Setup to free memory/设置要被释放的资源 freeTimer = srchTimer;