The register for the CAN RX & TX buffer/FIFO start address (F0SA/TBSA) only consider the lower 16 bits of an address but a RAM address can span from 0x20000000 to 0x20040000 (18 bits).
Link to datasheet.
So if I initialize an array to work as the RX FIFO like so:
uint8_t can1_rx_fifo0[CAN1_RX_FIFO_ELEMENTS * 16] __attribute__((__aligned__(4)));
And the compiler puts it at the memory address 0x20005A70, it's no problem as I can write 0x5A70 into F0SA/TBSA and CAN is going to see the correct buffer/FIFO address. But if that array gets put at address 0x20015A70, I can still only write 0x5A70 to F0SA/TBSA and this is the wrong address.
I tried doing it like this and the FIFO gets put at an appropriate address that I specified but then that address gets overwritten/used for other things in RAM.
#define CAN1_RX_FIFO (volatile struct can1_rx_fifo_struct*)(0x20000000)
static struct can1_rx_fifo_struct
{
uint8_t can1_rx_fifo[CAN1_RX_FIFO_ELEMENTS * 16];
};
Am I misunderstanding how this works? If not, how can I best and safely initialize the array so it gets stored at a memory address between 0x20000000 - 0x2000FFFF?


When I wrote a CAN driver for another ATSAM part I just cheekily made sure it was allocated in
.bssby making itstaticand then ensured that.bsswas on top of the RAM.From my driver code:
can0andcan1will be allocated in.bss. And.bssisn't large enough to go out of the addressable range, and it was allocated at0x20000000, so this will (cheekily) work.You could also ensure that these aren't allocated in the wrong section by a static assert:
Note that using structures also sorts out alignment automatically.