carraysshared-memory

Initialize array starting from specific address in memory - C programming


Do you have idea how to initialize array of structs starting from specific address in memory (not virtual, physical DDR memory)?

I am working on implementation of TxRx on SoC (ARM-FPGA). Basically ARM (PS) and FPGA (PL) communicate to each other by using shared RAM memory.

Currently I am working on transmitter side, so I need to constantly load packets that I get from MAC layer to memory, then my Tx reads data and sends it in air. To achieve this I want to implement circular FIFO buffer on (ARM) side, in way that I can store up to 6 packets into buffer and send them one by one, in same time loading other packets on places of already sent packages. Because I need to use specific memory addresses I am interested is it possible to initialize array of structure that will be stored on specific addresses in memory.

For example I want that my array starts at adress 0x400000 and ends at address 0x400000 + MaximumNumberOfPackets x SizeOfPackets.

I know how to do it for one instantiate of structure for example like this:

buffer_t *tmp = (struct buffer_t *)234881024;

But how to do it for array of structures?


Solution

  • A pointer to a single struct (or int, float, or anything else) is inherently a pointer to an array of them. The pointer type provides the sizeof() value for an array entry, and thus allows pointer arithmetic to work.

    Thus, given a struct buffer you can simply do

    static struct buffer * const myFIFO = (struct buffer *) 0x40000
    

    and then simply access myFIFO as an array

    for (size_t i = 0; i < maxPackets; ++i)
    {
        buffer[i].someField = initialValue1;
        buffer[i].someOtherField = 42;
    }
    

    This works just the way you expect.

    What you can't do (using pure standard C) is declare an array at a particular address like this:

    struct buffer myFIFO[23] @ 0x400000;
    

    However, your compiler may have extensions to allow it. Many embedded compilers do (after all, that's often how they declare memory-mapped device registers), but it will be different for every compiler vendor, and possibly for every chip because it is a vendor extension.

    GCC does allow it for AVR processors via an attribute, for example

    volatile int porta __attribute__((address (0x600)));
    

    But it doesn't seem to support it for an ARM.