cancel
Showing results for 
Search instead for 
Did you mean: 

Complete graphical assets not displayed on custom STM32 board

Ameya M
Associate III

Hello,

We have developed a custom STM32 board using STM32F746G controller, with the hardware design based on STM32F746G-DISCO EVAL board.

We are using TouchGFX for developing graphics.

The debug interface we are using is JTAG, and the debugger we are using is STLINK-V3SET

We are using ST-LINK Utility for flashing the hex file.

The device gets programmed but the graphics displayed are incomplete.

The texts with colour variation are seen but widgets such as buttons and image are not seen. Also, wildcard text changes are visible.

Our pin mapping are exactly same as per EVAL board for QSPI, SDRAM, LCD TFT, etc

Please refer below images, the image needs to be displayed but the screen shows blank.

I understand graphical assets get normally stored in QSPI memory and based on the log of ST Link Utility the program is not getting written at QSPI memory locations at all due to which we are able to produce text content but not able to show graphics as programmed in TouchGFX.

We expect your expert advice to understand cause of this issue and solve this.

Thanks,

Ameya0690X00000AQsxsQAD.jpg0690X00000AQsuyQAD.jpg

8 REPLIES 8
HP
Senior III

This might be related to my issue here: https://community.st.com/s/question/0D50X0000BI1CvjSQF/external-vs-internal-flash-memory-for-touchgfx-assets?t=1567963909749

I found the solution to loading the external flash assets here: https://community.st.com/s/question/0D50X0000Ap1gIO/problem-using-qspi-with-stm32f746-and-touchgfx

it's quite interesting that you have the text but no visuals - that could be caused by the fact that fonts and texts are stored internally while the graphics are externally placed...

The STM32 Cube Programmer is arguably a better application to write the external flash, but both it and the ST-LINK Utilities are poorly tested.

You should perhaps checksum/crc the QSPI content and check that it is correct and valid, rather than rely on others. Perhaps sign your AXF, ELF or HEX files so they can be properly authenticated.

Consider your own means of delivering data to the application, so it can pull/update images from an SDCard, as part of an IAP or OTA strategy for the design.

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

As @HP​ states - Your texts may be in internal flash (since they are displayed), but your image entries in the image database in touchgfx may be pointing to memory in external flash (which isn't programmed properly).

Check your linker script to find out where assets are placed. I'm not even sure how you created this project, so we'll see.

You must load your external flashloader manually in ST-Link/STCubeProgrammer. Depending on how your QSPI chip is connected you may have to write your own - Since you state that it is pin compatible you should be able to use an existing one.

/Martin

Ameya M
Associate III

Hello @Martin KJELDSEN​ ,

Thanks for replying.

I used TouchGFX 4.9.3 in which Keil project is created, I use keil for writing the backend and use the .hex file generated by Keil to flash.

I use STM32 ST-Link Utility for flashing.

Yes, the QSPI, SDRAM is pin compatible as per ST EVAL board.

Also, another point is that since the EVAL board QSPI chip is obsolete, we used it's alternative which is having almost same specifcations and also, same pin to pin compatibility.

Please refer below datasheets of the QSPI chips

1) EVAL Board QSPI chip - https://www.mouser.in/datasheet/2/671/n25q_128mb_3v_65nm-1283709.pdf

2) Custom board QSPI chip - https://www.mouser.in/datasheet/2/949/w25q128jv_dtr_revc_03272018_plus-1489858.pdf

Thanks,

Ameya

Hello @Martin KJELDSEN​ , @HP​ , @Community member​ ,

I have couple of questions:

1) How do I modify the linker script, I found it in C ->TouchGFXProjects -> Projectxx -> target -> gcc as 'application.ld'

Below is the linker script:

_STACKSIZE = 1024;
_HEAPSIZE = 512;
 
MEMORY
{
    CODE (rx)   : ORIGIN = 0x08000000, LENGTH = 1024K
    RAM (rw)    : ORIGIN = 0x20000000, LENGTH = 304K
    QUADSPI (r) : ORIGIN = 0x90000000, LENGTH = 16M
}
 
/* Section Definitions */
 
ENTRY(ResetISR)
 
SECTIONS
{
	/* first section is .text which is used for code */
	.text :
	{
		CREATE_OBJECT_SYMBOLS
		KEEP(*(.isr_vectors))
		*(.text .text.*)
		*(.gnu.linkonce.t.*)
		*(.glue_7t) *(.glue_7) *(.vfp11_veneer)
		KEEP(*(.fini))
		*(.gcc_except_table)
		. = ALIGN(0x4);
	} >CODE = 0
	. = ALIGN(4);
 
	/* .ctors .dtors are used for c++ constructors/destructors */
	
	.ctors :
	{
		PROVIDE(__ctors_start__ = .);
		KEEP(*(SORT(.ctors.*)))
		KEEP(*(.ctors))
		PROVIDE(__ctors_end__ = .);
	} >CODE
 
	.dtors :
	{
		PROVIDE(__dtors_start__ = .); 
		KEEP(*(SORT(.dtors.*)))
		KEEP(*(.dtors))
		PROVIDE(__dtors_end__ = .);
	} >CODE
	
	/* .rodata section which is used for read-only data (constants) */
 
	.rodata :
	{
		*(.rodata .rodata.*)
		*(.gnu.linkonce.r.*)
	} >CODE
	. = ALIGN(4);
 
	.init_array :
	{
		*(.init)
        *(.fini)
		PROVIDE_HIDDEN (__preinit_array_start = .);
		KEEP (*(.preinit_array))
		PROVIDE_HIDDEN (__preinit_array_end = .);
		PROVIDE_HIDDEN (__init_array_start = .);
		KEEP (*(SORT(.init_array.*)))
		KEEP (*(.init_array))
		PROVIDE_HIDDEN (__init_array_end = .);
		PROVIDE_HIDDEN (__fini_array_start = .);
		KEEP (*(.fini_array))
		KEEP (*(SORT(.fini_array.*)))
		PROVIDE_HIDDEN (__fini_array_end = .);
	} >CODE
 
	. = ALIGN(4);
 
	/* .ARM.exidx is sorted, so has to go in its own output section.  */
	__exidx_start = .;
	.ARM.exidx :
	{
		*(.ARM.exidx* .gnu.linkonce.armexidx.*)
	} >CODE
	__exidx_end = .;
 
 
 	_etext = .;
	PROVIDE (etext = .);
 
	.data : AT (_etext)
	{
		__data_start = .;
		*(.data .data.*)
		*(.gnu.linkonce.d.*)
		SORT(CONSTRUCTORS)
		. = ALIGN(4);
		*(.fastrun .fastrun.*)
	} >RAM
	. = ALIGN(4);
	
	_edata = .;
	PROVIDE (edata = .);
 
	/* .bss section which is used for uninitialized data */
 
	.bss :
	{
		__bss_start = .;
		__bss_start__ = .;
		*(.bss .bss.*)
		*(.gnu.linkonce.b.*)
		*(COMMON)
		. = ALIGN(4);
	} >RAM
	__bss_end__ = .;
	
	_end = .;
	PROVIDE(end = .);
 
	/* .heap section which is used for memory allocation */
	
	.heap (NOLOAD) :
	{
		__heap_start__ = .;
		*(.heap)
		. = MAX(__heap_start__ + _HEAPSIZE , .);
	} >RAM
	__heap_end__ = __heap_start__ + SIZEOF(.heap);
	
	/* .stack section - user mode stack */
	
	.stack (__heap_end__ + 3) / 4 * 4 (NOLOAD) :
	{
		. = ALIGN(8);
		__stack_start__ = .;
		*(.stack)
		. = ALIGN(8);
		. = MAX(__stack_start__ + _STACKSIZE , .);
	} >RAM
	__stack_end__ = __stack_start__ + SIZEOF(.stack);
 
	/* Stabs debugging sections.  */
	.stab          0 : { *(.stab) }
	.stabstr       0 : { *(.stabstr) }
	.stab.excl     0 : { *(.stab.excl) }
	.stab.exclstr  0 : { *(.stab.exclstr) }
	.stab.index    0 : { *(.stab.index) }
	.stab.indexstr 0 : { *(.stab.indexstr) }
	.comment       0 : { *(.comment) }
	/* DWARF debug sections.
		Symbols in the DWARF debugging sections are relative to the beginning
		of the section so we begin them at 0.  */
	/* DWARF 1 */
	.debug          0 : { *(.debug) }
	.line           0 : { *(.line) }
	/* GNU DWARF 1 extensions */
	.debug_srcinfo  0 : { *(.debug_srcinfo) }
	.debug_sfnames  0 : { *(.debug_sfnames) }
	/* DWARF 1.1 and DWARF 2 */
	.debug_aranges  0 : { *(.debug_aranges) }
	.debug_pubnames 0 : { *(.debug_pubnames) }
	/* DWARF 2 */
	.debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
	.debug_abbrev   0 : { *(.debug_abbrev) }
	.debug_line     0 : { *(.debug_line) }
	.debug_frame    0 : { *(.debug_frame) }
	.debug_str      0 : { *(.debug_str) }
	.debug_loc      0 : { *(.debug_loc) }
	.debug_macinfo  0 : { *(.debug_macinfo) }
	/* SGI/MIPS DWARF 2 extensions */
	.debug_weaknames 0 : { *(.debug_weaknames) }
	.debug_funcnames 0 : { *(.debug_funcnames) }
	.debug_typenames 0 : { *(.debug_typenames) }
	.debug_varnames  0 : { *(.debug_varnames) }	
 
	ExtFlashSection :
	{
		*(ExtFlashSection ExtFlashSection.*)
		*(.gnu.linkonce.r.*)
        . = ALIGN(0x4);
	} >QUADSPI
}
 
 __valid_user_code_checksum = 0 - (__stack_end__ + ResetISR + 1 + NMI_Handler + 1 + HardFault_Handler + 1 + MemManage_Handler + 1 + BusFault_Handler + 1 + UsageFault_Handler + 1);

2) If I am not able to use the same external loader even though the QSPI chip is connected to MCU as per EVAL board (except that they are of different makes but same specs and pin to pin compatibility), How do I make a custom external loader?

Please refer the below image for the comparison of QSPI chips used in custom board and EVAL board.

0690X00000AQxhVQAT.jpg

Looking forward to your advice.

Thanks,

Ameya

HP
Senior III

Hey @Ameya M​ 

Maybe you can have a look at my answer here: https://community.st.com/s/question/0D50X0000BI1CvjSQF/external-vs-internal-flash-memory-for-touchgfx-assets

It might be the same issue you're having? Adding the qspi files and the proper init code did it for me at least.

Did you manage to solve your issue ? I am building a custom board based on f746 disco .... and the obselete QSPI flash in concerning me.

@Abdullah İhsanoğlu​ 

Hi,

No, we haven't yet able to build a custom external loader for Winbond QSPI.

Thanks,

Ameya