PlatformIO is only available in the Microsoft marketplace, as per discussed per PlatformIO IDE not in marketplace and related.
Reported issue with missing shelll-escape: Upload protocol can't identify space char " " for dfu-util · Issue #422 · platformio/platform-ststm32 · GitHub. The bug stems from the original STM32Duino developer.
Hope the PlatformIO devs can workaround / fix it soon.
I repeated this experiment with my Bluepill. In the beginning, it did not have a bootloader on it. So, I grabed the 2.0 bootloader from the github and flashed it on my bluepill using an STLink. Then I only plugged in the bluepill via USB, and got the expected USB device / virtual COM port.
I then went ahead and created a new project with the platformio.ini
[env:bluepill_f103c8_128k]
platform = ststm32
board = bluepill_f103c8_128k
framework = arduino
upload_protocol = dfu
(no upload_port
, PlatformIO will detect it just fine…) and wrote the src\main.cpp
file as a blinky on PC13.
#include <Arduino.h>
void setup() { pinMode(PC13, OUTPUT);}
void loop() { digitalWrite(PC13, digitalRead(PC13) ^ 1); delay(200); }
Before uploading, I also had to install the necessary Windows drivers.
And then a “upload” gave me…
Auto-detected: COM23
Uploading .pio\build\bluepill_f103c8_128k\firmware.bin
maple_loader v0.1
Resetting to bootloader via DTR pulse
Searching for DFU device [1EAF:0003]...
Reset via USB Serial Failed! Did you select the right serial port?
Assuming the board is in perpetual bootloader mode and continuing to attempt dfu programming...
Found it!
Opening USB Device 0x1eaf:0x0003...
Found Runtime: [0x1eaf:0x0003] devnum=1, cfg=0, intf=0, alt=2, name="STM32duino bootloader v1.0 Upload to Flash 0x8002000"
Setting Configuration 1...
Claiming USB DFU Interface...
Setting Alternate Setting ...
Determining device status: state = dfuIDLE, status = 0
dfuIDLE, continuing
Transfer Size = 0x0400
bytes_per_hash=205
Starting download: [##################################################] finished!
state(8) = dfuMANIFEST-WAIT-RESET, status(0) = No error condition is present
error resetting after download: usb_reset: could not reset device, win error: Ein nicht vorhandenes Gerät wurde angegeben.
Done!
Resetting USB to switch back to runtime mode
And the LED started flashing as I wanted. After plugging the device in- and out of the USB port, I still have my Maple DFU device though.
But, the serial port was gone with which the reset-into-bootloader mode is triggered (by opening the virtual COM port and sending a magic sequence of DTR/RTS/bytes). This is because I just uploaded a firmware wich uses the STM32 core (GitHub - stm32duino/Arduino_Core_STM32: STM32 core support for Arduino) and not the Maple core (GitHub - rogerclarkmelbourne/Arduino_STM32: Arduino STM32. Hardware files to support STM32 boards, on Arduino IDE 1.8.x including LeafLabs Maple and other generic STM32F103 boards) with which this DFU bootloader is supposed to be used continuously. I will show how to do it properly in a minute, but to prove a point:
A new firmware is still flashable to the device. The bootlaoder is still on there and executes on boot – so the technique here to unplug the device first, then start the upload process until it says Searching for DFU device [1EAF:0003]
, and then plug the device in again. Another caveat though is that the Maple upload program still requires a COM port on which it wants to do the reset dance. So I write upload_port = COM1
in my platformio.ini
which is my motherboard’s UART port that’s not connecting to anything, but makes the program happy. I upload again and…
Looking for upload port...
Use manually specified: COM1
Uploading .pio\build\bluepill_f103c8_128k\firmware.bin
maple_loader v0.1
Resetting to bootloader via DTR pulse
Searching for DFU device [1EAF:0003]...
Found it!
Opening USB Device 0x1eaf:0x0003...
Found Runtime: [0x1eaf:0x0003] devnum=1, cfg=0, intf=0, alt=2, name="STM32duino bootloader v1.0 Upload to Flash 0x8002000"
Setting Configuration 1...
Claiming USB DFU Interface...
Setting Alternate Setting ...
Determining device status: state = dfuIDLE, status = 0
dfuIDLE, continuing
Transfer Size = 0x0400
bytes_per_hash=205
Starting download: [##################################################] finished!
error resetting after download: usb_reset: could not reset device, win error: Ein nicht vorhandenes Gerät wurde angegeben.
state(8) = dfuMANIFEST-WAIT-RESET, status(0) = No error condition is present
Done!
Resetting USB to switch back to runtime mode
==================== [SUCCESS] Took 11.61 seconds ====================
The firmware is uploaded successfully and the device string
Found Runtime: [0x1eaf:0x0003] devnum=1, cfg=0, intf=0, alt=2, name=“STM32duino bootloader v1.0 Upload to Flash 0x8002000”
Is still present. The LED is now blinking at the rate of the newly compiled firmware. So, all is well and I can reflash arbitrary firmwares however many times I like by unplugging the USB device first, then uploading, waiting until it looks for the device, and replugging the device.
This also does not need a board_upload.offset_address
directive. This is not used / needed in the Maple DFU upload, but in the STM32 USB DFU bootloader for other STM32 chips (refer code).
So, how to do it correctly? Use the Maple core with the Maple USB bootloader. The documentation states how to switch the used core. So, we write the platformio.ini
as
[env:bluepill_f103c8_128k]
platform = ststm32
board = bluepill_f103c8_128k
framework = arduino
upload_protocol = dfu
board_build.core = maple
and we let the src\main.cpp
be the same.
For my first upload, I also had to write upload_port = COM1
again and do the unplug-plug trick to upload the new firmware initially.
Looking for upload port...
Use manually specified: COM1
Uploading .pio\build\bluepill_f103c8_128k\firmware.bin
maple_loader v0.1
Resetting to bootloader via DTR pulse
Searching for DFU device [1EAF:0003]...
Found it!
Opening USB Device 0x1eaf:0x0003...
Found Runtime: [0x1eaf:0x0003] devnum=1, cfg=0, intf=0, alt=2, name="STM32duino bootloader v1.0 Upload to Flash 0x8002000"
Setting Configuration 1...
Claiming USB DFU Interface...
Setting Alternate Setting ...
Determining device status: state = dfuIDLE, status = 0
dfuIDLE, continuing
Transfer Size = 0x0400
bytes_per_hash=389
Starting download: [##################################################] finished!
state(8) = dfuMANIFEST-WAIT-RESET, status(0) = No error condition is present
Done!
error resetting after download: usb_reset: could not reset device, win error: Ein nicht vorhandenes Gerät wurde angegeben.
Resetting USB to switch back to runtime mode
==================== [SUCCESS] Took 10.53 seconds ====================
After the new firmware was uploaded, the device was reset and now I have a new USB device: The virtual COM port.
Notice how the firwmare code (src\main.cpp
) that I’ve uploaded does not do anything with a Serial or the USB serial – the USB serial device simply appears as it’s baked into the Maple core that we’ve switched to.
Now that a firmware with the Maple core is uploaded to the device, I can remove my uplaod_port = COM1
line again and upload new firmwares absolutely normally, without plugging or unplugging the device. A new firmware upload with changed LED interval and no USB re-plugging gives:
Looking for upload port...
Auto-detected: COM23
Uploading .pio\build\bluepill_f103c8_128k\firmware.bin
maple_loader v0.1
Resetting to bootloader via DTR pulse
Searching for DFU device [1EAF:0003]...
Reset via USB Serial Failed! Did you select the right serial port?
Assuming the board is in perpetual bootloader mode and continuing to attempt dfu programming...
Found it!
Opening USB Device 0x1eaf:0x0003...
Found Runtime: [0x1eaf:0x0003] devnum=1, cfg=0, intf=0, alt=2, name="STM32duino bootloader v1.0 Upload to Flash 0x8002000"
Setting Configuration 1...
Claiming USB DFU Interface...
Setting Alternate Setting ...
Determining device status: state = dfuIDLE, status = 0
dfuIDLE, continuing
Transfer Size = 0x0400
bytes_per_hash=389
Starting download: [##################################################] finished!
error resetting after download: usb_reset: could not reset device, win error: Ein nicht vorhandenes Gerät wurde angegeben.
state(8) = dfuMANIFEST-WAIT-RESET, status(0) = No error condition is present
Done!
Resetting USB to switch back to runtime mode
==================== [SUCCESS] Took 10.57 seconds ====================
An auto-detected upload port and a good upload to the device with the new firmware running. After the upload, the virtual USB COM port of course still exists and I can directly do it another time…
Auto-detected: COM23
Uploading .pio\build\bluepill_f103c8_128k\firmware.bin
maple_loader v0.1
Resetting to bootloader via DTR pulse
Searching for DFU device [1EAF:0003]...
Reset via USB Serial Failed! Did you select the right serial port?
Assuming the board is in perpetual bootloader mode and continuing to attempt dfu programming...
Found it!
Opening USB Device 0x1eaf:0x0003...
Found Runtime: [0x1eaf:0x0003] devnum=1, cfg=0, intf=0, alt=2, name="STM32duino bootloader v1.0 Upload to Flash 0x8002000"
Setting Configuration 1...
Claiming USB DFU Interface...
Setting Alternate Setting ...
Determining device status: state = dfuIDLE, status = 0
dfuIDLE, continuing
Transfer Size = 0x0400
bytes_per_hash=389
Starting download: [##################################################] finished!
error resetting after download: usb_reset: could not reset device, win error: Ein nicht vorhandenes Gerät wurde angegeben.
state(8) = dfuMANIFEST-WAIT-RESET, status(0) = No error condition is present
Done!
Resetting USB to switch back to runtime mode
==================== [SUCCESS] Took 9.53 seconds ====================
And the device string is also still there.
So, regarding your situation now: The bootloader on your device is probably still fine and your device is not bricked. The first thing you should do is use a platformio.ini
like
[env:bluepill_f103c8_128k]
platform = ststm32
board = bluepill_f103c8_128k
framework = arduino
upload_protocol = dfu
board_build.core = maple
upload_port = /dev/arbitrary_serial_device_here
and upload any firmware (e.g. blinky from above) to the device with the discussed procedure.
Also, your device is never truly bricked until the chip fails. You can program the board over the SWD interface with a cheap ST-Link V2 programming probe (which also enables you to debug firmwares instead of just uploading them), and you can reboot your chip into bootloader mode by connecting the BOOT0 pin to GND and resetting it. The BOOT0 and BOOT1 pins are accessible through the two jumpers to the left of the reset button, which can be connected to GND or VCC (0/1). The embedded bootloader in the STM32F103 chip will then make the chip flashable via a serial UART interface, which PlatformIO also supports per upload_protocol = serial
. If you have any cheap USB-UART adapter, you can reflash the chip. So, it’s never truly bricked.
Should the bootloader be damaged by some kind of miracle (that shouldn’t have happened), use one of the two methods listed above. Otherwise, you’ll be able to recover it just fine.
So as a TL;DR:
- double check which Arduino core you want to use with the device
- double check the PlatformIO STSTM32 documentation
- use the Maple USB DFU bootloader with the Maple Arduino core for maximum comfort
- the Maple USB DFU bootloader can still be used to flash STM32-core firmwares, but needs a USB replug for every firmware upload
- if you want debugging and comfortable uploading to the STM32 chip in every situtation / core, invest the 5€ in an ST-Link clone
- STM32 chips can be reflashed via SWD, the embedded UART bootloader or the Maple bootloader
- you cannot override the bootloader when uploading via the Maple DFU USB bootloader – it takes care of that itself. (not so with the other upload methods)