You can use SDRAM with sdram.malloc() or even without using malloc (directly from start 0x60000000). With sdram.malloc() you do not need to know where SDRAM address is.
#include <SDRAM.h>
uint8_t* GsdramStart = NULL; // not yet initialized
SDRAMClass sdram;
void setup() {
//initialize SDRAM
sdram.begin(); //DO NOT FORGET TO DO THIS
#if 0
GsdramStart = (uint8_t*)sdram.malloc((8 * 1024 * 1024)/8 - 12); //first 12 bytes are used for malloc?
#else
GsdramStart = (uint8_t*)0x60000000; //hard-coded start of SDRAM (bank 1, NOR/PSRAM)
#endif
if (GsdramStart)
strcpy((char*)GsdramStart, (const char *)"SDRAM"); //0x60000000
//with sdram.malloc(): string starts at 0x6000000C: before, on 0x60000008 seems to be the allocated length for the sdram.malloc()
You can use SDRAM like any other RAM in system. Even it is just an 8bit external SDRAM interface, you can use it with any type (char, int, long, ...), as 8bit, 16bit or 32bit data. The memory controller makes sure to store longer types with several read/write cycles (transparent for you).
You can also use MPU. Per default, the SDRAM is cachable, so the read and writes go through DCache (a nice performance improvements, esp. for an 8bit interface).
Just to bear in mind:
You cannot define variables which are stored on SDRAM. The SDRAM location (0x60000000) is not defined in linker script. So, you cannot use variables assigned to SDRAM location.
You had to use a pointer, set to start of SDRAM address, 0x60000000. And read/write via such a pointer.
If you would add something in your linker_script.ld, like this:
MEMORY
{
FLASH (rx) : ORIGIN = 0x08040000, LENGTH = 0x8040000 - CM4_BINARY_START
DTCMRAM (rwx) : ORIGIN = 0x20000000 + (((166 * 4) + 7) & 0xFFFFFFF8), LENGTH = 128K - (((166 * 4) + 7) & 0xFFFFFFF8)
RAM (xrw) : ORIGIN = 0x24000000, LENGTH = 0x80000
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K
ITCMRAM (rwx) : ORIGIN = 0x00000000, LENGTH = 64K
SDRAM (rwx) : ORIGIN = 0x60000000, LENGTH = 8M
}
SD :
{
. = ALIGN(4);
_ssdram = .;
KEEP(*(.sdramtext.vectors))
. = ALIGN(4);
*(.sdramtext)
. = ALIGN(4);
*(.sdramdata)
. = ALIGN(4);
_esdram = .;
} >SDRAM AT> FLASH
you could use attribute for variables, whcih should be located on SDRAM, e.g.:
char SDRAM_string[80] __attribute__((section(".sdramdata"))) = "Hallo from SDRAM\r\n";
BUT: initialization code needed
The SDRAM would not be initialized! You need additional code, which should be actually code done in startup.S, way before main() is called.
Here the code I use to initialize SDRAM with these global, initialized variables (using this attribute((section(".sdramdata"))):
ITCM_Startup.cpp (2.6 KB)
ITCM_Startup.h (275 Bytes)
Call the function provided there (as assembly code - rename file *.cpp into *.S !) after SDRAM is initialized but before you use any variable on it the first time:
extern "C" {
void SDRAM_Startup(void); /* initialize: copy code and data to SDRAM */
}
SDRAM_Startup(); //before first use of SDRAM variables, but after initialization of SDRAM done!
This extern C is needed because the function implemented in Assembly code behaves like a C-function (not like C++).
But the easiest way is to use pointers, set to an address in SDRAM location, as:
unsigned long *mySDRAMlongPtr = (unsigned long *)0x60000180;
*mySDRRAMlongPtr = myLongVal;
if (*mySDRAMlongPtr > 0) {
...