cancel
Showing results for 
Search instead for 
Did you mean: 

Extend RAM STM32F429

juliuscaesar
Associate III

Hey,

I have a discovery board (https://www.st.com/resource/en/data_brief/32f429idiscovery.pdf)

This board has an on board 64 MBit SDRAM.

Now i have read in other posts that RAM extension is not possible in an SPC line MCU. However what about the STM32F429.

According to the datasheet (https://www.st.com/resource/en/datasheet/stm32f427vg.pdf) the STM32F429 has an

"Flexible external memory controller with up to 32-bit data bus: SRAM, PSRAM, SDRAM/LPSDR SDRAM, Compact Flash/NOR/NAND memories"

Can this be used to extend the internal RAM? (I know that NXP has an option here with their kinetis MCUs)

1 ACCEPTED SOLUTION

Accepted Solutions

The SDRAMDISK example has code to initialize the memory, it doesn't tell the linker about it because the entire memory is accessed via an indexed pointer.

You might want to look at other examples where the SDRAM is used as a frame buffer

  1. SDRAM (rw) : ORIGIN = 0xD0000000, LENGTH = 8M

You'd then need to direct content there, or have it as NOLOAD

If you direct content into the SDRAM, you'd need to direct the backing content to FLASH, and then add code to startup.s to bring up the memory, and then move the initial content out there.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

View solution in original post

8 REPLIES 8

SPC? Small Pin Count? Typically you're going to want >=144-pin devices if you're entertaining external memories

External memory interfaces are pin hogs, and not particularly fast. The F4 doesn't cache.

In 2021 perhaps consider NEWER STM32 parts with faster processors, caches, and more on-board memory. And those with QSPI Flash Memory support, ie 256 MB with 6-pins.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
TDK
Guru

Both the STM32F427 and STM32F429 can use SDRAM to extend memory, as well as other RAM types, as long as the package has the pins required to do so.

If you feel a post has answered your question, please click "Accept as Solution".
juliuscaesar
Associate III

hey thx for your fast answer. The disc board above has an LQFP144 pin package. 🙂

I know that QuadSPI or Octa SPI is recommended for using external memory. However I ony got this board here, and it should only serve as a proof of conecpt 😉

How can I extend my linker script the use the external memory of the discovery board

I'm using the default linker script generated by Stm32Cube

/**
 ******************************************************************************
 * @file      LinkerScript.ld
 * @author    Auto-generated by STM32CubeIDE
 *  Abstract    : Linker script for STM32F429I-DISC1 Board embedding STM32F429ZITx Device from stm32f4 series
 *                      2048Kbytes FLASH
 *                      64Kbytes CCMRAM
 *                      192Kbytes RAM
 *
 *            Set heap size, stack size and stack location according
 *            to application requirements.
 *
 *            Set memory bank area and size if external memory is used
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
 * All rights reserved.</center></h2>
 *
 * This software component is licensed by ST under BSD 3-Clause license,
 * the "License"; You may not use this file except in compliance with the
 * License. You may obtain a copy of the License at:
 *                        opensource.org/licenses/BSD-3-Clause
 *
 ******************************************************************************
 */
 
/* Entry Point */
ENTRY(Reset_Handler)
 
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM);	/* end of "RAM" Ram type memory */
 
_Min_Heap_Size = 0x200 ;	/* required amount of heap  */
_Min_Stack_Size = 0x400 ;	/* required amount of stack */
 
/* Memories definition */
MEMORY
{
  CCMRAM    (xrw)    : ORIGIN = 0x10000000,   LENGTH = 64K
  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 192K
  FLASH    (rx)    : ORIGIN = 0x8000000,   LENGTH = 2048K
}
 
/* Sections */
SECTIONS
{
  /* The startup code into "FLASH" Rom type memory */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >FLASH
 
  /* The program code and other data into "FLASH" Rom type memory */
  .text :
  {
    . = ALIGN(4);
    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */
    *(.glue_7)         /* glue arm to thumb code */
    *(.glue_7t)        /* glue thumb to arm code */
    *(.eh_frame)
 
    KEEP (*(.init))
    KEEP (*(.fini))
 
    . = ALIGN(4);
    _etext = .;        /* define a global symbols at end of code */
  } >FLASH
 
  /* Constant data into "FLASH" Rom type memory */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >FLASH
 
  .ARM.extab   : { 
    . = ALIGN(4);
    *(.ARM.extab* .gnu.linkonce.armextab.*)
    . = ALIGN(4);
  } >FLASH
  
  .ARM : {
    . = ALIGN(4);
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
    . = ALIGN(4);
  } >FLASH
 
  .preinit_array     :
  {
    . = ALIGN(4);
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
    . = ALIGN(4);
  } >FLASH
  
  .init_array :
  {
    . = ALIGN(4);
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
    . = ALIGN(4);
  } >FLASH
  
  .fini_array :
  {
    . = ALIGN(4);
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
    . = ALIGN(4);
  } >FLASH
 
  /* Used by the startup to initialize data */
  _sidata = LOADADDR(.data);
 
  /* Initialized data sections into "RAM" Ram type memory */
  .data : 
  {
    . = ALIGN(4);
    _sdata = .;        /* create a global symbol at data start */
    *(.data)           /* .data sections */
    *(.data*)          /* .data* sections */
 
    . = ALIGN(4);
    _edata = .;        /* define a global symbol at data end */
    
  } >RAM AT> FLASH
 
  /* Uninitialized data section into "RAM" Ram type memory */
  . = ALIGN(4);
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss section */
    _sbss = .;         /* define a global symbol at bss start */
    __bss_start__ = _sbss;
    *(.bss)
    *(.bss*)
    *(COMMON)
 
    . = ALIGN(4);
    _ebss = .;         /* define a global symbol at bss end */
    __bss_end__ = _ebss;
  } >RAM
 
  /* User_heap_stack section, used to check that there is enough "RAM" Ram  type memory left */
  ._user_heap_stack :
  {
    . = ALIGN(8);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(8);
  } >RAM
 
  /* Remove information from the compiler libraries */
  /DISCARD/ :
  {
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
  }
 
  .ARM.attributes 0 : { *(.ARM.attributes) }
}

You will have an 8MB memory at 0xD0000000 once you initialize the pins, peripheral and memory

One should refrain from putting the stack in SDRAM as it is significantly slower. You might want two pools for your heap

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

SDRAM Disk Example

STM32Cube_FW_F4_V1.25.0\Projects\STM32F429I-Discovery\Applications\FatFs\FatFs_RAMDisk

BSP Code

STM32Cube_FW_F4_V1.25.0\Drivers\BSP\STM32F429I-Discovery\stm32f429i_discovery_sdram.c

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
juliuscaesar
Associate III

Hey thx for your reply. I have been looking at the example project.

But I still have 2 questions:

1) in middlewares/fatfs/drivers/sdram_diskio.c there are 2 functions which seem to be used read/write variables in the external RAM

/**
  * @brief  Reads Sector(s)
  * @param  lun : not used
  * @param  *buff: Data buffer to store read data
  * @param  sector: Sector address (LBA)
  * @param  count: Number of sectors to read (1..128)
  * @retval DRESULT: Operation result
  */
DRESULT SDRAMDISK_read(BYTE lun, BYTE *buff, DWORD sector, UINT count)
{
  uint32_t *pSrcBuffer = (uint32_t *)buff;
  uint32_t BufferSize = (BLOCK_SIZE * count)/4;
  uint32_t *pSdramAddress = (uint32_t *) (SDRAM_DEVICE_ADDR + (sector * BLOCK_SIZE));
 
  for(; BufferSize != 0; BufferSize--)
  {
    *pSrcBuffer++ = *(__IO uint32_t *)pSdramAddress++;
  }
 
  return RES_OK;
}
 
/**
  * @brief  Writes Sector(s)
  * @param  lun : not used
  * @param  *buff: Data to be written
  * @param  sector: Sector address (LBA)
  * @param  count: Number of sectors to write (1..128)
  * @retval DRESULT: Operation result
  */
#if _USE_WRITE == 1
DRESULT SDRAMDISK_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count)
{
  uint32_t *pDstBuffer = (uint32_t *)buff;
  uint32_t BufferSize = (BLOCK_SIZE * count)/4;
  uint32_t *pSramAddress = (uint32_t *) (SDRAM_DEVICE_ADDR + (sector * BLOCK_SIZE));
 
  for(; BufferSize != 0; BufferSize--)
  {
    *(__IO uint32_t *)pSramAddress++ = *pDstBuffer++;
  }
 
  return RES_OK;
}
#endif /* _USE_WRITE == 1 */

Now these functions do not access the external RAM. Where is the external RAM accessed

2) The start address of 0xD0000000 is added to the requested address in SDRAMDISK_write/SDRAMDISK_read

But should there be an extra section in the linker script (Address 0-64k) to tell the linker thesse addresses are valid ram adresses too?

let's say i have a function

void foo()
 
{
 
  //access some global var
  int bar = g_bar;
}

In my code I don't care wheter g_bar is located in the internal or external RAM. How does the program know where to load this value from?

The SDRAMDISK example has code to initialize the memory, it doesn't tell the linker about it because the entire memory is accessed via an indexed pointer.

You might want to look at other examples where the SDRAM is used as a frame buffer

  1. SDRAM (rw) : ORIGIN = 0xD0000000, LENGTH = 8M

You'd then need to direct content there, or have it as NOLOAD

If you direct content into the SDRAM, you'd need to direct the backing content to FLASH, and then add code to startup.s to bring up the memory, and then move the initial content out there.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
juliuscaesar
Associate III

hey thx for your answers

this seams a little more complicated than I hoped :p

I need to do some backgroud reading first. But i believe I get the idea of how it's working. 😉

greets Julian