在Cortex-M內(nèi)核中,系統(tǒng)節(jié)拍由Systick時(shí)鐘提供,當(dāng)配置好系統(tǒng)滴答時(shí)鐘后,每次時(shí)鐘中斷就會(huì)觸發(fā)中斷處理數(shù)xPortSysTickHandler()。
void xPortSysTickHandler( void ){ /* The SysTick runs at the lowest interrupt priority, so when this interrupt * executes all interrupts must be unmasked. There is therefore no need to * save and then restore the interrupt mask value as its value is already * known - therefore the slightly faster vPortRaiseBASEPRI() function is used * in place of portSET_INTERRUPT_MASK_FROM_ISR(). */ vPortRaiseBASEPRI();//屏蔽歸屬FreeRTOS的中斷優(yōu)先級(jí) { /* Increment the RTOS tick. */ if( xTaskIncrementTick() != pdFALSE )//時(shí)鐘計(jì)數(shù)處理 { /* A context switch is required. Context switching is performed in * the PendSV interrupt. Pend the PendSV interrupt. */ portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;//如果需要切換上下文操作,PendSV標(biāo)記置位 } }
vPortClearBASEPRIFromISR();}
這部分主要是依靠 xTaskIncrementTick(),來判斷任務(wù)切換是否在此次系統(tǒng)時(shí)鐘中斷時(shí)被需要。如果是,則PendSV標(biāo)記置位,等待觸發(fā)PendSV中斷。來看看 xTaskIncrementTick()。
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 any * tasks to be unblocked. */ traceTASK_INCREMENT_TICK( xTickCount );
if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) //調(diào)度是否被掛起,默認(rèn)為否 { /* Minor optimisation. The tick count cannot change in this * block. */ const TickType_t xConstTickCount = xTickCount + ( TickType_t ) 1;
/* Increment the RTOS tick, switching the delayed and overflowed * delayed lists if it wraps to 0. */ xTickCount = xConstTickCount;
if( xConstTickCount == ( TickType_t ) 0U ) /*lint !e774 'if' does not always evaluate to false as it is looking for an overflow. 如果xConstTickCount為0,說明溢出了*/ { taskSWITCH_DELAYED_LISTS();/*切換延遲列表*/ } else { mtCOVERAGE_TEST_MARKER(); }
/* See if this tick has made a timeout expire. Tasks are stored in * the queue in the order of their wake time - meaning once one task * has been found whose block time has not expired there is no need to * look any further down the list. */ if( xConstTickCount >= xNextTaskUnblockTime ) { for( ; ; ) { if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) { /* The delayed list is empty. Set xNextTaskUnblockTime * to the maximum possible value so it is extremely * unlikely that the * if( xTickCount >= xNextTaskUnblockTime ) test will pass * next time through. */ xNextTaskUnblockTime = portMAX_DELAY; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ break; } else { /* The delayed list is not empty, get the value of the * item at the head of the delayed list. This is the time * at which the task at the head of the delayed list must * be removed from the Blocked state. */ pxTCB = listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) );
關(guān)鍵問題是,這個(gè)函數(shù)使用到了pxDelayedTaskList, 這定義在本文件
PRIVILEGED_DATA static List_t * volatile pxDelayedTaskList;
該變量初始化為0,該變量正常初始化位置在創(chuàng)建 Task 對(duì)象等的函數(shù)中, 也就是說,如果在Tick中斷到來時(shí),如果還沒有任務(wù)被創(chuàng)建,就會(huì)導(dǎo)致不可預(yù)期的結(jié)果,中斷服務(wù)函數(shù)會(huì)使用這個(gè)野指針,執(zhí)行任務(wù)切換。這會(huì)導(dǎo)致觸發(fā)棧溢出鉤子函數(shù),或者是直接Hardfault。有些硬件初始化需要借助delay功能,不得不在初始化之前配置SysTick。而又不希望在硬件初始化階段觸發(fā)這個(gè)Bug。所以在配置SysTick之前,先創(chuàng)建一個(gè)初始化任務(wù),初始化 pxDelayedTaskList 這個(gè)指針,在初始化任務(wù)里配置SysTick,和其他初始化,這樣能夠避免此類問題?;蛘呤窃谂渲肧ysTick的時(shí)候屏蔽中斷,一切準(zhǔn)備就緒后,開啟中斷。執(zhí)行vTaskStartScheduler()默認(rèn)創(chuàng)建一個(gè)空閑任務(wù)。
-
內(nèi)核
+關(guān)注
關(guān)注
4文章
1468瀏覽量
42881 -
FreeRTOS
+關(guān)注
關(guān)注
14文章
499瀏覽量
66947 -
Systick
+關(guān)注
關(guān)注
0文章
67瀏覽量
13970
發(fā)布評(píng)論請(qǐng)先 登錄
FreeRTOS內(nèi)核默認(rèn)會(huì)初始化systick是必須的嗎?
使用FreeRTOS時(shí)Systick時(shí)鐘的配置分享
SysTicK的函數(shù)重復(fù)定義
使用CubeMX 6為freeRTOS生成代碼的問題如何解決?
系統(tǒng)節(jié)拍定時(shí)(SysTick)
如何使用STM32實(shí)現(xiàn)systick的精確延時(shí)
如何使用STM32單片機(jī)systick來實(shí)現(xiàn)延時(shí)定時(shí)功能
STM32—關(guān)于SYSTICK系統(tǒng)時(shí)鐘的詳解及學(xué)習(xí)筆記
STM32_SysTick—系統(tǒng)定時(shí)器
systick定時(shí)器 延時(shí)計(jì)時(shí)
STM32單片機(jī)systick使用注意事項(xiàng)
什么是FreeRTOS的延時(shí)
SysTick時(shí)鐘
FreeRTOS中Systick的問題
評(píng)論