How to assign a variable to a specific SRAM memory address.


I've made a board that uses a SAME51 for the canbus peripheral. Now I am trying to adopt some atmel code into an arduino library.

The canbus peripheral seems to be split into two halves, the configuration registers and then some working message ram for storing canbus data, filters, and other related things. Part of the requirement of this memory is that it all resides below 64KB in SRAM.

I understand how to calculate the size of this RAM, and move around inside to extract message data and similar functions from the atmel code, but what I don't know how to do is assign a specific set of memory just for this purpose.

I am thinking I might be able to modify the CMSIS-Atmel or DFU files (same51g19a.h, in my case) so that the SRAM start address is after my chunk of message ram, but that doesn't seem like the proper way to do it, and I'm not sure pointers to the original SRAM base address to use the memory would actually work?

Further, the size of message ram is calculated by defines, like this. So it would be nice if the offset to SRAM could be calculated off however these values are configured. Is this possible?

#define CAN_RAM_BUF_HDR_SIZE (2u)   // Length (in 32b words) of CAN Header Packet
#define CAN_RAM_FILT_STD_SIZE (1u)  // Length (in 32b words) of a standard CAN filter
#define CAN_RAM_FILT_EXT_SIZE (2u)  // Length (in 32b words) of a extened CAN filter
#define CAN_RAM_TX_EVT_SIZE (2u)    // Length (in 32b words) of a TX event 

#define RAM_ARRAY_SIZE_FILT_STD       (32u) // Number of standard filters
#define RAM_ARRAY_SIZE_FILT_EXT       (32u) // Number of extended filters
#define RAM_FIFO_SIZE_RX0             (64u) // Number of RX FIFO0 elements
#define RAM_FIFO_SIZE_RX1             (32u) // Number of RX FIFO1 elements
#define RAM_ARRAY_SIZE_RX             (8u)  // Number of dedicated RX recieve buffers
#define RAM_ARRAY_SIZE_TX             (8u)  // Number of dedicated TX buffers
#define RAM_FIFO_SIZE_TX              (16u) // Number of TX FIFO elements
#define RAM_TX_EVENT_SIZE             (8u)  // Number of TX Event elements

#define RAM_FIFO_DATA_SIZE_RX0        (8u)  // Length of data (in bytes) in RX FIFO0
#define RAM_FIFO_DATA_SIZE_RX1        (8u)  // Length of data (in bytes) in RX FIFO1
#define RAM_ARRAY_DATA_SIZE_RX        (8u)  // Length of data (in bytes) in array buffer
#define RAM_ARRAY_DATA_SIZE_TX        (8u)  // Length of data (in bytes) in array buffer/fifo

#define MSG_RAM_SIZE      ( \               // Formula for calculating the total CAN Message RAM usage
                            (RAM_ARRAY_SIZE_FILT_STD * CAN_RAM_FILT_STD_SIZE) \
                            + (RAM_ARRAY_SIZE_FILT_EXT * CAN_RAM_FILT_EXT_SIZE) \
                            + (RAM_TX_EVENT_SIZE * CAN_RAM_TX_EVT_SIZE) \
                            + (RAM_FIFO_SIZE_RX0 * (CAN_RAM_BUF_HDR_SIZE + (RAM_FIFO_DATA_SIZE_RX0 / 4))) \
                            + (RAM_FIFO_SIZE_RX1 * (CAN_RAM_BUF_HDR_SIZE + (RAM_FIFO_DATA_SIZE_RX1 / 4))) \
                            + (RAM_ARRAY_SIZE_RX * (CAN_RAM_BUF_HDR_SIZE + (RAM_ARRAY_DATA_SIZE_RX / 4))) \
                            + (RAM_ARRAY_SIZE_TX * (CAN_RAM_BUF_HDR_SIZE + (RAM_ARRAY_DATA_SIZE_TX / 4))) \
                            + (RAM_FIFO_SIZE_TX * (CAN_RAM_BUF_HDR_SIZE + (RAM_ARRAY_DATA_SIZE_TX / 4))) )

Thank you!

I think I figured it out, and even how to make it adjust to the size of my buffer after compilation!

It’s all in the linker script apparently, and every board gets a variant. Most everything globally defined as read/writable is assigned to a section called “.bss”, static defines are assigned to section “.text”. There are a few others, mostly system functions from the look of it. These ones take up about 2K of ram right at the start, called section “.data”.

So to get a static block of memory very near the start of SRAM you have to have the linker script add it to the binary file after the system ram, but before bss ram, the stack, heap and all that stuff.

So Flash_with_bootloader.ld needs modified, somewhere in the board variant file. Somewhere after “data_end = .; } > RAM” but before “.bss :” need to add a new section. Mine looks like this…

        .canram : 
		. = ALIGN(4);
		__canram_start__ = .;
		. = ALIGN(4);
		 __canram_end__ = .;
	} > RAM

This defines a section called .canram. The variable “.” contains the total offset from the start of RAM, so . = ALIGN(4); makes sure the offset starts at an accessible offset, “canram_start”.

KEEP((.canram)) makes sure the compiled code is actually stored in the binary even if nothing apparently uses it. Anything assigned to the .canram section gets saved here.

From there it aligns the end of the offset and keeps a record of that offset for logging. “>RAM” stores it to the RAM (rw) section defined earlier in the linker script.

From there now just define variables with the section attribute. That looks like this.

uint32_t testram[5] __attribute__((section(".canram.msg")));

And looking at the .map file, can see where this “code” eventually ends up.

.canram         0x20000100       0x14 load address 0x00006ab8
                0x20000100                . = ALIGN (0x4)
                0x20000100                __canram_start__ = .
 .canram.msg    0x20000100       0x14 C:\Users\AppData\Local\Temp\VMBuilds\RAM_PO~1\DEEZUM~1\Debug/core.a(main.cpp.o)
                0x20000100                testram
                0x20000114                . = ALIGN (0x4)
                0x20000114                __canram_end__ = .

Does this look correct?

Thank you!