ZigBee_CC2530_0DH_关于协议栈时钟的一些记录
扫描二维码
随时随地手机看文章
使用CC2530的芯片,ZStack-CC2530-2.5.1a协议栈。对于任意接受到的数据包均有afIncomingMSGPacket_t::timestamp。根据对协议栈代码的阅读和网上一些资料的查询,只知道这个afIncomingMSGPacket_t::timestamp是数据包发送者发送时的MAC的时间。
timestamp unit is based on a basic time unit called Backoff Period(BP)
a Unit Backoff Period = the transmission time of 80bits(0.32ms)
对于osal_systemClock参数,通过对协议栈代码的阅读和网上一些资料的查询,这个参数将在osalTimeUpdate()中被更新,而osalTimeUpdate()函数在osal_run_system中被调用。而对于osal_run_system()函数的功能的介绍,我发现这是一个任务队列的检测和任务事件实现的入口函数。
1.OSAL 1.1 osal_start_system()函数
首先,通过协议栈会调用OSAL.c文件中osal_start_system()函数启动系统:
/********************************************************************* * @fn osal_start_system * * @brief * * This function is the main loop function of the task system (if * ZBIT and UBIT are not defined). This Function doesn't return. * * @param void * * @return none */ void osal_start_system( void ) { #if !defined ( ZBIT ) && !defined ( UBIT ) for(;;) // Forever Loop #endif { osal_run_system(); } }
该函数在一个一直循环中调用同位于OSAL.c文件中的osal_run_system()函数: 1.2 osal_run_system()
/********************************************************************* * @fn osal_run_system * * @brief * * This function will make one pass through the OSAL taskEvents table * and call the task_event_processor() function for the first task that * is found with at least one event pending. If there are no pending * events (all tasks), this function puts the processor into Sleep. * * @param void * * @return none */ void osal_run_system( void ) { uint8 idx = 0; osalTimeUpdate(); //更新时钟 Hal_ProcessPoll(); //查看硬件是否有事件发生 do { if (tasksEvents[idx]) // Task is highest priority that is ready. { break; } } while (++idx < 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); activeTaskID = idx; events = (tasksArr[idx])( idx, events ); activeTaskID = TASK_NO_TASK; 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? { osal_pwrmgr_powerconserve(); // Put the processor/system into sleep } #endif /* Yield in case cooperative scheduling is being used. */ #if defined (configUSE_PREEMPTION) && (configUSE_PREEMPTION == 0) { osal_task_yield(); } #endif }
通过代码我们可以看出,osal_run_system是一个事件的唤起函数,通过该函数中调用的osalTimeUpdate()更新系统时钟,调用Hal_ProcessPoll()处理任务事件,然后循环的查看是否需要添加任务事件。对于Hal_ProcessPoll()函数我们暂时不管。现在我们看一下位置为OSAL_Clock.c文件中的osalTimeUpdate()函数:
1.3 osalTimeUpdate()
/********************************************************************* * @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 ) { halIntState_t intState; uint32 tmp; uint32 ticks320us; uint16 elapsedMSec = 0; HAL_ENTER_CRITICAL_SECTION(intState); // Get the free-running count of 320us timer ticks tmp = macMcuPrecisionCount(); HAL_EXIT_CRITICAL_SECTION(intState); if ( tmp != previousMacTimerTick ) { // Calculate the elapsed ticks of the free-running timer. ticks320us = (tmp - previousMacTimerTick) & 0xffffffffu; // Store the MAC Timer tick count for the next time through this function. previousMacTimerTick = tmp; // update converted number with remaining ticks from loop and the // accumulated remainder from loop tmp = (ticks320us * 8) + remUsTicks; // Convert the 320 us ticks into milliseconds and a remainder CONVERT_320US_TO_MS_ELAPSED_REMAINDER( tmp, elapsedMSec, remUsTicks ); // Update OSAL Clock and Timers if ( elapsedMSec ) { osalClockUpdate( elapsedMSec ); osalTimerUpdate( elapsedMSec ); } } }
该函数通过调用macMcuPrecisionCount()函数去返回自定时器2启动到现在为止的单位是320us的时间戳tmp,然后对于使用ticks320us去存储新增加的时间数,然后将previousMacTimerTick设置为当前读取的tmp,再将tmp设置为距离上次记录时间时新增的时间和上次转换成单位为ms时剩下的单位为us的剩余量之和,然后将tmp转换成单位为ms的elapseMSec和小于1000us的单位为40us的remUsTicks,当elapseMSec不为0是通过调用OSAL_Clock.c文件中的osalClockUpdate( elapseMSec )函数去修改系统时钟,调用OSAL_Timers.c文件中的osalTimerUpdate( elapseMSec )函数去修改定时器系统时钟。
1.4 系统时钟 osalClockUpdate( uint16 elapsedMSec )
/********************************************************************* * @fn osalClockUpdate * * @brief Updates the OSAL Clock time with elapsed milliseconds. * * @param elapsedMSec - elapsed milliseconds * * @return none */ static void osalClockUpdate( uint16 elapsedMSec ) { // Add elapsed milliseconds to the saved millisecond portion of time timeMSec += elapsedMSec; // Roll up milliseconds to the number of seconds if ( timeMSec >= 1000 ) { OSAL_timeSeconds += timeMSec / 1000; timeMSec = timeMSec % 1000; } }
其中OSAL_timerSeconds参数可以通过osal_setClock()函数设置,也可以通过osal_getClock()函数读取:
/********************************************************************* * @fn osal_setClock * * @brief Set the new time. This will only set the seconds portion * of time and doesn't change the factional second counter. * * @param newTime - number of seconds since 0 hrs, 0 minutes, * 0 seconds, on the 1st of January 2000 UTC * * @return none */ void osal_setClock( UTCTime newTime ) { OSAL_timeSeconds = newTime; } /********************************************************************* * @fn osal_getClock * * @brief Gets the current time. This will only return the seconds * portion of time and doesn't include the factional second * counter. * * @param none * * @return number of seconds since 0 hrs, 0 minutes, 0 seconds, * on the 1st of January 2000 UTC */ UTCTime osal_getClock( void ) { return ( OSAL_timeSeconds ); }
而OSAL_Timers.c文件中的osalTimerUpdate( elapseMSec )函数如下所示: 1.5 定时器 osalClockUpdate( uint16 elapsedMSec )
/********************************************************************* * @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 timeout = 0; } else { srchTimer->timeout = srchTimer->timeout - updateTime; } // Check for reloading if ( (srchTimer->timeout == 0) && (srchTimer->reloadTimeout) && (srchTimer->event_flag) ) { // Notify the task of a timeout osal_set_event( srchTimer->task_id, srchTimer->event_flag ); // Reload the timer timeout value srchTimer->timeout = srchTimer->reloadTimeout; } // 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; // Next srchTimer = 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 ); } } } }
通过这个函数去判断是否有定时器事件产生并更新定时器事件剩余事件timeout参数。
2.MAC
2.1 macMcuPrecisionCount()
该函数位于~/MAC/Low Level/System/mac_mcu.c中
/************************************************************************************************** * @fn macMcuPrecisionCount * * @brief This function is used by higher layer to read a free running counter driven by * MAC timer. * * @param none * * @return overflowCount ************************************************************************************************** */ uint32 macMcuPrecisionCount(void) { uint32 overflowCount = 0; halIntState_t s; HAL_ENTER_CRITICAL_SECTION(s); /* This T2 access macro allows accessing both T2MOVFx and T2Mx */ MAC_MCU_T2_ACCESS_OVF_COUNT_VALUE(); /* Latch the entire T2MOVFx first by reading T2M0. * T2M0 is discarded. */ T2M0; ((uint8 *)&overflowCount)[UINT32_NDX0] = T2MOVF0; ((uint8 *)&overflowCount)[UINT32_NDX1] = T2MOVF1; ((uint8 *)&overflowCount)[UINT32_NDX2] = T2MOVF2; /* the overflowCount needs to account for the accumulated overflow count in Beacon mode. */ overflowCount += accumulatedOverflowCount; /* * Workaround to take care of the case where a rollover just occured and the call to * macBackoffTimerPeriodIsr() hasn't yet occured or if one rollover occured during * sleep then update the accumulatedoverflowCount with the rollover */ if((prevoverflowCount > overflowCount) && (prevAccumulatedOverflowCount == accumulatedOverflowCount)) { accumulatedOverflowCount += macGetBackOffTimerRollover(); overflowCount += macGetBackOffTimerRollover(); /*don't update the rollover since it has been updated already */ updateRolloverflag = TRUE; } /* store the current value of overflowcount and accumulatedOverflowCount */ prevoverflowCount = overflowCount; prevAccumulatedOverflowCount = accumulatedOverflowCount; HAL_EXIT_CRITICAL_SECTION(s); return(overflowCount); }
该函数将当前定时器2的24位溢出寄存器的值读入参数overflowCount(实际最大为24bit)中,然后将overflowCount参数与积累的24位溢出计数值accumulatedOverflowCount进行加法计数,此时overflowCount为从定时器2开始到现在的总的单位为320us的时间值。然后通过判断是否存在溢出计数寄存器是否溢出一次,若溢出一次则更新accumulatedOverflowCount和overFlowCount,函数macGetBackOffTimerRollover()返回的是设置的溢出周期。然后返回当前定时器2自启动至现在的单位为320us的总的时间值。
2.2 macMcuOverflowSetCount()函数
/************************************************************************************************** * @fn macMcuOverflowSetCount * * @brief Sets the value of the hardware overflow counter. * * @param count - new overflow count value * * @return none ************************************************************************************************** */ MAC_INTERNAL_API void macMcuOverflowSetCount(uint32 count) { halIntState_t s; MAC_ASSERT(! (count >> 24) ); /* illegal count value */ /* save the current overflow count */ accumulatedOverflowCount += macMcuOverflowCount(); /* deduct the initial count */ accumulatedOverflowCount -= count; HAL_ENTER_CRITICAL_SECTION(s); MAC_MCU_T2_ACCESS_OVF_COUNT_VALUE(); /* for efficiency, the 32-bit value is decoded using endian abstracted indexing */ /* T2OF2 must be written last */ T2MOVF0 = ((uint8 *)&count)[UINT32_NDX0]; //T2MOVF0 = ((uint8 *)&count)[0]; T2MOVF1 = ((uint8 *)&count)[UINT32_NDX1]; T2MOVF2 = ((uint8 *)&count)[UINT32_NDX2]; HAL_EXIT_CRITICAL_SECTION(s); }
该函数作用是在不修改总的时间值的前提下设置Timer2的溢出寄存器的值。
而osal_systemClock为当前节点自身晶振读取修改的以ms为单位的时间值。