完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
转rtx操作系统
本章节为大家讲解RTX支持的内存管理。 本章教程配套的例子含Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407。 18.1 内存管理介绍 18.2 内存管理API函数 18.3 实验例程说明(4字节对齐) 18.4 实验例程说明(8字节对齐) 18.5 总结 18.1 内存管理介绍 在ANSIC中,可以用malloc()和free()2个函数动态的分配内存和释放内存,但是,在嵌入式实时操作系统中,调用malloc()和free()却是危险的,因为多次调用这两个函数会把原来很大的一块连续内场区域逐渐地分割成许多非常小而且彼此又不相邻的内存块,也就是内存碎片。由于这些内存碎片的大量存在,使得程序到后来连一段非常小的连续内存也分配不到。另外,由于内存管理算法上的原因,malloc()和free()函数的执行时间是不确定的。 在RTX中,操作系统把连续的大块内存按分区来管理。每个分区中包含整数个大小相同的内存块。如图18.1所示: 图18.1 内存分区 利用这种机制,就可以得到和释放固定大小的内存块。这样内存的申请和释放函数的执行时间就是确定的了。 在一个系统中可以有多个内存分区,这样,应用程序就可以从不同的内存分区中得到不同大小的内存块。但是特定的内存块在释放时,必须重新放回到它以前所属于的内存分区。显然,采用这样的内存管理算法,上面的内存碎片文件就得到了解决。 其实RTX的内存管理也非常好理解,可以理解成一个二维数组,比如我们定义一个二维数组为:uint8_t mpool[10][32]。对应到RTX的内存管理上就是定义了10个内存块,每块大小是32字节。如果还需要其它大小的内存块,还可以多定义几个其它大小的。 |
|
相关推荐
|
|
18.2 内存管理API函数
使用如下7个函数可以实现RTX的内存管理: u _declare_box u _declare_box8 u _init_box u _init_box8 u _alloc_box u _calloc_box u _free_box 关于这7个函数的讲解及其使用方法可以看教程第3章3.3小节里面说的参考资料rlarm.chm文件 这里我们重点的说一下函数_declare_box,_declare_box8,_init_box,_init_box8,_alloc_box和_free_box。 |
|
|
|
|
|
18.2.1 函数_declare_box
函数原型: [url=]复制代码[/url]
函数描述: 函数_declare_box用于定义一块内存池。 u 第1个参数填写内存池的变量名。 u 第2个参数填写内存块的大小,单位字节。 u 第3个参数填写内存池中内存块的个数。 使用这个函数要注意以下问题: 1. 宏定义中通过操作(size+3)/4保证了每个内存块大小是4字节的倍数,从而也就保证了每个内存块的首地址是4字节对齐的(4字节对齐的含义是地址对4求余等于0)。这里初学者也要注意数据类型的字节对齐问题。 基本数据类型的字节对齐问题 这个问题在MDK5安装目录里面的文档DUI0375G_02_mdk_armcc_user_guide.pdf里面有详细的说明, 简单的说明,数据类型有几个字节,那么这个数据类型的变量就是几字节对齐,比如32位的int型 有4个字节,那么此int型定义的变量就是4字节对齐,对于初学者要牢牢的记住这个知识点。 |
|
|
|
|
|
2. 内存池中额外定义的12个字节用于将内存块做指针链表,方便动态的申请和释放。
使用举例: 复制代码 #include #define PoolBlocks 10 #define PoolPerBlockSize 8 /* 声明一个内存池,10块,每块大小8字节 */ _declare_box(mpool, PoolPerBlockSize, PoolBlocks); |
|
|
|
|
|
18.2.2 函数_declare_box8
函数原型: 复制代码 #define _declare_box8( pool, /* 内存池变量名 */ size, /* 内存块大小,单位字节 */ cnt ) /* 内存池中内存块的个数 */ U64 pool[((size+7)/8)*(cnt) + 2] 函数描述: 函数_declare_box用于定义一块内存池。 u 第1个参数填写内存池的变量名。 u 第2个参数填写内存块的大小,单位字节。 u 第3个参数填写内存池中内存块的个数。 使用这个函数要注意以下问题: 1. 宏定义中通过操作(size+7)/8保证了每个内存块大小是8字节的倍数,从而也就保证了每个内存块的首地址是8字节对齐的(8字节对齐的含义是地址对8求余等于0)。这里初学者也要注意数据类型的字节对齐问题。 2. 内存池中额外定义的16个字节用于将内存块做指针链表,方便动态的申请和释放。 使用举例: 复制代码 #include #define PoolBlocks 10 #define PoolPerBlockSize 8 /* 声明一个内存池,10块,每块大小8字节 */ _declare_box8(mpool, PoolPerBlockSize, PoolBlocks); |
|
|
|
|
|
18.2.3 函数_init_box
函数原型: 复制代码 int _init_box ( void* box_mem, /* 内存池首地址 */ U32 box_size, /* 内存池大小,单位字节 */ U32 blk_size ); /* 内存块大小,单位字节 */ 函数描述: 函数_init_box用于内存池的初始化,初始化时用到的参数都是源自于_declare_box。 u 第1个参数填写内存池的首地址。 u 第2个参数填写内存池的大小,单位字节。 u 第3个参数填写内存块大小,单位字节。 使用这个函数要注意以下问题: 1. 强烈建议跟函数_declare_box一起使用。用户不要自己去初始化这个函数,用_declare_box声明的才是最保险的。 2. 如果用户没有使用函数_declare_box进行定义,那么要保证内存池首地址是4字节对齐的。 3. 如果用户没有使用函数_declare_box进行定义,那么要保证内存池的大小box_size至少有12个字节,因为这个12个字节是用于将内存块做成指针链表,方便动态申请和释放。 |
|
|
|
|
|
使用举例:
复制代码 #include #define PoolBlocks 10 #define PoolPerBlockSize 8 /* 声明一个内存池,10块,每块大小8字节 */ _declare_box(mpool, PoolPerBlockSize, PoolBlocks); /* ********************************************************************************************************* * 函 数 名: AppObjCreate * 功能说明: 创建任务通信机制 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ static void AppObjCreate (void) { /* 初始化内存池,4字节对齐,*/ _init_box (mpool, sizeof (mpool), PoolPerBlockSize); } |
|
|
|
|
|
18.2.4 函数_init_box8
函数原型: 复制代码 int _init_box ( void* box_mem, /* 内存池首地址 */ U32 box_size, /* 内存池大小,单位字节 */ U32 blk_size ); /* 内存块大小,单位字节 */ 函数描述: 函数_init_box8用于内存池的初始化,初始化时用到的参数都是源自于_declare_box8。 u 第1个参数填写内存池的首地址。 u 第2个参数填写内存池的大小,单位字节。 u 第3个参数填写内存块大小,单位字节。 使用这个函数要注意以下问题: 1. 强烈建议跟函数_declare_box8一起使用。用户不要自己去初始化这个函数,用_declare_box声明的才是最保险的。 2. 如果用户没有使用函数_declare_box8进行定义,那么要保证内存池首地址是8字节对齐的。 3. 如果用户没有使用函数_declare_box8进行定义,那么要保证内存池的大小box_size至少有16个字节,因为这个16个字节是用于将内存块做成指针链表,方便动态申请和释放。 |
|
|
|
|
|
使用举例:
复制代码 #include #define PoolBlocks 10 #define PoolPerBlockSize 8 /* 声明一个内存池,10块,每块大小8字节 */ _declare_box8(mpool, PoolPerBlockSize, PoolBlocks); /* ********************************************************************************************************* * 函 数 名: AppObjCreate * 功能说明: 创建任务通信机制 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ static void AppObjCreate (void) { /* 初始化内存池,4字节对齐,*/ _init_box8 (mpool, sizeof (mpool), PoolPerBlockSize); } |
|
|
|
|
|
18.2.5 函数_alloc_box
函数原型: 复制代码 void *_alloc_box ( void* box_mem ); /* 内存池的首地址 */ 函数描述: 函数_alloc_box用于从首地址是box_mem的内存池中申请一个内存块。 u 第1个参数填写内存池的首地址。 使用这个函数要注意以下问题: 1. 调用此函数前,一定要使用函数_init_box或者_init_box8进行初始化。 2. 函数_alloc_box支持重入,而且是线程安全的,也即是说用户可以没有限制的在主函数和中断中调用此函数。 |
|
|
|
|
|
18.2.6 函数_free_box
函数原型: 复制代码 int _free_box ( void* box_mem, /* 内存池首地址 */ void* box ); /* 要释放的内存块首地址 */ 函数描述: 函数_free_box用于释放使用函数_alloc_box申请的内存块。 u 第1个参数填写内存池的首地址。 u 第2个参数填写要释放的内存块首地址。 使用这个函数要注意以下问题: 1. 此函数的第二个参数必须要填写正确,也就是用户使用的时候最好配套_alloc_box一起使用。 2. 函数_alloc_box支持重入,而且是线程安全的,也即是说用户可以没有限制的在主函数和中断中调用此函数。 |
|
|
|
|
|
18.3 实验例程说明(4字节对齐)
18.3.1 STM32F103开发板实验 配套例子: V4-417_RTX实验_内存管理(4字节对齐) 实验目的: 1. 学习RTX的内存管理(4字节对齐)。 2. 函数_declare_box和_init_box用于4字节对齐的内存池初始化。这里4字节对齐的含义 a.内存池的首地址是4字节对齐(4字节对齐就是地址对4求余等于0)。 b.每个内存块大小也得是4字节的倍数,这样才能保证每申请到的一个内存块的首地址也是4字节对齐。 c.4字节对齐是由RTX系统完成的。 实验内容: 1. K1按键按下,串口打印。 2. K2键按下,申请一个内存块用于8位整形变量,然后向消息邮箱发送数据。 3. K3键按下,申请一个内存块用于16位整形变量,然后向消息邮箱发送数据。 4. 摇杆OK键按下,申请一个内存块用于32位整形变量,然后向消息邮箱发送数据。 5. 各个任务实现的功能如下: AppTaskUserIF任务 :按键消息处理。 AppTaskLED任务 :LED闪烁。 AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。 AppTaskStart任务 :启动任务,也是最高优先级任务,这里实现按键扫描。 |
|
|
|
|
|
RTX配置:
RTX配置向导详情如下: u Task Configuration l Number of concurrent running tasks 允许创建4个任务,实际创建了如下四个任务: AppTaskUserIF任务 :按键消息处理。 AppTaskLED任务 :LED闪烁。 AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。 AppTaskStart任务 :启动任务,也是最高优先级任务,这里实现按键扫描。 l Number of tasks with user-provided stack 创建的4个任务都是采用自定义堆栈方式。 |
|
|
|
|
|
程序设计:
u 任务栈大小分配: staticuint64_t AppTaskUserIFStk[512/8]; /* 任务栈 */ staticuint64_t AppTaskLEDStk[256/8]; /* 任务栈 */ staticuint64_t AppTaskMsgProStk[512/8]; /* 任务栈 */ staticuint64_t AppTaskStartStk[512/8]; /* 任务栈 */ 将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数,浮点运算和uint64_t类型数据运算会出问题。 u 系统栈大小分配: |
|
|
|
|
|
RTX初始化:
复制代码 /* ********************************************************************************************************* * 函 数 名: main * 功能说明: 标准c程序入口。 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ int main (void) { /* 初始化外设 */ bsp_Init(); /* 创建启动任务 */ os_sys_init_user (AppTaskStart, /* 任务函数 */ 4, /* 任务优先级 */ &AppTaskStartStk, /* 任务栈 */ sizeof(AppTaskStartStk)); /* 任务栈大小,单位字节数 */ while(1); } |
|
|
|
|
|
RTX任务创建:
复制代码 /* ********************************************************************************************************* * 函 数 名: AppTaskCreate * 功能说明: 创建应用任务 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ static void AppTaskCreate (void) { HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF, /* 任务函数 */ 1, /* 任务优先级 */ &AppTaskUserIFStk, /* 任务栈 */ sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */ HandleTaskLED = os_tsk_create_user(AppTaskLED, /* 任务函数 */ 2, /* 任务优先级 */ &AppTaskLEDStk, /* 任务栈 */ sizeof(AppTaskLEDStk)); /* 任务栈大小,单位字节数 */ HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro, /* 任务函数 */ 3, /* 任务优先级 */ &AppTaskMsgProStk, /* 任务栈 */ sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */ } |
|
|
|
|
|
内存管理的初始化和消息邮箱的创建:
复制代码 #define PoolBlocks 10 #define PoolPerBlockSize 8 /* 声明一个支持10个消息的消息邮箱 */ os_mbx_declare (mailbox, 10); /* 声明一个内存池,10块,每块大小8字节 */ _declare_box(mpool, PoolPerBlockSize, PoolBlocks); /* ********************************************************************************************************* * 函 数 名: AppObjCreate * 功能说明: 创建任务通信机制 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ static void AppObjCreate (void) { /* 创建消息邮箱 */ os_mbx_init (&mailbox, sizeof(mailbox)); /* 初始化内存池,4字节对齐,*/ _init_box (mpool, sizeof (mpool), PoolPerBlockSize); } |
|
|
|
|
|
嵌入式学习-飞凌嵌入式ElfBoard ELF 1板卡-移植前准备之git管理内核源码
1792 浏览 0 评论
【瑞萨RA2L1入门学习】+ MacOS安装e2studio
733 浏览 0 评论
嵌入式学习-飞凌嵌入式ElfBoard ELF 1板卡-本地仓库管理之分支间的操作
784 浏览 0 评论
【RA-Eco-RA4E2-64PIN-V1.0开发板试用】3D 图形显示
656 浏览 0 评论
754 浏览 1 评论
【youyeetoo X1 windows 开发板体验】少儿AI智能STEAM积木平台
12251 浏览 31 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-2-2 23:08 , Processed in 0.942169 second(s), Total 101, Slave 83 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号