简体   繁体   中英

Dynamic vector allocation in external RAM

I am currently working on a large project of my own on an STM32F7 cortex-m7 microcontroller in C++ using GCC. I need to store a wide array in an external SDRAM (16 MB) containing vectors of notes structures (12 bytes each). I have already a working FMC and a custom ram region created

/* 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

my array is declared like this :

std::vector<SequencerNoteEvent> NotesVectorArray[kMaxPpqn] __attribute__((section(".fmc")));

So far it's OK. I created an array of vectors in my external RAM. How can i proceed in order to make my vectors element creation

NotesVectorArray[position].push_back(note);

happening in the same external RAM dynamically ? I am currently only able to declare static data using the __attribute__(section)

I read lot of things about C++ allocators, memory pools, but i don't get where the allocation take place in the vector code and how i should replace it... I "just" need to have the same allocation system than the usual but in another part of my memory for this precise type.

It seems possible to have multiple heaps. Where is located the connection between scatter file and the effective memory allocation ?

Thanks in advance,

Ben

I was facing the same issue and got a working solution by redefining operator new . The benefit of this over using a custom allocator is that all dynamic allocations will automatically be in SDRAM, so you're free to use std::function or any STL container that requires the heap, without having to pass a custom allocator argument every time.

I did the following:

  1. Remove the standard library by adding -nostdlib to the compilation flags. I also added this to the linker flags. Also remove and --specs=... from your compiler and linker flags. Bonus: you'll save ~60-80k of code space!

  2. Write your own replacement for operator new , operator delete . I created a new file called new.cpp added the following: (taken from 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); }
  1. Define a variable in the linker script that corresponds to the lowest SDRAM address (start of the heap). This isn't strictly necessary, as you could use a constant (0xC0000000) in your code in step 4, but it makes things easier to keep the SDRAM address in just one place. Just add one line: 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

  1. The new implementation of new will directly call malloc() , which will call _sbrk() when it needs a block of memory in the heap. So you have to define _sbrk() to keep track of the heap pointer, and simply start the pointer at the lowest SDRAM address that you just defined in the linker script. Here's what I did:
//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;
}
  1. At this point, if you try to compile you will probably get many linker errors. The exact errors will depend on what parts of the standard library your project uses besides just new and delete. In my case, I was using std::function and the compiler complained that it didn't have __throw_bad_function_call() . You probably will also see an error for things like _init() and _fini() and __errno . The basic strategy is to create your own empty function stub or variable declaration for each of these. It's worth doing a quick search for each of these to see what purpose they serve, you might find out your project or a library you're including is using some features you weren't aware of! When you create a stub, you'll need to match the function signature correctly, so that will require searching the internet as well. Many of the stubs are for handling errors/exceptions, so you can decide how to handle it in the function body (or ignore errors).

For example, here's some info on the (obsolete, but required) _init() and _fini() functions:https://tldp.org/HOWTO/Program-Library-HOWTO/miscellaneous.html

Here's some info on __dso_handle : https://lists.debian.org/debian-gcc/2003/07/msg00057.html

__cxa_pure_virtual(): What is the purpose of __cxa_pure_virtual?

Here's what my project required to work:

//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

After all that, it will finally compile and if you use a debugger you'll see that the address of your vectors start at 0xC0000000 !

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM