Author Topic: STM 32F4: any way to make it self program its FLASH from an external SPI FLASH?  (Read 2900 times)

0 Members and 1 Guest are viewing this topic.

Online peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 4121
  • Country: gb
  • Doing electronics since the 1960s...
The factory boot loader supports UART, USB and CAN loading. Has anyone found a way to make it do SPI - like some other arm32 chips do (ESP32?)?

The answer must be "not possible" since the boot loader cannot be reprogrammed.

And if you are loading the FLASH via SWD then you may as well load the whole FLASH :)
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Online langwadt

  • Super Contributor
  • ***
  • Posts: 4729
  • Country: dk
The factory boot loader supports UART, USB and CAN loading. Has anyone found a way to make it do SPI - like some other arm32 chips do (ESP32?)?

The answer must be "not possible" since the boot loader cannot be reprogrammed.

And if you are loading the FLASH via SWD then you may as well load the whole FLASH :)

I believe it is possible to load a program in RAM and execute it using the bootloader
 

Offline wek

  • Frequent Contributor
  • **
  • Posts: 536
  • Country: sk
You can use a second mcu which reads the external flash and implements the SPI bootloader protocol.

> like some other arm32 chips do (ESP32?)?

Most chips which appear to boot from external FLASH or EEPROM in fact run a bootloader from internal ROM.

JW
 

Offline wek

  • Frequent Contributor
  • **
  • Posts: 536
  • Country: sk
The factory boot loader supports UART, USB and CAN loading. Has anyone found a way to make it do SPI - like some other arm32 chips do (ESP32?)?

The answer must be "not possible" since the boot loader cannot be reprogrammed.

And if you are loading the FLASH via SWD then you may as well load the whole FLASH :)

I believe it is possible to load a program in RAM and execute it using the bootloader
Sure, but the STM32 running bootloader is in the role of a slave, so again, there must be "somebody" (PC or a second mcu) implementing the bootloader's "master" portion on any of the available interfaces, to fill up that RAM.

JW
 

Online peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 4121
  • Country: gb
  • Doing electronics since the 1960s...
Quote
You can use a second mcu which reads the external flash and implements the SPI bootloader protocol.

Yes. Incidentally I recall an STM32 project (not mine) where the customer demanded a provably non-brickable firmware upgrade feature, and a 2nd CPU was the only way to do it.
« Last Edit: September 23, 2024, 07:03:54 am by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Online Siwastaja

  • Super Contributor
  • ***
  • Posts: 8775
  • Country: fi
Quote
You can use a second mcu which reads the external flash and implements the SPI bootloader protocol.

Yes. Incidentally I recall an STM32 project (not mine) where the customer demanded a provably non-brickable firmware upgrade feature, and a 2nd CPU was the only way to do it.

There is absolutely nothing magic in adding another MCU that makes it any more provably non-brickable: exactly same concerns still apply. Adding a second MCU only adds even more potential points of failure.
 
The following users thanked this post: newbrain

Offline newbrain

  • Super Contributor
  • ***
  • Posts: 1768
  • Country: se
Unless "provably" means "passing all the tests that that we managed to devise with our humanly limited fantasy".
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Online peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 4121
  • Country: gb
  • Doing electronics since the 1960s...
Well, obviously, there would be a presumption that the 2nd CPU has well tested code which the customer thinks is solid and which will never be upgraded. That 2nd CPU would waggle the /NRST and I guess the BOOTx pins, while feeding the data into the main CPU via one of the routes provided.

There is a thread here describing the CAN mode is horrible, and USB is absolutely never going to be "provably" reliable, so I guess serial (at some decent speed) would be the way to do it.

Quote
Most chips which appear to boot from external FLASH or EEPROM in fact run a bootloader from internal ROM.

That makes sense, as otherwise they would need hardwired logic to implement the loading. No point really.
« Last Edit: September 23, 2024, 07:47:54 am by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline Psi

  • Super Contributor
  • ***
  • Posts: 10228
  • Country: nz
What's wrong with just writing your own bootloader? 
Have I missed something?
Greek letter 'Psi' (not Pounds per Square Inch)
 

Offline fchk

  • Frequent Contributor
  • **
  • Posts: 255
  • Country: de
The factory boot loader supports UART, USB and CAN loading. Has anyone found a way to make it do SPI - like some other arm32 chips do (ESP32?)?

Read AN4286:
https://www.st.com/resource/en/application_note/an4286-spi-protocol-used-in-the-stm32-bootloader-stmicroelectronics.pdf

fchk
 

Online Siwastaja

  • Super Contributor
  • ***
  • Posts: 8775
  • Country: fi
Well, obviously, there would be a presumption that the 2nd CPU has well tested code which the customer thinks is solid and which will never be upgraded.

This presumption indeed makes life easy, if it holds. You get the same result without the extra chip by running that solid non-upgradeable code as a bootloader, which is why I said there are no extra magical qualities in putting an extra physical part in the design.

Of course, sometimes you hit a useful corner case where you almost have enough flash but not quite. Then maybe dedicating some part (such as update, but could be something else too like some IO task) to a separate microcontroller is not necessarily any worse than adding an external flash chip for more memory; especially if the offloaded part is trivially simple to never change.
« Last Edit: September 23, 2024, 08:20:35 am by Siwastaja »
 

Online peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 4121
  • Country: gb
  • Doing electronics since the 1960s...
Quote
Read AN4286:

Yes; the 32F4 is a slave. It can accept data via SPI (so indeed that might be the best way to load the data into it) but cannot be a master which extracts data from an SPI FLASH chip.

There needs to be some CRC which gets checked and the process restarts if it is duff.

I have a RAM based loader in my project (posted about it previously) and that has a brickable time window when it is rewriting the bottom 32k, but that takes only a fraction of a second, and it is extremely improbable that the problem would happen during that time (having successfully programmed and verified the other half a meg or so).
« Last Edit: September 23, 2024, 08:29:59 am by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Online mikeselectricstuff

  • Super Contributor
  • ***
  • Posts: 13979
  • Country: gb
    • Mike's Electric Stuff
Presumably this ST part  can write its own flash under program control, so of course can write data  read from an external SPI flash - you just need to write the code to do it.
This is a good way to handle situations where a firmware update comes from some storage/comms interface that the end-product uses - e.g. wifi, bluetooth etc. Write the SPI flash, and only when the whole image has been downloaded and verified, copy from  SPI to main MCU flash.
Plenty of scope for added- extras like a fallback image in case of a bad update, encryption etc.
Much more flexible than using the factory bootloader, and may offer a more user-friendly way to do updates.
Youtube channel:Taking wierd stuff apart. Very apart.
Mike's Electric Stuff: High voltage, vintage electronics etc.
Day Job: Mostly LEDs
 

Online mikeselectricstuff

  • Super Contributor
  • ***
  • Posts: 13979
  • Country: gb
    • Mike's Electric Stuff
Quote
Read AN4286:

Yes; the 32F4 is a slave. It can accept data via SPI (so indeed that might be the best way to load the data into it) but cannot be a master which extracts data from an SPI FLASH chip.

There needs to be some CRC which gets checked and the process restarts if it is duff.

I have a RAM based loader in my project (posted about it previously) and that has a brickable time window when it is rewriting the bottom 32k, but that takes only a fraction of a second, and it is extremely improbable that the problem would happen during that time (having successfully programmed and verified the other half a meg or so).
Of course it can be a master, you just have to  write your own code to do it. It is possible to make this bulletproof - as you say the window is short, but your bootloader can check flash integrity at startup and restart the SPI flash copy process if it got interrupted.
Youtube channel:Taking wierd stuff apart. Very apart.
Mike's Electric Stuff: High voltage, vintage electronics etc.
Day Job: Mostly LEDs
 

Offline fchk

  • Frequent Contributor
  • **
  • Posts: 255
  • Country: de
Quote
Read AN4286:

Yes; the 32F4 is a slave. It can accept data via SPI (so indeed that might be the best way to load the data into it) but cannot be a master which extracts data from an SPI FLASH chip.

All you need is an extra small uC (a 14 pin PIC16F18326 would do the job) that reads the firmware from a SPI NOR flash or a SD Card and feed it into the STM32. This should be unbrickable then.

I remember ATmel having an extra AT90S1200 uC for recovery on an STK500 devboard.
 

Online peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 4121
  • Country: gb
  • Doing electronics since the 1960s...
The "custom bootloader" is just normal user code, starting at 0x08000000 like any other code. The 32F4 does not provide for a "custom bootloader" as such. So this bootloader is nothing special. No BOOTx pin selection needed (both are 0). The lowest block, 16k, is erasable at 16k, so your loader ought to fit into that, which is easy. I did all that already (except my "boot block" is 32k).

But this all assumes that code never gets overwritten by rogue code running elsewhere. It would really need program protection. This appears possible on a per-block basis via FLASH_OPTCR etc.

Quote
I remember ATmel having an extra AT90S1200 uC for recovery on an STK500 devboard.

That's funny since I have used tens of thousands of the 90S1200 and while it is a great chip I would not call it 100% reliable. I reckon 1 in 1k to 10k corrupts its firmware. That is in addition to the documented bug of corrupting the 1st EEPROM location.

Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 27977
  • Country: nl
    • NCT Developments
Quote
You can use a second mcu which reads the external flash and implements the SPI bootloader protocol.

Yes. Incidentally I recall an STM32 project (not mine) where the customer demanded a provably non-brickable firmware upgrade feature, and a 2nd CPU was the only way to do it.
I doubt that is true. I have implemented such systems myself and the way to do it is to have 2 images: active and update. You can even resort to having a third (backup) image in case everything else fails. But it is all driven by a fixed bootloader which never gets overwritten. ESP32 has such a system as well.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 
The following users thanked this post: Siwastaja

Offline Jeroen3

  • Super Contributor
  • ***
  • Posts: 4185
  • Country: nl
  • Embedded Engineer
    • jeroen3.nl
Maybe you can modify the external loader programs to your needs?
https://github.com/STMicroelectronics/stm32-external-loader/tree/main

The external loader program is used by the toolchain to get data into the spi flash.
 

Online peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 4121
  • Country: gb
  • Doing electronics since the 1960s...
Yes; the SWD debugger route is another way. Probably the most robust of them all.

Quote
the way to do it is to have 2 images: active and update.

I think that depends on the error recovery you have. If you can download the OTA image only once, then yes. Otherwise you might have two firmware copies in the CPU FLASH but how do you select them? You have to assume 0x08000000 is corrupted which means any custom "boot loader" is also dead. The 2nd CPU has no way to select them via external pins.

Actually 0x08000000 doesn't matter if you are loading SP in your startup code, but 0x08000004 definitely does matter ;)
« Last Edit: September 23, 2024, 10:35:53 am by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Online Siwastaja

  • Super Contributor
  • ***
  • Posts: 8775
  • Country: fi
But this all assumes that code never gets overwritten by rogue code running elsewhere

Fair enough, but then again what prevents your separate MCU from having a bug where "rogue code running elsewhere" overwrites it, or controls it to overwrite the main MCU, or both? Or both your main MCU and separate MCU having bugs that make them do weird things together?

This all sounds like a very typical case "solve understandable surface area for bugs by adding more complexity until everything is so complex that we lose track on what kind of bugs could appear" engineering. I'm pretty sure in real world you are never going to see a case where you have a bug causing runaway code to write magic flash unlock values, write correct erase bits and/or write to those correct areas. I mean, this is common enough concern that MCU vendors long ago implemented those magic unlock sequences and you can pretty easily just sanitize the inputs to your write_to_flash(void* addr, size_t n) function. Good old normal software engineering.

Then again, an attacker who deliberately does this does not care, they will do whatever they want regardless of whether it's a 1- or 2-chip solution. With 2 chips they have the convenience of more surface area to grip to.

You are blinded by the fact that the simple and usual solution is hard to prove completely failure-proof, and forget that no one is able to prove the alternative 2-chip solution any more failure-proof either.
« Last Edit: September 23, 2024, 11:08:23 am by Siwastaja »
 

Online Siwastaja

  • Super Contributor
  • ***
  • Posts: 8775
  • Country: fi
You have to assume 0x08000000 is corrupted which means any custom "boot loader" is also dead.

This sounds like a very arbitrary requirement, but sure, if you say so, then you will need a second chip. Let's not forget though that you must also assume that its 0x08000000 is corrupted too, so you will need a third chip to recover the second chip... and so on.
 

Online mikeselectricstuff

  • Super Contributor
  • ***
  • Posts: 13979
  • Country: gb
    • Mike's Electric Stuff
There are ways to guard against (accidental, not malicious) rogue code - most MCU flash write mechanisms require one or more actions to unlock the write capability. You can arrange for the register values/actions required for this to not exist anywhere in the code, but be created by a specific sequence of actions performed by the bootloader.
e.g. the value needed to write to a register is read from SPI flash as part of an update image, and erased after a successful update. That way there is nowhere that code can randomly start running from that can corrupt the flash.
Some MCus have zone-based hardware write protections designed to protect bootloader code.

Youtube channel:Taking wierd stuff apart. Very apart.
Mike's Electric Stuff: High voltage, vintage electronics etc.
Day Job: Mostly LEDs
 

Online peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 4121
  • Country: gb
  • Doing electronics since the 1960s...
Quote
are never going to see a case where you have a bug causing runaway code to write magic flash unlock values

Usually the code with the magic numbers gets put into a function, and a crashing program eventually ends up inside that function. I have seen this with the 28C256 EEPROM which uses magic values too... Hard to believe, yes.

You get the same problem with watchdog triggering. A crashed program can still be doing it, unless you do something more complicated. But ultimately if the code is there (and it must be) it can get executed.

Quote
what prevents your separate MCU from having a bug where "rogue code running elsewhere" overwrites it,

The idea is that the 2nd CPU is never put into a programming mode. Its firmware does not contain the FLASH unlock codes, etc. It only ever runs code placed into it using whatever production process was used (SWD etc).

I am not keen on the 2nd CPU idea either, FWIW, but it seems to be the only way to load code from an SPI device, unless natively implemented.
« Last Edit: September 23, 2024, 11:42:29 am by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Online Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6878
  • Country: fi
    • My home page and email address
Welp, the way Teensy LC, 3.x, 4.x and Micromod have successfully used NXP MKL02 and MKL04 chips for exactly this purpose – to load the firmware update program to the RAM of the main MCU, doing the actual new firmware upload stuff; see basic schematic – indicates it is definitely possible to do this right.  These buggers are surprisingly hard to brick (excluding actual electrical damage).

Note how these are implemented: the bootloader MCU is connected only to a button initiating the firmware upload procedure, and to the JTAG interface, plus boot mode selection pins, DCDC_PSWITCH, and POR_B pin so that it can reboot and handle the power sequencing details on i.MX RT1062.  It only transfers the bootloader code to RAM on the main MCU, which takes over the bootloading procedure.

The only way I know software can brick this (without electric damage, that is), is disabling the JTAG interface.  As the "bootloader chip" is one of the secure ones, it can also provide signature verification for the firmware image (in as large chunks as fit in the rest of the RAM).



I do disagree somewhat with Siwastaja's "Adding a second MCU only adds even more potential points of failure" assessment, simply because it is not the number of potential points of failure, but the complexity in the points of failure, that tends to be the deciding factor in robustness or lack thereof.

As an example, if you have say 3N potential points of failure, but each one is simple, it is preferable to say N potential complex points of failure, because the probability of complex point failure is more than three times that of a simple point failure.

Here, using the secondary chip allows keeping the bootloader completely separate from the application on the main MCU.  During normal operation, the bootloader is not on the main MCU at all; it is only loaded during firmware updates.  This simplifies things a lot.  Really, it boils down to how robust can you make the bootloader MCU and main MCU communications, the part that loads the firmware updater program to the main MCU RAM, and the firmware updater itself.

Unfortunately, I do not have enough design or practical implementation experience to say whether that simplification is more significant than the number of added possible failure points.  It just depends too much on the practical implementation.
 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 27977
  • Country: nl
    • NCT Developments
There are ways to guard against (accidental, not malicious) rogue code - most MCU flash write mechanisms require one or more actions to unlock the write capability. You can arrange for the register values/actions required for this to not exist anywhere in the code, but be created by a specific sequence of actions performed by the bootloader.

Some MCus have zone-based hardware write protections designed to protect bootloader code.
Yes. And you can have some protection in software as well. In a recent implementation I did I put a small layer on top of the flash which divides the flash into sections: bootloader, running image, update image. The bootloader can only update the running image from the update image. The running image can only write to the update image. Neither bootloader or running image can write to the bootloader.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf