Skip to content

Configuring a BTT GTR 1.0 for automatic flashing

John Lagonikas edited this page Nov 14, 2022 · 11 revisions

This page covers all the aspects of implementing automatic firmware flashing on a BTT GTR 1.0 board, but could provide insights into other board implementations as well.

WARNING: This page contains instructions to perform operations that can easily damage your board if not done properly. Make sure you understand what is needed, how to do it properly, and be aware of any differences between the process described below and your own version of hardware / software. PROCEED AT YOUR OWN RISK!

1. Setup

We start with a GTR board and a Raspberry Pi running OctoPi. We already have a USB connection between the RPi and GTR, and the intention is to control GTR's reset pin and an additional pin that will act as a trigger for booting into DFU mode, through RPi's GPIO.

  • 2 jumper wires to connect an RST pin and an input pin (lots of candidate pins) to RPi's GPIO
  • 1 jumper wire to start GTR in internal bootloader mode OR an ST-Link/V2 compatible device
  • DFU-Util for flashing stuff (if using ST-Link, also STM32 ST-Link Utility)
  • VSCode and PlatformIO extensions for VSCode
  • If we want to connect the GTR board to a windows host in DFU mode, we'll also need Driver Install Creator Wizard from libusbK

2. Background

There are two ways to flash a new bootloader to the board:

  • Via internal MCU bootloader
  • Using a programmer (ST-Link device) like this one.

Let's start with the first option, which is a bit harder to perform but does not require any special hardware, just a jumper cable.

All current STM32 MCUs have an internal bootloader that can be activated under certain conditions. This bootloader provides a variety (different for each MCU) of communication protocols which allow downloading binaries anywhere within the MCU's memory space (including the internal flash). A complete guide to this mode can be found here.

Since BTT GTR 1.0 has an STM32F407IGT6 MCU, the internal bootloader is activated by setting BOOT0 pin to high, and supports the DFU protocol for uploading, so we can use DFU-Util to upload Bootloader-Z. The tricky part here is that we need to set BOOT0 pin to high (that is, connect it to 3.3V) while resetting the MCU.

BigTreeTech is kind enough to share the schematic diagrams of their boards with us, and that's where we'll start. First, we need to understand how BOOT0 is wired:

image

This tells us that, if we locate R3 on the board, we can use a jumper wire to connect the resistor's end in the red circle to 3.3V. Using the pin map, we can see where R3 is located:

image

To find which end is the one we need to connect to 3.3V, we must use a multimeter on the unpowered board to measure the resistance between each of the two R3 resistor's contacts and the ground. We're looking for a 100KΩ resistance, so we set our multimeter accordingly, and test both R3's ends. This way, we find that the correct end to apply the voltage (which displays 100KΩ resistance between it and the ground) is the lower end (towards the usb connectors):

image

The second option, requires an ST-Link programmer, which is a specialized hardware tool for programming and debugging MCU software. The ST-Link allows to access any portion of the MCU's memory space (flash, RAM, hardware registers, etc.), as well as reading the MCU's internal registers, setting code breakpoints, erasing flash memory etc. While the original ST-Link is expensive, clones are available for less than $10, and it's a good investment if you're intending to program or debug stuff on STM32 boards. The ST-Link is connected here:

image

Typically, you need to make a special cable to match the header's pinout, or use jumper wires to connect the ST-Link's pins to the respective pins on the board.

From that point on, you can use the STM32 ST-Link Utility (or the newer STM32 Cube Programmer, but it doesn't always work with clone devices) to write a binary file (Bootloader-Z's firmware.bin) to the MCU's flash memory.

3. Preparation

The instructions given here, assume a windows host for compilation / preparation / bootloader flashing. If you have a linux host, I'm sure you can apply these actions to your setup.

The first thing you need to do is to extract DFU-Util in a folder and get a backup of the stock bootloader in case you need to revert to it. Please see Addendum A for the backup procedure before continuing.

Next, we need to build the Bootloader-Z binary. If you don't have VSCode + PlatformIO installed, now it's time to do that. I won't go into the details of this, you can easily find instructions all over the Internet, like here.

Then, download Bootloader-Z sources from this repository into a folder and open it with VSCode. Depending on your setup, you'll need to choose a pin from the board that will be used to trigger booting into DFU mode for flashing firmware. If you're using a RepRap discount LCD display, a good choice is the encoder button pin (PA15), which is easy to push together with the reset button on the display to boot into firmware flashing mode. In order to set this as the trigger pin, change the trigger macros in Configuration.h as follows:

#define TRIGGER_PORT                 A              // port letter
#define TRIGGER_PIN                  15             // pin number
#define TRIGGER_STATE                PIN_RESET      // PIN_SET / PIN_RESET

You'll also want to select a led to indicate firmware flashing boot mode. Best choice for GTR is PA0, which is the 4th (green) led at the center of the board:

image

This can be configured in Configuration.h as follows:

#define LED_PORT                     A              // port letter
#define LED_PIN                      0              // pin number
#define LED_ON                       PIN_SET        // PIN_SET / PIN_RESET

If you don't want the led, just comment out any of these 3 lines (prepend with //).

Now, you need to choose a flashing protocol, in this paradigm we are choosing DFU:

#define USB_PROTOCOL_DFU            // Fast, standardized, compatible. Will require a customized driver in windows (see: https://bit.ly/3gzkopp)
//#define USB_PROTOCOL_HID            // No specialized driver needed in windows. Slower, works only with HID-Flash tool (see: https://bit.ly/34JPXdt)

The default choice for the device's ID is USB_DEVICE_USE_STM_ID, which is the same ID with the internal bootloader's USB device. Since these two will never connect to the host at the same time, this is a safe choice, which also has a default driver in windows (so we don't need to create a new driver with the libusbK wizard mentioned above). The second choice (USB_DEVICE_USE_STLINK_ID) is the ID of the ST-Link/V2 device, and it is the default device ID hardcoded into PlatformIO's DFU upload protocol implementation. This means that, if you use this ID you won't have to modify PlatformIO to directly upload a firmware to the board, but you will need to create a driver for it in windows, using the libusbK Driver Install Creation Wizard (which will also require you to boot windows with driver signature check disabled in order to install it, see Addendum B - Windows DFU device driver).

Configuration is now complete. Make sure you select the right build environment in PlatformIO:

image

Then build the project:

image

If compilation succeeds, you're ready to flash. Otherwise, something's gone wrong with the above, or there is something unforeseen that needs to be tackled, in which case you may open a new issue in this repository.

4. Flashing Bootloader-Z

If you have an ST-Link device, just press the PlatformIO upload button to flash it:

image

If you are going to use the internal STM32 Bootloader to flash it, follow these steps:

image

The board must be powered up and connected to a host (PC, RPi). Using a jumper wire, connect the lower end of R3 to a 3.3V pin (in the photo, the upper left pin of the ESP8266 connector, but many other options are available, like the ST-Link header's rightmost pin, or any other pin marked 3.3V). This needs a steady hand, since you must avoid making contact with the jumper wire anywhere else on the board, a mistake that might destroy your board immediately. Keeping the pin high, press and release the reset button (lower right) and then remove the jumper wire. Now the board is in system memory boot mode.

Open a command prompt (or powershell; same exact parameters also apply to the linux version of the tool), navigate to the folder you placed DFU-Util.exe in, and execute the following: .\dfu-util.exe -l The result should be the following:

PS C:\Program Files\DFU-Util> .\dfu-util.exe -l
dfu-util 0.10

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2020 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=57, cfg=1, intf=0, path="2-7.4.1", alt=3, name="@Device Feature/0xFFFF0000/01*004 e", serial="387536593439"
Found DFU: [0483:df11] ver=2200, devnum=57, cfg=1, intf=0, path="2-7.4.1", alt=2, name="@OTP Memory /0x1FFF7800/01*512 e,01*016 e", serial="387536593439"
Found DFU: [0483:df11] ver=2200, devnum=57, cfg=1, intf=0, path="2-7.4.1", alt=1, name="@Option Bytes  /0x1FFFC000/01*016 e", serial="387536593439"
Found DFU: [0483:df11] ver=2200, devnum=57, cfg=1, intf=0, path="2-7.4.1", alt=0, name="@Internal Flash  /0x08000000/04*016Kg,01*064Kg,07*128Kg", serial="387536593439"

The last one is the DFU device we need, so now we run the following:

.\dfu-util.exe -D [path to Bootloader-Z project]\.pio\build\genericSTM32F407VGT6\firmware.bin -a 0 --dfuse-address 0x08000000:leave

And you should see this (sizes might differ slightly):

dfu-util 0.10

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2020 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/

Warning: Invalid DFU suffix signature
A valid DFU suffix will be required in a future dfu-util release!!!
Match vendor ID from file: 0000
Match product ID from file: 0000
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 element to address = 0x08000000, size = 15120
Erase           [=========================] 100%        15120 bytes
Erase    done.
Download        [=========================] 100%        15120 bytes
Download done.
File downloaded successfully
Transitioning to dfuMANIFEST state

If everything is done correctly, your board should boot normally into your installed firmware. But if you set the trigger pin (press the LCD encoder button) and reset, it should now boot into firmware flashing mode, where the green led is on (if you configured it accordingly) and running .\dfu-util -l should display the following:

dfu-util 0.10

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2020 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=0300, devnum=56, cfg=1, intf=0, path="2-7.4.1", alt=0, name="@Internal Flash/0x08000000/01*016Ka,03*016Kg,01*064Kg,07*128Kg,04*016Kg,01*064Kg,07*128Kg", serial="387536593439"

If you're seeing this, all has gone well and your board is ready to flash a new firmware. The command to do so, is: .\dfu-util.exe -D [path to your firmware binary]\firmware.bin --dfuse-address 0x08008000:leave

5. Setting up Raspberry Pi for automatic flashing

To do this, you'll need two wires to connect the RPi and the GTR.

As shown in the following pictures, the blue wire connects RPi's GPIO18 pin to EXP1's PA15 (LCD button pin), and the orange wire connects RPi's GPIO17 pin to EXP2's RST (reset) pin:

image image image

As you can see in the last picture, and since my setup includes a RepRap LCD (so EXP1 and EXP2 IDC headers are not free), I used 2 10-pin IDC connectors to inject my jumper wires on the LCD ribbon cables. This way I can enter DFU boot mode both manually (from my LCD controls) and through RPi GPIO control.

After you wire your respective pins, all you need is the RPi GPIO Utility and something similar to the following script:

#!/bin/bash

gpio -g mode 18 out
gpio -g write 18 0   # PA15 -> low

sleep .1

gpio -g mode 17 out
gpio -g write 17 1   # RST -> high
gpio -g write 17 0   # RST -> low
gpio -g mode 17 in

sleep .2

gpio -g mode 18 in   # PA15 -> high

sleep 2

dfu-util -D [path to firmware binary]/firmware.bin --dfuse-address 0x08008000:leave

Addendum A: Backing up the stock bootloader

The simplest option is to download the stock bootloader from GadgetAngel's excellent bootloader repository and have it at hand for flashing.

If you want to create your own backup, and you have an ST-Link device, use the STM32 ST-Link Utility to dump the first 32K (0x8000 bytes) of flash, from address 0x08000000 to 0x08007FFF (this is a safe length, the bootloader is smaller, but to determine the actual size you need to figure it out visually from the contents of flash memory).

If you don't have an ST-Link, follow the instructions in step 4 to enter the STM32 bootloader mode and use the following command to create a dump of the bootloader:

.\dfu-util.exe -U stock_bootloader_backup.bin --dfuse-address 0x08000000:0x8000

If you ever need to revert to this (e.g. if Bootloader-Z does not work, or you just want to go back), follow the instructions in step 4, but use the backup binary (or the one downloaded from GadgetAngel's repository) instead of the Bootloader-Z firmware.bin.