当前位置:文档之家› ZigBee协议栈任务处理分析笔记

ZigBee协议栈任务处理分析笔记

ZigBee协议栈任务处理分析笔记----(转载请注明出处774910349@)Everhuai写于2011-11-17 弄了这么久ZigBee协议栈,今天终于有一点头绪了,基本上知道了整个系统任务怎么被添加,又是怎么被切换的一个过程。

下面就简单讲一讲这部分内容。

首先看的当然是main()函数,不过这个函数不是今天的重点,里面有我添加的注释,先就一笔带过吧。

int main( void ){// Turn off interruptsosal_int_disable( INTS_ALL );//关闭全局中断EA=0,初始化过程不响应任何中断// Initialization for board related stuff such as LEDsHAL_BOARD_INIT();//配置了时钟、LED、串口// Make sure supply voltage is high enough to runzmain_vdd_check();//检查电源电压// Initialize stack memoryzmain_ram_init();//初始化堆内存// Initialize board I/O /初始化板子用到的IO口InitBoard( OB_COLD );// Initialze HAL driversHalDriverInit();//初始化外设// Initialize NV System //系统初始化osal_nv_init( NULL );// Initialize basic NV items//任务初始化zgInit();// Initialize the MACZMacInit();// Determine the extended address //确定长地址zmain_ext_addr();#ifndef NONWK// Since the AF isn't a task, call it's initialization routineafInit();#endif// Initialize the operating systemosal_init_system(); //系统初始化// Allow interruptsosal_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_SUPPORTEDzmain_lcd_init(); //显示信息#endif#ifdef WDT_IN_PM1/* If WDT is used, this is a good place to enable it. */WatchDogEnable( WDTIMX ); //使用看门狗#endifosal_start_system(); // No Return from here//正常情况下不返回// Shouldn't get herereturn ( 0 );} // main()其中含有osal的都是与操作系统相关的。

这里主要提一下这些函数:// Initialze HAL driversHalDriverInit();//初始化外设片内外设与片外外设基本上在这个函数中初始化,像Timer、DMA、LCD等。

该函数调用后设备即可使用。

// Initialize basic NV itemszgInit();这个函数通过调用// Initialize the items tablezgInitItems( setDefault );初始化了zgItemTable[]//ZGlobal Item Table我反正没搞懂这个数组干嘛用的,至少跟我们今天讨论的任务没有关系。

我们讨论的任务在// Initialize the operating systemosal_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 interruptstasksEvents[task_id] |= event_flag; // Stuff the event bit(s)/添加需要处理的事件的掩码HAL_EXIT_CRITICAL_SECTION(intState); // Release interrupts}elsereturn ( 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 slotif ( 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 listif ( prevTimer == NULL )timerHead = srchTimer->next;elseprevTimer->next = srchTimer->next;// Setup to free memory/设置要被释放的资源freeTimer = srchTimer;// NextsrchTimer = srchTimer->next;}else{// Get next/下一个任务prevTimer = srchTimer;srchTimer = srchTimer->next;}HAL_EXIT_CRITICAL_SECTION( intState ); // Re-enable interrupts.if ( freeTimer )//释放任务{if ( freeTimer->timeout == 0 ){osal_set_event( freeTimer->task_id, freeTimer->event_flag );//时间到了,设置事件标志以等待处理}osal_mem_free( freeTimer );//释放该定时器任务的资源}}}}在我所使用的版本中该函数只被两个函数调用,分别是:/********************************************************************** @fn osal_adjust_timers** @brief Update the timer structures for elapsed ticks.** @param none** @return none*********************************************************************/void osal_adjust_timers( void ){uint16 eTime;if ( timerHead != NULL ){// Compute elapsed time (msec)eTime = TimerElapsed() / TICK_COUNT;if ( eTime )osalTimerUpdate( eTime );}}/********************************************************************* * FUNCTIONS*********************************************************************//********************************************************************* * @fn osalTimeUpdate** @brief Uses the free running rollover count of the MAC backoff timer;* this timer runs freely with a constant 320 usec interval. The* count of 320-usec ticks is converted to msecs and used to update* the OSAL clock and Timers by invoking osalClockUpdate() and* osalTimerUpdate(). This function is intended to be invoked* from the background, not interrupt level.** @param None.** @return None.*/void osalTimeUpdate( void )//定时器任务更新{uint16 tmp;uint16 ticks320us;uint16 elapsedMSec = 0;// Get the free-running count of 320us timer ticks//设置时间片tmp = macMcuPrecisionCount();//获取溢出值,该溢出值是一个累计的溢出值if ( tmp != previousMacTimerTick )//相等则代表没有溢出{// Calculate the elapsed ticks of the free-running timer.//计算已经消耗的时间ticks320us = tmp - previousMacTimerTick;// Store the MAC Timer tick count for the next time through this function.previousMacTimerTick = tmp;//保存当前时间/* It is necessary to loop to convert the usecs to msecs in increments so as* not to overflow the 16-bit variables.**这是必要的循环转换usecs毫秒的增量,以免溢出16位变量。

相关主题