STM32F103移植FreeRTOS必须搞明白的系列知识---1(Cortex-CM3中断优先级)
STM32F103移植FreeRTOS必须搞明白的系列知识---2(FreeRTOS任务优先级)
STM32F103移植FreeRTOS必须搞明白的系列知识---3(堆栈)
STM32F103移植FreeRTOS必须搞明白的系列知识---4(FreeRTOSConfig.h配置文件) ?
目录
一、FreeRTOSConfig.h配置文件概述
二、configCPU_CLOCK_HZ
三、configTICK_RATE_HZ
四、configMAX_PRIORITIES
五、configMINIMAL_STACK_SIZE
六、configTOTAL_HEAP_SIZE
七、configKERNEL_INTERRUPT_PRIORITY
八、configMAX_SYSCALL_INTERRUPT_PRIORITY?
九、实例
? ? ? ?1、配置configMAX_PRIORITIES
? ? ? ?2、配置configTOTAL_HEAP_SIZE
?? ? ? ?3、配置configKERNEL_INTERRUPT_PRIORITY
?? ? ? ?4、配置configMAX_SYSCALL_INTERRUPT_PRIORITY
?? ? ? ?5、创建5个任务
?? ? ? ?6、配置NVIC中断优先级组和抢占优先级和响应优先级
一、FreeRTOSConfig.h配置文件概述
? ? ? ??FreeRTOSConfig.h配置文件是由FreeRTOS官网提供给用户针对具体的某一款MCU并且独立于FreeRTOS内核的配置文件。
? ? ? ? 要想实现STM32F103移植,必须熟悉FreeRTOSConfig.h配置文件中的以下几项(注:博主使用的FreeRTOS版本为FreeRTOS Kernel V10.2.1)。
? ? ? ? ?1、configCPU_CLOCK_HZ
? ? ? ? ?2、configTICK_RATE_HZ
? ? ? ? ?3、configMAX_PRIORITIES
? ? ? ? ?4、configMINIMAL_STACK_SIZE
? ? ? ? ?5、configTOTAL_HEAP_SIZE
? ? ? ? ?6、configKERNEL_INTERRUPT_PRIORITY
? ? ? ? ?7、configMAX_SYSCALL_INTERRUPT_PRIORITY?
二、configCPU_CLOCK_HZ
? ? ? ? 写入实际的CPU内核时钟频率,也就是CPU指令执行频率。(stm32f103芯片的晶振为72MHZ。)
? ? ? ? ?配置此值是为了正确的配置系统节拍中断周期。
? ? ? ? 例如,在STM32F10X中,FreeRTOS Kernel V10.2.1
#define configCPU_CLOCK_HZ?? ??? ??? ?( ( unsigned long ) 72000000 )
三、configTICK_RATE_HZ
? ? ? ? FreeRTOS系统自己的节拍中断的频率。即一秒中断的次数,每次中断FreeRTOS都会进行任务调度。
? ? ? ? 系统节拍中断用来测量时间,因此,越高的测量频率意味着可测到越高的分辨率时间。但是,高的系统节拍中断频率也意味着RTOS内核占用更多的CPU时间,因此会降低效率。RTOS演示例程都是使用系统节拍中断频率为1000HZ,这是为了测试RTOS内核,比实际使用的要高。(实际使用时不用这么高的系统节拍中断频率) ??多个任务可以共享一个优先级,RTOS调度器为相同优先级的任务分享CPU时间,在每一个RTOS 系统节拍中断到来时进行任务切换。高的系统节拍中断频率会降低分配给每一个任务的“时间片”持续时间。
??例如,在STM32F10X中,FreeRTOS Kernel V10.2.1
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
??表示滴答中断(SYSTICK)1毫秒中断1次。
??如果想让滴答中断(SYSTICK)100微秒中断1次,可以如下进行配置
#define configTICK_RATE_HZ ( ( TickType_t ) 100 )
四、configMAX_PRIORITIES
? ? ? ? 配置应用程序最大可用的优先级数目。
??在FreeRTOS内核中,每个有效优先级都会消耗一定量的RAM,因此这个值最好不要超过你的应用实际需要的优先级数目,FreeRTOS官网建议,宏configMAX_PRIORITIES最大数目不要超过32,那么工程项目可以使用的任务的优先级号范围为(0~31)。
? ? ? ? 每一个任务都会被分配一个优先级,任务的优先级值在0~ (configMAX_PRIORITIES - 1)之间。
? ? ? ? FreeRTOS任务优先级数值越小,表示任务优先级越低;FreeRTOS任务优先级数值越大,表示任务优先级越高。
? ? ? ? 空闲任务的优先级为0(tskIDLE_PRIORITY),因此它是最低优先级任务。
? ? ? ? 例如,在STM32F103中,FreeRTOS Kernel V10.2.1
#define configMAX_PRIORITIES ( 5 )
? ? ? ? 程序中给任务分配优先级时,可用的优先级号为:(0~configMAX_PRIORITIES-1)。
? ? ? ??#define configMAX_PRIORITIES=5,因此工程项目中任务可用的优先级号范围为(0~4)。优先级号0被FreeRTOS内核固定分配给空闲任务;优先级号1,优先级号2,优先级号3,优先级号4都可以分配给用户任务。 ? ? ? ? 警告:优先级号5禁止分配给任务。如果优先级号5分配给任务,则会造成系统崩溃。
五、configMINIMAL_STACK_SIZE
? ? ? ? 定义空闲任务使用的堆栈大小。
? ? ? ? 通常此值不应小于对应处理器演示例程文件FreeRTOSConfig.h中定义的数值。
? ? ? ?例如,在STM32F103中,FreeRTOS Kernel V10.2.1
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 128 )
? ? ? ?在STM32F103中,堆栈大小不是以字节为单位,而是以字为单位的。在32位架构下,栈大小为128表示栈内存占用128*4=512字节的空间。
六、configTOTAL_HEAP_SIZE
? ? ? ? 配置FreeRTOS任务栈可用的RAM总量。
? ? ? ? 工程项目分配的所有任务都在该区域申请用户栈,每个任务的形参、非静态局部变量以及函数调用信息也在该区域申请空间。也就是说,工程项目中动态创建的每一个任务,都需要从configTOTAL_HEAP_SIZE空间申请栈区(称之为任务栈)。
? ? ? ? 工程项目中动态创建的每个任务从configTOTAL_HEAP_SIZE空间申请到栈区(称之为任务栈)后,该任务的形参、非静态局部变量以及函数调用信息都会使用这个栈区(称之为任务栈)进行入栈和出栈。
? ? ? ? 例如,在STM32F10X中,FreeRTOS Kernel V10.2.1
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 17 * 1024 ) )
? ? ? ? 如果实际工程项目创建的任务比较大,可以增加configTOTAL_HEAP_SIZE空间,例如:
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 25 * 1024 ) )
七、configKERNEL_INTERRUPT_PRIORITY
? ? ? ? 设置FreeRTOS内核的中断优先级(内核PendSV中断和SysTick中断使用的中断优先级),因为FreeRTOS内核中断(PendSV中断和SysTick中断)不允许抢占用户使用的中断(例如:用户的USART1中断,用户的SPI1中断),因此这个宏configKERNEL_INTERRUPT_PRIORITY一般定义为硬件最低优先级(例如:15)。
? ? ? ? 对于STM32F103 Cortex-M3 内核而言,硬件最低优先级为15。因此宏configKERNEL_INTERRUPT_PRIORITY=255,参见下图。
/* This is the raw value as per the Cortex-M3 NVIC. Values can be 255
(lowest) to 0 (1?) (highest). */
/*这是Cortex-M3 NVIC的原始值。值可以是255(最低)到0(1?)(最高)*/
#define configKERNEL_INTERRUPT_PRIORITY 255
? ? ? ? configKERNEL_INTERRUPT_PRIORITY=255和中断优先级15有什么联系呢?
? ? ? ? (1)、对于STM32F103Cortex-M3内核,只使用了8位中的高四位[7:4]作为中断优先级,低四位无任何意义,一般填充1。
? ? ? ? (2)、configKERNEL_INTERRUPT_PRIORITY=255,而255=1111?1111B,高4位的1111B=0x0F=15。所以,255就表示FreeRTOS内核的中断优先级号=15。
提示:
? ? ? ? (1)、宏configKERNEL_INTERRUPT_PRIORITY用于设置FreeRTOS内核PendSV中断和SysTick(滴答定时器)中断的中断优先级。
? ? ? ? (2)、port.c 中有如下定义:
#define portNVIC_PENDSV_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL )
#define portNVIC_SYSTICK_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL )
八、configMAX_SYSCALL_INTERRUPT_PRIORITY?
? ? ? ? 配置可受FreeRTOS内核控制的最高中断优先级号,这个宏配置的中断优先级号范围为(1~15),禁止将宏configMAX_SYSCALL_INTERRUPT_PRIORITY设置为0。
? ? ? ?警告:宏configMAX_SYSCALL_INTERRUPT_PRIORITY的设置范围为1~15,千万不能将宏configMAX_SYSCALL_INTERRUPT_PRIORITY设置为0。因为中断优先级号0是专门用于SVC中断启动任务使用的。(内核启动中断vTaskStartScheduler())
? ? ? ? 优先级号低于这个宏(configMAX_SYSCALL_INTERRUPT_PRIORITY)的硬件中断,不受FreeRTOS管控,FreeRTOS无权用taskENTER_CRITICAL()函数禁止这些硬件中断,同时也不能在这些硬件中断中调用任何FreeRTOS API函数,否则系统会有崩溃的风险。优先级号高于这个宏(configMAX_SYSCALL_INTERRUPT_PRIORITY)的硬件中断,才接受FreeRTOS的管控,FreeRTOS可以用taskENTER_CRITICAL()函数禁止这些硬件中断,FreeRTOS可以在这些硬件中断中调用FreeRTOS API函数,
? ? ? ? 在文件portmacro.h 中,将宏(configMAX_SYSCALL_INTERRUPT_PRIORITY)?写入到BASEPRI 寄存器,最终对应于taskENTER_CRITICAL()函数,参见下图。
static portFORCE_INLINE uint32_t ulPortRaiseBASEPRI( void )
{
uint32_t ulReturn, ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
__asm
{
/* Set BASEPRI to the max syscall priority to effect a critical section. */
mrs ulReturn, basepri //先读出 BASEPRI 的值,保存在 ulReturn 中
msr basepri, ulNewBASEPRI //将 configMAX_SYSCALL_INTERRUPT_PRIORITY 写入到寄存器 BASEPRI 中。
dsb
isb
}
return ulReturn; //返回 ulReturn,退出临界区代码保护的时候要使用到此值
}
? ? ? ? 例如,在STM32F10X中,FreeRTOS Kernel V10.2.1
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY不能设置为零!!!! */
/*相当于0x5F或优先级5*/
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 95 /*equivalent to 0x50, or priority 5. */
? ? ? ? 上面的代码中,配置宏configMAX_SYSCALL_INTERRUPT_PRIORITY中断优先级号为5。
? ? ? ? configMAX_SYSCALL_INTERRUPT_PRIORITY=95和中断优先级号5有什么联系呢?
? ? ? ? (1)、对于STM32F103Cortex-M3内核,只使用了8位中的高四位[7:4]作为中断优先级,低四位无任何意义,一般填充1。
? ? ? ? (2)、configMAX_SYSCALL_INTERRUPT_PRIORITY=95,而95=0101?1111B,高4位的0101B=0x05=5。所以,95就表示可受FreeRTOS管控的起始中断优先级号=5。
? ? ? ? 1、如果配置configMAX_SYSCALL_INTERRUPT_PRIORITY = 95(0x5F也即中断优先级号为5),那么,中断优先级号为0~4 ?的中断不受FreeRTOS控制,用户不能在中断优先级号为0~4 ?的中断服务程序中调用以?FromISR结尾的API函数,否则会造成系统崩溃。
? ? ? ? 2、如果配置configMAX_SYSCALL_INTERRUPT_PRIORITY = 95(0x5F也即中断优先级号为5),那么,中断优先级号为5~15 ?的中断可以接受FreeRTOS控制,用户可以在中断优先级号为5~15 ?的中断服务程序中调用以?FromISR结尾的API函数。
? ? ? ? 3、如果用户在用户任务中调用关闭中断的API函数taskENTER_CRITICAL(); 如果中断优先级号为0~4的中断触发,那么用户关中闭断的操作不起任何作用,程序仍然会跳转到中断优先级号为0~4?的中断服务程序中执行。中断优先级号为0~4的中断称之为不受FreeRTOS控制的中断(原因:configMAX_SYSCALL_INTERRUPT_PRIORITY宏配置的优先级号为5,优先级号5及5以上的硬件中断才受FreeRTOS控制的控制;优先级号低于5以下的中断不受FreeRTOS控制的控制)。
? ? ? ? 4、如果用户在用户任务中调用关闭中断的API函数taskENTER_CRITICAL(); 如果中断优先级号为5~15的中断触发,那么用户关闭中断的操作起作用,程序不会跳转到中断优先级号为5~15的中断服务程序中,仍然会执行用户任务中的程序,只有当用户任务中执行开中断API函数taskEXIT_CRITICAL();,系统才会去响应中断优先级号为5~15的中断,跳转到中断优先级号为5~15的中断服务程序中执行。
九、实例
? ? ? ?实际的工程项目需要:3个串口中断(USART1,USART2,USART3),1个定时器TIM2中断,创建5个任务,请问:该如何配置FreeRTOSConfig.h。
? ? ? ?1、配置configMAX_PRIORITIES
? ? ? ? ? ? ?由于需要创建5个任务,因此宏configMAX_PRIORITIES=6。
#define configMAX_PRIORITIES ( 6 )
? ? ? ? ? ? ?任务优先级号1,分配给用户任务vTaskVoltage_Task(void *pvParameters)
?? ? ? ? ? ? 任务优先级号2,分配给用户任务vTaskDT_Poll_Task(void *pvParameters)
?? ? ? ? ? ? 任务优先级号3,分配给用户任务vTaskDT_Parse_Task(void *pvParameters)
?? ? ? ? ? ? 任务优先级号4,分配给用户任务vFreeModbus_Task(void *pvParameters)
?? ? ? ? ? ? 任务优先级号5,分配给用户任务vGPS_Task(void *pvParameters)
? ? ? ?2、配置configTOTAL_HEAP_SIZE
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 20 * 1024 ) )
?? ? ? ?3、配置configKERNEL_INTERRUPT_PRIORITY
?? ? ? ?设置FreeRTOS内核的中断优先级=15。(内核PendSV中断和SysTick中断使用的中断优先级)? ??
/* This is the raw value as per the Cortex-M3 NVIC. Values can be 255
(lowest) to 0 (1?) (highest). */
#define configKERNEL_INTERRUPT_PRIORITY 255
?? ? ? ?4、配置configMAX_SYSCALL_INTERRUPT_PRIORITY
?? ? ? ?设置可受FreeRTOS内核控制的最高中断优先级号=5。
?? ? ? ?(1)、中断优先级号为0的中断禁止用户配置。
?? ? ? ?(2)、中断优先级号为1~4的中断不受FreeRTOS内核控制。
?? ? ? ?(3)、中断优先级号为5~15的中断受FreeRTOS内核控制。
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY不能设置为零!!!! */
/*相当于0x5F或优先级5*/
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 95 /*equivalent to 0x50, or priority 5. */
?? ? ? ?5、创建5个任务
xTaskCreate( vTaskVoltage_Task, // 任务函数
"vTaskStart", // 任务名
512, // 任务栈大小,单位word,也就是4字节
NULL, // 任务参数
tskIDLE_PRIORITY + 1, // 任务优先级
&xHandleTaskVoltage); // 任务句柄
xTaskCreate( vTaskDT_Poll_Task, // 任务函数
"vTaskDT_Poll", // 任务名
//configMINIMAL_STACK_SIZE,// 任务栈大小,单位word,也就是4字节
512, // 任务栈大小,单位word,也就是4字节
NULL, // 任务参数
tskIDLE_PRIORITY + 2, // 任务优先级
&xHandleTaskDT); // 任务句柄
xTaskCreate( vTaskDT_Parse_Task, // 任务函数
"vTaskDT_Parse", // 任务名
//configMINIMAL_STACK_SIZE,// 任务栈大小,单位word,也就是4字节
512, // 任务栈大小,单位word,也就是4字节
NULL, // 任务参数
tskIDLE_PRIORITY + 3, // 任务优先级
&xHandleTaskDT); // 任务句柄
xTaskCreate( vFreeModbus_Task, // 任务函数
"vFreeModbus", // 任务名
512, // 任务栈大小,单位word,也就是4字节
NULL, // 任务参数
tskIDLE_PRIORITY + 4, // 任务优先级
&xHandleTaskFreeModbus); // 任务句柄
xTaskCreate( vGPS_Task, // 任务函数
"vGPS", // 任务名
512, // 任务栈大小,单位word,也就是4字节
NULL, // 任务参数
tskIDLE_PRIORITY + 5, // 任务优先级
&xHandleTaskGps); // 任务句柄
?? ? ? ?6、配置NVIC中断优先级组和抢占优先级和响应优先级
? ? ? ? (1)、优先级分组设置为NVIC_PriorityGroup_4
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);?
? ? ? ??中断优先级号为1~4的中断不受FreeRTOS内核控制,中断优先级号为5~15的中断受FreeRTOS内核控制。
? ? ? ? (2)、设置USART1的抢占优先级号=5
? ? ? ? (3)、设置USART2的抢占优先级号=6
? ? ? ? (4)、设置USART4的抢占优先级号=7
? ? ? ? (5)、设置TIM2定时中断的抢占优先级号=8
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 6;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 7;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 8;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
致谢:
(20条消息) FreeRTOS内核配置说明---FreeRTOS Kernel V10.2.1_ba_wang_mao的博客-CSDN博客
|