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):

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:

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 libopencm3. 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.

(hit 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 blink.bin:

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) ...

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. Furthermore, hitting 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!

Weblog © Jean-Claude Wippler. Generated by Hugo.