Electronic – Possible to re-program microcontroller over Bluetooth

bluetoothmicrocontrollerprogramming

I am looking at making an embedded design featuring an ARM Cortex M3 MCU and bluetooth. I would like to be able to update its firmware over Bluetooth periodically.

Is this possible with the following chip? From ST:

http://www.st.com/web/en/catalog/mmc/FM141/SC1169/SS1031

I am used to connecting the bluetooth to the MCU via UART. Does the bootloader need to be modified when I want to program "over the air"? How does one load their own bootloader on the device? What does bootloader code look like?

I'm also open to other suggestions based on my objective.

Best Answer

Yes, you can do remote firmware updates with the STM32.

Now you have two choices:

  • using the STM32's factory-programmed bootloader
  • writing your own bootloader

Using the factory-programmed bootloader requires booting the chip with pin BOOT1 pulled low and BOOT0 pulled high, and the Bluetooth module needs to be connected to a specific USART peripheral (there are other interfaces, depending on the specific STM32 model, but I assume the USART makes the most sense here). Also, you need to write an app to interface with the bootloader, following the bootloader's command protocol which is documented here. To avoid writing code to interface to the bootloader, you could use the STM32 Flash Loader demonstrator application; of course this requires that the other end of the Bluetooth connection be plugged into a PC, so it doesn't make sense in every scenario.

The other possibility is writing your own bootloader, which gives you more control. You can, for instance, trigger the bootloader using a software-only sequence, so that you don't need to set certain pins as required by the factory-programmed bootloader. Of course, writing such a bootloader involves a lot more effort than using one that is already written, tested and shipped with the MCU.

Some brief comments about writing your own bootloader. A bootloader is a piece of firmware code like any other. It's loaded into the MCU during the production (or debugging) process together with the main code.

Despite being code like any other, since the bootloader is used to reprogram the MCU's firmware, it merits a few special considerations. First of all, for simplicity, you may want to make your bootloader a fully separate piece of code from your main code. Edit the bootloader's and the main code's linker scripts, so that each uses a completely distinct segment of flash memory. That way, you can update the main code without touching the bootloader. When the bootloader is part of the main code, if the updating process encounters any kind of problem, then your device is bricked. Bootloader code needs to be very reliable, since a bug in a bootloader may be the difference between the user being able to service the device by himself after a botched update, versus being forced to take it to a service center. Personally, I'd make the bootloader as small and simple as possible, even going so far as to avoid using interrupts, since in a way they make code less predictable. Usually I'm all for interrupts, but this is the one case where I'm against using them.

Briefly, a bootloader is loaded when the device boots, and usually just hands control over to the main code. However, when performing a firmware update, then the bootloader runs its own code after boot instead. This code must include some kind of communication (in your case) or storage driver, so it can receive/read the binary for the updated code, via Bluetooth, Ethernet, an SD card, flash drive or whatever. It then erases the old code and reprograms the flash memory with the new code.

One of the tricks that must be done when reprogramming the flash memory is relocating (copying) part of the bootloader code to the RAM, since you can't run code from flash while it is programmed (even if the address being read is different from the address being programmed). Also, the updated binary code that is going to be written to flash must be in RAM as well. Usually there won't be enough RAM to store the full code for the update, so it's not unusual to receive/read a partial block of code, write it, receive/read another partial block of code, write it, and so on.

Programming flash memory is not a simple matter of writing data to the desired addresses. There's a flash programming manual for each member of the STM32 series (for instance, here is the manual for the STM32F10x series). In brief, due to low-level details of how flash memory is implemented, before reprogramming a given block, you'll need to issue an erase command to it. Also, you can't make any reads from flash while it is being programmed, so forget about interrupts, DMA, etc. unless there's just no chance that they'll try to read from flash while it is being written.