cancel
Showing results for 
Search instead for 
Did you mean: 

TouchGFX on custom Board

LucasStartTech
Associate III

Hi, I wonder if someone could help me with my setup.

@Tesla DeLorean  @Amel NASRI @Andrew Neil 

I am currently trying to use touchGFX to design my GUI in a custom board. Before trying to use touchGFX, I set up the LTDC and FMC to use an external SDRAM to hold the buffer and it works fine (I can draw on the screen). However, I've been struggling to setup the touchGFX and being able to only get some random pixels. I noticed from the templates that an external flash is being used to hold initial assets generated at touchGFX, but my board does not have an external flash right now.

Is it possible to run touchGFX from internal flash, and use only external sdram for the framebuffer?

I'll share the configurations I have so far:

LucasStartTech_0-1753184049391.png

LucasStartTech_1-1753184088891.pngLucasStartTech_2-1753184103723.png

And here is my ld file:

/*
******************************************************************************
**
** @file        : LinkerScript.ld
**
** @author      : Auto-generated by STM32CubeIDE
**
** @brief       : Linker script for STM32F469IITx Device from STM32F4 series
**                      2048KBytes FLASH
**                      64KBytes CCMRAM
**                      320KBytes 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.
**
******************************************************************************
** @attention
**
** Copyright (c) 2025 STMicroelectronics.
** All rights reserved.
**
** This software is licensed under terms that can be found in the LICENSE file
** in the root directory of this software component.
** If no LICENSE file comes with this software, it is provided AS-IS.
**
******************************************************************************
*/

/* 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 = 320K
  FLASH    (rx)    : ORIGIN = 0x8000000,   LENGTH = 2048K
  SDRAM (xrw)	   : ORIGIN = 0xD0000000, LENGTH = 32M
}

/* 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 (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
  {
    . = ALIGN(4);
    *(.ARM.extab* .gnu.linkonce.armextab.*)
    . = ALIGN(4);
  } >FLASH

  .ARM (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
  {
    . = ALIGN(4);
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
    . = ALIGN(4);
  } >FLASH

  .preinit_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
  {
    . = ALIGN(4);
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
    . = ALIGN(4);
  } >FLASH

  .init_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
  {
    . = ALIGN(4);
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
    . = ALIGN(4);
  } >FLASH

  .fini_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
  {
    . = 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 */
    *(.RamFunc)        /* .RamFunc sections */
    *(.RamFunc*)       /* .RamFunc* sections */

    . = ALIGN(4);
    _edata = .;        /* define a global symbol at data end */

  } >RAM AT> FLASH

  _siccmram = LOADADDR(.ccmram);

  /* CCM-RAM section
  *
  * IMPORTANT NOTE!
  * If initialized variables will be placed in this section,
  * the startup code needs to be modified to copy the init-values.
  */
  .ccmram :
  {
    . = ALIGN(4);
    _sccmram = .;       /* create a global symbol at ccmram start */
    *(.ccmram)
    *(.ccmram*)

    . = ALIGN(4);
    _eccmram = .;       /* create a global symbol at ccmram end */
  } >CCMRAM 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
  
   .graphics_frame_buffer (NOLOAD) :
  {
    . = ALIGN(4); /* Align to 4 bytes */
    __FRAMEBUFFER_START__ = .; /* Define a global symbol for TouchGFX to find the start address */
    *(.graphics_frame_buffer) /* This will contain the framebuffer data */
    
    /* Reserve space for TWO 800x480 RGB565 framebuffers for double buffering */
    /* Calculation: 800 pixels * 480 lines * 2 bytes/pixel (RGB565) = 768000 bytes = 0xBC000 */
    /* For double buffering: 0xBC000 * 2 = 0x178000 bytes */
    . = . + 0x178000;
    
    __FRAMEBUFFER_END__ = .; /* Optional: Define a symbol for the end of the framebuffer area */
  } >SDRAM AT>SDRAM /* This places the section in the SDRAM memory region */
  
 

    /* Remove information from the compiler libraries */
  /DISCARD/ :
  {
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
  }
  .ARM.attributes 0 : { *(.ARM.attributes) }
}

 

3 REPLIES 3

>>Is it possible to run touchGFX from internal flash, and use only external sdram for the framebuffer?

I'd imagine if the content fit. Your linker script doesn't describe any external NOR Flash, so wouldn't use it. Does it build now, or run out of space?

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

@Tesla DeLorean 

Thank you for the fast response! 

I - I thought that if the content would not fit, it would appear in the terminal during the flashing, is it incorrect?

II - This is the ld file generated by the IDE. I've never coded in the ld file before, so I was a little afraid of trying to change things in that file, because I already erased the vector table once trying things like this and wasn't able to boot the MCU again. So, is there a RM that I could read to learn how to deal with it?

III - The code builds it, I can even flash the code onto the MCU, however I never see changes in the screen other than some random static pixels.

 

Note: I even used a fill.rect function within the touchGFX file, and confirmed that it changed the data in the SDRAM, but for some reason it does not send the data generated for the GUI (just a picture) created in the touchGFX. I tried to read the documentation, but I mostly found instructions of how to set it up in the development boards and nothing about how to make it work in a custom board. Is there a document you recommend so I can learn?

LucasStartTech
Associate III

@Tesla DeLorean 

 

I think I got it working.

 

I added in the ld file:

    .rodata :
  {
    . = ALIGN(4);
    *(.rodata)
    *(.rodata*)
    . = ALIGN(4);
  } >FLASH
 
/* Place TouchGFX assets in FLASH */
.TouchGFX_Assets :
{
  . = ALIGN(4);
  *(.TouchGFX*)
  *(.assets*)
  *(.IntFlashSection*)  /* <== Add this line */
  . = ALIGN(4);
} >FLASH

 

After this I was able to change the colors, but as you said... I got memory overflow once I tried to put a photo. However, I have a question. After getting the ld file correct, I had a bug with the HAL_Delay. I know it is an issue to use it when using RTOS, however it was located before osKernelInitialize(). Here is where it is located:

 

  MX_DMA2D_Init();
  MX_TouchGFX_Init();
  /* Call PreOsInit function */
  MX_TouchGFX_PreOSInit();
  /* USER CODE BEGIN 2 */

  /* Infinite loop */
	// Allocate buffer

	//  int y_ = 0;

	/*  uint16_t yellow_rgb565 = 0x0f0f;
	  for (int y = 0; y < FRAMEBUFFER_HEIGHT; y++) {
	          for (int x = 0; x < FRAMEBUFFER_WIDTH; x++) {
	        	  uint32_t index = y * FRAMEBUFFER_WIDTH + x; // 1D index
	        	  uint32_t address = (uint32_t)BUFFER_LAYER_1_ADDRESS + index * BYTES_PER_PIXEL; // SDRAM address
	              HAL_SDRAM_Write_16b(&hsdram1, (uint32_t *)address, &yellow_rgb565, 1);
	              address += BYTES_PER_PIXEL; // Increment by 2 bytes for each pixel
	          }
	      }*/
	//  HAL_Delay(1000);

	//LCD_Fill(BUFFER_LAYER_1_ADDRESS, 0, 0,FRAMEBUFFER_WIDTH,FRAMEBUFFER_HEIGHT,RGB565_Celtic_blue);
	ESP_RST_GPIO_Port->BSRR = 1U << (4+16);
	ESP_EN_GPIO_Port->BSRR = 1U << (5+16);
	//HAL_Delay(1000);
	ESP_RST_GPIO_Port->BSRR = 1U << (4);
	ESP_EN_GPIO_Port->BSRR = 1U << 5;

	//sprintf(msg2, "JUST GOT HERE 7\n");
	//HAL_UART_Transmit(&huart8, (uint8_t *)msg2, strlen(msg2), 1000);


	//HAL_Delay(1000);
	ESP_RTS_GPIO_Port->BSRR = 1U << (8+16);
	//ESP_RTS_GPIO_Port->BSRR = 1U << (8);
	GPIOC->BSRR = 1U << 2; // YD
	//char msg1[100] = "RUN 2 200";
//	MX_TouchGFX_Init();
  /* USER CODE END 2 */

  /* Init scheduler */
  osKernelInitialize();

 

Would the cause for this be this call: MX_TouchGFX_PreOSInit(); ?