cancel
Showing results for 
Search instead for 
Did you mean: 

External loader STM32L442 and S25FL127 Cypress

Dimitar Dyakov
Associate III

Hello all,

I have written a External Loader using nucleo-l476rg and S25FL127 16mb NOR flash using 64k sectors. I was using it with TouchGFX and it worked just fine.

I migrated to stm32l442. I have copied the code for the flash driver, changed the linker etc. as of this video https://www.youtube.com/watch?v=YFIvJVsvIsE

The loader for the 442 does not work. It does not read or write in CubeProgrammer. I could put the memory into memory mapped mode, read and write to it when using the 442 when I debug the test code provided in the example. So the code is still good.

My suspicions are that the 442 has only 64K of SRAM and this might be the problem. How can I fix this? Are there any other reasons for the loader not to work.

Some notes:

  1. I can provide the code for the flash if needed.
  2. Also I want to use the 64k sectors so that my memory sectors are uniform.
  3. I am adding the log from the CubeProgrammer if it is of help:
  4. I don't think the problem is HW. I am running it on low frequencies, I have added decupling capacitor and pull up resistor on CS as per instructions. Also it runs on the nucleo.
17:54:11:863 : UPLOADING ...
17:54:11:864 :   Size          : 1024 Bytes
17:54:11:864 :   Address       : 0x90000000
17:54:11:864 : Read progress:
17:54:11:864 : Reading data...
17:54:11:864 : halt ap 0 
17:54:11:864 : w ap 0 reg 15 PC   (0x20000000)  
17:54:11:865 : w ap 0 reg 17 MSP  (0x20000500)  
17:54:11:865 : w ap 0 reg 16 xPSR (0x01000000)  
17:54:11:865 : Init flashloader...
17:54:11:865 : halt ap 0 
17:54:11:865 : w ap 0 reg 0 R0   0x00000000
17:54:11:865 : w ap 0 reg 1 R1   0x00000000
17:54:11:865 : w ap 0 reg 2 R2   0x00000000
17:54:11:865 : w ap 0 reg 3 R3   0x00000000
17:54:11:866 : w ap 0 reg 4 R4   0x00000000
17:54:11:866 : w ap 0 reg 5 R5   0x00000000
17:54:11:866 : w ap 0 reg 6 R6   0x00000000
17:54:11:866 : w ap 0 reg 7 R7   0x00000000
17:54:11:866 : w ap 0 reg 8 R8   0x00000000
17:54:11:866 : w ap 0 reg 9 R9   0x00000000
17:54:11:867 : w ap 0 reg 10 R10  0x00000000
17:54:11:867 : w ap 0 reg 11 R11  0x00000000
17:54:11:867 : w ap 0 reg 12 R12  0x00000000
17:54:11:867 : w ap 0 reg 13 SP   0x00000000
17:54:11:867 : w ap 0 reg 14 LR   0x00000000
17:54:11:868 : w ap 0 reg 15 PC   0x20000579
17:54:11:868 : w ap 0 reg 16 xPSR 0x01000000
17:54:11:869 : w ap 0 reg 17 MSP  0x00000000
17:54:11:869 : w ap 0 reg 18 PSP  0x00000000
17:54:11:869 : run ap 0 
17:54:16:000 : halt ap 0 
17:54:16:000 : Init function fail with timeout
17:54:16:002 : r ap 0 reg 16 xPSR 0x41000003
17:54:16:007 : halt ap 0 
17:54:16:007 : w ap 0 reg 15 PC   (0x20000000)  
17:54:16:008 : w ap 0 reg 17 MSP  (0x20000500)  
17:54:16:008 : w ap 0 reg 16 xPSR (0x01000000)  
17:54:16:008 : Error: Data read failed

6 REPLIES 6

>>Are there any other reasons for the loader not to work.

More than you might imagine, ST has made this far more difficult than necessary. A scripted solution like that used be IAR might be simpler.

Your loader is choking in the Init function, so assume it's probably stuck in a while() loop of some kind, either one denoting error or failure, or waiting on a clock counter that isn't advancing in a timeout loop within the HAL library, BSP or wherever. Check if reinitializing the clocks or QSPI cause issues.

The serial ports and other hardware on your board is viable, output diagnostic, telemetry and checkpoint info to understand flow and failure.

>>My suspicions are that the 442 has only 64K of SRAM and this might be the problem. 

An external loader doesn't need vast amounts, as I recall most I've built in less than 8KB

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

I did an experiment. I put the board into debug mode with the external loader configuration. And put a break point in the Init function and it goes there. It runs through the init and it goes to hard fault. I will try a serial port for debug just to be sure. 10x for the info.

How do you check the size of the loader after you compile it ?

I've got some ELF dumping tools, but things like FromELF or objcopy might do the trick.

The GNU LD does output stats to the console as I recall, and there's the .MAP file.

The .ELF (.STLDR) itself can be of quite significant size as the linker puts all the symbolic and debug information, but the sections that actually load into RAM tend to be smaller. The HAL based ones do bring a lot of baggage, ST originally built most of their loaders with an SPL and small footprint library, but then had to pivot into using HAL/Cube because they'd sold that as the solution to everything.

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

To all lost souls do not despair there is hope. You will get it to work. 

I made it to work. I can't tell you what was wrong with the loader, but i can tell you how i fixed it. It would have been nice to know the reason... but i will take this as is. 

If someone more knowledgeable than me can tell me the answer, be kind and share. 

As you can see from the post above, I have some success with STM32CubeIDE and nucleo-STM32L476, but when switching to STM32L442 I hit a wall. 

User Tesla DeLorean suggested there was a need to debug this program somehow. But the problem is that if SystemInit(); SystemClock_Config(); or MX_GPIO_Init(); fails

you don't get GPIO UARTS... 

So what I did is I put a while(1) in the beginning of the Init function compile and i ran the code. Init function fail with timeout - Great! Expected result. 

Then i get rid of the while loop and put return FAIL statement in the beginning of the function and again ran the code. I get the same error Init function fail with timeout - ah? Okay.. it fails but what's with the timeout?

And you have guested I put return OK in the beginning of the function and ran the code. I get the same error Init function fail with timeout - wait what?

I want to get some information out of the loader. The return values does not going to cut it. Next i did is got rid of the return statement and I added a little bit of assembly asm( "LDR R11, =0xDEADBEAF" );

I run the code and see if the deadbeaf appears in register R11. Nothing. No deadbeaf. No matter where i put it. It seems that the code does not get executed at all.

Another interesting thing is that when i set the same external loader in STM32 ST-LINK Utility i get the error that the elf file is too big for the ram of the device. 

So... how I fix it?

1. deleted STM32CubeIDE

2. Using STM32CubeMX i generated a IAR project for the MCU 

3. from https://github.com/STMicroelectronics/stm32-external-loader/tree/main/STM32L4x_boards/MX25LM51245G_STM32L4R9I-DISCO/Project/EWARM i downloaded the IAR project

4. I looked at the settings they use and copied them to my project. 

- in Options -> Linker -> Config set Linker Config file to Target.icf (from example project see above point)

- in Options -> Linker -> Output set output file name to "Loader.stldr"

- in Options -> Linker -> Library set Overwrite default program entry to "Init"

- in General Options -> Library Configuration -> Library dropdown set Normal

- in General Options -> Library Options 1 -> set printf/scanf to small

    - in C/C++ Compiler -> Optimizations set level none

5. And here user Tesla DeLorean comes again to save the day by point out in a different thread that you need to add "__root " directive to your Loader functions i.e. "__root int SectorErase(uint32_t EraseStartAddress, uint32_t EraseEndAddress)" 

6. Compile and copy the loader to STM32CubeProgrammer folder. Worked form the first try...

So yeah... fixed it. Hope i helped you. 

USARTs and GPIOs aren't technically constrained by HAL/Cube initialization. The processor is clocking at entry, if you change the clock sources and PLLs later the USART baud rates will be off, but can be adjusted.

As you say you can use the register dump the tools provide in the verbose dump to track progress and report back information.

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

Additional info.

After I did all of the above steps the loader was kind of working with the cube programmer, but always form the second try. For example the first time I did sector erase it would say that I should check if the sector is protected etc. When I click again it would erase the sector no problem. If the debugger was disconnected and then connected it fails the first time again.

I did not make much of this, but when I try to use it with TouchGFX it was not going to work. I have narrowed the problem down to auto polling. And more specifically to HAL_GetTick. The systick was not getting updated. I went through the git repo I linked above to see if there was something different in the hal libraries. I find the workaround in the Loader_Src.c file. The following code is added in the beginning of the source files.

#pragma section=".bss"
/* Private functions ---------------------------------------------------------*/
__root HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{ 
  return HAL_OK;
}
 
__root uint32_t HAL_GetTick(void)
{
  return 1;
}
 
void HAL_Delay(uint32_t Delay)
{
  int i = 0;
  for (i=0;i<0x100;i++);
}

Best regards,

Mitko Dyakov