We have a problem that in pre v0.8.0-rc4 an electron may not successfully boot after power cycling and the battery having been disconnected by using the disableBATFET function. Updating the bootloader and firmware via DFU mode with a USB cable fixes the issue. Unfortunately a number of devices out in the field are exhibiting the same problem (despite running the same application code) and we cannot easily update via USB. So having performed an OTA with the same application built against v0.8.0-rc4 the problem persists. Is it the case that the bootloader may not/cannot get updated when an OTA is performed? I have tried updating the bootloader using OTA with ‘particle flash NAME bootloader-0.8.0-rc4-electron.bin’ to no avail.
Yes, the bootloader should be upgraded OTA when required. Not all system firmware upgrade requires a bootloader upgrade. For example, all of the 0.7.0 rc and final versions shared a single bootloader version so an upgrade was not required within the 0.7.0 versions.
The Version mapping table can be helpful in figuring out if an upgrade is needed.
The bootloader upgrade is generally done last. The order will typically be:
- User firmware
- Safe mode healer kicks in because of unmet dependencies
- System Part 1
- System Part 2
- System Part 3
It is normally possible to manually flash the bootloader using the command you listed. The bootloader can only be flashed OTA or using the --serial option, it cannot be flashed in DFU mode (blinking yellow) manually.
(The particle update command can update the bootloader in DFU mode through some magic that’s hard to replicate manually.)
What system firmware version were you upgrading from and to?
This is the interesting thing - the unit was already programmed with v0.8.0-rc4 and suffered the problem that it would not restart after a power cycle (although pressing reset restored functionality). Using DFU mode I wrote the v0.8.0-rc4 boot loader (although your comment that you cannot update bootloader via DFU is noted!) followed by parts 1 through 3 of the firmware. This fixed the problem. So maybe the bootloader did not get rewritten - but the firmware parts 1-3 did and the problem went away. So I have units in the field that are running code built with v0.8.0-rc4 that after updating with code that uses disableBATFET() will no longer power back up unless someone manually hits the reset button. What I need to do is replicate exactly what would have happened when I rewrote 0.8.0-rc4 firmware via USB but do it OTA. Or put another way, how do I force a reflash of the firmware parts 1-3? I have tried flashing using the CLI and OTA to no avail - and suspect that the target device is ignoring the updates since they have the same revision. Is that the case?
No, you should be able to flash system parts OTA even when it’s the same version.
In fact, flashing system part 1 OTA is a great way to get devices unstuck remotely. For example, if you have a remote device that is missing functions and variables, flashing system part 1 often will make them come back, where just flashing the user firmware again does not.
Is this a product device (using the products section of the console) or a developer device?
Thank you. All the devices are currently set as developer devices. I have tried OTA’ing parts 1-3 but no fix. Need to understand what might be different between a DFU USB firmware update and a firmware OTA update.
I think as shipped the units must have had 0.7.0 installed, then an OTA which bought them up to 0.8.0-rc4. The console reports the have 0.8.0-rc4. Recent new application code which performs disableBATFET() when the operator turns the system off was a recent update but now causes the units in the field to require a manual reset when repowered (i.e. they are unusable until someone removes the faceplate and manually pushes the reset button while power is on.) All works properly until someone turns the unit off again (5V is lost and the code calls disableBATFET(), and the unit won;t turn back on again! Serious issue! Units on the bench which have v0.5.x (as purchased) and updated to 0.8.0-rc4 via DFU do not have the problem.
You can delete this topic in case it is a red-herring. I took a fresh Electron out the box (v0.5.4) and attempted an OTA with an app built for v0.8.4-rc4. First attempt: magenta rapid flash then reboot. Still at 0.5.4 and no app running. Second attempt: unit did about 4 OTAs and ended running the new code without exhibiting the fault described earlier. So problem lies elsewhere - not the OTA mechanism per se.
Thanks @rickkas7, but I must admit I’m still confused by what it means to flash system vs. user code. I’ve been using Particle products for years now, and I still don’t understand it fully. I just use my well trodden path of using DFU mode updates through ‘particle flash --usb’ and don’t ask questions. But I have to wonder …
When I use ‘particle flash --usb xxx’, with a binary that I compiled with a target version, say 0.7.0, does that also update the system firmware to 0.7.0 if it is not already at that version? If not, then will my user code fail? If so, then why have a separate mechanism to update system firmware, since I could always just update it by compiling my user code against a particular target and loading it all at once?
Why are there 3 different parts to the system firmware? What would happen if I mixed parts of the firmware between versions (I’m guessing it isn’t good)? Why not just have one part?
Each binary file (.bin) contains either system or user binary code, and has a header to determine which it is, and also a CRC to determine validity. When using
particle flash --usb (or --serial, or OTA) you don’t need to tell it which it is, because the header inside the .bin file lets the device know where to put it. It also includes some dependency information, described below.
(If you directly call dfu-util you do need to tell it which address to write to, because DFU does not know how to read the headers in the binary files.)
When writing to flash memory, one caveat is that you can only erase to sector boundaries. In order to write new firmware to flash, the sector needs to be erased, and the sectors are 128K. That’s sort of the minimum quantity that can be updated at one time practically.
The other part is that the STM32 processor does execute-in-place. The running system (and user) firmware is fetched directly out of flash instruction-by-instruction, not copied into RAM. That also means you can’t erase the sector that’s currently running while it’s running.
Thus when doing a flash OTA, the OTA sector is erased, the data copied into it, then the integrity checked by examining the CRC. If valid, the OTA sector is flagged, and the system rebooted.
The bootloader takes care of swapping in the OTA sector, if necessary, into the real sector, before running it.
While we could have made one gigantic 384K system part for the Electron, this would have required setting aside 384K for OTA temporary storage. By making the parts 128K, it reduces the amount of flash required to be set aside for OTA. (The Photon uses 256K system parts, which is why there are only 2 on the Photon.)
The other thing that happens at boot is the dependencies are examined. If you were to flash different system parts from different versions this would be detected and fixed, if possible, at this stage. The device would attempt to go into safe mode, then download the missing parts. If a cloud connection could not be made, then it would stay in safe mode.
Another dependency is the user firmware system target version. This is the minimum system version supported for this user firmware. If the installed system firmware is too old, it will be upgraded automatically using the safe mode healer as well.
You can also OTA flash the system parts manually before you upgrade the user firmware, if you wanted to, instead of relying on the safe mode healer, but this is a lot more work.