External memory access/allocation

When we start declaring big global arrays, we quickly run out of internal memory on the HMI board. How do we control where the compiler allocates the variables (internal vs. external memory). Could you point to the documentation or an example? Thanks so much!

Kut

  • Hello Kut,

    BSP defines few useful macros to control static memory allocation out of which, BSP_PLACE_IN_SECTION(x) is the most useful one (x is the memory section defined in your linker script, e.g. .sdram). This macro then resolves to GCC or IAR syntax depending on which toolchain you've set when creating a project.

    Regards

  • In reply to karol:

    Hi,

    I've had the same problem awhile ago. Unfortunately, there are almost no documents including BSP_PLACE_IN_SECTION, let alone how to use it. Also changing .bss to sdram didn't help.

    Here's what I have done to solve it. (This might work only for Synergy boards, I'm not sure at this moment)

    Detect which variables need most RAM space. In my case, I had an array of 100k limit that would be do better in SDRAM.

    Say your variable is:

    float cQ;

    This would normally be stored in RAM. RAM only has 640K for PE-HMI1 board. In order for this variable to be stored in SDRAM region or others you simply add the following next to the variable definition once.

    float cQ __attribute__ ((aligned(64), section(".sdram")));

    This is not something I came up with myself, but I found it using JPEG module. 

    Best

  • In reply to furkanicus:

    The BSP_PLACE_IN_SECTION macro works just fine, as long as you remember to put the dot before the section name i.e. BSP_PLACE_IN_SECTION(".sdram"). When creating custom sections, make sure they don't start with .data* as this will automatically default to .rodata section.

  • In reply to Karol:

    Alright, that works, too. Here's a sample for those who might have the same problem in the future:

    float sampleVariable BSP_PLACE_IN_SECTION(".sdram");

  • In reply to furkanicus:

    I just tried placing an std::queue<some_class> in SDRAM using the BSP_PLACE_IN_SECTION(".sdram") macro. The variable is declared as extern queue<log_entry> logs BSP_PLACE_IN_SECTION(".sdram"); in the header and defined as queue<log_entry> logs BSP_PLACE_IN_SECTION(".sdram") = queue<log_entry>(); in the source file.

    However, I get an "expected initializer before 'BSP_PLACE_IN_SECTION'" error. I have used the same syntax on static arrays before, but without initialization. The error here occurs with and without initializing the queue though. When I remove the BSP_PLACE_IN_SECTION macro it compiles fine. Any ideas?
  • In reply to ChrisS:

    Hello ChrisS,

    I am not sure what can cause this error. Please try to use: __attribute__ ((section(".sdram"))) instead of the macro: BSP_PLACE_IN_SECTION(".sdram").

    Best regards,
    anper

  • In reply to anper:

    Hello anper,

    that method works!

    However, since the queue stores elements on the heap and these elements may also contain data allocated on the heap (like std::string), will the data be on the RAM of the microcontroller? I suppose there is only one heap, right? If so, then a fixed size array with character arrays with limited length might actually be preferable to save µC RAM.
  • In reply to ChrisS:

    Hello ChrisS,

    that's a good question. You can try to figure it out. The address of a variable can be found in e2 studio in the debug mode. To view the address you should run and then suspend the program and then hover the mouse cursor over the variable name in the code editor - a pop-up window will be displayed showing variable details. The same details can be viewed using the "Expressions" window:
    menu Window > Show View > Expressions

    Then you can compare this address with data available in the "Memory Usage" window:
    menu Renesas Views > Debug > Memory Usage
    There is the "Section" tab which shows address ranges for defined memory sections.

    Please also refer to the documentation:
    S7G2 User's Manual > 4. Address Space

    Best regards,
    anper

  • In reply to anper:

    One more question on this topic. Is it possible to move the heap to .sdram? When I tried this I got an error in network initialization. However, it would be very helpful to have a heap in SDRAM as I need quite some dynamic memory. If this is not working then I will have to check if I can use some memory pool in SDRAM for the allocation functions.
  • In reply to ChrisS:

    Oh and one more, how can we see RAM vs. SDRAM usage? I'm not sure which is displayed after compilation. SDRAM can be seen by looking at the .sdram section in memory panel, but what about RAM? Is RAM really bss + data or is SDRAM included in there as well?
  • In reply to ChrisS:

    The heap for example is also moved to RAM in the linker script, so there are more sections other than .bss and .data which are moved to RAM?
  • In reply to ChrisS:

    Hi ChrisS,

    The heap can be placed in SDRAM by moving entry of script/S7G2.ld:

    .heap (NOLOAD):
    {
        . = ALIGN(8);
        KEEP(*(.heap_d1))
        . = ALIGN(8);
        __HeapBase = .;
        __end__ = .;
        end = __end__;
        KEEP(*(.heap*))
        __HeapLimit = .;
    } > RAM

    after

    /* SDRAM */
    .sdram (NOLOAD):
    {
        __SDRAM_Start = .;
        KEEP(*(.sdram*))
        KEEP(*(.frame*))
        __SDRAM_End = .;
    } > SDRAM

    and changing the last line to "} > SDRAM":

    .heap (NOLOAD):
    {
        . = ALIGN(8);
        KEEP(*(.heap_d1))
        . = ALIGN(8);
        __HeapBase = .;
        __end__ = .;
        end = __end__;
        KEEP(*(.heap*))
        __HeapLimit = .;
    } > SDRAM

    Regards,
    adboc

  • In reply to adboc:

    Hi ChrisS,

    arm-none-eabi-size -A -d tool can provide more detailed information. Most likely you'll find this tool in C:\Program Files (x86)\GNU Tools ARM Embedded\4.9 2015q3\bin, it should be invoked like this: arm-none-eabi-size.exe -A -d PATH_TO_ELF_FILE

    Regards,
    adboc
  • In reply to adboc:

    This seems to work, but errors happen if you don't clean the project first and do a full rebuild.

    Next question: I can move global variables to a section with BSP_PLACE_IN_SECTION or with __attribute__ ((section(".sdram"))). However, if I want to assign them constant data, say, a character array, this doesn't seem to work properly.
    BSP_PLACE_IN_SECTION
    unsigned char index_htm[] BSP_PLACE_IN_SECTION(".sdram" )= {
    0x1f, 0x8b, 0x08, 0x08, 0x2a, 0x72, 0x4f, 0x5a, 0x02, 0x03, 0x69, 0x6e, ... };
    doesn't compile at all, while the code below produces wrong behaviour during program execution (corrupted or missing data, in some cases also crashes in free_r()):
    unsigned char index_htm[] __attribute__ ((section(".sdram")))= {
    0x1f, 0x8b, 0x08, 0x08, 0x2a, 0x72, 0x4f, 0x5a, 0x02, 0x03, 0x69, 0x6e, ... };
    Should one declare those arrays with a fixed size in SDRAM and copy the constant data manually into it on startup instead?
  • In reply to adboc:

    arm-none-eabi-size -A -d gives additional information about the debug data, but it doesn't tell me the size of the RAM and SDRAM sections separately as far as I can tell. However, I did some calculations by summing the separate sections like .data .stack_dummy etc and noticed that data+bss gives the size of the sum of RAM and SDRAM. To get the separate sizes, one needs to sum the size of the sections given by "arm-none-eabi-size -A -d" according to the linker script.