小人物专栏

主机环境:Windows

开发环境:MDK4.7.2

FreeRTOS版本:FreeRTOS8.1.2

目标环境:STM32F030C8T6

FreeRTOS中关于时间的管理分为两部分:一部分是任务的延时管理;前面叙述过一些,还有一部分就是SysTick中断,管理任务的延时时间。SysTick是由STM32内核提供的,时钟源可选,用于产生FreeRTOS所需要的系统时钟,且是由用户可配的,用户在FreeRTOSConfig.h文件中配置configCPU_CLOCK_HZ以及configTICK_RATE_HZ两个宏来设置系统时钟,产生时间片时间,系统每隔固定时间进入SysTick中断处理时间。

有关时钟配置的初始化函数在port.c文件中,如下

void prvSetupTimerInterrupt( void ){/* Configure SysTick to interrupt at the requested rate. */*(portNVIC_SYSTICK_LOAD) = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) – 1UL;*(portNVIC_SYSTICK_CTRL) = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE;}配置的是portNVIC_SYSTICK_LOAD和portNVIC_SYSTICK_CTRL两个寄存器,有关SYSTICK寄存器的说明可以在armv6-m体系结构参考手册中查看

LOAD寄存器是装载的计数值由用户配置,CTRL寄存器配置SYSTICK计数器的时钟源以及是否产生中断,且是否使能该计数器,该函数在调度器启动时调用,即在xPortStartScheduler()函数中调用,启动该计数器,这样在计数值为0时进入SysTick中断函数,即xPortSysTickHandler()中断函数

void xPortSysTickHandler( void ){uint32_t ulPreviousMask;ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();{/* Increment the RTOS tick. */if( xTaskIncrementTick() != pdFALSE ){/* Pend a context switch. */*(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;}}portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );}在该中断函数中首先记录中断屏蔽位,并关闭中断,在处理完后恢复中断屏蔽位并打开中断,如果在处理完后需要产生任务切换,则进行一次任务切换调用,

BaseType_t xTaskIncrementTick( void ){TCB_t * pxTCB;TickType_t xItemValue;BaseType_t xSwitchRequired = pdFALSE;/* Called by the portable layer each time a tick interrupt occurs.Increments the tick then checks to see if the new tick value will cause anytasks to be unblocked. */traceTASK_INCREMENT_TICK( xTickCount );if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ){/* Increment the RTOS tick, switching the delayed and overfloweddelayed lists if it wraps to 0. */++xTickCount;{/* Minor optimisation. The tick count cannot change in thisblock. */const TickType_t xConstTickCount = xTickCount;if( xConstTickCount == ( TickType_t ) 0U ){taskSWITCH_DELAYED_LISTS();}else{mtCOVERAGE_TEST_MARKER();}/* See if this tick has made a timeout expire. Tasks are stored inthequeue in the order of their wake time – meaning once one taskhas been found whose block time has not expired there is no need tolook any furtherdown the list. */if( xConstTickCount >= xNextTaskUnblockTime ){for( ;; ){if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ){/* The delayed list is empty. Set xNextTaskUnblockTimeto the maximum possible value so it is extremelyunlikely that theif( xTickCount >= xNextTaskUnblockTime ) test will passnext time through. */xNextTaskUnblockTime = portMAX_DELAY;break;}else{/* The delayed list is not empty, get the value of theitem at the head of the delayed list. This is the timeat which the task at the head of the delayed list mustbe removed from the Blocked state. */pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) );if( xConstTickCount < xItemValue ){/* It is not time to unblock this item yet, but theitem value is the time at which the task at the headof the blocked list must be removed from the Blockedstate -so record the item value inxNextTaskUnblockTime. */xNextTaskUnblockTime = xItemValue;break;}else{mtCOVERAGE_TEST_MARKER();}/* It is time to remove the item from the Blocked state. */( void ) uxListRemove( &( pxTCB->xGenericListItem ) );/* Is the task waiting on an event also? If so removeit from the event list. */if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ){( void ) uxListRemove( &( pxTCB->xEventListItem ) );}else{mtCOVERAGE_TEST_MARKER();}/* Place the unblocked task into the appropriate readylist. */prvAddTaskToReadyList( pxTCB );/* A task being unblocked cannot cause an immediatecontext switch if preemption is turned off. */#if ( configUSE_PREEMPTION == 1 ){/* Preemption is on, but a context switch shouldonly be performed if the unblocked task has apriority that is equal to or higher than thecurrently executing task. */if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ){xSwitchRequired = pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}}#endif /* configUSE_PREEMPTION */}}}}/* Tasks of equal priority to the currently running task will shareprocessing time (time slice) if preemption is on, and the applicationwriter has not explicitly turned time slicing off. */#if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ){if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > ( UBaseType_t ) 1 ){xSwitchRequired = pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}}#endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */#if ( configUSE_TICK_HOOK == 1 ){/* Guard against the tick hook being called when the pended tickcount is being unwound (when the scheduler is being unlocked). */if( uxPendedTicks == ( UBaseType_t ) 0U ){vApplicationTickHook();}else{mtCOVERAGE_TEST_MARKER();}}#endif /* configUSE_TICK_HOOK */}else{++uxPendedTicks;/* The tick hook gets called at regular intervals, even if thescheduler is locked. */#if ( configUSE_TICK_HOOK == 1 ){vApplicationTickHook();}#endif}#if ( configUSE_PREEMPTION == 1 ){if( xYieldPending != pdFALSE ){xSwitchRequired = pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}}#endif /* configUSE_PREEMPTION */return xSwitchRequired;}xTaskIncrementTick()函数看名字就晓得它的主要工作就是对时钟计数器进行更新工作即对xTickCount进行更新,延时任务链表也是在该函数中进行管理的,进入该函数中首先判断调度器是否处于挂起状态,当调度器没有挂起正常运行时对xTickCount进行加1操作,这里又申请了一个xTickCount的副本xConstTickCount记录当前xTickCount的值,感觉xTickCount的值在这里不会更改那。。。根据xConstTickCount的值判断其是否溢出,如果溢出的话需要交换两个延时任务链表,计数器溢出表明通用延时任务链表中的任务已经处理完毕,剩下的都是处理溢出延时任务链表,通过调用taskSWITCH_DELAYED_LISTS()实现

未曾失败的人恐怕也未曾成功过。

小人物专栏

相关文章:

你感兴趣的文章:

标签云: