亲爱的支持,
目前,我正在一个自定义嵌入式项目中实现GTL接口(通过UART)。我的第一个目标是让prox_reporter_ext项目与我们的外部处理器(DA1458x_SDK\5.0.2.1\projects\target_apps\ble_examples文件夹)一起工作。我使用了host_proxr_sdk项目作为参考(DA1458x_SDK\5.0.2.1\projects\host_apps\windows\proximity\reporter\文件夹)。
我面临的挑战是内存分配。到目前为止,我们一直避免在我们的嵌入式代码中使用malloc/free,这只是为了防止引入灾难性的副作用,比如内存泄漏(它还可能与我们的RTOS结合带来新的挑战)。在上述项目的ble_msg中,我看到malloc和free是通过BleMsgAlloc和BleFreeMsg使用的,uart.c中的SendToMain也是如此。此外,UARTProc (uart.c)中的接收缓冲区大小为1000字节,MAX_PACKET_LENGTH为350字节(uart.h)。在UARTSend (uart.c)中分配另外500个字节。
根据我的理解,从综合过程应用。pdf和UM-B-017 GTL接口的来源和读取UM-B-010_DA14580_581_583邻近应用_v1.3.pdf, GTL接口不能被分类为停止和等待协议。换句话说,DA14580可以在任何给定时刻向外部处理器发送多个事件包/消息。另一方面,外部处理器可以在应用程序需要时发送命令包/消息。
我完全理解使用动态内存分配的原因,它对可变数量的包和变量PAR_LEN字段值是有意义的。然而,我想知道静态内存分配是否是一个可行的选择(并且可以通过查看内存需求来实现)。在本例中,我想知道PAR_LEN的最大值是什么(消息可以包含的参数的最大字节数),以及DA14580可能发送的包/消息的数量。如果可行,我可以创建一个循环缓冲区(X)的数据包数量,每个MAX_PAR_LEN字节的参数(我们有32 kb的内存可用,例如三包与一个单独的每个350字节的读350字节的缓冲区和写350字节的缓冲区(异步读/写)不太现实)。
我很想听听你对此的看法。如果可能的话,我宁愿不使用malloc / free。
亲切的问候,
阿扬
编辑02-11-2015
我已经在下面添加了关于字节顺序和数据结构填充的信息,也许其他论坛用户也会觉得这很有用。
我很想知道其他人是如何在内存有限的嵌入式系统中实现这一点的,或者在malloc/free被认为是不好的实践的地方。
亲切的问候,
阿扬
嗨,艾伯曼,
我们从来没有想过要做这样的事情,尽管它是可以做到的。潜在的最大数据包,可以交换是完全依赖于当前应用程序,我想,你可以动态地计算在当前实现中有多少被分配和发送数据包,都使用某种计数器,你要能够判断应该预先分配的内存大小。
由于MT_dialog
您可以使用动态内存分配,并且可以选择一个由静态缓冲区实现的内存分配,而不是原来的内存分配。更重要的是,您可以添加一个调试函数,如printf到项目DA14580_SDK_3.0.4.0\host_apps\windows\proximity\monitor,以查看发送和接收了多少数据包。就我而言,32kB的RAM就足够了,也许5kB就足够了。
@MT_dialog谢谢你的回复,因为显而易见的原因,我最终使用了动态内存分配。然而,静态内存分配的实验是有意义的。
@summer20100514感谢您的回复。请注意,我提到的32kB RAM用于整个系统,而不仅仅是BLE相关的部分。所以5kB仍然是一个相当大的块;-)。
也许你能帮我出个新问题;SDK中的所有数据结构是否在正确的边界上显式对齐?或者假设数据结构将被打包在DA14580和主机代码中(为了使用SDK)?我注意到sizeof经常用于确定不同消息参数的大小,我只是想知道是否考虑了潜在的隐式填充。
谢谢
阿扬
如果不太确定对齐方式,可以打印地址。
@summer20100514也许我应该澄清我的问题。
让我们以struct proxr_enable_req为例:
/ / sdk \ ble_stack \ profiles \ prox \ proxr \ proxr_task.h
/// @ref PROXR_ENABLE_REQ消息的参数
struct proxr_enable_req
{
/ / /连接句柄
uint16_t conhdl;
///安全级别
uint8_t sec_lvl;
///在ATT DB中保存LLS警报级别
uint8_t lls_alert_lvl;
/// TX功率
int8_t txp_lvl;
};
在创建PROXR_ENABLE_REQ GTL包时,使用sizeof(struct PROXR_ENABLE_REQ)来确定参数长度。在这种情况下,结构体的编译值,以及包参数长度的值是6;在成员txp_lvl之后添加一个额外的填充字节。换句话说;最后一个成员用所需的字节数填充,以便结构的总大小是任何结构成员的最大对齐倍数。
当将传入字节数组强制转换为消息的相应参数结构类型时,我们需要确保发送方和接收方都考虑到或没有考虑到这种隐式填充。在使用proxr_enable_req的情况下,解除对单个成员的引用不会有真正的问题,因为填充仅仅是在最后一个成员之后添加的。然而,如果你举下面的例子,个人成员可能不会在你期望他们在的地方(取决于发送者和接收者是否对包装结构采取不同的规则)。
长话短说,我很想从Dialog中了解到DA SDK的设计选择。数据包参数是否在字段之间发送带有或没有填充字节?
我之前没有注意到这件事,但似乎没有什么不对劲的。也许填充字节总是添加在最后一个成员之后?
由于我还没有遇到任何文档明确指定数据的结尾,以及数据结构是否打包,或者结构成员之间是否存在填充字节,因此我猜测,到目前为止,SDK只用于/打算用于(32位)具有少量endian内存体系结构的平台,没有打包结构(例如,我确实在SDK代码中找到了任何_属性_(打包))。
只要两个系统都使用sizeof(struct)来设置GTL包参数长度,并将传入和输出参数字节数组转换为这些结构类型,一切都将正常工作(因为两个平台都期望相同的结构成员填充/成员对齐)。
尽管我认为这是迄今为止使用SDK的情况,但我真的希望Dialog能够对此做出回应。
-假设结构未打包(编译器添加的隐式填充)是否正确?
-没有显式填充添加,以确保成员对齐正确和结构体大小是其最大成员的倍数?(也就是说,这是留给编译器的)
请注意,我完全可以使用这种方法(使用我们当前的主机平台),因为我们的主机也使用32位ARM Cortex-M0+处理器。DA14580和主机处理器都配置了小端字节顺序。换句话说,sizeof()将在两个平台上返回相同的结果,并且struct成员将在两个平台上完全对齐(通过编译器添加相同的隐式填充)。
我在跨平台解决方案(具有不同的内存架构)中使用了大量面向字节、打包的基于协议。对于SDK来说,未来一个好的补充可能是增加一个额外的抽象级别,指定字段之间不存在填充字节,并使用写/读模块以独立于字节的方式写/读多字节数据类型。通过这种方式,您可以完全删除与平台相关的部分。
我是SDK的超级粉丝(特别是5.0.3,我爱它!),我只是想把事情弄清楚尽可能多:-)。
期待你的回复。
亲切的问候,
阿扬
嗨,艾伯曼,
对齐由编译器决定,原因是windows和ARM具有相同的端序(小端序)和大小。如果是不同的体系结构,编译器将会失败,你将不得不显式地声明结构。
由于MT_dialog
嗨MT_dialog,
谢谢你的确认。这个主题现在可以结束了。
亲切的问候,
阿扬