Is it worth using STM32 bootloaders this way? - Page 1
Forum section: electronics / general

author: void_error
author_rank: Frequent Contributor
timestamp: July 19, 2018, 07:54:43 pm
content: Sorry for the possibly misleading title, I'll explain my question below:I'm going to have a bunch of STM32F1s and I want to use the integrated (factory programmed) bootloader activated by the BOOTx pins to provide the user with the option of flashing the software themselves since it's an open source project.Can I make / is it worth the effort to make updating the firmware possible without opening the case to have access to the BOOTx pin(s) and UART?It'll basically look like this: [USB-UART] --- [MCU1_UART1 MCU1_UART2] --- [MCU2UART1, MCU3UART1, MCUxUART1].In other words MCU1 bootloader will be directly accessible via the USB-UART interface with the boot pin tied to a button available already on the front panel when there is no firmware on the MCU. The next few MCUs are connected to another UART on MCU1 and will only be accessible through that via a RS-485-like full-duplex multi-drop configuration and function as slaves.Once MCU1 has the firmware running on it there will be a possibility to communicate directly (tunneling of some sort between MCU1_UART1 and MCU1_UART2) with them via the USB-UART interface. The problem is how to get MCU2 (or MCU3, etc) into boot mode without having a dedicated line for each of the BOOTx pin(s). I also have and I2C and a one wire bus available so I could use I/O expanders and address those but that seems to be a waste if that's their only purpose. The MCUs are going to be on separate boards and some of them may be electrically isolated from each other.Any ideas/thoughts on this?

author: ajb
author_rank: Super Contributor
timestamp: July 19, 2018, 08:15:06 pm
content: It should be possible to jump to the bootloader from your application the same way you would jump from a bootloader to an application. You may need to disable your application's interrupts and reset the clock configuration first, I haven't messed with the ST bootloaders so I'm not sure how defensive their initializations are. The reference manual should tell you the address in memory of the bootloader.Something like:Code:/* get stack pointer (first entry in application vector table) */volatile uint32_t bootStack = *((volatile uint32_t*)BOOTLOADER_ADDRESS);/* get application entry point (second entry in application vector table */void (*bootEntry)(void)= (void (*)(void)) *(volatile uint32_t*) (BOOTLOADER_ADDRESS + 4);/* set stack pointer */__set_MSP(bootStack);/* Jump into the application */bootEntry();The above assumes that you can access the devices some other way to program them initially, and perhaps to recover from a failed update. Another option would be to have a hardware latch linked to the slave device's upstream UART such that a long break signal sets the BOOT0 pin and then resets the MCU. This would work even without a working application in the MCU, but you'd have to be careful to make sure that your bus won't accidentally send that special signal during normal operation. Actually since you mentioned this is a multidrop bus arrangement you'll need some way of isolating the link to a single MCU at a time to use the stock ST bootloader, so in any case you're going to need a scheme like the above to put a single slave device into the bootloader at a time anyway, unless you have some sort of hardware address decoding or something on each slave.

author: void_error
author_rank: Frequent Contributor
timestamp: July 19, 2018, 08:36:29 pm
content: Thanks for the replyajb.I was looking into avoiding the opening of the enclosure just in case something gets bricked, I'm going to have my own bootloader(S) in order to update the firmware on the slave MCU(s) so that's relatively easy.The idea here was how to enable boot mode on a specific slave by setting the BOOT0 pin high. I guess the simple and cheap way to do it is open the case and move a jumper to set BOOT0 high. Also, setting the BOOT0 pin high and resetting the MCU is going to bypass whatever is in the main flash area.

author: Siwastaja
author_rank: Super Contributor
timestamp: July 20, 2018, 04:19:25 pm
content: Why not write your own custom flasher or "bootloader"? This way, you can program while running, without any need to use the specific strap pins. You can, for example, enter programming mode by a special UART sequence. Of course, this has a risk that your new firmware has a bug which prevents it from detecting the enter-the-flasher pattern, but this hasn't been an issue for me after I started including checksumming and sanity checks to the firmware update sequence.

author: Gibson486
author_rank: Frequent Contributor
timestamp: July 20, 2018, 04:57:22 pm
content: Quote from: Siwastaja on July 20, 2018, 04:19:25 pmWe did something similar, but we used an EEPROM on the board. When we wanted to program, we just changed a bit on the EEPROM. That way, when it came out of reset, it just looked at the flag to determine if it was in programming mode.

author: ajb
author_rank: Super Contributor
timestamp: July 20, 2018, 05:23:37 pm
content: Now I'm confused as to the specific problem you're tying to solve. Are you trying to use BOOTx to activate the factory bootloader for initial flashing/recovery, or to activate your own bootloader for normal updates? Or both at different times?The problem with initial flashing is that you have no way of isolating a single slave device on the bus using the stock bootloader protocol, so you pretty much have to do the jumper method, or have the master drive the BOOTx pin. Actually if you wanted to get clever, you could daisy chain the BOOTx pin from one slave to the next. The master would drive BOOTx on the first slave, then once that's programmed slave 1 would drive slave 2's BOOTx, etc, but of course that's an extra wire.Once you've got some code on the slave devices all sorts of possibilities open up, and you can use your program to either jump into the stock bootloader directly as I described above or possibly even change the boot configuration in the option bytes and then reset the chip (depends on your particular MCU, different ones have different boot config options).Quote from: void_error on July 19, 2018, 08:36:29 pmThe conventional way of doing bootloaders is to have the device start from the bootloader and then hand execution off to the application, so once you have your bootloader installed you can have it wait for a particular string on the UART or something, and if it doesn't receive it in a certain amount of time jump to the application. Then you never need to touch the boot configuration again.

author: void_error
author_rank: Frequent Contributor
timestamp: July 21, 2018, 08:19:51 am
content: Quote from: ajb on July 20, 2018, 05:23:37 pmI want to use the BOOTx pins for initial flashing/recovery.QuoteDaisy chaining would only work if the slaves were on the same board, with my current setup multiple boards, each containing one slave is connected via a single ribbon cable which has one IDC connector for each board. This would have worked when I had two ribbon cables for each board, something like  ---  ---  but I changed that since laying out the PCB with two IDC connectors proved to be impractical.QuoteThat would be where things get a lot easier.QuoteEither wait for the trigger on UART which will work for both master and slaves or since the master has buttons they can be used to trigger jumping to bootloader but only for the master.So far I have two options: jumpers for BOOTx pins and do the initial flashing or recovery manually which is quite tedious but I don't have to do it too often or use something like a PCF8574 for each slave to trigger the factory bootloader. That would limit me to 8 slaves on the bus but I don't expect having more than that. It would also allow me to reset any slave. That would leave me with 6 pins on the PCF8574 for other things.

author: ajb
author_rank: Super Contributor
timestamp: July 21, 2018, 06:01:18 pm
content: That sounds like a reasonable option if you have a way of setting the address bits on the expander

author: nctnico
author_rank: Super Contributor
timestamp: July 21, 2018, 07:56:17 pm
content: The easiest way is to make the application jump into the bootloader. But there are several pitfalls because the bootloader assumes the device is in the reset state. IIRC you need to at least reconfigure the UART to the reset state and probably several other peripherals as well. No, this isn't documented.

author: Siwastaja
author_rank: Super Contributor
timestamp: July 23, 2018, 10:28:47 am
content: Quote from: nctnico on July 21, 2018, 07:56:17 pmIMO, easier to write your own flasher - at least in the long run. You get what you want, and don't need to reverse engineer anything or rely on undocumented behavior. This is very good if the product is ever commercialized and you want to offer firmware updates to the end user through your own UI.Additionally, the stock STM32 UART bootloader seems to be slow as hell, a bigger firmware tends to take minutes to finish, also a good reason to write your own.Learning flash programming becomes a useful skill, as EEPROM-like permanent storage is needed in many projects anyway.It isn't too difficult.Here's an example of an in-application flasher tool (working through SPI), which can be run any time and includes some basic safety checks:https://github.com/siwastaja/pulutof1-fw/blob/master/flash.cThis is nice because I can reflash the application in less than 1 second, any time, from an userland program (https://github.com/siwastaja/pulutof1-devkit/blob/master/spiprog.c), without needing to press any button or similar.I avoid the term "bootloader", since it seems to refer to something that runs during boot and loads something (the original meaning). Flash updater tool has nothing to do with this. It's a common misconception that the flasher needs to run "at boot", possibly stemming from the wrong term used to describe it. This is an arbitrary limitation. With your own, you just... write the flash! Whenever and wherever you want. You don't even need to reset afterwards, although thatmost likelymakes sense and is the most sensible and safe thing to do in most cases.