FreeRTos笔记(5d):vTaskStartScheduler(3c)调用了 xPortStartScheduler(源码)配置内核寄存器、systick 和 pendSV 中断优先级并启动任务 54这里用的是 103 M3 内核的 port.c 文件源码#if(configASSERT_DEFINED1)// port.c 167 行的全局静态变量staticuint32_tulMaxPRIGROUPValue0;staticuint8_tucMaxSysCallPriority0;staticconstvolatileuint8_t*constpcInterruptPriorityRegisters(uint8_t*)portNVIC_IP_REGISTERS_OFFSET_16;#endifBaseType_txPortStartScheduler(void)// FreeRTOS - port - 103 M3 264 行{#if(configASSERT_DEFINED1)// configASSERT_DEFINED 1 定义于 FreeRtos.h{volatileuint8_tucMaxPriorityValue;volatileuint32_tulOriginalPriority;// 下面的变量指向了外部 240 个中断优先级寄存器的首地址第一个寄存器 WWDG_IRQHandlervolatileuint8_t*constpucFirstUserPriorityRegister(uint8_t*)(portNVIC_IP_REGISTERS_OFFSET_16portFIRST_USER_INTERRUPT_NUMBER);// #define portNVIC_IP_REGISTERS_OFFSET_16 (OxE000E3F0)// 指向SCB-SHPR 及紧跟的 NVIC-IPRx 这些中断优先级寄存器// #define portFIRST_USER_INTERRUPT_NUMBER (16)ulOriginalPriority*pucFirstUserPriorityRegister;// 这俩都是局部变量//确定可以调用 ISR 安全 FreeRTOS API 函数的最高优先级。ISR 安全函数以 FromlSR 结尾。// FreeRTOS 维护独立的线程和 ISR API 函数以确保中断入口尽可能快速简便。// 保存即将被覆盖的中断优先级值。 即 WWDG_IRQHandler 的原始优先级值/* 确定可用的优先级位数。首先写入所有可能的位。*/*pucFirstUserPriorityRegisterportMAX_8_BIT_VALUE;// 0xFF/* Read the value back to see how many bits stuck. 读取数值以查看有多少位被卡住。*/ucMaxPriorityValue*pucFirstUserPriorityRegister;// 0xFFconfigASSERT(ucMaxPriorityValue(configKERNEL_INTERRUPT_PRIORITYucMaxPriorityValue));/* The kernel interrupt priority should be set to the lowest priority. 内核中断优先级应设置为最低优先级。*/// #define configKERNEL_INTERRUPT_PRIORITY 15 4//static uint8_t ucMaxSysCallPriority 0; // 本文件上面定义的全局静态变量ucMaxSysCallPriorityconfigMAX_SYSCALL_INTERRUPT_PRIORITYucMaxPriorityValue;/* Use the same mask on the maximum system call priority. */// ucMaxSysCallPriority 5 4 // 这里似乎是记录 FreeRTOS 管理的中断范围/* Calculate the maximum acceptable priority group value for the number of bits read back. *///计算最大可接受的优先级组值该值基于读取回的位数。ulMaxPRIGROUPValueportMAX_PRIGROUP_BITS;// 7//static uint32_t ulMaxPRIGROUPValue 0; 也是本文件开头处定义的全局静态变量// ucMaxPriorityValue 是局部变量 // 宏 portTOP_BIT_OF_BYTE 0x80while((ucMaxPriorityValueportTOP_BIT_OF_BYTE)portTOP_BIT_OF_BYTE){ulMaxPRIGROUPValue--;ucMaxPriorityValue(uint8_t)0x01;}//#define __NVIC_PRIO_BITS 4 /*! STM32 uses 4 Bits for the Priority Levels */#ifdef__NVIC_PRIO_BITS// 定义于 stm32f103xe.h{/* Check the CMSIS configuration that defines the number of priority bits matches the number of priority bits actually queried from the hardware. *///检查 CMSIS 配置确认其定义的优先级位数与从硬件实际查询到的优先级位数一致。configASSERT((portMAX_PRIGROUP_BITS-ulMaxPRIGROUPValue)__NVIC_PRIO_BITS);}#endif#ifdefconfigPRIO_BITS// 4{/* Check the FreeRTOS configuration that defines the number of priority bits matches the number of priority bits actually queried from the hardware. *///检查 FreeRTOS 配置确认其定义的优先级位数与从硬件实际查询到的优先级位数一致。configASSERT((portMAX_PRIGROUP_BITS-ulMaxPRIGROUPValue)configPRIO_BITS);}#endif/* Shift the priority group value back to its position within the AIRCR register. */ulMaxPRIGROUPValueportPRIGROUP_SHIFT;// 将优先级组值移回 AIRCR 寄存器中的位置。ulMaxPRIGROUPValueportPRIORITY_GROUP_MASK;// SCB - AIRCR 的 10-9-8 记录中断的优先级分组类别// 上面这俩都是全局静态变量/* Restore the clobbered interrupt priority register to its original value. */*pucFirstUserPriorityRegisterulOriginalPriority;//将被覆盖的中断优先级寄存器恢复到其原始值。}#endif/* configASSERT_DEFINED *//* Make PendSV and SysTick the lowest priority interrupts. */portNVIC_SHPR3_REG|portNVIC_PENDSV_PRI;// 都配置成了 15 pendSV 中断portNVIC_SHPR3_REG|portNVIC_SYSTICK_PRI;// sistick 中断的优先级/* Start the timer that generates the tick ISR. Interrupts are disabled here already. */vPortSetupTimerInterrupt();//启动生成 tickISR 的定时器。此处已禁用中断。/* Initialise the critical nesting count ready for the first task. */uxCriticalNesting0;// 初始化关键嵌套计数为第一个任务做好准备。//static UBaseType_t uxCriticalNesting 0xaaaaaaaa; // 本文件里定义的全局静态变量// 每个任务在其临界嵌套变量中维护自己的中断状态。prvStartFirstTask();/* Start the first task. *//* Should not get here! */return0;}// BaseType_t xPortStartScheduler( void )55解释上面出现的关于内核寄存器的宏定义 #define portNVIC_IP_REGISTERS_OFFSET_16 ( 0xE000E3F0 )doubao 的讲解56xPortStartScheduler 又调用了 vPortSetupTimerInterrupt#defineconfigUSE_TICKLESS_IDLE0// FreeRTOSConfig.h/* 1: 使能tickless低功耗模式, 默认: 0 */// 默认不使能低功耗模式// 主动把这个心跳关掉让 CPU 安心睡个长觉不被 tick 频繁吵醒。所以是暂时关闭 tick 计数__weakvoidvPortSetupTimerInterrupt(void)// port.c 625{/* Calculate the constants required to configure the tick interrupt. 计算配置定时中断所需的常量。*/#if(configUSE_TICKLESS_IDLE1)// 默认不使能低功耗模式{ulTimerCountsForOneTick(configSYSTICK_CLOCK_HZ/configTICK_RATE_HZ);xMaximumPossibleSuppressedTicksportMAX_24_BIT_NUMBER/ulTimerCountsForOneTick;ulStoppedTimerCompensationportMISSED_COUNTS_FACTOR/(configCPU_CLOCK_HZ/configSYSTICK_CLOCK_HZ);}#endif/* configUSE_TICKLESS_IDLE *//* Stop and clear the SysTick. */portNVIC_SYSTICK_CTRL_REG0UL;// 先对 systick 的控制寄存器复位清 0portNVIC_SYSTICK_CURRENT_VALUE_REG0UL;// 当前计数值寄存器/* Configure SysTick to interrupt at the requested rate. */portNVIC_SYSTICK_LOAD_REG(configSYSTICK_CLOCK_HZ/configTICK_RATE_HZ)-1UL;// 9000_000 / 1000 重装值portNVIC_SYSTICK_CTRL_REG(portNVIC_SYSTICK_CLK_BIT|portNVIC_SYSTICK_INT_BIT|portNVIC_SYSTICK_ENABLE_BIT);// 0 | 1 1 | 1 0// 意思是使能 systick 寄存器 1 0 使能 systick 的中断 1 1}57xPortStartScheduler 又调用了 prvStartFirstTask ()__asmvoidprvStartFirstTask(void)// m3 port.c 236{/* *INDENT-OFF* */PRESERVE8/* Use the NVIC offset register to locate the stack. */ldr r0,0xE000ED08ldr r0,[r0]ldr r0,[r0]/* Set the msp back to the start of the stack. */msr msp,r0/* Globally enable interrupts. */cpsie i cpsie f dsb isb/* Call SVC to start the first task. 出现了大名鼎鼎的 SVC 0据说就是使能 FreeRTOS 调度器*/svc0nop nop/* *INDENT-ON* */}58谢谢