Embedded 估计剩余可用RAM,安全裕度为C(STM32F4)

Embedded 估计剩余可用RAM,安全裕度为C(STM32F4),embedded,heap,dynamic-memory-allocation,stm32,hal,Embedded,Heap,Dynamic Memory Allocation,Stm32,Hal,我目前正在使用STM32CubeMx和Keil uVision开发STM32F407应用程序。我知道嵌入式系统中的动态内存分配基本上是不被鼓励的,但在互联网上我可以找到一些支持它的论点 由于我的发明者的灵魂,我想尝试做这件事,但要安全地做。假设我正在为传入的UART消息创建一个动态分配的fifo,其中包含由msg本身及其“长度”组成的结构。但是,我不希望这样做消耗所有堆大小,因此我想检查我还剩下多少:Me new(?)想法是尝试临时分配一些大块内存(比如100个字符)-如果成功,我接受传入的消息

我目前正在使用STM32CubeMx和Keil uVision开发STM32F407应用程序。我知道嵌入式系统中的动态内存分配基本上是不被鼓励的,但在互联网上我可以找到一些支持它的论点

由于我的发明者的灵魂,我想尝试做这件事,但要安全地做。假设我正在为传入的UART消息创建一个动态分配的fifo,其中包含由msg本身及其“长度”组成的结构。但是,我不希望这样做消耗所有堆大小,因此我想检查我还剩下多少:Me new(?)想法是尝试临时分配一些大块内存(比如100个字符)-如果成功,我接受传入的消息,如果没有-这意味着我的堆快用完了,忽略msg(或者接受它并将最早的消息出列)。检查后,我当然会释放临时内存

我想到了几个问题:

  • 首先,这有意义吗?根据您的经验,您认为它有用且安全吗
  • 我找不到关于ES中到底是什么共享RAM的确切信息(我知道堆、堆栈和volatile变量),所以我的问题是:为1提供这个答案。“地狱不回家”不是吗?你会为提到的控制器选择多大的临时内存检查器
  • 关于micro本身-它有192kB的RAM,但是在Drivers\CMSIS\Device\ST\STM32F4xx\Source\Templates\arm\startup\u stm32f407xx.s文件中,只有512B+1024B被分配给堆和堆栈-这不是很小,留下了呼呼声,剩下190kB给易失性变量吗?将堆大小增加到50kB是否明智?如果是,我是直接在这个文件中做,还是在其他地方做比较好

  • 也许对你们中的一些人来说,“安全动态内存”和“嵌入”在一篇文章中既令人震惊又令人眼花缭乱,但请记住,这是在试验和探索新的视野:)谢谢大家。Keil uVision只描述了IDE。如果您使用的是KEil MDK-ARM,这意味着ARM的RealView编译器,那么您可以使用

    \uuu heapstats()
    有点奇怪,它不是简单地返回一个值,而是通过传递给它的函数指针和文件描述符将堆信息输出到格式化的输出流。输出函数必须具有类似于fprintf()的接口。当然,您可以使用
    fprintf()
    ,但这需要您有正确的

    例如:

    typedef int (*__heapprt)(void *, char const *, ...);
    __heapstats( (__heapprt)fprintf, stdout ) ; 
    
    输出,例如:

    4180 bytes in 1 free blocks (avge size 4180)
    1 blocks 2^11+1 to 2^12
    
    不幸的是,这并不能真正实现您所需要的,因为它输出文本。但是,您可以实现自己的函数来捕获内存中的数据并解析结果。您可能只需要捕获第一个十进制数字字符,并丢弃任何其他字符,但可用内存量和最大的可分配块当然不一定是同一件事。碎片由空闲块的数量及其平均大小表示。您也许可以保证能够分配至少一个平均大小的块

    嵌入式系统中的动态分配问题与处理内存耗尽有关,而在实时系统中,则与使用默认malloc/free实现的分配和解除分配的不确定性定时有关。在您的情况下,最好使用固定块分配器。您可以通过创建内存块的静态数组(或在启动时从堆中动态分配内存块)并将指向队列、链表或堆栈结构上每个块的指针来实现这样的分配器。要分配,只需从队列/列表/堆栈中删除一个指针,然后释放一个指针。当可用块结构为空时,内存将耗尽。它完全是确定性的,而且因为它是确定性的,所以您的实现可以很容易地监控性能和容量

    关于问题3。您需要调整堆和系统堆栈大小以适合您的应用程序。我使用过的大多数工具都有一个链接器脚本,该脚本自动将所有可用内存分配给堆,这些内存不是静态分配的、分配给堆栈的或为其他目的保留的。但是,MDK-ARM在默认链接器脚本中不这样做,而是分配一个固定大小的堆


    您可以使用链接器映射文件摘要来确定未使用的空间量,并手动扩展堆。当静态分配的数据量可能增加时,我通常会留下少量未使用的空间来进行维护。然而,在某些时候;您最终会耗尽内存,并且链接器发出的神秘错误消息可能不会使您的堆太大变得明显。可以覆盖默认链接器脚本并提供您自己的脚本,当然也可以自动调整堆的大小-尽管我从未尝试过。

    好的,我已经用动态堆可用空间检查测试了我的想法,它运行得很好(尽管我没有执行长期测试),然而,@Clifford的回答说服了我放弃动态分配的想法。最终,我实现了自己的静态堆,其中包含页面(2d数组)、占用页面指示器(页面数量大小的0-1数组)和结构的fifo,结构由指向静态堆上消息的指针(实际上只是数组的索引)和消息长度(以确定它占用了多少连续页面)组成。我收到的95%的消息应该只占用一页,5%-2或3页,所以碎片仍然是可能的,但至少我严格控制它,它只影响分配给代码模块的内存部分(换句话说:碎片不会泄漏到代码的其他部分)。到目前为止,它的工作没有任何问题,当然是