
在本文中,我们将继续回顾RTOS的内存部分。
Nucleus RTOS具有三个API调用,这些API调用提供了与存储分区池相关的实用程序功能:返回有关分区池的信息,返回应用程序中分区池的数量以及返回指向应用程序中所有分区池的指针。 前两个挑战是在Nucleus SE中实现的。
该系列中的先前文章:
第十四条 内存部分:简介和基本服务第十三条 任务数据结构和不受支持的API调用第十二条 任务处理服务第11条 任务:API的配置和介绍第10条 计划程序:高级功能和上下文保留第9条。 调度程序:实施第8条 Nucleus SE:内部设计和部署第7条 Nucleus SE:简介第6条。 其他RTOS服务第5条 任务交互和同步第4条 任务,上下文切换和中断第3条 任务与计划第2条。 RTOS:结构和实时模式
第1条 RTOS:简介。
检索分区池信息
该服务调用提供有关分区池的部分信息。 Nucleus SE的实现与Nucleus RTOS的不同之处在于,它返回的信息较少,因为不支持命名对象和暂停请求,并且无法暂停任务。
在Nucleus RTOS中调用分区池信息
调用原型:
状态NU_Partition_Pool_Information(NU_PARTITION_POOL *池,CHAR *名称,VOID **起始地址,UNSIGNED * pool_size,UNSIGNED * partition_size,UNSIGNED *可用,UNSIGNED *已分配,选项* suspend_type,UNSIGNED * task_waiting ** first_task;第一参数:
池 -指向有关其信息的分区池的指针;
name-指向分区池名称的8个字符目标区域的指针; 包括一个终止零的位置;
start_address-指向变量的指针,该变量接收一个指向分区池数据区开头的指针;
pool_size-指向接收分区池大小(以字节为单位)的变量的指针;
partition_size-指向变量的指针,该变量获取给定池中分区的大小;
可用 -指向变量的指针,该变量接收该池中当前可用的分区数;
已分配 -指向变量的指针,该变量接收给定池中当前使用的分区数;
suspend_type-指向获取任务挂起类型的变量的指针; 有效的挂起类型:
NU_FIFO和
NU_PRIORITY ;
task_waiting-指向一个变量的指针,该变量接收给定分区池中挂起的任务数;
first_task-指向第一个挂起任务的指针所在的任务指针的指针。
返回值:
NU_SUCCESS-调用成功完成;
NU_INVALID_POOL-指向分区池的无效指针。
在Nucleus SE中调用分区池信息
调用原型:
状态NUSE_Partition_Pool_Information(NUSE_PARTITION_POOL池,ADDR *起始地址,U32 * pool_size,U16 * partition_size,U8 *可用,U8 *已分配,U8 * task_waiting,NUSE_TASK * first_task)参数:
pool-请求有关信息的分区池的索引;
start_address-指向变量的指针,该变量接收一个指向分区池数据区开头的指针;
pool_size-指向接收分区池大小(以字节为单位)的变量的指针;
partition_size-指向变量的指针,该变量获取给定池中分区的大小;
可用 -指向变量的指针,该变量接收该池中当前可用的分区数;
已分配 -指向变量的指针,该变量接收给定池中当前使用的分区数;
task_waiting-指向一个变量的指针,该变量接收此分区池中已挂起的任务数(如果禁用了任务挂起,则返回0);
first_task-指向类型为
NUSE_TASK的变量的指针,该变量接收第一个挂起任务的索引(如果禁用了任务挂起,则返回0)。
返回值:
NUSE_SUCCESS-呼叫成功完成;
NUSE_INVALID_POOL-无效的分区池索引;
NUSE_INVALID_POINTER-传递的一个或多个指针无效。
在Nucleus SE中实现信息检索和分区合并
实现这样的API调用很容易执行:

该函数返回分区池的状态。 然后,如果激活了API调用阻止,则将返回挂起的任务数和它们中第一个的索引(否则,这些参数设置为0)。
获取分区池数
该调用返回有关在应用程序中配置的分区池数量的信息。 在Nucleus RTOS中,此数字会随着时间变化,返回值将代表当前的池数,而在Nucleus SE中,返回值是在组装期间设置的,并且保持不变。
在Nucleus RTOS中获取分区池数量的挑战
该调用支持Nucleus RTOS API的核心功能。
调用原型:
UNSIGNED NU_Established_Partition_Pools(VOID);参数:
缺席。
返回值:
在应用程序中创建的分区池的数量。
在Nucleus SE中获取分区池数量的挑战
该实用程序调用支持Nucleus RTOS API的核心功能。
调用原型:
U8 NUSE_Partition_Pool_Count(无效);参数:
缺席
返回值:
在应用程序中创建的分区池的数量。
实作
此API调用的实现非常简单:
返回NUSE_PARTITION_POOL_NUMBER符号的
#define值。
资料结构
与所有其他Nucleus SE对象一样,分区池在ROM和RAM中都使用结构数组,其数量取决于设置中指定的池数量。
我强烈建议应用程序代码通过API函数而非直接访问此类数据结构。 这样可以避免与Nucleus SE的未来版本不兼容以及不必要的副作用,并且还简化了将应用程序移植到Nucleus RTOS的过程。 以下是对数据结构的详细描述,以帮助理解服务调用代码和调试。
放在RAM中的内核数据的结构
这些数据结构包括:
NUSE_Partition_Pool_Partition_Used [] -类型为
U8的数组,每个配置的分区池都有一个条目,其中包含当前使用的池的计数器;
NUSE_Partition_Pool_Blocking_Count [] -类型为
U8的数组,其中包含每个分区池中已阻止任务的计数器。 如果可以阻止API调用,则此数组存在。
启动Nucleus SE时,使用
NUSE_Init_ Partition_Pool()将此类数据结构初始化为零。 这是合乎逻辑的,因为它使每个池中的每个分区都未使用(空闲)。 下面的文章将提供Nucleus SE中启动过程的完整说明。
以下是对
nuse_init.c文件中数据结构的
描述 。

RAM用户数据
用户需要在RAM中分配一个区域来存储每个分区池的数据。 RAM中的空间量必须对应于已配置分区的容量(请参见下面的“ ROM中的数据”),并为池中的每个分区增加一个字节。 数据区的每一节前面都有一个状态字节。
ROM数据
这些包括:
NUSE_Partition_Pool_Data_Address []-ADDR类型的数组,每个配置的分区池都有一个条目,其中包含数据存储区开始的地址;
NUSE_Partition_Pool_Partition_Number []-U8类型的数组,每个配置的分区池都有一个条目,其中包含有关池中分区数量的信息;
NUSE_Partition_Pool_Partition_Size []-U16类型的数组,每个配置的分区池都有一个条目,其中包含池的分区大小。
此类数据结构在
nuse_config.c中声明和初始化(静态):

分区池的数据占用量
与Nucleus SE中的所有核心对象一样,分区池所需的内存量是可以预测的。
可以如下计算所有应用程序分区池的ROM大小(以字节为单位):
NUSE_PARTITION_POOL_NUMBER *(sizeof(ADDR)+ 2)激活API调用阻止时,所有应用程序分区池的RAM中的内核数据量每个分区池仅占用2个字节,而未激活阻止时,它占用1个字节。
对于每个分区池,用于在RAM中存储用户数据的内存量各不相同,尽管如上所述,对于索引为n的池,可以将其计算为:
NUSE_Partition_Pool_Partition_Number [n] *(NUSE_Partition_Pool_Partition_Size [n] + 1)未实现的API调用
Nucleus SE不支持对Nucleus RTOS中实现的分区池的三个API调用。
创建分区池
此API调用创建一个分区池。 Nucleus SE不需要它,因为任务是静态创建的。
调用原型:
状态NU_Create_Partition_Pool(NU_PARTITION_POOL *池,CHAR *名称,VOID *起始地址,UNSIGNED pool_size,UNSIGNED partition_size,OPTIONsuspant_type);参数:
pool-指向用户定义的分区
池控制单元的指针; 在其他API调用中用作分区池的句柄;
name-指向分区池名称的指针,它是一个7字符的字符串,结尾为零;
start_address-设置分区池的内存区域的起始地址;
pool_size-内存总量(以字节为单位);
partition_size-池中每个分区的内存量(以字节为单位)。 最重要的是,为每个节分配了额外的少量内存,这要归功于所使用的两个数据指针。
suspend_type-确定如何在分区池中挂起任务; 有效的参数选项是
NU_FIFO和
NU_PRIORITY 。
返回值:
NU_SUCCESS-指示呼叫成功完成;
NU_INVALID_POOL-指示分区池控制单元的零值(
NULL );
NU_INVALID_MEMORY-表示由
start_ address (
NULL )定义的存储区域的零值;
NU_INVALID_SIZE-指示分区大小为0或大于为该分区分配的内存;
NU_INVALID_SUSPEND-无效的
suspend_type值。
删除分区池
此API调用将删除以前创建的分区池。 Nucleus SE不需要它,因为对象是静态创建的,无法删除。
调用原型:
状态NU_Delete_Partition_Pool(NU_PARTITION_POOL *池);参数:
pool-指向分区池控制单元的指针;
返回值:
NU_SUCCESS-指示呼叫成功完成;
NU_INVALID_POOL-指示分区池指针的值无效;
分区池指针
此API调用将建立指向系统中所有分区池的指针的顺序列表。 Nucleus SE不需要这样做,因为对象是由索引而不是指针标识的。
调用原型:
UNSIGNED NU_Partition_Pool_Pointers(NU_PARTITION_POOL **指针列表,UNSIGNED maximum_pointers);参数:
pointer_list-指针数组
NU_PARTITION_POOL的指针; 数组中填充了指向系统中已配置池的指针;
maximum_pointers-可以放置在数组中的最大指针数。
返回值:
放置在数组中的
NU_PARTITION_POOL指针的数量。
兼容Nucleus RTOS
开发Nucleus SE时,主要任务之一是确保与Nucleus RTOS的代码高度兼容。 分区池也不例外,从开发人员的角度来看,它们的实现方式与Nucleus RTOS中的实现方式几乎相同。 现有的一些不兼容领域是可以接受的,尽管值得考虑的是最终代码在内存方面更易于理解和更有效。 但是,Nucleus RTOS API调用几乎可以直接用作Nucleus SE调用。 计划在未来的文章中提供有关Nucleus RTOS用户使用Nucleus SE的信息。
对象标识符
在Nucleus RTOS中,所有对象均由特定类型的数据结构(控制单元)描述。 指向该控制块的指针用作分区池的标识符。 我认为Nucleus SE需要一种不同的方法来更有效地使用内存。 RAM和/或ROM中的几个表描述了所有内核对象。 这些表的大小由所有对象的可配置类型的数量确定。 特定对象的标识符是这些表中的索引。 因此,我确定
NUSE_PARTITION_POOL等效于
U8 ,此后此类型的变量(而非指针)用作任务的标识符。 如果代码是从Nucleus RTOS移植或移植到Nucleus RTOS,则很容易发现这种轻微的不兼容性。 对象标识符通常被存储和发送不变。
Nucleus RTOS还支持命名分区池。 这些名称仅用于调试。 我从Nucleus SE中排除了它们以节省内存。
节数及其数量
在Nucleus RTOS中,分区池是根据池的总容量和分区的容量(带有2个指针)配置的。 这些参数定义为UNSIGNED(大约32位)。 在Nucleus SE中,分区池是根据分区的大小(已为其添加一个额外的字节)和分区总数配置的。 这些参数分别定义为U16和U8。
未实现的API调用
Nucleus RTOS支持使用7个分区池调用,其中3个未在Nucleus SE中实现。 上面概述了有关这些挑战及其被排除的原因的更多详细信息。
下一篇文章将讨论信号。
关于作者: Colin Walls在电子行业工作了30多年,大部分时间用于固件。 他现在是Mentor Embedded(Mentor Graphics的一个部门)的固件工程师。 Colin Walls经常在会议和研讨会上发表演讲,他撰写了许多技术文章并撰写了两本有关固件的书。 居住在英国。
Colin的专业
博客 ,电子邮件:colin_walls@mentor.com。