
1. FreeRTOSConfig.h文件; ?2 S0 n5 h. Q1 Q0 A3 g- _ 1.1 "INCLUDE_"开始的宏 使用"INCLUDE_"开头的宏用来使能或失能FreeRTOS中相应的API函数,如下图,INCLUDE_vTaskPrioritySet设置为1,表示使用vTaskPrioritySet函数。1 B: g+ t$ B+ v( x ![]() R2 B4 R" k* J6 h7 s, ^& D 其作用就是条件编译,这样可以根据实际需求减少系统占用的ROM和RAM大小。在移植的FreeRTOS_CORE分组中的task.c源文件里,有如下函数,这样就理解了吧。3 W" M" }/ B- X, h ![]() 1.2 "config"开始的宏! b9 e* E# S" U3 |8 k$ L0 [ "config"开始的宏和"INCLUDE_"开头的宏作用一样,都是用来完成FreeRTOS的配置和裁剪。 4 N1 a- b# P" I' I, A ![]() 8 ~# o' l! V3 j, [# y" g; `* ~ 接下来对"config"开始的宏进行简单解读 4 @# o0 t: l) `! ]8 b$ H7 Y6 T 1)configAPPLICATION_ALLOCATED_HEAP 默认情况下FreeRTOS的堆内存是由编译器来分配的,将configAPPLICATION_ALLOCATED_HEAP定义为1可由用户自行设置,堆内存在heap_1.c、heap_2.c、heap_3.c、heap_4.c、heap_5.c有定义。在前章节移植时采用heap_4.c,如下图定义: ![]() 如果configAPPLICATION_ALLOCATED_HEAP定义为1,那么堆内存由ucHeap决定,否则由编译器来分配。 % y* e' @: n- ^) |& O 2)configASSERT FreeRTOS内核中的关键点都会用configASSERT(x),当x为0时说明有错误发生,该函数一般在调试阶段使用,因为开销较大。* M' x3 w% f9 j' n# m! j+ _- n 使用举例:- A, Z& u S1 N1 _3 ?
一般vAssertCalled()函数有用户定义,当参数x错误时通过串口打印发送错误文件名和错误号。 3)configCHECK_FOR_STACK_OVERFLOW/ n/ j* d5 ^3 g; d) d* \; r 设置堆栈溢出检测,每个任务都有一个任务堆栈:9 ]2 F" g' {+ |: B# S$ m/ o! I 若使用函数xTaskCreate()创建一个任务的话那么这个任务的堆栈是自动从FreeRTOS的堆(ucHeap)中分配的,堆栈的大小是由函数xTaskCreate()的参数usStackDepth来决定的;- a2 [* f ?7 g, T Y! G7 i) x7 V" m 若使用xTaskCreateStatic()创建任务的话,其任务堆栈是由用户设置的,参数pxStackBuffer为任务堆栈,一般是一个数组。: D4 a% [7 i$ c! b6 i3 m; { 堆栈溢出会导致应用程序不稳定。& m" B. W; c- W) E" D: w& t. P FreeRTOS提供两个机制来检测和调试堆栈溢出,即configCHECK_FOR_STACK_OVERFLOW不为0时,必须提供一个回调函数,当内核检测到堆栈溢出后就调用这个回调函数: % w/ f' v& u8 n# _+ c d& A
参数xTask是任务句柄,pcTaskName是任务名字,查看变量pxCurrentTCB可确定哪个任务发生堆栈溢出。" n! f1 u% h+ y3 u8 c8 H: n* _ 4)configCPU_CLOCK_HZ+ p( f& U* C0 ~9 `: } 设置CPU的频率 3 s! K6 a3 v3 y# A8 a" @3 ^ 5)configSUPPORT_DYNAMIC_ALLOCATION 1时,创建FreeRTOS内核对象时需要的RAM从FreeRTOS的堆中动态获取内存;0时需要用户自行提供。默认设1。; n. T& c% ^) _8 Q6 I / v; I! O) |/ Q1 t1 I 6)configENABLE_BACKWARD_COMPATIBILITY 默认1,保证代码从v8.0.0之前版本升级到最新版本后不需要修改。 7)configGENERATE_RUN_TIME_STATS 设置为1开启时间统计功能,相应API函数会被编译,且还要定义如下的宏;为0时关闭统计功能。4 M2 l" y& L1 K. ~( {9 L- E ![]() ' C0 D+ u+ q" k) l* ]6 L 8)configIDLE_SHOULD_YIELD 定义了与空闲任务(idle Task)处同等优先级的其他用户任务的行为,为0时空闲任务不会为其他处于同等优先级的任务让出CPU使用权;为1时就让出使用权,除非没有就绪的用户任务,这样话费在空闲任务上的时间会很少,但也有副作用。# {- z. _! U- | $ G6 l* x p+ K9 I ![]() ! e+ B( X5 Q2 H4 B4 M& O 参考上图进一步说明,有三个用户任务:A、B、C,还有一个空闲任务I,用户任务和空闲任务处于同一优先级,任务切换发生在T0 ~ T7时刻。T0 ~ T1之间的时间为一个时间片。开始任务后,B、C执行了一个完整的时间片,T2时刻空闲任务I开始运行,运行一段时间后被A任务抢走CPU使用权,A任务运行到T3时刻发生任务切换,B任务开始运行。可以看出任务I和任务A一起使用了一个时间片,即A任务运行时间比其他任务少。 一般建议关闭该功能。 ) ~! j) f0 N/ d: `7 ^ 9)configMAX_CO_ROUTINE_PRIORITIES& b2 ]5 q, n# |) Q( K3 f. ~ 设置可以分配给协程的最大优先级,即协程的优先级数。优先级可以从0(最低优先级) ~ configMAX_CO_ROUTINE_PRIORITIES-1(最高优先级)。5 J5 d) q7 J/ _3 E* R/ C% I a - N: b* b7 S! u9 [) T! Q- d3 Q 10)configMAX_PRIORITIES 设置任务的优先级数量,优先级从0(最低优先级) ~ configMAX_PRIORITIES-1(最高优先级)。 5 _! u+ V/ b" b: h" \ t2 [ 11)configMAX_TASK_NAME_LEN2 \/ k1 u" Z% }# c) |" }2 q! O 设置任务名最大长度。+ A. d* V2 t. t u& T3 D 12)configMINIMAL_STACK_SIZE 设置空闲任务的最小任务堆栈大小,以字为单位,不是字节。如设为100的话,则堆栈大小是100*4=400字节。 13)configNUM_THREAD_LOCAL_STORAGE_POINTERS 设置每个任务的本地存储指针数组大小,任务控制块中有本地存储数组指针,用户应用程序可以在这些本地存储中存入一些数据。 14)configQUEUE_REGISTRY_SIZE. k. d( _# t, l: ^' C6 E 设置可以注册队列和信号量的最大数量,在使用内核调试器查看信号量和队列的时候需要设置此宏,且要先将消息队列和信号量进行注册,只有注册了队列和信号量才会再内核调试器中看到。+ Y; v% c2 p6 y+ `7 o 15)configSUPPORT_STATIC_ALLOCATION 当此宏定义为1,在创建一些内核对象时需要用户指定RAM,为0时使用heap.c中的动态内存管理函数来自动申请RAM。 16)configTICK_RATE_HZ 设置FreeRTOS的系统时钟节拍频率,单位Hz,此频率就是滴答定时器的中断频率。 4 x+ [, _: L8 c# { 17)configTIMER_QUEUE_LENGTH3 x |. ]) P. } 配置FreeRTOS软件定时器的命令队列长度,软件定时器API函数会通过命令队列向软件定时器任务发送消息。 18)configTIMER_TASK_PRIORITY, o" i0 B: F8 a: Y* N 设置软件定时器任务的优先级。5 M( E6 i( ?! M& N; { & X* ~0 \# j& [" b; q 19)configTIMER_TASK_STACK_DEPTH 设置定时器服务任务的任务堆栈大小。 {2 T" i7 z/ w. y1 @ 20)configTOTAL_HEAP_SIZE 设置堆大小,如果使用了动态内存管理的话,FreeRTOS在创建任务、信号量、队列等时候会使用heap.c中的内存申请函数来申请内存。这些内存是从堆ucHeap[configTOTAL_HEAP_SIZE]中申请的,堆的大小由configTOTAL_HEAP_SIZE定义。 ) B& G! E+ h' ^" B2 v4 G# e% e 21)configUSE_16_BIT_TICKS6 k s/ h" A5 V. j* @ 设置系统节拍计数器变量数据类型,1时为16位,0时为32位。 ; ]6 X# |+ U0 e0 Q$ y( U7 F4 } 22)configUSE_APPLICATION_TASK_TAG 1时,configUSE_APPLICATION_TASK_TAGF()和xTaskCallApplicationTaskHook()会被编译。 23)configUSE_CO_ROUTINES 1时启动协程,协程可以节省开销,但功能有限。建议关闭。 24)configUSE_COUNTING_SEMAPHORES 1时开启计算型信号量。2 v8 o6 H; w6 w$ C" h4 L & @! W5 ~: b5 j2 q& L2 c/ d3 y 25)configUSE_DAEMON_TASK_STARTUP_HOOK* u: Z+ O* o' ~ p" i# _8 [' F 当宏configUSE_TIMERS和configUSE_DAEMON_TASK_STARTUP_HOOK都为1时,定义vApplicationDaemonTaskStartupHook()函数。/ T; h, L+ V0 [7 N# {+ S% M ( m& j( `- e, v: a+ V7 H 26)configUSE_IDLE_HOOK7 W* S W0 r9 n4 d+ t 1时使用空闲任务回调函数(钩子函数)。7 K: {. q) A2 w+ V* W5 O _4 ^ 27)configUSE_MALLOC_FAILED_HOOK 1时使用内存分配失败回调函数。5 j1 r' q( F+ x( p$ K$ [7 l0 p / r5 T+ _5 u/ Z 28)configUSE_MUTEXES+ J6 ]9 @, e$ y3 \$ L) L 1时使用互斥信号量。 + A+ p, A9 k( I( P: T 29)configUSE_PORT_OPTIMISED_TASK_SELECTION FreeRTOS有两种方法选择下一个要运行的任务:2 H# h- f! `- x* ^ 一是通用方法,特点如下:* T% w9 H' f" J0 p4 n! L 1)当宏configUSE_PORT_OPTIMISED_TASK_SELECTION为0,或硬件不支持时;' }& w# p. U1 m+ \3 W8 } 2)希望所有硬件通用; 3)全部用C语言实现,但效率比特殊方法低; 4)不限制最大优先级数目的时候。 二是特殊方法(硬件方法),用MCU自带硬件指令实现,特点如下:" |' @! p( { V 1)不是所有的硬件都支持;, s) `, g- @( w0 y 2)当宏configUSE_PORT_OPTIMISED_TASK_SELECTION为1时;# \4 B8 H# w( W& H x; O 3)硬件拥有特殊指令,如计算前导零(CLZ)指令; 4)比通用方法效率高; 5)会限制优先级数目,一般是32个。 / {- [+ Y+ N9 d7 }. ?; ~/ t$ z 30)configUSE_PREEMPTION% K: t. W! W& {* u2 ?- H 1时使用抢占式调度器,0时使用协程。 使用抢占式调度器时,内核会每个时钟节拍中断进行任务切换; 使用协程时,在如下地方进行任务切换: 1)一个任务调用了函数taskYIELD();2 G Q! {5 [2 c1 P& D9 G+ w 2)一个任务调用了可以使任务进入阻塞态的API函数; 3)应用程序明确定义了在中断中执行上下文切换。 8 }+ o* N/ r# E; L1 }# P5 E 31)configUSE_QUEUE_SETS- o% N2 M# B+ M- k4 G- _9 f6 Q 1时启用队列集功能。4 u6 n! N" i# l9 @4 T % B/ }( K7 e" c0 Z 32)configUSE_RECURSIVE_MUTEXES 1时使用递归互斥信号量。 * C1 O# ~' s# k. x% \' T, F 33)configUSE_STATS_FORMATTING_FUNCTIONS 宏configUSE_TRACE_FACILITY和configUSE_STATS_FORMATTING_FUNCTIONS都为1时,函数vTaskList()和vTaskGetRunTimeStats()会被编译。 34)configUSE_TASK_NOTIFICATIONS8 l( Q4 B; D1 Z( M 1时使用任务通知功能,开启后每个任务会多消耗8个字节。 35)configUSE_TICK_HOOK 1时使能时间片回调函数。; V9 c$ n% ~) N" g: m; W+ F 1 C# y, T$ D8 u# B( b 36)configUSE_TICKLESS_IDEL 1时使能低功耗tickless模式。 37)configUSE_TIMERS 1时使用软件定时器。当configUSE_TIMERS为1时,configTIMER_TASK_PRIORITY、configTIMER_QUEUE_LENGTH和configTIMER_TASK_STACK_DEPTH必须定义。; J% y) |" o7 b$ T& ?, S5 @ 38)configUSE_TIME_SLICING 默认情况,FreeRTOS使用抢占式调度器,这意味调度器永远都在执行已经就绪了的最高优先级任务,优先级相同的任务在时钟节拍中断中进行切换,当宏configUSE_TIME_SLICING为0时不会在时钟节拍中断中执行相同优先级任务的任务切换。默认设1。 0 S1 N6 ~0 l& T9 t* a 39)configUSE_TRACE_FACILITY# g! B# U( G3 v& ~% f 1时启用可视化跟踪调式。! k0 Z5 a: F. e ————————————————2 i, i& H- t9 k) f8 z( N 版权声明:天亮继续睡 + w% a! f; P* [7 \9 \6 _; _ |
OpenBLT移植到STM32F405开发板
为什么要先开启STM32外设时钟?
【STM32MP157】从ST官方例程中分析RPMsg-TTY/SDB核间通信的使用方法
【经验分享】STM32实例-RTC实时时钟实验④-获取RTC时间函数与中断服务函数
STM32 以太网 MAC Loopback 的实现
STM32功能安全设计包,助力产品功能安全认证
基于STM32启动过程startup_xxxx.s文件经验分享
HRTIM 指南
ST 微控制器电磁兼容性 (EMC) 设计指南
适用于STM32微控制器的ΣΔ数字接口入门