☰
FreeRTos笔记(5d):vTaskStartScheduler(3c)调用了 xPortStartScheduler(源码)配置内核寄存器、systick 和 pendSV 中断优先级并启动任务
2026/11/4 7:12:41 网站建设 项目流程

(54)这里用的是 103 , M3 内核的 port.c 文件:

++源码:

#if(configASSERT_DEFINED==1)// port.c 167 行的全局静态变量staticuint32_tulMaxPRIGROUPValue=0;staticuint8_tucMaxSysCallPriority=0;staticconstvolatileuint8_t*constpcInterruptPriorityRegisters=(uint8_t*)portNVIC_IP_REGISTERS_OFFSET_16;#endifBaseType_txPortStartScheduler(void)// FreeRTOS - port - 103 M3 , 264 行{#if(configASSERT_DEFINED==1)// configASSERT_DEFINED = 1 ,定义于 FreeRtos.h{volatileuint8_tucMaxPriorityValue;volatileuint32_tulOriginalPriority;// 下面的变量,指向了外部 240 个中断优先级寄存器的首地址,第一个寄存器 WWDG_IRQHandlervolatileuint8_t*constpucFirstUserPriorityRegister=(uint8_t*)(portNVIC_IP_REGISTERS_OFFSET_16+portFIRST_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 的原始优先级值/* 确定可用的优先级位数。首先写入所有可能的位。*/*pucFirstUserPriorityRegister=portMAX_8_BIT_VALUE;//= 0xFF/* Read the value back to see how many bits stuck. 读取数值以查看有多少位被卡住。*/ucMaxPriorityValue=*pucFirstUserPriorityRegister;//= 0xFFconfigASSERT(ucMaxPriorityValue==(configKERNEL_INTERRUPT_PRIORITY&ucMaxPriorityValue));/* The kernel interrupt priority should be set to the lowest priority. 内核中断优先级应设置为最低优先级。*/// #define configKERNEL_INTERRUPT_PRIORITY = 15 << 4//static uint8_t ucMaxSysCallPriority = 0; // 本文件上面定义的全局静态变量ucMaxSysCallPriority=configMAX_SYSCALL_INTERRUPT_PRIORITY&ucMaxPriorityValue;/* 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. *///计算最大可接受的优先级组值,该值基于读取回的位数。ulMaxPRIGROUPValue=portMAX_PRIGROUP_BITS;//= 7//static uint32_t ulMaxPRIGROUPValue = 0; 也是本文件开头处定义的全局静态变量// ucMaxPriorityValue 是局部变量 // 宏 portTOP_BIT_OF_BYTE = 0x80while((ucMaxPriorityValue&portTOP_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. */ulMaxPRIGROUPValue<<=portPRIGROUP_SHIFT;// 将优先级组值移回 AIRCR 寄存器中的位置。ulMaxPRIGROUPValue&=portPRIORITY_GROUP_MASK;// SCB -> AIRCR 的 10-9-8 记录中断的优先级分组类别// 上面这俩都是全局静态变量/* Restore the clobbered interrupt priority register to its original value. */*pucFirstUserPriorityRegister=ulOriginalPriority;//将被覆盖的中断优先级寄存器恢复到其原始值。}#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. */uxCriticalNesting=0;// 初始化关键嵌套计数,为第一个任务做好准备。//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 的讲解:


(56)xPortStartScheduler 又调用了 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_IDLE==1)// 默认不使能低功耗模式{ulTimerCountsForOneTick=(configSYSTICK_CLOCK_HZ/configTICK_RATE_HZ);xMaximumPossibleSuppressedTicks=portMAX_24_BIT_NUMBER/ulTimerCountsForOneTick;ulStoppedTimerCompensation=portMISSED_COUNTS_FACTOR/(configCPU_CLOCK_HZ/configSYSTICK_CLOCK_HZ);}#endif/* configUSE_TICKLESS_IDLE *//* Stop and clear the SysTick. */portNVIC_SYSTICK_CTRL_REG=0UL;// 先对 systick 的控制寄存器复位清 0portNVIC_SYSTICK_CURRENT_VALUE_REG=0UL;// 当前计数值寄存器/* 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}

(57)xPortStartScheduler 又调用了 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)

谢谢

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询