Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
沁恒CH32V
RT-Thread一般讨论
堆_heap_动态内存管理
随笔、ch32v的堆内存最大化(动态创建堆内存)
发布于 2023-01-11 21:26:24 浏览:1247
订阅该版
[tocm] 从[基于CH32V的RT-Thread学习笔记(持续更新中)](https://club.rt-thread.org/ask/article/e7d5612fb6d17df5.html)挪过来的,方便直接搜到 #### 前言 前面说了我用的MRS IDE,它生成的模板工程,默认堆大小是4KB,可以到board.c里查看 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230111/dfc5e0e5cec284b5b9cb899a96e641a4.png) 如果都是动态创建的话,这肯定是不够用啊,多几个线程就用光了 所以我决定把堆分配搞到最大化,先看看RTT Studio的ch32v307模板是怎么做的 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230111/6666a898b2a510beae8cd236c3876d1e.png) 好吧,RTT Studio是16KB,可能是够了,但有点不满足,再看看RTT Studio的STM32模板是怎么做的 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230111/f2632ae94981b0ac58c7b7a048a74e64.png) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230111/9b616f9131c6668e13049dbb2331add1.png) 了解STM32堆栈分配的同学肯定一样就看出来了(不了解的也没关系,马上的ch32我会出手,笑),没错,这就是我要的堆内存最大化!把bss段结尾作为堆起始地址, RAM的最高地址处作为堆结尾地址。 CH32V和STM32的链接脚本略有不同,CH32V的栈结尾是放在RAM最高地址处的,所以我们不能像STM32那么做。 但也只要略微修改一下就好,下面是我理解的修改过程和原理,嫌麻烦的可以直接到后面的实操部分。 #### 理论部分 我们先下载一下MRS的模板工程到芯片,用free命令看看修改前的堆内存,方便对比(RTT Studio一样操作) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230111/f14a9d2e49895330c178c7d8250fd151.png) 可以看到堆内存总大小:4072 B 已使用:2468 B 最大使用:2468 B 接着我们打开链接脚本Link.ld文件看看ch32v的各个段是怎么分配的,不熟悉链接脚本的盆友可以先看这个,这个文章讲的挺好, [RISC-V MCU CH32V307 ld链接脚本说明](https://www.cnblogs.com/wahahahehehe/p/15149960.html) 点开Link.ld(RTT Studio是link.lds),看看SECTIONS(段分配),鉴于篇幅有点大,我就把各个段做的事情删了(删掉的我会用......代替),仅保留待会我们要用的东西 /* 初始化段,程序的入口 _start 存放在该段 */ .init :{......} >FLASH AT>FLASH /* 存放中断向量表 */ .vector :{......} >FLASH AT>FLASH /* 代码段 */ .text :{......} >FLASH AT>FLASH /*我看不懂的段,反正都是>FLASH AT>FLASH*/ ...... /*重头戏来了,RAM*/ .data : { ...... /*这里这个__global_pointer我看不懂是干嘛的,有懂得前辈指导一下嘛*/ PROVIDE( __global_pointer$ = . + 0x800 ); ...... /*这里的PROVIDE提供的符号,我们可以在C程序里以取地址的方式获得值, *我们待会改堆起始地址和堆结束地址就要用到PROVIDE提供的符号 */ PROVIDE( _edata = .); /* _edata代表data段结尾地址 */ }>RAM AT>FLASH /*RAM AT>FLASH含义 *这里表示data段(已初始化的静态/全局变量)是从FLASH复制到RAM的(这个功能由启动文件 *startup_ch32v30x.S完成),所以data段会占用镜像文件(FLASH空间)*/ .bss : { ...... PROVIDE( _sbss = .); /* _sbss代表bss段起始地址 */ ...... /* _ebss代表bss段结尾地址 ,我们可以用它作为我们的堆起始地址,当然,后面也提供了另外的 *符号_end,end 都是一样的*/ PROVIDE( _ebss = .); } >RAM AT>FLASH /*RAM AT>FLASH含义 *这里表示bss段(未初始化的静态/全局变量)是从FLASH复制到RAM的(这个功能由启动文件 *startup_ch32v30x.S完成),但是未初始化的静态或全局变量没有初值,启动文件搬运的时候只要 *从RAM划出一块内存全部填0就好,所以bss段不会占用镜像文件(FLASH空间)*/ PROVIDE( _end = _ebss);/*我刚刚提到的堆内存起始地址*/ PROVIDE( end = . ); .stack ORIGIN(RAM) + LENGTH(RAM) - __stack_size : { /* 堆结束 ORIGIN(RAM) + LENGTH(RAM) - __stack_size/*stack *w我们用它来作为堆结束地址*/ PROVIDE( _heap_end = . ); . = ALIGN(4); PROVIDE(_susrstack = . );/* 栈底 ORIGIN(RAM) + LENGTH(RAM) - __stack_size */ . = . + __stack_size;/*查看完整Link.ld会发现__stack_size=2048*/ PROVIDE( _eusrstack = .); } >RAM 程序注释我写的比较详细,有需要的可以看看啊。由此我们可以得出通过这个ch32v链接脚本所得到的镜像文件(elf,bin,hex之类)结构和RAM分配情况,首先镜像文件结构(这里应该不够完整,少一些Header,符号表之类的,不是不写,是我也没完全了解。有知道的欢迎补充) | | | ------------ | |header | |.init | |.text | |其它一些初始化段 | |.data | |符号表 | 然后是RAM被初始化后的结构 | | | ------------ | |.data | |.bss | |空白,我们要把这部分用作堆| |.stack| 知道了RAM结构,接下来的事情就好办了,只要把堆起始地址改为link.ld提供的_ebss/_end /end就可以了,堆结束地址改为_heap_end/_susrstack。OK,理论部分结束,下面开始实操。 #### 实操部分 打开board.c 我们先看看原始代码 #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP) #define RT_HEAP_SIZE (1024) static uint32_t rt_heap[RT_HEAP_SIZE]; // heap default size: 4K(1024 * 4) RT_WEAK void *rt_heap_begin_get(void) { return rt_heap; } RT_WEAK void *rt_heap_end_get(void) { return rt_heap + RT_HEAP_SIZE; } #endif 改为下面这个: #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP) /* 最大堆大小开关*/ #define USING_MAX_HEAP_SIZE 1 #if (USING_MAX_HEAP_SIZE == 0) #define RT_HEAP_SIZE (1024) static uint32_t rt_heap[RT_HEAP_SIZE]; // heap default size: 4K(1024 * 4) void *rt_heap_begin_get(void) { return rt_heap; } void *rt_heap_end_get(void) { return rt_heap + RT_HEAP_SIZE; } #else void *rt_heap_begin_get(void) { return HEAP_BEGIN; } void *rt_heap_end_get(void) { return HEAP_END; } #endif /* END OF USING_MAX_HEAP_SIZE*/ #endif 打开board.h可以看到模板工程已经定义了HEAP_BEGIN和HEAP_END, ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230111/f3cac0d867127149ab576a3f5ced5d0c.png) 但是他这个不对,__stack_size的值应该以以取地址方式获得,而且SRAM_SIZE也被写成立64K,那如果我们后面修改ch32v的FLASH和RAM配置的话,还要多改一下这里,所以直接用我这个 extern int _ebss,_heap_end; #define HEAP_BEGIN ((void *)&_ebss) #define HEAP_END ((void *)&_heap_end) 修改完成后编译下载,使用free命令查看堆内存分配 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230111/4939c5ac825566fb889d93a677d184c9.png) 堆内存总大小:61568 B 大约60KB了. 大功告成!(擦汗)RTT Studio一样的操作,大家自己搞搞就行了。
6
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
初级踩坑仔
这家伙很懒,什么也没写!
文章
6
回答
4
被采纳
0
关注TA
发私信
相关文章
1
有关动态模块加载的一篇论文
2
最近的调程序总结
3
晕掉了,这么久都不见layer2的踪影啊
4
继续K9ii的历程
5
[GUI相关] FreeType 2
6
[GUI相关]嵌入式系统中文输入法的设计
7
20081101 RT-Thread开发者聚会总结
8
嵌入式系统基础
9
linux2.4.19在at91rm9200 上的寄存器设置
10
[转]基于嵌入式Linux的通用触摸屏校准程序
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
ota在线升级
UART
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
at_device
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
张世争
8
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
用户名由3_15位
11
个答案
1
次被采纳
KunYi
6
个答案
1
次被采纳
本月文章贡献
程序员阿伟
6
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
2
次点赞
ThinkCode
1
篇文章
1
次点赞
Betrayer
1
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部