- NUCLEO-L476RG 开发板,板载 STM32L476RGT6(96K SARM1 + 32K SRAM2)
- Win10 64 位
- Keil MDK 5.36
- RT-Thread 5.0.1 版本(2023-05-28 master 主线)
- bsp : bspstm32stm32l476-st-nucleo
- 最近在研究 RT-Thread 内存的管理,熟悉了一下 memheap 的功能实现,并且了解到 memheap 支持多块内存(物理地址不连续)的管理,当开启 memheap 后,rt_malloc 可以遍历所有注册过的 memheap 内存块,并且进行 内存的申请与释放。
- 当前 STM32L476RGT6 支持两块 SRAM,其中 SRAM1 96KB,还有一块 SRAM2 32KB,SRAM2 默认没有使用,尝试开启 SRAM2
- stm32l476-st-nucleo 开启 memheap 的方法
- stm32l476-st-nucleo 开启 SRAM2 的方法
1#defineHEAP_SRAM2_BEGIN(0x10000000) 2#defineHEAP_SRAM2_SIZE(32*1024) 3staticstructrt_memheapmemheap_sram2; 4intsystem_sram2_init(void) 5{ 6returnrt_memheap_init(&memheap_sram2,"sram2",(void*)HEAP_SRAM2_BEGIN,(rt_size_t)HEAP_SRAM2_SIZE); 7} 8INIT_BOARD_EXPORT(system_sram2_init); 功能测试
- 写两个测试命令:一直申请内存直到无法申请内存,一直释放所以申请的内存,确认 rt_malloc 会自动到新增加的 memheap SRAM2 中申请内存
- 功能验证通过,但是遇到死机问题
- 测试的函数
1void*user_alloc(rt_size_tsize) 2{ 3returnrt_memheap_alloc(&memheap_sram2,size); 4} 5voiduser_free(void*ptr) 6{ 7rt_memheap_free(ptr); 8} 9voiduser_alloc_test(void) 10{ 11for(inti=0;i< MEMHEAP_BLOCK_NUM; i++) 12{ 13user_ptr[i]=user_alloc(500); 14if(!user_ptr[i]) 15{ 16rt_kprintf("mallocfailed,index=%d ",i); 17return; 18} 19else 20{ 21rt_kprintf("[%d]:0x%08x ",i,user_ptr[i]); 22} 23} 24} 25MSH_CMD_EXPORT(user_alloc_test,user_alloc_test); 26voiduser_free_test(void) 27{ 28for(inti=0;i< MEMHEAP_BLOCK_NUM; i++) 29{ 30if(user_ptr[i]) 31{ 32rt_kprintf("[%d]:0x%08x ",i,user_ptr[i]); 33user_free(user_ptr[i]); 34} 35} 36} 37MSH_CMD_EXPORT(user_free_test,user_free_test);
- 死机的信息
- 死机后,打印线程,发现 idle 线程栈异常
- 开启CmBacktrace 组件后,发现死机的问题不是固定的,申请申请一个小内存,都会触发异常
- idle 线程的结构数据被破坏了,这就说明,内存越界了,但是测试例程只调用了 RT-Thread memheap 的 内存申请与释放 API,并没有其他的操作
- 手动申请一块内存,没有触发死机, list thread 发现,idle 线程的栈数据,依旧是异常的!
- 由于 开发板可以 单步调试,所以经过单步调试,加上分析,确认内存的范围,各个线程栈的内存范围,发现了一个奇怪的问题:申请的内存偶尔会与线程栈的【静态内存】重叠
- 由于死机问题并不是必现,但是 idle 线程栈数据异常是必现的。当前怀疑 memheap 的内存范围设置存在问题,通过对比其他开发板的 bsp,发现了问题所在。
- 原来 bsp stm32l476-st-nucleo 系统的内存 HEAP_BEGIN 设置有问题,直接设置的 第一块内存的起始地址:
1#defineSTM32_SRAM1_START(0x20000000) 2#defineHEAP_BEGINSTM32_SRAM1_START
- 初步看上去好像没有问题,其实RT-Thread 开机后,静态的内存数据、线程栈,依旧会占用一些内存,也就是其实内存地址,不能设置为 STM32_SRAM1_START,而是 【剩余内存】
- 【剩余内存】或者叫【空闲内存】的获取方法如下:
1#ifdefined(__ARMCC_VERSION) 2externintImage$$RW_IRAM1$$ZI$$Limit; 3#defineHEAP_BEGIN((void*)&Image$$RW_IRAM1$$ZI$$Limit) 4#elif__ICCARM__ 5#pragmasection="CSTACK" 6#defineHEAP_BEGIN(__segment_end("CSTACK")) 7#else 8externint__bss_end; 9#defineHEAP_BEGIN((void*)&__bss_end) 10#endif
- 如在 Keil MDK5 上,是 #define HEAP_BEGIN ((void *)&Image$$RW_IRAM1$$ZI$$Limit), 也就是 SRAM1 的 剩余内存作为系统 堆内存使用,而不是 SRAM1 的全部内存作为 堆内存使用
- 如上,重新设置 HEAP_BEGIN 即可
- 编译发现 RW_IRAM1 不存在,需要修改链接文件:bspstm32stm32l476-st-nucleooardlinker_scriptslink.sct,增加 RW_IRAM1 的定义
1RW_IRAM10x200000000x00018000{;RWdata 2.ANY(+RW+ZI) 3}
- 以上修改后,memheap 内存测试通过,不再触发死机
- memheap 使用起来还是比较的简单,可以通过设置 开启 RT_USING_MEMHEAP_AUTO_BINDING,也就是 勾选 [*] Use all of memheap objects as heap,决定新增加的 memheap 的内存是否参与系统常规的内存管理,如 rt_malloc、rt_free
- 用户可以单独的实现自己的 memheap 内存块 alloc、free 函数,这样只操作特定的 memheap。
- 当前的一个小缺点:如果 memheap 内存块较多,超过2个,如 RAM1、RAM2、RAM3,并且开启了 [*] Use all of memheap objects as heap,想实现 RAM1与 RAM2 作为系统通用内存管理,RAM3 用户专用内存管理,那么当前的 memheap 机制做不到,因为 rt_malloc 依旧会在 RAM1、RAM2 不能申请内存时,去 RAM3 申请内存
原文:https://club.rt-thread.org/ask/article/736c78aba1dcd82e.html
———————End———————
RT-Thread线下入门培训
6月 - 郑州、杭州、深圳
1.免费2.动手实验+理论3.主办方免费提供开发板4.自行携带电脑,及插线板用于笔记本电脑充电5.参与者需要有C语言、单片机(ARM Cortex-M核)基础,请提前安装好RT-Thread Studio 开发环境
立即扫码报名
报名链接
https://jinshuju.net/f/UYxS2k
巡回城市:青岛、北京、西安、成都、武汉、郑州、杭州、深圳、上海、南京
你可以添加微信:rtthread2020 为好友,注明:公司+姓名,拉进RT-Thread官方微信交流群!
点击阅读原文,进入RT-Thread 官网
-
RT-Thread
+关注
关注
31文章
1272浏览量
39918
原文标题:RT-Thread 学习笔记:memheap 死机问题的分析与解决
文章出处:【微信号:RTThread,微信公众号:RTThread物联网操作系统】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论