Problem regarding external memory on STM32F746G-DISC board

int main(void)
{
    HAL_Init();

    /* Configure the system clock to 216 MHz */
    SystemClock_Config();

    /* Enable I-Cache */
    SCB_EnableICache();

    /* Enable D-Cache */
    SCB_EnableDCache();

    BSP_SDRAM_Init();
    HAL_EnableFMCMemorySwapping();

    lv_init();

    tft_init();
    touchpad_init();


    lv_demo_benchmark();

    while (1)
    {
        HAL_Delay(5);
        lv_task_handler();
    }
}

This is how my main looks like, I have commented out BSP_SDRAM_init from LCD_init as well & set LV_MEM_ADR to 0x60100000. Now the hardfault is gone, but all I can see is a white blank screen, No output on the screen.

Upon debugging it looks like lv_refr_vdb_flush could not flush the VDB. the execution just stuck there.

Change the my_fb line in tft.c to this:

static __IO uintpixel_t * my_fb = (__IO uintpixel_t*) (0x60000000);

Testing right now.
Just to be clear I can use SDRAM address 0xC0000000, if I do not enable FMC Swapping right?

Yes (that is how the v7 project originally worked), however, you may run into an issue where the display content starts flickering. The only solution we were able to find was to use swapping.

Now that worked finally!!!

I am still having issue with QSPI though, even though I am calling BSP_QSPI_Init(); and BSP_QSPI_MemoryMappedMode(); just after SCB_EnableDCache().
I am getting hardfault, when trying to set the label text from a global char * like below, also another I have tried to put a 480x272 image (converted true color), but the image is kinda distorted/corrupted like the below image. I have also added __attribute__((section(".textqspi"))) to the bitmap array var.

__attribute__((section(".textqspi"))) char *x = "Hello Bello Cello!!";

LV_IMG_DECLARE(bg_test)

int main(void)
{
    HAL_Init();

    /* Configure the system clock to 216 MHz */
    SystemClock_Config();

    /* Enable I-Cache */
    SCB_EnableICache();

    /* Enable D-Cache */
    SCB_EnableDCache();

    BSP_QSPI_Init();
    BSP_QSPI_MemoryMappedMode();

    BSP_SDRAM_Init();
    HAL_EnableFMCMemorySwapping();
    lv_init();

    tft_init();
    touchpad_init();

/*    lv_obj_t *bg = lv_img_create(lv_scr_act(), NULL);
    lv_img_set_src(bg, &bg_test); // distorted image?
    lv_obj_align(bg, NULL, LV_ALIGN_CENTER, 0, 0);*/

    lv_obj_t *lb = lv_label_create(lv_scr_act(), NULL);
    lv_label_set_text(lb, x);     // causes hardfault
    lv_obj_set_style_local_text_font(lb, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &lv_font_montserrat_48);
    lv_obj_align(lb, NULL, LV_ALIGN_CENTER, 0, 0);

 //   lv_demo_benchmark();

    while (1)
    {
        HAL_Delay(5);
        lv_task_handler();
    }
}

Have you flashed the bitmap to QSPI first?

That’s onboard flash, I am using stm32cubeIDE and selected external loader for that in debugger config. So, I think the QSPI Flash is being written through that right?.
However when I tried to read the memory 0x90000000, nothing expected was there.

Strangely I am facing this issue with other inbuilt examples in cubef7 pack. But the original demo of my board works fine. :thinking: :thinking:

Are you 100% sure that the external loader is working properly? It’s sounding like the original contents of QSPI are still there and have never been changed. Perhaps check the log at the bottom and see if any errors pop up?

Got the issue, and fixed it!!
I forgot to add .textqspi : { *(.textqspi) } >QSPI after .ARM.attributes 0 : { *(.ARM.attributes) }
Aaah damn. Due to this loader wasn’t actually pushing that stuff to QSPI flash at all.
Thanks for your help @embeddedt :slight_smile:
Here is my whole linker script just for reference:

/*
*****************************************************************************
**

**  File        : LinkerScript.ld
**
**  Abstract    : Linker script for STM32F746NGHx Device with
**                1024KByte FLASH, 320KByte RAM
**
**                Set heap size, stack size and stack location according
**                to application requirements.
**
**                Set memory bank area and size if external memory is used.
**
**  Target      : STMicroelectronics STM32
**
**
**  Distribution: The file is distributed as is, without any warranty
**                of any kind.
**
**  (c)Copyright Ac6.
**  You may use this file as-is or modify it according to the needs of your
**  project. Distribution of this file (unmodified or modified) is not
**  permitted. Ac6 permit registered System Workbench for MCU users the
**  rights to distribute the assembled, compiled & linked contents of this
**  file as part of an application binary file, provided that it is built
**  using the System Workbench for MCU toolchain.
**
*****************************************************************************
*/

/* Entry Point */
ENTRY(Reset_Handler)

/* Highest address of the user mode stack */
_estack = 0x20050000;    /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x800;      /* required amount of heap  */
_Min_Stack_Size = 0x1000; /* required amount of stack */

/* Specify the memory areas */
MEMORY
{
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 320K
FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 1024K
QSPI (xrw)      : ORIGIN = 0x90000000, LENGTH = 16M
}

/* Define output sections */
SECTIONS
{
  /* The startup code goes first into FLASH */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >FLASH
  
   .textqspi :
  {
    . = ALIGN(4);
    _qspi_start = .;        /* create a global symbol at qspi start */
    *(.textqspi)         /* .textqspi sections */
    *(.textqspi*)        /* .textqspi* sections */
    . = ALIGN(4);
    _qspi_end = .;         /* define a global symbols at end of textqspi */
    
  } >QSPI AT> FLASH

  /* The program code and other data goes into FLASH */
  .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 goes into FLASH */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >FLASH

  .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
  .ARM : {
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
  } >FLASH

  .preinit_array     :
  {
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
  } >FLASH
  .init_array :
  {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
  } >FLASH
  .fini_array :
  {
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
  } >FLASH

  /* used by the startup to initialize data */
  _sidata = LOADADDR(.data);

  /* Initialized data sections goes into RAM, load LMA copy after code */
  .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 */
  . = ALIGN(4);
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss secion */
    _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 left */
  ._user_heap_stack :
  {
    . = ALIGN(8);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(8);
  } >RAM
  

  /* Remove information from the standard libraries */
  /DISCARD/ :
  {
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
  }

  .ARM.attributes 0 : { *(.ARM.attributes) }
  .textqspi : { *(.textqspi) } >QSPI
}

You also have select the respective external loader in debug config, and also call these too in main before using any lvgl objects placed on external flash, you can add these before lv_init()

    BSP_QSPI_Init();
    BSP_QSPI_MemoryMappedMode();

Thanks for this, great info!

May I ask one question? How can you flash a bitmap to QSPI?

Thanks in advance

You will need to use external loader to flash the bitmap to QSPI.
In STM32CubeProgrammer, connect to the board using ST-Link.
Go to external loader and select the one for F746.
From flash, select the binary image and enter the correct address of the flash memory and flash the flash memory.