硬件平台:STM32H750
软件平台:RT-Thread
开发环境:Keil
一、出现问题的原因
在公司的一款 关产品的开发过程中,由于新需求过多,导致原本只在512K内存块上的使用变得捉襟见肘,无奈,为了满足需求,将原本H750拆分开的内存块通过RT-Thread提供的内存算法(memheap)来增加内存的实际大小。
二、问题是什么
1、增加完内存后,大小在理论上是够用了,但是由于边缘计算功能占据了大量的动态内存,导致边缘计算和 页同开的情况下, 页无法正常刷新,经过问题分析和定位,发现虽然每次free查询的显示还有100k多的内存,但是 页还是会提示申请不到内存。
这里要提示大家的是,我们webnet在使用时是静态 页,单次刷新最大需要动态申请20k左右的内存空间,而我们free出来的内存虽然显示总和还有一百多,但是是分布在不同的内存块之间的,并且由于memheap特别容易导致内存碎片化,到时malloc不能申请到这么大的连续内存,此时,我就想到了一种曲线救国的方法:
主要是利用专用堆的理念,将原本混合使用的程序代码段分开专用,就是在这种操作下,经过改动调整后,程序每次启动都死在同一个位置。
而在原来加入其他内存款进行编码调试的过程中就经常因为内存不够而占用到ram1等其他内存块,当当每次检测到有跨内存使用的时候,都会出现Hard Fault 错,且 错的pc指针都是0x90002456,通过map文件查询此地址端是在一个memcpy的位置,但是当时并没有找到具体是哪个copy函数。
而在解决这次问题的过程中,想到有的内存块是还没有使用的,所以想把 页的内存申请单独放在一个内存块使用,这样就不会出现内存不足的问题了,可是经过如下改动后, 页每次刷新必死机。
webnet中的主要改动就是将 页的内存申请函数替换成自己的malloc函数,指定从一个内存块申请。
内存申请函数如下,优先从ram1申请,不够再从链表中申请,这里主要是基于RT-Thread提供的memheap算法接口实现的。
(本来考虑只允许从ram1申请来,但是考虑到频繁刷新 页等其他操作,还是加上了如果从ram1没申请到,就去链表中其他内存块申请的操作。)
而就是在此方法下,再次复现了原来经常困扰我的Hard Fault死机问题,而且这次是必死机,更加方便来定位问题,具体现象如下图所示:
为了抓这次机会,所以我将固件换回到片内运行,通过ST-Link和keil的debug进行调试,发现每次死机地点都很统一,且稳定复现。
待死机后,在Disassembly界面鼠标右击,选中Show Disassembly at Address。
随后在弹出的输入框中复制进Hard Fault中提示的lr寄存器的地址,随后回车,可以看到跳转到的代码段有一个copy函数,并且位置在LWIP内部,如下图所示:
我们跳转进去发现此copy函数映射的是一个C库的memcpy接口,如下图所示:
由于之前我们遇到过memcpy不能跨内存拷贝的问题,所以我们将此函数改为rt_memcpy再次进行测试。
此时发现,固件正常运行,不再出现死机等问题。
这里可能有同学就要问了,memcpy和rt_memcpy具体有什么区别,其实我们去看rt_memcpy内部的实现代码,并没有看出啥特别的地方,而且 上也经常有人问有啥区别,我只能说,能力有限,既然我们在使用的系统提供给我们了官方的接口,我们在编码过程中还是尽量使用官方的接口,说兼容C库,但具体也不清楚兼容到了什么程度,对吧,为了少掉几根头发,还是乖乖听话直接用吧。
如果有大神看到,并且了解这两个函数的区别也可以在评论区说明一下,正好解惑一下。
文章知识点与官方知识档案匹配,可进一步学习相关知识 络技能树跨区域 络的通信学习 络层的作用22557 人正在系统学习中
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!