Skip to main content
Graduate II
August 26, 2024
Question

Update Firmware over USB Virtual Comm Port

  • August 26, 2024
  • 10 replies
  • 4884 views

Hello,

I am using the STM32F373's virtual USB port successfully.  I can connect and send packets to the uC from a web browser.  I now want to allow the user to update the firmware from the web browser by uploading a file, instead of the traditional method involving the ST flash software.  

It would need to happen via WebSerial API so over the USB virtual port.  What is the best way to accomplish this?  Is there an appnote I should look at?  I'm looking at AN2606 [bootloader] and AN3156 [DFU] and AN3156 now.

Thank you,

    This topic has been closed for replies.

    10 replies

    Graduate II
    August 26, 2024

    I can't recall ever coming across the notion of "Virtual USB port" before. Can you explain what you mean? Perhaps you meant "Virtual COM port" aka VCP, instead?

    LMorr.3Author
    Graduate II
    August 26, 2024

    Yes, I meant the virtual com port.  I changed the title.  Does the booloader automatically set the USB port ( PA11 and PA12 ) to DFU mode even though I have set the CubeMX config for USB to 'Virtual Comm Port'?

    I could then try using WebUSB to upload the firmware and see there are a couple of such projects on github...

    Graduate II
    August 26, 2024

    CubeMX generates configuration code for your user application. The bootloader is firmware already burned into a special region of the chip's flash at the factory. The former does not affect the latter. Once you boot into the bootloader code, it tries to detect which interface you're communicating through, and configures the device peripherals accordingly. It's all well-documented in the appnotes.

    LMorr.3Author
    Graduate II
    August 26, 2024

    Is there a way to put the device into boot mode from the web browser?  ( i did not see anything about that in the docs )

    The only way I can think of is to have a user button to set Boot0 and Boot1 to high while turning on the device.

    I've seen apps where the browser shows a notice when the firmware needs to be udpated.  If you click to update, the browser refreshes after uploading a file in the background via javascript.  It must somehow put the device in boot mode.  It's can't be using the USB+5 signal since that is always present.  ( the same PA11 and PA12 DM/DP USB pins are used as a Virtual Comm Port and use it to detect a USB connection. )  I"m trying to envision how the whole process would flow.

    Graduate II
    August 26, 2024

    I suppose it should be possible, while your user application is running, to accept a command from the client, and then go through some sort of state cleanup followed by a jump to the bootloader. Might work.

    But i'm not sure it's good from a usability standpoint to go this route, since it would mean that a failed update might brick your device, as far as the user is concerned. If you want to hide all STM32-like details from the user, you probably want to have more control over the update process and error recovery (i.e. a fail-safe update procedure).

    Otherwise, once you'll inevitably get some percentage of failures in the field, you'll have to document a manual recovery procedure anyway. At which point, you might as well just skip the whole thing and just do all the updates via this manual procedure + the bootloader to begin with.

    LMorr.3Author
    Graduate II
    August 26, 2024

    Is the simplest way for the user to update firmware on the end-product to connect a USB cable, hold a button on the device while powering it on, and then using the ST app to upload the file?

    Since it's a web app, I could include instructions for the user when there is a new firmware update detected.

    I'm wondering how that wold work on a mobile device too.

    Graduate II
    August 26, 2024

    Probably not simplest for the user, but certainly easier for the developer and possibly safer. Why reinvent the wheel? You should also skim through the official USB DFU specification, freely available online.

     

    Another popular model (though not native to STM32 chips) for easily programming a board over USB is to use a UF2 bootloader. The user puts the device into the UF2 bootloader mode, and the board enumerates as a USB mass-storage device / drive on your computer. You then drag the firmware update file into the drive and this triggers the update. The Raspberry PI Pico is one major example, but I've also seen this type of update flow on some pen-style soldering irons. Here are some details from Adafruit about how they implement it on some of their Atmel SAM Based boards. I've not (yet, though I probably will now) looked at whether anything out tthere implements this for STM32.

     

    If you want something very user friendly UF2 is a good model, but could mean much more work for you.

    LMorr.3Author
    Graduate II
    August 27, 2024

    I'm looking to implement USB DFU. The solution requires the USB DM to be pulled up to 3.3V using a 1.5k resistor. 

    The problem I'm facing now is that my app was already pulling up the USB DM programatically via a GPIO output.  When I go into boot mode, USB DM is not pulled up so it does not get detected for USB DFU.

    Is the solution to leave the pull-up resistor, and to configure the GPIO as a drain output, and ensuring it is set low when my app starts?  ( it gets set high when the USB+5V is detected )

    Or should I leave the 1.5k pull-up and remove the GPIO output toggle?  ( then there will be no way for my app to detect when the USB cable is connected to pull the USB DM hight as per the spec )

    Graduate II
    August 28, 2024

    That sounds like a good subject for a new thread.

    LMorr.3Author
    Graduate II
    August 28, 2024

    I'm still learning about the best approach.  The USB connection starts off as a virtual com port, and then sends a command to the uC to switch it to boot mode via USB DFU.  That is as far as I got, but I'm guessing there are github projects which will show me how to get the dowload from browser done, instead of using the ST32 programmer app.  The uC would then receive the 'Go' command to get back to running the newly updated app.  I'm surprised there is no well-documented solution to this since it seems to be the most convenient way to upgrade end-user products.  The USB DFU even allows a web URL to be discovered by the host, so the checking of the latest version, downloading of new firmware and flashing could all be done behind the scenes.  I've seen this done with other end-user devices.  I'm not sure if bricking of device is a concern so I still need to do more research.  

    Graduate II
    August 28, 2024

    I suppose it should be possible, while your user application is running, to accept a command from the client,

    > and then go through some sort of state cleanup followed by a jump to the bootloader. Might work.

     

    Just saw this,

    KB:How to jump to system bootloader from application code on STM32 microcontrollers

     

    I still think this is the wrong approach, since the possibility of a failed update means you'll still have to instruct your users on how to access the bootloader independently of your application. But it's nice to know it's possible.

    LMorr.3Author
    Graduate II
    August 29, 2024

    Thanks for the info.  I had to spin up new boards ( to pull-up the USB DM correctly ) so I need to wait to get those before I can try.

    I understand what you mean about failed updates.  If the USB DFU method fails, I plan on having instructions for the user to set the jumper to 'boot', and use the STM32Cube programmer app.  ( Direct the user to a web page using the default web URL of USB DFU, where they can download the STM32 programmer app )

    I'm wondering though; considering the same data is sent with either method, what could cause the update to fail via USB DFU versus using the STM32Cube programmer app?  

    Can the user always recover using the STM32Cube programmer app, or can the STM32F373 sometimes become 'bricked' and un-usable if an update fails?

    Graduate II
    August 29, 2024

    what could cause the update to fail

    Many users own cats.

     

    If an update is initiated through your application and fails, perhaps due to feline intervention, the user will not be able to try again through your application. They will then arm themselves with pitchforks and twitter and loudly demand that you furnish them with a recovery procedure. If you delay too long in responding, they will first dox you and then SWAT your home. Then they will create attack websites using the very latest AI diffusion models, websites that will portray you as a sexual deviant. And I'm not talking about the trendy, acceptable, kind of perv, either. So you see, It really is best to get the firmware update flow right the first time.

     

    can the STM32F373 sometimes become 'bricked' and un-usable if an update fails?

    A failed update can leave the application flash area in an indeterminate state but the bootloader is held in a separate part of memory ("system memory") which is not touched by a normal firmware download process (it is writable though - you could replace it with a custom bootloader for example. Kind of like android recovery).

     

    It is also possible to roll your own update process with additional safeguards, and many vendors do so. Consider for example the various fail-safe measures introduced by motherboard manufacturers, over the years, to deal with BIOS updates. One common theme is keeping two  copies/versions of firmware side by side, so that the updated version become active only after the update completes successfully, and so the system can fail over to a known-good version if it detects a problem during boot. There are all kinds of variations on this theme as well as other kinds of protections. It all depends on the level of assurance you need. Your typical USB gadget doesn't usually bother.

    LMorr.3Author
    Graduate II
    August 29, 2024

    From what I gather, it's not possible to 'brick' the STM32F373 if the STM32Cube programmer app is used.  The STM32Cube programmer download can also fail under the same conditions, but the user can just re-start the download if it fails.  In my case, I plan on having the web app will persist a 'downloading firmware' state via the browser's localstore, and show a firmware update web page if the state is present, with a link to download the STM32Cube programmer.    ( clear local store upon fresh install/upgrade or successful connection )  The user would need to set a jumper and restart the device.

    Graduate II
    August 29, 2024

    From what I gather, it's not possible to 'brick' the STM32F373 if the STM32Cube programmer app 

    As they say, give me a big enough hammer and I will make your hard real-time system fail to meet its deadline.

    But true, you can try over and over by manually placing the chip into the bootloader and using the programmer software. What I said was that if you use your own software routine to go into the bootloader, that software will not be available for a second try if martians attack the power grid during your first attempt (or the battery dies, etc').

    LMorr.3Author
    Graduate II
    September 12, 2024

    Ok, I built a new board and I see USB device when I run 'dmesg':

    [3552008.377434] usb 3-2: new full-speed USB device number 101 using xhci_hcd
    [3552008.526223] usb 3-2: New USB device found, idVendor=0483, idProduct=df11, bcdDevice=22.00
    [3552008.526227] usb 3-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
    [3552008.526229] usb 3-2: Product: STM32 BOOTLOADER
    [3552008.526230] usb 3-2: Manufacturer: STMicroelectronics
    [3552008.526231] usb 3-2: SerialNumber: 2077345D2039

     But now when I run the STM32CubeProgrammer, it does not connect to the USB device or even show it listed in the dropdown box.  It shows 'No DFU detected'.

    I have set the boot jumper on my board and it does seem to be detected as 'STM32 BOOTLOADER'.

    Any ideas on what I could try?

    Best,

    Graduate II
    September 12, 2024

    You best start a new thread for a new issue.