Skip to main content
BWKidd
Senior
September 10, 2024
Solved

Custom Loaders for the STM32L496 with MT25QL128 QuadSPI External Flash (ultimately for touchGFX)

  • September 10, 2024
  • 14 replies
  • 10705 views

Hi All,

I've been trying to bring up a custom external loader for well over a week and I'm just not getting anywhere.

My processor is an STM32L496VGT6 and its connected via quadSPI to an MT25QL128A 16MB external flash memory. I'm running the clock at 80MHz, and my QUADSPI is setup like this (both in my custom loader, and in the application code I'm developing):

BWKidd_3-1725980804997.png

BWKidd_4-1725980856276.png

Following mostly along with the "External QSPI loader how to" (from here External QSPI loader how to - 05 – QSPI driver coding - YouTube), and utilizing the files in the contrib branch of the stm external loader github repository (GitHub - STMicroelectronics/stm32-external-loader at contrib), I've put together what seems like a working driver for the MT25QL128. I got there by starting with the quadspi.h/c files in the stm32-custom-loader/QSPI_Drivers/MT25QL512/ folder, and then modifying them using the micro datasheet for the part to swap different commands where necessary. I pulled in test code from the main.c file in stm32-external-loader-contrib\Loader_Files\other devices\, and also used the Loader_Src.c, Dev_Inf.h/c, an linker.ld files from the same folder. The following test code runs with no issues when debugging:

 

/* USER CODE BEGIN 2 */
uint8_t buffer_test[MEMORY_SECTOR_SIZE];
uint32_t var = 0;

CSP_QUADSPI_Init();

for (var = 0; var < MEMORY_SECTOR_SIZE; var++) {
buffer_test[var] = (var & 0xff);
}

for (var = 0; var < SECTORS_COUNT; var++) {

if (CSP_QSPI_EraseSector(var * MEMORY_SECTOR_SIZE, (var + 1) * MEMORY_SECTOR_SIZE - 1) != HAL_OK) {

while (1)
; //breakpoint - error detected
}

if (CSP_QSPI_WriteMemory(buffer_test, var * MEMORY_SECTOR_SIZE, sizeof(buffer_test)) != HAL_OK) {

while (1)
; //breakpoint - error detected
}

}

if (CSP_QSPI_EnableMemoryMappedMode() != HAL_OK) {

while (1)
; //breakpoint - error detected
}

for (var = 0; var < SECTORS_COUNT; var++) {
if (memcmp(buffer_test, (uint8_t*) (QSPI_BASE + var * MEMORY_SECTOR_SIZE), MEMORY_SECTOR_SIZE) != HAL_OK) {
while (1)
; //breakpoint - error detected - otherwise QSPI works properly
}
}
/* USER CODE END 2 */

 

 

I then modified my project options to generate the stldr file per the youtube video, changed to the "linker.ld" file, and copied the stldr file it into my STM32CubeProgrammer ExternalLoader folder. I used the STM32CubeProgrammer to read memory (starting at 0x90000000), and write to the same memory area using the "testbinary1M.bin" file from \stm32-external-loader-contrib\QSPI_testing\.

Everything up to this point seems to work without problems so far.

Where my problem begins is when I attempt to use the new external loader I generated in my debug sessions while trying to develop my main application. Here I've gone into the debug sessions, pointed to my generated loader file, and started to debug.

BWKidd_2-1725978700482.png

BWKidd_0-1725978665088.png

With the external loader enabled as above, the code stops on the first use of:

HAL_Delay(1);

If I drill down a little with the debugger, the code is stuck within HAL_Delay() in the while loop:

 

 

__weak void HAL_Delay(uint32_t Delay)
{
uint32_t tickstart = HAL_GetTick();

uint32_t wait = Delay;

/* Add a period to guaranty minimum wait */
if (wait < HAL_MAX_DELAY)
 {
 wait += (uint32_t)uwTickFreq;
 }

while ((HAL_GetTick() - tickstart) < wait) // <===== STUCK HERE!
 {
 }
}

Where HAL_GetTick() constantly returns 0, which doesn't seem right.

 

 

When I disable the external loader, everything goes back to working fine. What do I check next? Is my external loader really just not working in some untested way? Or is there some initialization I need to do in my main() initialization when using an external loader? Or maybe some deinitialization I didn't do in my loader? 

Best answer by BWKidd

Holy Carp! 

BWKidd_1-1726261865191.png

My external loader was more or less working all along. I just needed to not have "initialize" checked in the external loader debug settings.

An ST field applications engineer took a look at it and that was all it was. I'll try to post a follow up with a few more details on Monday, but that was pretty much it. Many thanks for those of you who offered advice, and a special thanks to @Tesla DeLorean for trying to help me work through it.

BWKidd_0-1726261321683.png

 

14 replies

BWKidd
BWKiddAuthor
Senior
September 17, 2024

MT25QL128 driver code (use at your own risk!)

BWKidd
BWKiddAuthor
Senior
September 17, 2024

And finally main.h/c

BWKidd
BWKiddAuthor
Senior
April 1, 2025

Hi @Abhiram_12 Abhiram_12,

Unfortunately its been a while since i've looked at this and I've only done it once, so hopefully someone more experienced can weigh in here, but my experience was that I needed to have that "initialize" checkbox left un-checked. If you check it, I think your main application attempts to initialize based on the init function in your loader, which almost certainly what you don't want. So if I understand your question properly, then the answer is you definitely want to leave "initialize" un-checked in your debug options for the external loader.

Associate III
April 11, 2025

@BWKidd Thanks BWKidd.