Computing stuff tied to the physical world

Lots of chickens and eggs

Let’s step back for a moment. There are a number of ways to communicate with a bare STM32 µC, and it basically dictates the terms of that first exchange. After that, we can make the µC start up and do anything we like – within its capabilities, obviously!

For development, there are several requirements:

  1. the ability to upload new code, even if the previous version is non-functional
  2. the ability to see debug output, and possibly also provide some text input
  3. the use of hardware debugging, for when the bugs we chase are really tricky

Without requirement #1, no development is possible, while #2 is the most widely used approach in the current world of hobbyist physical computing (“add a print statement!”). Requirement #3 seems advanced and esoteric, but is essential for complex software.

These requirements interfere a bit with one another if you try to do all this via the same connection. Yet the most practical solutions are those which do just that: a USB cable from a laptop, going into some sort of device, with wires coming out, attached to the target µC.

Let’s examine a few different types of such magical devices.

FTDI adapter

This implements a serial port, with usually 1 .. 2 additional wires, tied to the target µC’s RESET and ISP pin. Requires a µC with a serial boot loader protocol (i.e. any ARM chip).

To make this work, you need to have a suitable USB driver installed on your laptop, as well as some software which knows the protocol. There are many utilities for this:

  • avrdude – this is for AVR type µCs, and widely used with Arduino boards
  • stm32loader.py – specifically for STM32 type µCs, requires Python to run
  • lpc21isp – widely used for LPC µCs from NXP, sometimes lags the latest µCs
  • uploader – the Go utility from JeeLabs, specifically written for LPC8xx µCs

There are also many FTDI-like adapters, which each need their own specific USB driver. Often lower-cost, but the driver may not run on all platforms, and the interface may not support the extra RESET / ISP pins (may not be an issue, depending on s/w & protocol).

ST-LINK

This is an STM-specific tool, containing a low-end (surprise!) STM32F103, which acts as bridge between USB and the target µC. The code is proprietary & protected, and so is the protocol, but there’s stlink on Github and stm32flash on SourceForge which support it:

0019709 st linkv2 mini 600

ST-Link connects to the target µC as “JTAG programmer”, an old but extremely common way to connect to all sorts of logic hardware (not just µCs). This doesn’t talk to the µC, it uses dedicated hardware in the chip to control the µC. With JTAG, you can stop the CPU, reset it, inspect it, load and save data to internal memory, and much more.

Unlike a boot loader which runs code to accept upload requests, with JTAG you effectively stop all µC activity, and take over in its place. This is why JTAG is so much more powerful than a boot loader: it can also single-step the processor, view / change its internal registers, trigger when variables are changed, and even make the µC jump to a different address.

But JTAG normally needs about 5 I/O pins to do its magic, which is a bit heavy on µCs with very low pin counts. This is where SWD (Serial Wire Debug) comes in: it wraps all the JTAG communication into a minimal 2-signal protocol. For SWD, at a minimum, you only need 3 wires: SWCLK, SWDIO, and GND.

SWD sounds like the magic bullet, and in a way it is. But it’s not without its issues:

  • you need an SWD-capable device, such as an ST-Link
  • you may need a USB driver on your laptop to be able to talk to it
  • you need an application which “knows” SWD
  • and what about viewing the output from a serial port?

So while we do get a very powerful capability this way, we’ll need more wires if we also want to see debugging output. The two SWD pins can’t be used for that, since they are tied up for SWD already. Note that these I/O pins are not talking to the processor itself, but to that special part of the chip which controls the processor. You can’t just add some clever code and re-use these pins for serial I/O, at least not in a robust way.

One major benefit of SWD is that it doesn’t care whether your sketch crashed or got stuck. It will always be able to stop the processor, re-flash memory, and reset / start it up again.

There is one risk with SWD: when the µC powers up, it always starts with the SWD pins enabled. But your code can disable this functionality, and decide that it wants to re-use these pins for something else. SWD then ceases to function and cannot take control anymore!

The solution is simple: when the RESET pin is held low, the processor will be halted, but SWD will already work (it’s not part of the processor, it sits next to it, remember?).

So for a robust SWD interface which can always get you out of trouble, you need to either connect the RESET pin to the SWD device, or keep RESET low manually, as you update your code to a functioning state.

To summarise: a convenient development setup based on SWD needs at least six pins: SWCLK, SWDIO, RESET, RX, TX, and GND. Oh, and power – that makes seven!

There are numerous SWD-capable JTAG programming devices. At all price levels, and at very different performance levels. This matters if you need to re-flash 1 MB, for example.

There are even tricks to avoid that extra serial connection (which most JTAG programmers lack) for console use, using a mechanism called semi-hosting. But these can be slow or complex.

Black Magic Probe

Here is a little critter called a Black Magic Probe which attempts to solve it all:

DSC 5229

This is again a board based on a small (surprise!) STM32F103 chip, combining all of the above: a USB interface, an SWD interface, and a serial port pass-through interface.

The brilliance of this device is that it goes one step further: it also contains the code which until then was always being run as server on the laptop, to let debuggers and other tools control the SWD connection to the target µC. The gdb debugger can talk directly to a BMP.

Best of all, the author of the commercial “BMP” long ago released the code running on it as open source on GitHub. Since then, several people have worked on it and added to it, to allow the BMP to support a wide range of µC vendors.

In short, the BMP is one of the most flexible and powerful ways out there to connect to and develop for embedded µCs. When plugged into USB, on the laptop side the BMP appears as two virtual serial devices. One of them is a gdb-compatible “control port”, the other is a pass-through serial port.

To use a BMP, you first of all need to get a board working as BMP-type device, and then you need gdb, the debugger which pairs with the gcc compiler suite. Alternately, you could just use the pass-through and upload using a serial boot protocol.

MBED-enabled

And then there is MBED and the “MBED-enabled” boards. These boards have a second µC on them just for controlling the board and talking to USB (often, but not always, again an STM32F103). In a way, these are like a built-in Black Magic Probe. But with an extra feature: along with being an ST-Link compatible interface and a pass-through virtual serial port, these boards also act as memory disk.

When you plug in an MBED-enabled board, you will see it appear as a disk on your desktop. You can drag your binary firmware file to it, and the board will automatically re-flash itself with it and restart. It’s truly magical, and it looks like the perfect solution.

In a way it is – for naïve development use. Drag your code to your board, and bingo!

The problem is that on each upload, the USB device disconnects and reconnects, briefly. This “re-enumeration” messes up any current debugger and console output sessions you may have had running. So while it is indeed an effortless – and software-less! – way to get your code onto a target µC, it’s not an optimal fit for a fast iterative development cycle.

There is a huge range of MBED enabled platforms, and the list keeps growing.

Maple Boot

Last but not least, is a mechanism developed by LeafLabs when they created the Arduino-like STM32-based “Maple” board, and later also a “Maple Mini”.

What they did was implement a USB driver, which normally appears as virtual serial port. Great for use in a sketch. The clever trick was to make that driver respond to a special sequence sent over USB to make the board reset itself, and enter a special DFU (Device Firmware Update) boot loader mode. This is a standard in USB, for which several tools exist. Once you upload with this tool, and start your sketch again, it turns back into a virtual serial device, and you’re back in business.

This solves an important problem: re-using the same USB connection for uploading and debugging. Unfortunately, there are also some pitfalls (aren’t there always?). For one, if the sketch hangs, you need to manually put the board into a “perpetual boot loader” mode, and then you can again replace your code with a new version.

The Maple boot mechanism does not support hardware debugging (it doesn’t use SWD).

Ok, this concludes our whirlwind tour of how things work in embedded ARM-land. As you can see, there are many trade-offs, clever tricks, and different approaches. None of them seem to be perfect for casual hobby use, at least not in the sense of being truly fail-safe.

But stay tuned: getting started need not be that hard, despite all these challenges.

[Back to article index]