FreeRTOS之vTaskStartScheduler实现分析

FreeRTOS之vTaskStartScheduler实现分析

  • 1 FreeRTOS源码下载地址
  • 2 函数接口
  • 2.1 函数接口
  • 2.2 函数参数简介
  • 3 vTaskDelete的调用关系
    • 3.1 调用关系
    • 3.2 调用关系示意图
  • 4 函数源码分析
    • 4.1 vTaskStartScheduler
    • 4.2 prvCreateIdleTasks
      • 4.2.1 prvCreateIdleTasks
      • 4.2.2 xTaskCreate
  • 4.3 xTimerCreateTimerTask
    • 4.4 xTaskCreateAffinitySet
    • 4.5 xPortStartScheduler
    • 4.6 vPortRestoreTaskContext
    • 4.7 portRESTORE_CONTEXT
    • 4.8 pxPortInitialiseStack

1 FreeRTOS源码下载地址

https://www.freertos.org/
在这里插入图片描述

2 函数接口

2.1 函数接口

void vTaskStartScheduler( void )

2.2 函数参数简介

参数 - 无

3 vTaskDelete的调用关系

3.1 调用关系

|- vTaskStartScheduler|- prvCreateIdleTasks()|- xTaskCreate( pxIdleTaskFunction, ...)|- prvCreateTask|- pxStack = pvPortMallocStack( ( ( ( size_t ) uxStackDepth ) * sizeof( StackType_t ) ) );|- pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );|- prvInitialiseNewTask|- vListInitialiseItem( &( pxNewTCB->xStateListItem ) );|- vListInitialiseItem( &( pxNewTCB->xEventListItem ) );|- pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );|- *pxCreatedTask = ( TaskHandle_t ) pxNewTCB;|- prvAddNewTaskToReadyList|- prvInitialiseTaskLists|- prvAddTaskToReadyList|- listINSERT_END( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) );|- xTimerCreateTimerTask()|- xTaskCreateAffinitySet|- prvCreateTask|- pxStack = pvPortMallocStack( ( ( ( size_t ) uxStackDepth ) * sizeof( StackType_t ) ) );|- pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );|- prvInitialiseNewTask|- vListInitialiseItem( &( pxNewTCB->xStateListItem ) );|- vListInitialiseItem( &( pxNewTCB->xEventListItem ) );|- pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );|- *pxCreatedTask = ( TaskHandle_t ) pxNewTCB;|- prvAddNewTaskToReadyList|- prvInitialiseTaskLists|- prvAddTaskToReadyList|- listINSERT_END( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) )|- pxNewTCB->uxCoreAffinityMask = uxCoreAffinityMask;|- prvAddNewTaskToReadyList( pxNewTCB );|- xPortStartScheduler()|- vPortRestoreTaskContext|- portRESTORE_CONTEXT

3.2 调用关系示意图

4 函数源码分析

4.1 vTaskStartScheduler

  • xReturn = prvCreateIdleTasks(); 创建idle线程
  • xReturn = xTimerCreateTimerTask(); 创建timer线程
  • xSchedulerRunning = pdTRUE; 将当前系统的运行状态设置为pdTRUE
  • ( void ) xPortStartScheduler(); 开始调度,这个和当前处理器的架构相关的,和也栈结构的设置相关。
void vTaskStartScheduler( void )
{BaseType_t xReturn;traceENTER_vTaskStartScheduler();#if ( configUSE_CORE_AFFINITY == 1 ) && ( configNUMBER_OF_CORES > 1 ){/* Sanity check that the UBaseType_t must have greater than or equal to* the number of bits as confNUMBER_OF_CORES. */configASSERT( ( sizeof( UBaseType_t ) * taskBITS_PER_BYTE ) >= configNUMBER_OF_CORES );}#endif /* #if ( configUSE_CORE_AFFINITY == 1 ) && ( configNUMBER_OF_CORES > 1 ) */xReturn = prvCreateIdleTasks();#if ( configUSE_TIMERS == 1 ){if( xReturn == pdPASS ){xReturn = xTimerCreateTimerTask();}else{mtCOVERAGE_TEST_MARKER();}}#endif /* configUSE_TIMERS */if( xReturn == pdPASS ){/* freertos_tasks_c_additions_init() should only be called if the user* definable macro FREERTOS_TASKS_C_ADDITIONS_INIT() is defined, as that is* the only macro called by the function. */#ifdef FREERTOS_TASKS_C_ADDITIONS_INIT{freertos_tasks_c_additions_init();}#endif/* Interrupts are turned off here, to ensure a tick does not occur* before or during the call to xPortStartScheduler().  The stacks of* the created tasks contain a status word with interrupts switched on* so interrupts will automatically get re-enabled when the first task* starts to run. */portDISABLE_INTERRUPTS();#if ( configUSE_C_RUNTIME_TLS_SUPPORT == 1 ){/* Switch C-Runtime's TLS Block to point to the TLS* block specific to the task that will run first. */configSET_TLS_BLOCK( pxCurrentTCB->xTLSBlock );}#endifxNextTaskUnblockTime = portMAX_DELAY;xSchedulerRunning = pdTRUE;xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT;/* If configGENERATE_RUN_TIME_STATS is defined then the following* macro must be defined to configure the timer/counter used to generate* the run time counter time base.   NOTE:  If configGENERATE_RUN_TIME_STATS* is set to 0 and the following line fails to build then ensure you do not* have portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() defined in your* FreeRTOSConfig.h file. */portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();traceTASK_SWITCHED_IN();traceSTARTING_SCHEDULER( xIdleTaskHandles );/* Setting up the timer tick is hardware specific and thus in the* portable interface. *//* The return value for xPortStartScheduler is not required* hence using a void datatype. */( void ) xPortStartScheduler();/* In most cases, xPortStartScheduler() will not return. If it* returns pdTRUE then there was not enough heap memory available* to create either the Idle or the Timer task. If it returned* pdFALSE, then the application called xTaskEndScheduler().* Most ports don't implement xTaskEndScheduler() as there is* nothing to return to. */}else{/* This line will only be reached if the kernel could not be started,* because there was not enough FreeRTOS heap to create the idle task* or the timer task. */configASSERT( xReturn != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY );}/* Prevent compiler warnings if INCLUDE_xTaskGetIdleTaskHandle is set to 0,* meaning xIdleTaskHandles are not used anywhere else. */( void ) xIdleTaskHandles;/* OpenOCD makes use of uxTopUsedPriority for thread debugging. Prevent uxTopUsedPriority* from getting optimized out as it is no longer used by the kernel. */( void ) uxTopUsedPriority;traceRETURN_vTaskStartScheduler();
}

4.2 prvCreateIdleTasks

4.2.1 prvCreateIdleTasks

  • for( xCoreID = ( BaseType_t ) 0; xCoreID < ( BaseType_t ) configNUMBER_OF_CORES; xCoreID++ ) 遍历所有的core,为所有的core 都创建对应的idle task,并将其加入到Ready列表。
  • pxIdleTaskFunction = prvIdleTask; 对于主核core,设置当前idle任务的处理函数为prvIdleTask
  • pxIdleTaskFunction = prvPassiveIdleTask; 对于从核,其idle task的处理函数为prvPassiveIdleTask
  • 创建idle task
xReturn = xTaskCreate( pxIdleTaskFunction,cIdleName,configMINIMAL_STACK_SIZE,( void * ) NULL,portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */&xIdleTaskHandles[ xCoreID ] );
static BaseType_t prvCreateIdleTasks( void )
{BaseType_t xReturn = pdPASS;BaseType_t xCoreID;char cIdleName[ configMAX_TASK_NAME_LEN ];TaskFunction_t pxIdleTaskFunction = NULL;BaseType_t xIdleTaskNameIndex;for( xIdleTaskNameIndex = ( BaseType_t ) 0; xIdleTaskNameIndex < ( BaseType_t ) configMAX_TASK_NAME_LEN; xIdleTaskNameIndex++ ){cIdleName[ xIdleTaskNameIndex ] = configIDLE_TASK_NAME[ xIdleTaskNameIndex ];/* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than* configMAX_TASK_NAME_LEN characters just in case the memory after the* string is not accessible (extremely unlikely). */if( cIdleName[ xIdleTaskNameIndex ] == ( char ) 0x00 ){break;}else{mtCOVERAGE_TEST_MARKER();}}/* Add each idle task at the lowest priority. */for( xCoreID = ( BaseType_t ) 0; xCoreID < ( BaseType_t ) configNUMBER_OF_CORES; xCoreID++ ){#if ( configNUMBER_OF_CORES == 1 ){pxIdleTaskFunction = prvIdleTask;}#else /* #if (  configNUMBER_OF_CORES == 1 ) */{/* In the FreeRTOS SMP, configNUMBER_OF_CORES - 1 passive idle tasks* are also created to ensure that each core has an idle task to* run when no other task is available to run. */if( xCoreID == 0 ){pxIdleTaskFunction = prvIdleTask;}else{pxIdleTaskFunction = prvPassiveIdleTask;}}#endif /* #if (  configNUMBER_OF_CORES == 1 ) *//* Update the idle task name with suffix to differentiate the idle tasks.* This function is not required in single core FreeRTOS since there is* only one idle task. */#if ( configNUMBER_OF_CORES > 1 ){/* Append the idle task number to the end of the name if there is space. */if( xIdleTaskNameIndex < ( BaseType_t ) configMAX_TASK_NAME_LEN ){cIdleName[ xIdleTaskNameIndex ] = ( char ) ( xCoreID + '0' );/* And append a null character if there is space. */if( ( xIdleTaskNameIndex + 1 ) < ( BaseType_t ) configMAX_TASK_NAME_LEN ){cIdleName[ xIdleTaskNameIndex + 1 ] = '\0';}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}}#endif /* if ( configNUMBER_OF_CORES > 1 ) */#if ( configSUPPORT_STATIC_ALLOCATION == 1 ){StaticTask_t * pxIdleTaskTCBBuffer = NULL;StackType_t * pxIdleTaskStackBuffer = NULL;configSTACK_DEPTH_TYPE uxIdleTaskStackSize;/* The Idle task is created using user provided RAM - obtain the* address of the RAM then create the idle task. */#if ( configNUMBER_OF_CORES == 1 ){vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &uxIdleTaskStackSize );}#else{if( xCoreID == 0 ){vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &uxIdleTaskStackSize );}else{vApplicationGetPassiveIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &uxIdleTaskStackSize, ( BaseType_t ) ( xCoreID - 1 ) );}}#endif /* if ( configNUMBER_OF_CORES == 1 ) */xIdleTaskHandles[ xCoreID ] = xTaskCreateStatic( pxIdleTaskFunction,cIdleName,uxIdleTaskStackSize,( void * ) NULL,portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */pxIdleTaskStackBuffer,pxIdleTaskTCBBuffer );if( xIdleTaskHandles[ xCoreID ] != NULL ){xReturn = pdPASS;}else{xReturn = pdFAIL;}}#else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */{/* The Idle task is being created using dynamically allocated RAM. */xReturn = xTaskCreate( pxIdleTaskFunction,cIdleName,configMINIMAL_STACK_SIZE,( void * ) NULL,portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */&xIdleTaskHandles[ xCoreID ] );}#endif /* configSUPPORT_STATIC_ALLOCATION *//* Break the loop if any of the idle task is failed to be created. */if( xReturn != pdPASS ){break;}else{#if ( configNUMBER_OF_CORES == 1 ){mtCOVERAGE_TEST_MARKER();}#else{/* Assign idle task to each core before SMP scheduler is running. */xIdleTaskHandles[ xCoreID ]->xTaskRunState = xCoreID;pxCurrentTCBs[ xCoreID ] = xIdleTaskHandles[ xCoreID ];}#endif}}return xReturn;
}

4.2.2 xTaskCreate

xTaskCreate的处理流程可以参考FreeRTOS之xTaskCreate,其调用流程如下所示:

|- xTaskCreate|- prvCreateTask|- pxStack = pvPortMallocStack( ( ( ( size_t ) uxStackDepth ) * sizeof( StackType_t ) ) );|- pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );|- prvInitialiseNewTask|- vListInitialiseItem( &( pxNewTCB->xStateListItem ) );|- vListInitialiseItem( &( pxNewTCB->xEventListItem ) );|- pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );|- *pxCreatedTask = ( TaskHandle_t ) pxNewTCB;|- prvAddNewTaskToReadyList|- prvInitialiseTaskLists|- prvAddTaskToReadyList|- listINSERT_END( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) );

4.3 xTimerCreateTimerTask

  • 多核并设置亲和性:创建Timer 任务,同时做亲和性设置,该处理是在多核的情况下做的处理,如果是单核或者没有开启亲和性的配置则会调用xTaskCreate去创建Timer任务。
xReturn = xTaskCreateAffinitySet( prvTimerTask,configTIMER_SERVICE_TASK_NAME,configTIMER_TASK_STACK_DEPTH,NULL,( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,configTIMER_SERVICE_TASK_CORE_AFFINITY,&xTimerTaskHandle );
  • 单核或者未开启亲和性设置:
xReturn = xTaskCreate( prvTimerTask,configTIMER_SERVICE_TASK_NAME,configTIMER_TASK_STACK_DEPTH,NULL,( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,&xTimerTaskHandle );
BaseType_t xTimerCreateTimerTask( void )
{BaseType_t xReturn = pdFAIL;traceENTER_xTimerCreateTimerTask();/* This function is called when the scheduler is started if* configUSE_TIMERS is set to 1.  Check that the infrastructure used by the* timer service task has been created/initialised.  If timers have already* been created then the initialisation will already have been performed. */prvCheckForValidListAndQueue();if( xTimerQueue != NULL ){#if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ){#if ( configSUPPORT_STATIC_ALLOCATION == 1 ){StaticTask_t * pxTimerTaskTCBBuffer = NULL;StackType_t * pxTimerTaskStackBuffer = NULL;configSTACK_DEPTH_TYPE uxTimerTaskStackSize;vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &uxTimerTaskStackSize );xTimerTaskHandle = xTaskCreateStaticAffinitySet( prvTimerTask,configTIMER_SERVICE_TASK_NAME,uxTimerTaskStackSize,NULL,( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,pxTimerTaskStackBuffer,pxTimerTaskTCBBuffer,configTIMER_SERVICE_TASK_CORE_AFFINITY );if( xTimerTaskHandle != NULL ){xReturn = pdPASS;}}#else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */{xReturn = xTaskCreateAffinitySet( prvTimerTask,configTIMER_SERVICE_TASK_NAME,configTIMER_TASK_STACK_DEPTH,NULL,( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,configTIMER_SERVICE_TASK_CORE_AFFINITY,&xTimerTaskHandle );}#endif /* configSUPPORT_STATIC_ALLOCATION */}#else /* #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) */{#if ( configSUPPORT_STATIC_ALLOCATION == 1 ){StaticTask_t * pxTimerTaskTCBBuffer = NULL;StackType_t * pxTimerTaskStackBuffer = NULL;configSTACK_DEPTH_TYPE uxTimerTaskStackSize;vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &uxTimerTaskStackSize );xTimerTaskHandle = xTaskCreateStatic( prvTimerTask,configTIMER_SERVICE_TASK_NAME,uxTimerTaskStackSize,NULL,( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,pxTimerTaskStackBuffer,pxTimerTaskTCBBuffer );if( xTimerTaskHandle != NULL ){xReturn = pdPASS;}}#else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */{xReturn = xTaskCreate( prvTimerTask,configTIMER_SERVICE_TASK_NAME,configTIMER_TASK_STACK_DEPTH,NULL,( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,&xTimerTaskHandle );}#endif /* configSUPPORT_STATIC_ALLOCATION */}#endif /* #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) */}else{mtCOVERAGE_TEST_MARKER();}configASSERT( xReturn );traceRETURN_xTimerCreateTimerTask( xReturn );return xReturn;
}

4.4 xTaskCreateAffinitySet

  • pxNewTCB = prvCreateTask( pxTaskCode, pcName, uxStackDepth, pvParameters, uxPriority, pxCreatedTask ); 创建pcName任务,任务的处理函数为pxTaskCode;
  • pxNewTCB->uxCoreAffinityMask = uxCoreAffinityMask; 将当前的任务绑定到指定的core上去处理。
  • rvAddNewTaskToReadyList( pxNewTCB ); 将任务添加到Ready任务链表。
BaseType_t xTaskCreateAffinitySet( TaskFunction_t pxTaskCode,const char * const pcName,const configSTACK_DEPTH_TYPE uxStackDepth,void * const pvParameters,UBaseType_t uxPriority,UBaseType_t uxCoreAffinityMask,TaskHandle_t * const pxCreatedTask )
{TCB_t * pxNewTCB;BaseType_t xReturn;traceENTER_xTaskCreateAffinitySet( pxTaskCode, pcName, uxStackDepth, pvParameters, uxPriority, uxCoreAffinityMask, pxCreatedTask );pxNewTCB = prvCreateTask( pxTaskCode, pcName, uxStackDepth, pvParameters, uxPriority, pxCreatedTask );if( pxNewTCB != NULL ){/* Set the task's affinity before scheduling it. */pxNewTCB->uxCoreAffinityMask = uxCoreAffinityMask;prvAddNewTaskToReadyList( pxNewTCB );xReturn = pdPASS;}else{xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;}traceRETURN_xTaskCreateAffinitySet( xReturn );return xReturn;
}

4.5 xPortStartScheduler

该函数和具体的处理器架构以及其对应处理器的实现有关,下面以Cortex-R5的为例来介绍

  • __asm volatile ( "MRS %0, APSR" : "=r" ( ulAPSR )::"memory" ); 读取APSR寄存器的状态值,用于后面,随后将处理器模式设置为System模式
  • portCPU_IRQ_DISABLE(); disable IRQ
  • configSETUP_TICK_INTERRUPT(); 开启Tick中断。
  • vPortRestoreTaskContext(); 开启第一个任务的执行
BaseType_t xPortStartScheduler( void )
{uint32_t ulAPSR, ulCycles = 8; /* 8 bits per byte. */#if ( configASSERT_DEFINED == 1 ){volatile uint8_t ucOriginalPriority;volatile uint8_t * const pucFirstUserPriorityRegister = ( volatile uint8_t * const ) ( configINTERRUPT_CONTROLLER_BASE_ADDRESS + portINTERRUPT_PRIORITY_REGISTER_OFFSET );volatile uint8_t ucMaxPriorityValue;/** Determine how many priority bits are implemented in the GIC.* Save the interrupt priority value that is about to be clobbered.*/ucOriginalPriority = *pucFirstUserPriorityRegister;/** Determine the number of priority bits available.  First write to* all possible bits.*/*pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;/* Read the value back to see how many bits stuck. */ucMaxPriorityValue = *pucFirstUserPriorityRegister;/* Shift to the least significant bits. */while( ( ucMaxPriorityValue & portBIT_0_SET ) != portBIT_0_SET ){ucMaxPriorityValue >>= ( uint8_t ) 0x01;/** If ulCycles reaches 0 then ucMaxPriorityValue must have been* read as 0, indicating a misconfiguration.*/ulCycles--;if( ulCycles == 0 ){break;}}/** Sanity check configUNIQUE_INTERRUPT_PRIORITIES matches the read* value.*/configASSERT( ucMaxPriorityValue == portLOWEST_INTERRUPT_PRIORITY );/** Restore the clobbered interrupt priority register to its original* value.*/*pucFirstUserPriorityRegister = ucOriginalPriority;}#endif /* configASSERT_DEFINED *//** Only continue if the CPU is not in User mode.  The CPU must be in a* Privileged mode for the scheduler to start.*/__asm volatile ( "MRS %0, APSR" : "=r" ( ulAPSR )::"memory" );ulAPSR &= portAPSR_MODE_BITS_MASK;configASSERT( ulAPSR != portAPSR_USER_MODE );if( ulAPSR != portAPSR_USER_MODE ){/** Only continue if the binary point value is set to its lowest possible* setting.  See the comments in vPortValidateInterruptPriority() below for* more information.*/configASSERT( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE );if( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE ){/** Interrupts are turned off in the CPU itself to ensure tick does* not execute  while the scheduler is being started.  Interrupts are* automatically turned back on in the CPU when the first task starts* executing.*/portCPU_IRQ_DISABLE();/* Start the timer that generates the tick ISR. */configSETUP_TICK_INTERRUPT();/* Start the first task executing. */vPortRestoreTaskContext();}}/** Will only get here if vTaskStartScheduler() was called with the CPU in* a non-privileged mode or the binary point register was not set to its lowest* possible value.  prvTaskExitError() is referenced to prevent a compiler* warning about it being defined but not referenced in the case that the user* defines their own exit address.*/( void ) prvTaskExitError;return 0;
}

4.6 vPortRestoreTaskContext

  • CPS #SYS_MODE 切换当前处理器的模式为SYS模式
  • portRESTORE_CONTEXT 回复用户栈
/******************************************************************************* vPortRestoreTaskContext is used to start the scheduler.*****************************************************************************/
.type vPortRestoreTaskContext, %function
vPortRestoreTaskContext:/* Switch to system mode. */CPS     #SYS_MODEportRESTORE_CONTEXT

4.7 portRESTORE_CONTEXT

  • 取第一个任务,获取其对应的任务TCB,然后通过TCB获取其栈顶。
    LDR     R0, pxCurrentTCBConstLDR     R1, [R0]LDR     SP, [R1]
  • 恢复用户设置的critical section nesting depth
    LDR     R0, ulCriticalNestingConstPOP     {R1}STR     R1, [R0]
  • 恢复用户栈POP {R0-R12, R14}
.macro portRESTORE_CONTEXT/* Set the SP to point to the stack of the task being restored. */LDR     R0, pxCurrentTCBConstLDR     R1, [R0]LDR     SP, [R1]#if defined( __ARM_FP )/** Is there a floating point context to restore?  If the restored* ulPortTaskHasFPUContext is zero then no.*/LDR     R0, ulPortTaskHasFPUContextConstPOP     {R1}STR     R1, [R0]CMP     R1, #0/* Restore the floating point context, if any. */VPOPNE  {D0-D15}POPNE   {R0}VMSRNE  FPSCR, R0#endif /* __ARM_FP *//* Restore the critical section nesting depth. */LDR     R0, ulCriticalNestingConstPOP     {R1}STR     R1, [R0]/* Ensure the priority mask is correct for the critical nesting depth. */LDR     R2, ulICCPMRConstLDR     R2, [R2]CMP     R1, #0MOVEQ   R4, #255LDRNE   R4, ulMaxAPIPriorityMaskConstLDRNE   R4, [R4]STR     R4, [R2]/* Restore all system mode registers other than the SP (which is alreadybeing used). */POP     {R0-R12, R14}/* Return to the task code, loading CPSR on the way. */RFEIA   sp!.endm

4.8 pxPortInitialiseStack

针对Cortex-R5处理器所设置的栈结构如下图所示:

StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,TaskFunction_t pxCode,void * pvParameters )
{/** Setup the initial stack of the task.  The stack is set exactly as* expected by the portRESTORE_CONTEXT() macro.** The fist real value on the stack is the status register, which is set for* system mode, with interrupts enabled.  A few NULLs are added first to ensure* GDB does not try decoding a non-existent return address.*/*pxTopOfStack = ( StackType_t ) NULL;pxTopOfStack--;*pxTopOfStack = ( StackType_t ) NULL;pxTopOfStack--;*pxTopOfStack = ( StackType_t ) NULL;pxTopOfStack--;*pxTopOfStack = ( StackType_t ) portINITIAL_SPSR;if( ( ( uint32_t ) pxCode & portTHUMB_MODE_ADDRESS ) != 0x00UL ){/* The task will start in THUMB mode. */*pxTopOfStack |= portTHUMB_MODE_BIT;}pxTopOfStack--;/* Next the return address, which in this case is the start of the task. */*pxTopOfStack = ( StackType_t ) pxCode;pxTopOfStack--;/* Next all the registers other than the stack pointer. */*pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* R14 */pxTopOfStack--;*pxTopOfStack = ( StackType_t ) 0x12121212;              /* R12 */pxTopOfStack--;*pxTopOfStack = ( StackType_t ) 0x11111111;              /* R11 */pxTopOfStack--;*pxTopOfStack = ( StackType_t ) 0x10101010;              /* R10 */pxTopOfStack--;*pxTopOfStack = ( StackType_t ) 0x09090909;              /* R9 */pxTopOfStack--;*pxTopOfStack = ( StackType_t ) 0x08080808;              /* R8 */pxTopOfStack--;*pxTopOfStack = ( StackType_t ) 0x07070707;              /* R7 */pxTopOfStack--;*pxTopOfStack = ( StackType_t ) 0x06060606;              /* R6 */pxTopOfStack--;*pxTopOfStack = ( StackType_t ) 0x05050505;              /* R5 */pxTopOfStack--;*pxTopOfStack = ( StackType_t ) 0x04040404;              /* R4 */pxTopOfStack--;*pxTopOfStack = ( StackType_t ) 0x03030303;              /* R3 */pxTopOfStack--;*pxTopOfStack = ( StackType_t ) 0x02020202;              /* R2 */pxTopOfStack--;*pxTopOfStack = ( StackType_t ) 0x01010101;              /* R1 */pxTopOfStack--;*pxTopOfStack = ( StackType_t ) pvParameters;            /* R0 *//** The task will start with a critical nesting count of 0 as interrupts are* enabled.*/pxTopOfStack--;*pxTopOfStack = portNO_CRITICAL_NESTING;#if ( configUSE_TASK_FPU_SUPPORT == 1 ){/** The task will start without a floating point context.* A task that uses the floating point hardware must call* vPortTaskUsesFPU() before executing any floating point* instructions.*/pxTopOfStack--;*pxTopOfStack = portNO_FLOATING_POINT_CONTEXT;}#elif ( configUSE_TASK_FPU_SUPPORT == 2 ){/** The task will start with a floating point context. Leave enough* space for the registers and ensure they are initialized to 0.*/pxTopOfStack -= portFPU_REGISTER_WORDS;memset( pxTopOfStack, 0x00, portFPU_REGISTER_WORDS * sizeof( StackType_t ) );pxTopOfStack--;*pxTopOfStack = pdTRUE;ulPortTaskHasFPUContext = pdTRUE;}#elif ( configUSE_TASK_FPU_SUPPORT != 0 ){#error Invalid configUSE_TASK_FPU_SUPPORT setting - configUSE_TASK_FPU_SUPPORT must be set to 0, 1, or 2.}#endif /* configUSE_TASK_FPU_SUPPORT */return pxTopOfStack;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/482327.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于群晖搭建个人图书架-TaleBook based on Docker

前言 在群晖Container Manager中部署失败&#xff0c;转通过ssh部署。 一、准备工作 名称备注群晖SSH“终端机和SNMP”中启用SSH软件secureCRT等docker-compose.ymlGithub下载并修改 二、过程 2.1 创建本地文件夹 本地路径为&#xff1a; /docker/Calibre/data 2.2 下载d…

Ubuntu24.04初始化教程(包含基础优化、ros2)

将会不断更新。但是所有都是基础且必要的操作。 为重装系统之后的环境配置提供便捷信息来源。记录一些错误的解决方案。 目录 构建系统建立系统备份**Timeshift: 系统快照和备份工具****安装 Timeshift****使用 Timeshift 创建快照****还原快照****自动创建快照** 最基本配置换…

【论文笔记】A Token-level Contrastive Framework for Sign Language Translation

&#x1f34e;个人主页&#xff1a;小嗷犬的个人主页 &#x1f34a;个人网站&#xff1a;小嗷犬的技术小站 &#x1f96d;个人信条&#xff1a;为天地立心&#xff0c;为生民立命&#xff0c;为往圣继绝学&#xff0c;为万世开太平。 基本信息 标题: A Token-level Contrastiv…

yolov5 解决:export GIT_PYTHON_REFRESH=quiet

当我们在第一次运行YOLOv5中的train.py程序时&#xff1a;可能会出现以下报错&#xff1a; This initial warning can be silenced or aggravated in the future by setting the $GIT_PYTHON_REFRESH environment variable. Use one of the following values: - quiet|q|silen…

基于springboot中小型制造企业质量管理系统源码和论文

信息数据从传统到当代&#xff0c;是一直在变革当中&#xff0c;突如其来的互联网让传统的信息管理看到了革命性的曙光&#xff0c;因为传统信息管理从时效性&#xff0c;还是安全性&#xff0c;还是可操作性等各个方面来讲&#xff0c;遇到了互联网时代才发现能补上自古以来的…

【实验13】使用预训练ResNet18进行CIFAR10分类

目录 1 数据处理 1.1 数据集介绍 1.2数据处理与划分 2 模型构建- Pytorch高层API中的Resnet18 3 模型训练 4 模型评价 5 比较“使用预训练模型”和“不使用预训练模型”的效果&#xff1a; 6 模型预测 7 完整代码 8 参考链接 1 数据处理 1.1 数据集介绍 数据规模&…

Java之链表1

文章目录 1. 链表1.11.2 链表的概念及其结构1.3 自己实现一个链表 1. 链表 1.1 之前我们学习了 顺序表ArrayList&#xff0c;并自己实现了 ArrayList &#xff0c;发现它在删除元素和添加元素时很麻烦&#xff0c;最坏的情况时&#xff0c;需要将所有的元素移动&#xff0c;因…

二分搜索(三)x的平方根

69. x 的平方根 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 示例 1: 输入: nums [1,3,5,6], target 5 输出: 2…

AI开发-数据可视化库-Seaborn

1 需求 概述 Seaborn 是一个基于 Python 的数据可视化库&#xff0c;它建立在 Matplotlib 之上。其主要目的是使数据可视化更加美观、方便和高效。它提供了高层次的接口和各种美观的默认主题&#xff0c;能够帮助用户快速创建出具有吸引力的统计图表&#xff0c;用于数据分析和…

使用docker-compose部署搜索引擎ElasticSearch6.8.10

背景 Elasticsearch 是一个开源的分布式搜索和分析引擎&#xff0c;基于 Apache Lucene 构建。它被广泛用于实时数据搜索、日志分析、全文检索等应用场景。 Elasticsearch 支持高效的全文搜索&#xff0c;并提供了强大的聚合功能&#xff0c;可以处理大规模的数据集并进行快速…

LeetCode—74. 搜索二维矩阵(中等)

仅供个人学习使用 题目描述&#xff1a; 给你一个满足下述两条属性的 m x n 整数矩阵&#xff1a; 每行中的整数从左到右按非严格递增顺序排列。 每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target &#xff0c;如果 target 在矩阵中&#xff0c;返回 true…

Cento7 紧急模式无法正常启动,修复home挂载问题

Centos 7 开机失败进入紧急模式[emergency mode]&#xff0c;解决方案。 通过journalctl -xb查看启动日志&#xff0c;定位发现/home目录无法正常挂载。 退出启动日志检查&#xff0c;进行修复。 进行问题修复 # 修复挂载问题 mkdir /home mount /dev/mapper/centos-home /ho…

Matlab mex- setup报错—错误使用 mex,未检测到支持的编译器...

错误日志&#xff1a; 在使用mex编译时报错提示&#xff1a;错误使用 mex&#xff0c;未检测到支持的编译器。您可以安装免费提供的 MinGW-w64 C/C 编译器&#xff1b;请参阅安装 MinGW-w64 编译器。有关更多选项&#xff0c;请访问https://www.mathworks.com/support/compile…

【C语言】二叉树(BinaryTree)的创建、3种递归遍历、3种非递归遍历、结点度的实现

代码主要实现了以下功能&#xff1a; 二叉树相关数据结构定义 定义了二叉树节点结构体 BiTNode&#xff0c;包含节点数据值&#xff08;字符类型&#xff09;以及指向左右子树的指针。 定义了顺序栈结构体 SqStack&#xff0c;用于存储二叉树节点指针&#xff0c;实现非递归遍历…

Android -- 简易音乐播放器

Android – 简易音乐播放器 播放器功能&#xff1a;* 1. 播放模式&#xff1a;单曲、列表循环、列表随机&#xff1b;* 2. 后台播放&#xff08;单例模式&#xff09;&#xff1b;* 3. 多位置同步状态回调&#xff1b;处理模块&#xff1a;* 1. 提取文件信息&#xff1a;音频文…

Python语法基础(四)

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 高阶函数之map 高阶函数就是说&#xff0c;A函数作为B函数的参数&#xff0c;B函数就是高阶函数 map&#xff1a;映射 map(func,iterable) 这个是map的基本语法&#xff0c;…

大模型时代的人工智能基础与实践——基于OmniForce的应用开发教程

《大模型时代的人工智能基础与实践——基于 OmniForce 的应用开发教程》由京东探索研究院及京东教育联袂撰写&#xff0c;图文并茂地介绍传统人工智能和新一代人工智能&#xff08;基于大模型的通用人工智能技术&#xff09;&#xff0c;展示人工智能广阔的应用场景。同时&…

ESP8266 (ESP-01S)烧录固件 和 了解与单片机通信必需的AT指令

ESP8266&#xff08;ESP-01s&#xff09;烧录固件 工具&#xff1a; 需要安装的原装出厂固件库&#xff1a; ESP8266 --接线-- VCC 3.3&#xff08;外接开发板&#xff09; GND GND&#xff08;外接开发板&#xff09; IO0 GND&#xff08;外接…

【操作文档】mysql分区操作步骤.docx

1、建立分区表 执行 tb_intercept_notice表-重建-添加分区.sql 文件&#xff1b; DROP TABLE IF EXISTS tb_intercept_notice_20241101_new; CREATE TABLE tb_intercept_notice_20241101_new (id char(32) NOT NULL COMMENT id,number varchar(30) NOT NULL COMMENT 号码,cre…

S4 UPA of AA :新资产会计概览

通用并行会计&#xff08;Universal Parallel Accounting&#xff09;可以支持每个独立的分类账与其他模块集成&#xff0c;UPA主要是为了支持平行评估、多货币类型、财务合并、多准则财务报告的复杂业务需求 在ML层面UPA允许根据不同的分类账规则对物料进行评估&#xff0c;并…