2024-12-18 02:12 PM - edited 2024-12-18 02:13 PM
Hello,
I am attempting to make an external loader for a QuadSPI flash S25FL256SAGMFI000 using the STM32F769 and STM32CubeIDE.
I followed this tutorial: https://www.youtube.com/playlist?list=PLnMKNibPkDnHIrq5BICcFhLsmJFI_ytvE
I was able to run the code to the end of the while loop like described in the video and successfully wrote/read to memory at address 0x90000000.
I am able to generate an stldr file, but when I try to load it in the CubeProgrammer the file displays the error "ERROR PARSING FAIL". The programmer also does not display the right start address, the memory size, page size, or type, which leads me to believe there is a problem with the Dev_Inf.c file.
Has anyone seen this error before and can steer me in the right direction of where to look to correct it? I have attached the Dev_Inf.c, Loader_Src.c, and quadspi.c files. Please let me know what other files I can attach for review.
Thank you!
2024-12-18 02:24 PM
Start with the .ELF / .STLDR, inspect with tools like OBJDUMP, FROMELF or OBJCOPY, try to understand how the form differs from those that load/work properly.
Make sure it's exporting the expected functions, and builds for RAM at 0x20000004
Check also the Linker Script, .LD
2024-12-19 05:52 AM
Hi Tesla - I'm a bit new to this and am not sure how to use the tools you mentioned to view the .elf, .stldr files. Are there some resources I could be looking at for these?
I am not able to attach the linker file, but here is the code:
/*
*****************************************************************************
** File : linker.ld
**
** 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
**
*****************************************************************************
*/
/* Entry Point */
ENTRY(Init)
/* Generate 2 segment for Loader code and device info */
PHDRS {Loader PT_LOAD ; SgInfo PT_LOAD ; }
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200 ; /* required amount of heap */
_Min_Stack_Size = 0x400 ; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000004, LENGTH = 8M
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = . + 0x1FC;
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >RAM :Loader
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >RAM
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >RAM :Loader
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >RAM :Loader
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >RAM :Loader
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >RAM :Loader
/* 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 :Loader
/* 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 :Loader
/* 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 */
} >RAM :Loader
.Dev_info :
{
KEEP(*Dev_Inf.o ( .rodata* ))
} :SgInfo
/* Constant data goes into FLASH */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >RAM :Loader
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(4);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(4);
} >RAM :Loader
.ARM.attributes 0 : { *(.ARM.attributes) }
}
2024-12-19 05:55 AM
I did find this github for the exact quadspi I am using:
Through this post on the ST forums:
Is there a way I could modify this file to work with the F7?
2024-12-19 06:54 AM
The design of the cores and peripherals doesn't exactly make these things portable at a binary level. I'd have to back-port the SPANSION support into my build.
The .ELF object describes several sections that pull into memory, with symbols identifying the entry points, the data/size of StorageInfo typically driving the user interface in the External Loader menu, but it might be looking for Init, Write, SectorErase, etc.
2024-12-19 08:58 AM
Is there anything I can see in the .ELF that would indicate that it isn't loading the information from the Dev_Inf.c/h files?
2024-12-19 10:29 AM
Well dumping out the content of the data records describing StorageInfo should allow you to confirm the data in Dev_Inf.c is correctly reflected in the structure.
If you look at things that are working successfully, you can contrast that to the one that's not viable.
Is this really how you have the part wired? Is that viable? Have you programmed the part from application space?
PF10 CLK
PB10 NCS BK1
PF8 D0 BK1
PF9 D1 BK1
PC1 NCS BK2
PH2 D0 BK2
PH3 D1 BK2
fromelf.exe -csd CLIVEONE-W25Q64_STM32F4XX-PF10-PB6-PF8-PF9-PF7-PF6.stldr
========================================================================
** ELF Header Information
File Name: CLIVEONE-W25Q64_STM32F4XX-PF10-PB6-PF8-PF9-PF7-PF6.stldr
Machine class: ELFCLASS32 (32-bit)
Data encoding: ELFDATA2LSB (Little endian)
Header version: EV_CURRENT (Current version)
Operating System ABI: none
ABI Version: 0
File Type: ET_EXEC (Executable) (2)
Machine: EM_ARM (ARM)
Image Entry point: 0x20000895
Flags: EF_ARM_HASENTRY + EF_ARM_ABI_FLOAT_SOFT (0x05000202)
ARM ELF revision: 5 (ABI version 2)
Conforms to Soft float procedure-call standard
Header size: 52 bytes (0x34)
Program header entry size: 32 bytes (0x20)
Section header entry size: 40 bytes (0x28)
Program header entries: 2
Section header entries: 10
Program header offset: 6252 (0x0000186c)
Section header offset: 6316 (0x000018ac)
Section header string table index: 7
========================================================================
** Program header #0 (PT_LOAD) [PF_R]
Size : 200 bytes
Virtual address: 0x00000000 (Alignment 32768)
====================================
** Program header #1 (PT_LOAD) [PF_X + PF_W + PF_R]
Size : 5800 bytes (5708 bytes in file)
Virtual address: 0x20000004 (Alignment 32768)
========================================================================
** Section #1 '.info' (SHT_PROGBITS) [SHF_ALLOC]
Size : 200 bytes (alignment 4)
Address: 0x00000000
0x000000: 43 4c 49 56 45 4f 4e 45 2d 57 32 35 51 36 34 5f CLIVEONE-W25Q64_
0x000010: 53 54 4d 33 32 46 34 58 58 2d 50 46 31 30 2d 50 STM32F4XX-PF10-P
0x000020: 42 36 2d 50 46 38 2d 50 46 39 2d 50 46 37 2d 50 B6-PF8-PF9-PF7-P
0x000030: 46 36 00 73 6f 75 72 63 65 72 33 32 40 67 6d 61 F6.sourcer32@gma
0x000040: 69 6c 2e 63 6f 6d 00 00 00 00 00 00 00 00 00 00 il.com..........
0x000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x000060: 00 00 00 00 07 00 00 00 00 00 00 90 00 00 80 00 ................
0x000070: 00 01 00 00 ff 00 00 00 80 00 00 00 00 00 01 00 ................
0x000080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x000090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0000a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0000b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0000c0: 00 00 00 00 00 00 00 00 ........
** Section #2 '.prog' (SHT_PROGBITS) [SHF_ALLOC + SHF_EXECINSTR]
Size : 5680 bytes (alignment 4)
Address: 0x20000004
...
** Section #8 '.symtab' (SHT_SYMTAB)
Size : 128 bytes (alignment 4)
String table #9 '.strtab'
Last local symbol no. 0
Symbol table .symtab (7 symbols, 0 local)
# Symbol Name Value Bind Sec Type Vis Size
========================================================================
1 StorageInfo 0x00000000 Gb 1 Data De 0xc8
2 Init 0x20000895 Gb 2 Code De 0x1d0
3 DeInit 0x20000a65 Gb 2 Code De 0x4
4 Write 0x20000b69 Gb 2 Code De 0xa4
5 Read 0x20000af5 Gb 2 Code De 0x74
6 MassErase 0x20000ae5 Gb 2 Code De 0xe
7 SectorErase 0x20000a69 Gb 2 Code De 0x7c
...
2024-12-20 08:26 AM
The pinout does work, I am using the STM32F769IIT6. I am able to execute example code in the debug mode to erase, write and read contents or the flash successfully. I will have to look at the .elf file. I need to download KEIL MDK to get the fromelf.exe program.
Just an observation; the contents for the Dev_Inf .cyclo and .su files in the release folder are empty. Looking at other files, this doesn't seem normal. Could that be part of the problem?
2024-12-20 08:41 AM
In GNU objdump/objcopy should have some similar functionality, as I recall.
You could perhaps attach the offending .STLDR, probably need to be in a .7z or something.
I could use the memory in 1 or 2-bit modes, seems an odd configuration across two banks TBH
2024-12-20 08:50 AM - edited 2024-12-20 08:51 AM