c++ - 外部 RAM 中的动态向量分配
问题描述
我目前正在使用 GCC 在 C++ 中的 STM32F7 cortex-m7 微控制器上开展自己的大型项目。我需要在外部 SDRAM(16 MB)中存储一个宽数组,其中包含注释结构的向量(每个 12 个字节)。我已经创建了一个工作 FMC 和一个自定义 ram 区域
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 512K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
SDRAM (xrw) : ORIGIN = 0xC0000000, LENGTH = 16M
}
/* Define output sections */
SECTIONS
{
/* Section créée pour l'allocation dans la SDRAM externe*/
.fmc :
{
. = ALIGN(8);
*(.fmc)
*(.fmc*)
. = ALIGN(8);
} >SDRAM
我的数组声明如下:
std::vector<SequencerNoteEvent> NotesVectorArray[kMaxPpqn] __attribute__((section(".fmc")));
到目前为止还可以。我在我的外部 RAM 中创建了一个向量数组。我如何才能继续创建我的向量元素
NotesVectorArray[position].push_back(note);
动态发生在同一个外部 RAM 中?我目前只能使用声明静态数据__attribute__(section)
我读了很多关于 C++ 分配器、内存池的东西,但我不知道分配在向量代码中的位置以及我应该如何替换它......我“只是”需要与通常的分配系统相同但在我记忆的另一部分中,这种精确的类型。
似乎有可能有多个堆。分散文件和有效内存分配之间的联系在哪里?
提前致谢,
本
解决方案
我面临同样的问题,并通过重新定义operator new
. 与使用自定义分配器相比,这样做的好处是所有动态分配都将自动在 SDRAM 中,因此您可以自由使用 std::function 或任何需要堆的 STL 容器,而不必每次都传递自定义分配器参数.
我做了以下事情:
-nostdlib
通过添加到编译标志来删除标准库。我还将它添加到链接器标志中。还要--specs=...
从您的编译器和链接器标志中删除和。奖励:您将节省约 60-80k 的代码空间!operator new
为,编写您自己的替换operator delete
。我创建了一个名为new.cpp
添加以下内容的新文件:(取自https://arobenko.gitbooks.io/bare_metal_cpp/content/compiler_output/dyn_mem.html)
//new.cpp
#include <cstdlib>
#include <new>
void *operator new(size_t size) noexcept { return malloc(size); }
void operator delete(void *p) noexcept { free(p); }
void *operator new[](size_t size) noexcept { return operator new(size); }
void operator delete[](void *p) noexcept { operator delete(p); }
void *operator new(size_t size, std::nothrow_t) noexcept { return operator new(size); }
void operator delete(void *p, std::nothrow_t) noexcept { operator delete(p); }
void *operator new[](size_t size, std::nothrow_t) noexcept { return operator new(size); }
void operator delete[](void *p, std::nothrow_t) noexcept { operator delete(p); }
- 在链接描述文件中定义一个与最低 SDRAM 地址(堆的开始)相对应的变量。这不是绝对必要的,因为您可以在第 4 步中的代码中使用常量 (0xC0000000),但是将 SDRAM 地址保存在一个位置会使事情变得更容易。只需添加一行:
PROVIDE( _fmc_start = . );
//linker script
[snip]
/* Section créée pour l'allocation dans la SDRAM externe*/
.fmc :
{
. = ALIGN(8);
PROVIDE( _fmc_start = . );
*(.fmc)
*(.fmc*)
. = ALIGN(8);
} >SDRAM
- 新的实现
new
将直接调用malloc()
,_sbrk()
当它需要堆中的一块内存时会调用。因此,您必须定义_sbrk()
以跟踪堆指针,并且只需将指针从您刚刚在链接描述文件中定义的最低 SDRAM 地址开始。这是我所做的:
//sbrk.cpp, or append this to new.cpp
#include <cstdlib>
extern "C" size_t _sbrk(int incr)
{
extern char _fmc_start; // Defined by the linker
static char *heap_end;
char *prev_heap_end;
if (heap_end == 0)
heap_end = &_fmc_start;
prev_heap_end = heap_end;
//Optionally can check for out-of-memory error here
heap_end += incr;
return (size_t)prev_heap_end;
}
- 此时,如果您尝试编译,您可能会遇到很多链接器错误。确切的错误将取决于您的项目使用的标准库的哪些部分,除了 new 和 delete。就我而言,我正在使用
std::function
并且编译器抱怨它没有__throw_bad_function_call()
. 您可能还会看到诸如_init()
and_fini()
之类的错误__errno
. 基本策略是为每一个创建自己的空函数存根或变量声明。值得快速搜索其中的每一个以查看它们的用途,您可能会发现您的项目或您包含的库正在使用一些您不知道的功能!创建存根时,您需要正确匹配函数签名,因此也需要搜索 Internet。许多存根用于处理错误/异常,因此您可以决定如何在函数体中处理它(或忽略错误)。
例如,这里有一些关于(过时但需要)_init()
和_fini()
功能的信息:https ://tldp.org/HOWTO/Program-Library-HOWTO/miscellaneous.html
这里有一些信息__dso_handle
:https ://lists.debian.org/debian-gcc/2003/07/msg00057.html
__cxa_pure_virtual():__cxa_pure_virtual 的目的是什么?
这是我的项目需要的工作:
//syscalls.cpp
extern "C" {
void _init(void) {}
void _fini(void) {}
int __errno;
void *__dso_handle = (void *)&__dso_handle;
}
namespace std
{
//These are error handlers. They could alternatively restart, or log an error
void __throw_bad_function_call() { while (1); }
void __cxa_pure_virtual() { while (1); }
} // namespace std
毕竟,它最终会编译,如果您使用调试器,您会看到向量的地址从0xC0000000
!
推荐阅读
- python-3.x - 如何测试日期?
- python - 使用 pandas 根据条件排除特定日期
- python - 按频率对数组元素进行排序
- r - rstudio ANSI 转义序列无法正常工作
- javascript - 如何正确转义 html 以发送 AJAX 请求?
- autodesk-forge - 使用three.js生成的MasterView和房间材料替换缺少房间问题
- python - 如何在 Python Pandas 中输出回归表
- android - 如果我不打算在 Google Play 上发布应用程序,有没有办法获取蓝牙适配器地址?
- html - 加载一切都会中断一秒钟 CSS & HTML
- ios - 无法安装“应用程序”Xcode 11.5+ iOS 13.5.1