Fancy serial with a SerPlus Dec 2016
So far, to upload new code to a Blue Pill, you had to change a jumper, press reset, perform the upload, change the jumper back, and press reset again - this will quickly become very tedious!
So why not let the host computer do this?
What we need is a way to control the RESET and BOOT0 pins of the ARM µC. Reset is easy, and can be done in way similar to the Arduino: tie it to DTR (“Data Terminal Ready”), and have the host computer control this “modem control” pin.
On the wiring side, all we need to do is to make a connection between the FTDI’s DTR pin (sometimes marked “RST”) and the “R” pin on the Blue Pill header.
Controlling BOOT0 is slightly more involved. What we can do is use another modem control output pin for this, called RTS (“Request To Send”). This is not normally connected to an FTDI pin, but it’s not very hard to modify a BUB to do this as well.
The problem though, is that apart from not having these pins available on all USB serial adapters out there, we can also run into nasty issues w.r.t. platform support. Apple’s FTDI adapter does not support RTS, and at least some Windows and Linux versions have issues.
Getting DTR and RTS right on all platforms and making it work with various USB serial adapters turns out to be fairly tricky, to put it mildly.
But there’s a simple solution, and it works really well.
Ingredients: one Blue Pill, one 6-pin female header, and one firmware download.
What we can do, is to move the problem to a place where we can solve it: an implementation of a USB-serial bridge, based on an F103. After all, from a µC we can easily control a few pins, switch to even parity, and do whatever else is needed to program an attached “target” board.
The trick is to stay away from everything which is specific for any platform, and to only use the USB serial connection for just that: serial data. One way to accomplish this is to bring in an old-but-proven serial port control mechanism, called Telnet. This has an escape convention to send special messages in between the normal data flow. The escape byte is 0xFF, which does not normally occur in plain ASCII exchanges (and it’s properly wrapped in case it does).
So the idea is that instead of this setup:
… we switch to this approach:
The Folie utility defaults to the Telnet protocol (with the “-r” command-line option to fall back to raw mode where needed). All we need is that “smart µC-based serial” thing to make it work.
And that’s exactly what SerPlus is. An implementation for F103 boards, which does the required interpretation and translation between Telnet escapes and the real world (it only handles a subset, not the full Telnet protocol). Folie and Serplus were made for each other.
To create this setup, you need a spare Blue Pill (you might as well have a bunch of them lying around anyway, if you plan to follow along with some of the upcoming projects on JeeLabs), and you need to build a little setup similar to this one:
The connections are (bottom view, FTDI header, top to bottom):
- GND = power, ground
- RTS = tied to a spare I/O pin, i.e. PA2
- +5V = power, 5V in
- TX = tied to µC’s TX, i.e. PA9
- RX = tied to µC’s RX, i.e. PA10
- DTR = tied to a spare I/O pin, i.e. PA3
Note that this is not the same as when connecting a male 6-pin FTDI header to a Blue Pill to use it as target board. The connector is flipped, there’s no RX/TX cross-over in the above connections, and the DTR/RTS are not tied to RESET/BOOT0, but to pins which will be used as GPIO outputs to control the target board.
Now the chicken-and-egg part of the story: to program this board, you still need another USB-serial adapter. It could be another SerPlus board, but it’ll most likely be some other type. Not to worry - just follow the wiring setup instructions given in a previous article. If you plan to do this more than once, you could also consider creating an “FTDI cross-over plug”, like this:
Nothing fancy, just a way to streamline things. For one-off’s, four jumper wires will be quicker.
Just to make things clear: we’re about to program a board and turn it into a “SerPlus”, i.e. a variant of a host-side USB serial interface, just like a BUB or some other FTDI-like board. The difference being that this one will have slightly more smarts, to handle Folie’s Telnet escapes.
Last step: flashing the SerPlus code into the Blue Pill we just prepared:
- you can get the code from GitHub and build it yourself
- … or just grab the compiled binary, called serplus.bin
- then upload that to the Blue Pill, in the same way as with the
blink, etc. examples
SerPlus is considerably more complex than the other examples so far, but it’s
built in exactly the same way, with the same GCC and the same
There is a USB driver in there, as well as an interrupt-driven serial port, a
SysTick timer, and of course a Telnet protocol decoder (implemented as a small
finite state machine). Its main function is to get incoming data from USB to
serial, and get incoming serial data to USB - just like any USB-serial board.
But we’re not out of the woods yet. We’re only half-way in fact…
The last step is to make the target Blue Pills suitable for this new “extended” use of the FTDI header. We need to add two things: a connection from DTR to the F103’s RESET pin, and another one from RTS to the F103’s BOOT0 pin:
Almost there! - the one remaining issue, is that we can’t control the BOOT0 pin while there’s a jumper on it, and that without the jumper, the F103 may not start up properly in all situations.
A small “mod” will be required - in the form of an added 10 kΩ resistor where the jumper was:
This will make sure that BOOT0 is pulled low by default, but that the RTS wire can pull it high when needed to start an upload.
The result of all this work is TWO Blue Pills, a target (on the left), and a SerPlus (on the right):
Plug them together, connect a USB cable on the right, and you get a very convenient setup:
$ cd ../blink $ folie Folie v2.7-1-g94cba5e Select the serial port: 1: /dev/cu.Bluetooth-Incoming-Port 2: /dev/cu.usbmodem3430DC31 ? 2 Enter '!help' for additional help, or ctrl-d to quit. [connected to /dev/cu.usbmodem3430DC31] !u blink.bin 724b .+V22 #0410 R .W .E writing: 3/3 done.
ctrl-d to exit Folie)
Note the absence of the
-r option this time: we’re now using Folie’s default
Telnet protocol, not raw mode. Resets and uploads can now be done without
touching the Blue Pill at all.
And since the blink demo is built into Folie, you don’t even need to get
a copy of
!u These firmware images are built-in: 1: F103-BMP 50096b crc:F87A 2: F103-Blink 724b crc:4967 3: F103-Mecrisp 20500b crc:A585 4: F103-SerPlus 7052b crc:7DD0 Use '!u <n>' to upload a specific one. !u 2 724b .+V22 #0410 R +W +E writing: 3/3 done.
Here’s another upload, of the
echo example this time:
$ cd ../echo $ make CXX main.cpp CXX echo.cpp LD echo.elf OBJCOPY echo.bin text data bss dec hex filename 28528 2220 64 30812 785c echo.elf $ folie Folie v2.7-1-g94cba5e Select the serial port: 1: /dev/cu.Bluetooth-Incoming-Port 2: /dev/cu.usbmodem3430DC31 ? 2 Enter '!help' for additional help, or ctrl-d to quit. [connected to /dev/cu.usbmodem3430DC31] !u echo.bin 30748b .+V22 #0410 R .W .E writing: 121/121 done. Hit <enter> to toggle the LED (0) ... Hit <enter> to toggle the LED (1008) ... Hit <enter> to toggle the LED (2020) ... !reset Hit <enter> to toggle the LED (0) ... Hit <enter> to toggle the LED (1008) ... Hit <enter> to toggle the LED (2020) ...
As you can see, the upload was performed, the program was started, and since
Folie then switches to terminal mode, the output immediately appears.
CTRL-C generates a reset of the target board, at which
point it restarts from scratch.
For people used to the Arduino workflow, this is nothing spectacular - it’s the way the Arduino IDE has always worked (and it’s probably partly responsible for its runaway success).
And now, the same can be done on ARM: a single USB cable for uploads, for talking to the running application, and for supplying 5V power. Mission accomplished – onwards!