Computing stuff tied to the physical world

Most bare µCs are clueless

Small low-cost embedded micro-controllers are amazing devices. Programmable in C/C++, 32 bits of power, and a huge step up from how old micro- and mini-computers worked!

But whenever you power them up, some of these chips are ridiculously limited. Sure, there is a lot of flash memory, and they’ll start running the code in there the moment power is applied – but what about that very first time, before there is code at all in there?

How do we get our great new code into that empty chip?

Laptop to chip

There are two common solutions:

  1. The µC has hardware support for ISP, allowing you (or your supplier) to use an ISP-programmer to store some code in flash for you. This is how ATmega’s work.

  2. The µC includes a ROM, containing a “boot loader”, i.e. code which lets you add your own code into its flash memory. This is what all ARM µC’s support.

Either way, bare µC chips fresh from the factory each have their own specific way of allowing us to put our own code into flash memory.

With STM32 µCs, which is what we’re interested in here, there is always a boot loader in ROM present. The simplest chips only support a serial port in this mode, the more elaborate ones also support USB, I2C, SPI, CAN bus, and even Ethernet – depending on available hardware features.

In the case of the STM32F103 series, things get a little hairier on the low end: even though the 64K and 128K models support USB and CAN bus, and have several serial ports, the built-in ROM boot loader still only supports one (specific!) serial port. To get these chips to do anything for us, we need to first bring ourselves down to their level and… talk TTL 3.3V serial, using STM’s USART boot loader protocol – as defined in this document (PDF).

It would be awful to have to always connect those serial I/O pins to a serial port on our development computer, though. After all, these chips have USB, and who knows, they might even be used remotely in a Wireless Sensor Network.

That’s where “boot loaders” come in, once again: we can store a small amount of our code inside flash memory, which always runs on power up, and which terminates by jumping to a different area in flash memory. This secondary boot loader can be whatever we like. The most common ones talk to us in the way we prefer, will respond to requests to erase certain parts of flash memory for us, and will store whatever new code we send them into the just-erased parts of flash memory. As long as the boot loader takes care to never overwrite itself, it’ll always be the first thing that starts up after power up or after a reset.

All the ATmega-based Arduino’s are shipped with a boot loader, which talks to the (main) serial port, and reprograms the chip as needed. If no upload requests come in, the boot loader ends by jumping to “user code”. If that code crashes, we can reset the chip, and re-upload new code to fix the problem. Or to add more features. We control it via serial I/O.

For the STM32 chips, we really want to have a similar mechanism, using the USB port. That way, a single USB cable will be all we need to power our board, upload new code into it as needed, and communicate with our “sketch” once it starts running. Very convenient.

So far so good. But what about those initially-empty chips? And what if the boot loader gets overwritten by accident, because of some mistake or malice in the user code? Could we lock ourselves out, so the chip can’t be re-programmed? Can we read the code, once uploaded?

And what about that very impressive-sounding technique called “hardware debugging”? What’s JTAG and why does this term keep popping up? And what’s SWD? Should we care?

One step at a time, please! The bootstrap process has only just started…

[Back to article index]