深入解析FreeRTOS任务调度与内存管理机制及其在嵌入式系统中的应用
摘要:FreeRTOS是一款开源的免费嵌入式实时操作系统。通过研究其内核,我们可以更好地理解嵌入式操作系统的实现原理。本文主要讲解FreeRTOS系统中的任务调度机制、时间管理机制、任务管理。介绍了内存分配策略的机制和实现原理,并指出了FreeRTOS在应用中的优缺点。

在嵌入式领域,嵌入式实时操作系统的应用越来越广泛。采用嵌入式实时操作系统(RTOS)可以更加合理有效地利用CPU资源,简化应用软件的设计,缩短系统开发时间,更好地保证系统的实时性和可靠性。由于RTOS需要一定的系统资源(特别是RAM资源),因此只有μC/OS-II、embOS、salvo和FreeRTOS等少数实时操作系统可以在小RAM微控制器上运行。与C/OS-II、embOS等商业操作系统相比,FreeRTOS操作系统是完全免费的操作系统。具有代码开源、可移植、精简、调度策略灵活等特点。它可以很容易地移植到各种微控制器上运行。 ,其最新版本为2.6版本。
1.FreeRTOS操作系统功能
FreeRTOS作为一个轻量级操作系统,提供的功能包括:任务管理、时间管理、信号量、消息队列、内存管理、记录功能等,基本可以满足较小系统的需求。 FreeRTOS 内核支持优先级调度算法。可以根据每个任务的重要性为其分配一定的优先级。 CPU总是允许处于就绪状态且优先级最高的任务先运行。 FreeRT0S内核还支持轮转调度算法。系统允许不同的任务使用相同的优先级。当没有更高优先级任务就绪时,相同优先级的任务共享CPU使用时间。
FreeRTOS的内核可以根据用户需要设置为抢占式内核或非抢占式内核。当FreeRTOS设置为抢占式内核时,处于就绪状态的高优先级任务可以剥夺低优先级任务的CPU使用权,从而保证系统满足实时性要求;当FreeRTOS设置为非抢占式内核时,处于就绪状态的高优先级任务只有在当前运行的任务主动释放CPU使用权后才能运行,这样可以提高CPU的运行效率。
2. FreeRTOS操作系统原理及实现
2.1 任务调度机制的实现
任务调度机制是嵌入式实时操作系统的重要概念及其核心技术。对于可剥夺核,高优先级任务可以在就绪后剥夺低优先级任务的CPU使用权,提高系统的实时响应能力。与μC/OS-II不同的是,FreeRTOS对系统任务数量没有限制,同时支持优先级调度算法和轮换调度算法。因此,FreeRTOS使用双向链表而不是检查任务就绪表来进行任务调度。系统定义的链表和链表节点数据结构如下:
FreeRTOS 将就绪任务列表数组定义为 xList pxReady—TasksLists[portMAX_PRIORITIES]。其中,portMAX_PRIORITIES为系统定义的最大优先级。如果想让优先级为n的任务进入就绪状态,需要将这个任务对应的TCB中的节点xGenericListItem插入到链表pxReadyTasksLiStS[n]中,同时将xGenericListItem中的pvContainer指向pxReadyTasksLists[n]为了实现这一点。
调度算法在调度任务时,首先实现优先级调度。系统按照优先级从高到低的顺序,在就绪任务列表数组中查找优先级不为0的usNumberOfItems。该优先级是当前最高的就绪优先级,并据此进行优先级调度。如果该优先级下只有一个就绪任务,则就绪任务进入运行状态;如果该优先级下有多个就绪任务,则需要采用轮转调度算法来轮流执行多个任务。
如果轮转调度算法在优先级n下执行,系统首先通过执行(pxReadyTasksLists[n])→pxIndex=(pxReadyTasks-Lists[n])→pxlndex→pxNext语句获取当前节点指向的下一个节点,然后通过该节点的pvOwner指针获取对应的任务控制块,最终该任务控制块对应的任务进入运行状态。可见,在FreeRTOS中,相同优先级的任务之间的切换时间为1个时钟周期。
以图1为例,假设系统最大任务数为pottMAX_PRIORITIES,在某时刻进行任务调度时,得到pxReadyTasksLists[i]。 usNumberOfItems=O(i=2...portMAX_PRIORITIES) 和 pxReadyTasksLists[1]。 usNumberOfItems=3。由此,内核可以知道当前最高的就绪优先级为l,该优先级下的3个任务已经进入就绪状态。由于最高就绪优先级下存在多个就绪任务,因此系统需要执行轮转调度算法来实现任务切换;通过指针pxlndex,我们知道任务l是当前任务,而任务l的pxNext节点指向任务2,因此系统将pxIndex指向任务2。并执行任务2,实现任务调度。当下一个时钟节拍到来时,如果最高就绪优先级仍然为1,从图中可以看出,系统会将pxIndex指向任务3,并执行任务3。
图1 任务调度示意图
为了加速任务调度,FrecRTOS通过变量ucTopReadyPriority来跟踪当前就绪的最高优先级。将任务添加到就绪列表时,如果该任务的优先级高于ucTopReadyPriority,则将该任务的优先级分配给ucTopReadyPriority。这样,在进行优先级调度时,调度算法并不是从portMAX_PRIORITIES开始查找,而是从ucTopReady-Priority开始查找。这可以加快搜索速度并减少核心关闭时间。
为了加速任务调度,FrecRTOS通过变量ucTopReadyPriority来跟踪当前就绪的最高优先级。将任务添加到就绪列表时,如果该任务的优先级高于ucTopReadyPriority,则将该任务的优先级分配给ucTopReadyPriority。这样,在进行优先级调度时,调度算法并不是从portMAX_PRIORITIES开始查找,而是从ucTopReady-Priority开始查找。这可以加快搜索速度并减少核心关闭时间。
2.3 时间管理的实施
FreeRTOS提供的典型时间管理函数是vTaskDelay()。调用该函数可以将任务延迟特定的时间。在FreeRT0S中,如果任务需要延迟xTicksToDelay时钟节拍,系统内核会将xTicksToDelay加上当前系统已运行的时钟节拍总数(定义为xTickCount,32位长度)以获得时钟节拍数xTimeToWake 任务下次唤醒时。 。然后,内核从就绪链表中删除该任务的任务控制块,并将xTimeToWake作为节点值赋给该任务的xItemValue,然后根据xTimeToWake的值将任务控制块依次插入到不同的链表中。如果xTimeToWake > xTickCount,即计算没有溢出,内核将任务控制块插入到pxDelayedTaskList链表中;如果xTimeToWake < xTickCount,即计算过程中发生溢出,内核将任务控制块插入到pxOverflowDelayed-Taskust链表中。
每发生一个时钟节拍,内核都会将当前的xTick-Count加1。如果xTickCount的结果为0,即发生溢出,内核将使用pxOverflowDelayedTaskList作为当前链表;否则,内核将使用 pxDelaycdTaskList 作为当前链表。内核依次将xTickCotlrtt与链表中每个节点的xTimcToWake进行比较。如果xTick-Count等于或大于xTimeToWake,则意味着延迟时间已过,应将该任务从等待列表中删除并添加到就绪列表中。
可见,与μC/OS-II不同的是,FreeRTOS采用了“附加”的方式来实现时间管理。优点是时间tick函数的执行时间基本与任务数量无关,而μC/OS-II的OSTimcTick()的执行时间与应用程序中建立的任务数量成正比。因此,当任务较多时,FreeRTOS采用的时间管理方法可以有效加快时钟中断程序的执行速度。
2.4 内存分配策略
每当创建任务、队列和信号量时,FreeRTOS 都需要分配一定量的 RAM。虽然malloc()和free()函数可以用来申请和释放内存,但这两个函数有以下缺点:它们并不是在所有嵌入式系统中都可用,占用程序空间量不定,并且不能使用以人性化的方式。缺乏和执行时间是不确定的。为此,除了 malloc() 和 free() 函数之外,FreeRTOS 还提供了另外两种内存分配策略。用户可以根据实际需要选择不同的内存分配策略。
第一种方法是简单地将一大块内存根据所需内存的大小划分为几个小块,每个小块的大小与所需内存的大小相对应。这样做的好处是比较简单,并且可以严格确定执行时间。适合所有任务和队列创建完成后进行内核调度的系统。这样做的缺点是,由于内存无法有效释放,导致系统运行时应用程序无法执行。删除任务或队列。
第二种方法是使用链表分配内存,可以动态创建和删除任务或队列。系统根据空闲内存块的大小,按照升序组织空闲内存链表。当应用程序申请一块内存时,系统会根据所申请内存的大小依次查找空闲内存列表,找到满足所申请内存需求的最小空闲内存块。为了提高内存使用效率,当空闲内存块大于所申请的内存时,系统会将空闲内存块一分为二。使用一个块来满足内存申请需求,将一个块插入到链表中作为新的空闲内存块。
2.3 时间管理的实施
FreeRTOS提供的典型时间管理函数是vTaskDelay()。调用该函数可以将任务延迟特定的时间。在FreeRT0S中,如果任务需要延迟xTicksToDelay时钟节拍,系统内核会将xTicksToDelay加上当前系统已运行的时钟节拍总数(定义为xTickCount,32位长度)以获得时钟节拍数xTimeToWake 任务下次唤醒时。 。然后,内核从就绪链表中删除该任务的任务控制块,并将xTimeToWake作为节点值赋给该任务的xItemValue,然后根据xTimeToWake的值将任务控制块按顺序插入到不同的链表中。如果xTimeToWake > xTickCount,即计算没有溢出,内核将任务控制块插入到pxDelayedTaskList链表中;如果xTimeToWake < xTickCount,即计算过程中发生溢出,内核将任务控制块插入到pxOverflowDelayed-Taskust链表中。
每发生一个时钟节拍,内核都会将当前的xTick-Count加1。如果xTickCount的结果为0,即发生溢出,内核将使用pxOverflowDelayedTaskList作为当前链表;否则,内核将使用 pxDelaycdTaskList 作为当前链表。内核依次将xTickCotlrtt与链表中每个节点的xTimcToWake进行比较。如果xTick-Count等于或大于xTimeToWake,则意味着延迟时间已过,应将该任务从等待列表中删除并添加到就绪列表中。
可见,与μC/OS-II不同,FreeRTOS采用了“附加”的方式来实现时间管理。优点是时间tick函数的执行时间基本与任务数量无关,而μC/OS-II的OSTimcTick()的执行时间与应用程序中建立的任务数量成正比。因此,当任务较多时,FreeRTOS采用的时间管理方法可以有效加快时钟中断程序的执行速度。
2.4 内存分配策略
每当创建任务、队列和信号量时,FreeRTOS 都需要分配一定量的 RAM。虽然malloc()和free()函数可以用来申请和释放内存,但这两个函数有以下缺点:它们并不是在所有嵌入式系统中都可用,占用程序空间量不定,并且不能使用以人性化的方式。缺乏和执行时间是不确定的。为此,除了 malloc() 和 free() 函数之外,FreeRTOS 还提供了另外两种内存分配策略。用户可以根据实际需要选择不同的内存分配策略。
第一种方法是简单地将一大块内存根据所需内存的大小划分为几个小块,每个小块的大小与所需内存的大小相对应。这样做的好处是比较简单,可以严格确定执行时间。适合所有任务和队列创建完成后进行内核调度的系统。这样做的缺点是,由于内存无法有效释放,导致系统运行时应用程序无法执行。删除任务或队列。
第二种方法是使用链表分配内存,可以动态创建和删除任务或队列。系统根据空闲内存块的大小,按照升序组织空闲内存链表。当应用程序申请一块内存时,系统会根据所申请内存的大小,依次查找空闲内存列表,找到满足所申请内存需求的最小空闲内存块。为了提高内存使用效率,当空闲内存块大于所申请的内存时,系统会将空闲内存块一分为二。使用一个块来满足内存申请需求,将一个块插入到链表中作为新的空闲内存块。
下面以图2为例介绍方法2的实现。假设动态分配的RAM总共为8KB。系统首先初始化空闲内存块列表,并将所有8KB RAM视为一个空闲内存块。当应用程序分别申请1KB和2KB内存时,空闲内存块的大小变为5KB3。当2KB内存用完后,系统需要将2KB插入到已有的空闲内存块链表中。自 2 KB
图2 使用空闲内存块链表进行内存管理
方法2的优点是可以根据任务需要高效地使用内存,特别是当不同的任务需要不同大小的内存时。方法二的缺点是应用程序释放的内存不能与原来的空闲内存混合。因此,如果应用程序频繁地申请和释放“随机”大小的内存,则可能会造成大量的内存碎片。这就要求应用程序请求和释放的内存大小是一个“有限”的固定值(图2中,请求和释放的内存大小固定为l KB、2 KB或3 KB)。方法2的另一个缺点是程序执行时间具有一定程度的不确定性。
μC/OS-II提供的内存管理机制通过分区来管理连续的大块内存,每个分区包含整数个相同大小的内存块。由于每个分区大小相同,即使频繁申请和释放内存也不会产生内存碎片,但缺点是内存利用率比较低。当申请和释放的内存大小均为固定值(例如均为2KB)时,FreeRTOS的方法2内存分配策略可以达到类似于μC/OS-II的内存管理效果。
2.5 FreeRTOS移植
FreeRTOS操作系统可以很容易地移植到不同的处理器上工作。现提供ARM、MSP430、AVR、PIC、C8051F等多种处理器的移植。 FreeRTOS在不同处理器上的移植与μC/0S-II类似,因此本文不再详细介绍FreeRTOS的移植。另外,TCP/IP协议栈μIP已经移植到FreeRTOS上,具体代码可以在FreeRTOS网站上找到。
2.6 FreeRTOS的缺点
与常见的μC/OS-II操作系统相比,FreeRTOS操作系统既有优点也有缺点。它的缺点,一方面体现在系统的服务功能上。例如,FreeRTOS只提供了消息队列和信号量的实现,无法按照后进先出的顺序向消息队列发送消息;另一方面,FreeRTOS 只是一个操作系统。内核需要通过第三方GUI(图形用户界面)、TCP/IP协议栈、FS(文件系统)等进行扩展,以实现更复杂的系统。与μC/OS-II不同,它可以与μC/GUI、μC/FS、μC/TCP-IP等无缝集成。
三、结论
作为一个开源代码的操作系统,学习FreeRTOS可以更好的掌握嵌入式实时操作系统的实现原理;作为免费操作系统,使用FreeRTOS可以降低系统成本、简化开发,同时基本满足较小系统的需求。困难。实际应用中,FreeRTOS操作系统与MSP430单片机组成的温度控制系统稳定可靠,取得了良好的控制效果。相信随着时间的发展,FreeRTOS会不断完善其功能,更好地满足人们对嵌入式操作系统实时性、可靠性、易用性的要求。