The first thing to try out on every new board is to blink an LED: the embedded equivalent of writing a “Hello World” program. I’m going to do this for both the “DIYmore” and the “Black407” boards, as introduced here - using two different upload mechanisms.

DIYmore

First the minimal board, with an F407VG on it. Just to illustrate that it can be used with a Black Magic Probe, I created a little custom adapter - it turns out that all the required pins are conveniently grouped together in one 2x5 section of its three headers:

Yeah, it’s a bit of a hack with that dab of hot glue, but it does get the job done.

For this setup, we need the two files to create a PlatformIO project, i.e. platformio.ini:

[env:diymore]
build_flags = -DSTM32F4 -DDIYMORE
platform = ststm32
board = genericSTM32F407VGT6
framework = stm32cube
upload_protocol = blackmagic
upload_port = /dev/cu.usbmodemDFEAA5E7
lib_deps = jeeh

… and the blink demo itself, in src/main.cpp:

#include <jee.h>

PinE<0> led;

int main() {
    enableSysTick();
    led.mode(Pinmode::out);

    while (true) {
        led = 0;
        wait_ms(100);
        led = 1;
        wait_ms(400);
    }
}

And then it’s just a matter of typing pio run -t upload (assuming the port settings are correct). Sure enough, the LED blinks. No big deal, but it’s still useful, as first test.

I’ve also hooked up the serial port in the adapter shown above, but will skip the details here. It works the same way as described earlier for the Blue Pill.

Black407

For this board, I’m going to go for something a little more ambitious, by setting it up for DFU uploading and also using the USB link for the serial console. With this approach, no programming hardware at all will be needed - just a standard USB cable.

The platformio.ini file for this case is as follows:

[env:black407]
build_flags = -DSTM32F4 -DBLACK407
platform = ststm32
board = genericSTM32F407VET6
framework = stm32cube
upload_protocol = dfu
lib_deps = jeeh

The src/main.cpp code is only slightly more involved:

#include <jee.h>
#include <jee/usb.h>

UsbDev console;

int printf(const char* fmt, ...) {
    va_list ap; va_start(ap, fmt); veprintf(console.putc, fmt, ap); va_end(ap);
    return 0;
}

PinA<6> led;

int main() {
    fullSpeedClock();
    console.init();
    led.mode(Pinmode::out);

    uint32_t last = 0;
    while (true) {
        if (last != ticks / 500) {
            last = ticks / 500;
            printf("%d\n", ticks);
            led.toggle();
        }
        console.poll();
    }
}

The tricky part is that the current USB driver in JeeH needs to be continuously polled, so wait_ms() calls cannot be used. This code toggles the LED every 500 ms, i.e. at 1 Hz.

And although uploading requires no special programmer setup, we do need to put the board in “DFU mode”, by adjusting the BOOT jumpers as follows, before plugging it in:

Once plugged in, the board will register on USB in a special boot mode. E.g. on MacOS:

Next, we build the code with this command: pio run.

Note: “pio run -t upload” didn’t start the DFU utility, so I’m launching it manually.

Uploading requires the dfu-util software (brew install dfu-util or apt install dfu-util should do the trick, on MacOS, resp. Linux). This can then be used to look around on the USB bus. On my system, dfu-util -l produces the following output:

$ dfu-util -l
dfu-util 0.9

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2016 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/

Found DFU: [0483:df11] ver=2200, devnum=15, cfg=1, intf=0, path="20-6", alt=3,
    name="@Device Feature/0xFFFF0000/01*004 e", serial="3364348B3235"
Found DFU: [0483:df11] ver=2200, devnum=15, cfg=1, intf=0, path="20-6", alt=2,
    name="@OTP Memory /0x1FFF7800/01*512 e,01*016 e", serial="3364348B3235"
Found DFU: [0483:df11] ver=2200, devnum=15, cfg=1, intf=0, path="20-6", alt=1,
    name="@Option Bytes  /0x1FFFC000/01*016 e", serial="3364348B3235"
Found DFU: [0483:df11] ver=2200, devnum=15, cfg=1, intf=0, path="20-6", alt=0,
    name="@Internal Flash  /0x08000000/04*016Kg,01*064Kg,07*128Kg", serial="3364348B3235"
$

The entry we need is the last one (alt=0, “Internal Flash”) and since there are no other DFU devices in my setup, we can perform the firmware upload using:

dfu-util -a 0 -D .pioenvs/black407/firmware.bin -s 0x08000000

Note that dfu-util calls this a download (-D) - which is mighty confusing !!!

Here is a transcript, with some startup messages omitted for clarity:

$ dfu-util -a 0 -D .pioenvs/black407/firmware.bin -s 0x08000000
[...]
Opening DFU capable USB device...
ID 0483:df11
Run-time device DFU version 011a
Claiming USB DFU Interface...
Setting Alternate Setting #0 ...
Determining device status: state = dfuERROR, status = 10
dfuERROR, clearing status
Determining device status: state = dfuIDLE, status = 0
dfuIDLE, continuing
DFU mode device DFU version 011a
Device returned transfer size 2048
DfuSe interface name: "Internal Flash  "
Downloading to address = 0x08000000, size = 2328
Download	[=========================] 100%         2328 bytes
Download done.
File downloaded successfully
$

The only thing left to do is: unplug, restore the BOOT jumper, plug in again. Then the on-board LED2 will start blinking. And a new USB device will show up - again with MacOS:

It’s now a serial-over-USB port, accessible via a terminal emulator such as picocom:

$ picocom --imap lfcrlf -q /dev/cu.usbmodem14101
7500
8000
8500
9000
9500
[...etc...]

Note that with this serial USB connection there’s no need to specify a baud rate, because the USB device is built into the F407 µC itself and works with the raw USB packets.

This concludes two approaches to getting a LED blink + USB serial example into an F407.