At the first glance, it’s a very easy task. However it has a number of less obvious pitfalls when you’re working with microcontrollers via some kind of gdb stub or openocd and the memory you’re actually uploading your .bin file is the flash memory of an MCU (e.g. stm32). I decided to gather the common pitfalls in a single blog post.
So gdb can upload data to the target via 2 common commands: load and restore. If gdb is connected to an openocd server, we also have a couple of monitor commands to work with flash.
- load – can only upload elf format files. Loads all sections to their respective addresses, including flash.
- restore – Can upload arbitrary bin file to an address. If we try to load to flash – we’ll get an error (at least via black magic probe).
- monitor flash write_bank – supported only of we’re working using gdb/OpenOCD. But it can load binary files with no problems.
The problem is, that monitor flash write_bank is supported only if we’re working via OpenOCD (I was not), and restore command always gave me errors on the hardware/software combinations I’ve tried. The only remaining option left was load.
There’s no issue with that, if you’re compiling the project yourself – you’ll always have the elf file. Problems arise if you need to upload raw data (e.g. configuration) or a ready-to-use firmware you’ve downloaded from the internet as a bin file.
If that’s the case, we’ll need to make an elf from .bin file, adjusting the .data section load address as necessary (Normally, it should point to flash). Taking stm32 as the example, the magic spell to turn bin into elf will look like this:
arm-none-eabi-objcopy -I binary -O elf32-littlearm –change-section-address=.data=0x8000000 -B arm -S app.bin app.elf
For other MCUs/arhitectures you’ll need to change the address of .data section to point to flash (written in italic), output architecture and variant ( written in bold). It’s also better to use objcopy from your toolchain. Just in case you’re working with some weird/unsupported architecture.
Loading the file via gdb (black magic probe as the example) will look like this:
target extended-remote /dev/ttyACM0 mon swdp_scan att 1 load app.elf
If you get an ‘Error erasing flash with vFlashErase packet’, (like, just after you’ve erased the option bytes), power-cycle the target mcu and run mon swdp_scan and att 1 again.