adafruit / Adafruit_nRF52_Bootloader

USB-enabled bootloaders for the nRF52 BLE SoC chips
MIT License
461 stars 415 forks source link

Application can't trigger OTA DFU #63

Closed charlesportwoodii closed 5 years ago

charlesportwoodii commented 5 years ago

Boards: mdk-usb-dongle, pca10059 Env: Linux, nRF52 15.3 SDK

I have a custom application I've written that I've added buttonless DFU to, however I can't seem to get my application to actually flash an update over OTA. nRF Connect is able to initiate buttonless DFU (from both Android & nRF Connect on desktop), and I do see the board briefly go into DFU mode, however instead of flashing an update I simply get a GATT connection error and the board resets back into the application.

Looking at the bootloader code I should just be able to set gpregret to BOOTLOADER_DFU_START then do a reset from the soft device to get the chip to enter OTA DFU and perform a flash, however that doesn't seem to be working (which is what the default Nordic service does in ble_dfu).

Buttonless DFU is pretty straightforward, but for thoroughness:

UART logging in my app confirms that ble_dfu_buttonless_bootloader_start_finalize is called right before the board resets, so I'm confident that gpregret is set. It seems like the bootloader isn't seeing that register being set when it goes into DFU on reset.

Short of throwing a debugger at the bootloader to see if the register is picked up properly I've thrown everything I can think of at it, including adjusting the timeouts on both the bootloader and application. I feel like I'm missing something obvious in getting OTA DFU to work with this bootloader, but can't seem to figure it out myself so I'm looking for help. I've seen other users be able to get OTA DFU to work so I'm sure it's an implementation change I need to make, I'm just not sure what at this point.

Questions

Thanks for your help!

hathach commented 5 years ago

I am busy and couldn't look at this for now. Can you test it with our Arduino sketch with pca10056. Last time I chekced it still works

https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/libraries/Bluefruit52Lib/examples/Peripheral/bleuart/bleuart.ino

Check out our tutorial on adafruit.com for setting up Arduino

charlesportwoodii commented 5 years ago

More or less the same thing when using the bleuart sketch. I've tried to provide as much information as possible. Please let me know if you need more.

Setup

Steps

  1. Flash nRF52 Bootloader (this one, not the Arduino one).
  2. Flash bleuart sketch (0.9.3 is what I have installed already) from Arduino IDE.
  3. Start Arduino IDE Serial Monitor (sketch refused to start broadcasting until I did this). Open Bluefruit Android app and connect to Bluefruit52 that's now broadcasting.
  4. Select updates and select any update. Devices goes into DFU mode, but then Bluefruit says "Operation Failed" when trying to do the update.

Observations

  1. Unlike the nRF52 SDK 15.3 example however, the device appears to be in OTA DFU mode at this point despite the failure from Bluefruit. After the OTA DFU attempt fails, the device is now broadcasting as AdaDFU. I can't connect to the board at this point either to attempt to manually send the DFU packets.
  2. The applications appears to be wiped once the OTA DFU fails. That's probably expected from a failed flash. Pressing the reset button on the board sends me back to the bootloader and I have to re-upload the sketch and start the process over again.
  3. nRF Connect doesn't show the simple "DFU" button like it does in the nRF52 15.3 SDK example. Reading up on SDK11 is looks like legacy DFU mode is used, though implementations seem identical between the SDK versions (BOOTLOADER_DFU_START to GPREGRET0 to initiate).

I don't necessarily expect OTA DFU to work if I'm flashing a new Bootloader or SoftDevice, however I figured I would at least be able to update the application by itself OTA with either a hex or a sketch. If there's sufficient difference between how the bootloader expects SDK11 vs SDK15 calls I can probably port that on my own, I was just hoping to take advantage of y'alls great work on this before also needing to write my own custom bootloader.

Thanks for looking into this.

hathach commented 5 years ago

@charlesportwoodii I am still busy with other stuffs. But just give this a try today, I test with nrf Connect app on iOS from Nordic ( Bluefruit app doesn't support it yet).

I don't use nordic sdk any more, so I cannot help you with that. You need to use the sketch.ino.zip file generated by Arduino IDE to upload. There are several topic in our support forum regarding this e.g https://forums.adafruit.com/viewtopic.php?f=57&t=123583&hilit=ota

PS: Forgot to mention this repo use legacy (non-secure) DFU service

hathach commented 5 years ago

closed since hardware board and software sdk is not supported, it is user responsibility to make them compatible . My re-check confirms it works fine with out environment

charlesportwoodii commented 5 years ago

Sorry I haven't been able to respond with greater frequency - I have unfortunately been preoccupied with some more pressing matters.

PS: Forgot to mention this repo use legacy (non-secure) DFU service

That's probably why it doesn't work. The nRF15 SDK uses the secure DFU service. The SDK implies these are backwards compatible but it doesn't seem to be the case at least with this bootloader. If that isn't resolvable with this bootloader I can work on writing my own. Unfortunately I'm not in a position to downgrade my nRF52 apps from 14/15 back down to 11.

Thanks for your time.

hathach commented 5 years ago

Asaik, it doesn't matter what you write with the application. You only need to make sure the flash layout is the same. And generate dfu zip package with our correct id value. All command can be seen in Arduino compilation output. We don't use Nordic sdk so couldn't help you there. It isn't a bug, just compatible issue.

dsteinman commented 5 years ago

I wanted to add my experience with OTA on Adafruit nRF52840 Express.

I can successfully perform an OTA update using Adafruit's Bluefruit mobile app (android). If I export the compiled binary hex file from Arduino IDE, then perform the following:

adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application sketch.ino.feather_nrf52840_express.hex package.zip

Then I unzip that file, and use the .hex file, and the .dat file (that's the init file that Bluefruit requires).

The zip package that adafruit-nrfutil produces doesn't work in the nRF Toolbox mobile app, it fails in exactly the way charlesportwoodii describes.

charlesportwoodii commented 5 years ago

@dsteinman I ended up writing my own bootloader with a comparable feature set to get around the OTA problem: https://github.com/charlesportwoodii/kaidyth_nrf52_bootloader. It uses nrf SDK 15.3 and all the standard tools instead of the Adafruit specific ones. The board supports double-tap-reset, and both USB and BLE OTA DFU modes with the secure bootloader.

I haven't explicitly tested it on nrf52840 Feather, but I've built if for 6 or so boards I have on hand and it should work on any nrf52840 boards if a definition is built out for them.

dsteinman commented 5 years ago

Nice work charles. If I understand correctly, your bootloader is only for Nordic SDK with no Arduino support?

charlesportwoodii commented 5 years ago

@dsteinman I haven't specifically tried it with Arduino, but I don't see why it wouldn't work with the Arduino SDK. Really the only problem I set out to solve was getting OTA BLE DFU to work with a comparable featureset.

Arduino can output a app hex, and at that point you can flash it the same way as a regular nrf app.

I'll add a todo task for me to check if that works, I don't see why it wouldn't.

dsteinman commented 5 years ago

I'd appreciate that. It might actually be working, but possibly I am missing a step. I downloaded your project and was able to build the bootloader hex file (I made no changes to the code) and flashed it using a JLink:

nrfjprog -e -f nrf52
nrfjprog -f nrf52 --program _build_mdk-usb-dongle/nrf52840_xxaa.hex
nrfjprog -f nrf52 --reset

But now the board "appears" to be bricked. None of the LED light up, no OTA DFU shows up when I scan for devices in NRF Toolbox. I can still recover the board by reflashing the Adafruit bootloader.

I then tried adding the hex file I exported from my Arduino, but it didn't seem to do anything at all.

nrfjprog --program sketch.ino.feather_nrf52840_express.hex  -f nrf52
charlesportwoodii commented 5 years ago

@dsteinman Let's take this conversation here: https://github.com/charlesportwoodii/kaidyth_nrf52_bootloader/issues/3

chrisingis commented 5 years ago

More or less the same thing when using the bleuart sketch. I've tried to provide as much information as possible. Please let me know if you need more.

Setup

* Board: mdk-usb-dongle configured as Adafruit nRF52840 Bluefruit Feather Express (it's what I have free at the moment and seems to work just fine since the rst pin is the same. I'm not using any GPIO pins on the bleuart so any variants in the boards shoudn't matter since I'm powering it over USB).

* IDE: Arduino IDE 18.9

* Bluefruit Library Version: 0.9.3 (previously installed - I haven't tried updating to .10.x yet but expect the same behavior).

* Android 9, Bluefruit 3.0.9 app

Steps

1. Flash nRF52 Bootloader (this one, not the Arduino one).

2. Flash bleuart sketch (0.9.3 is what I have installed already) from Arduino IDE.

3. Start Arduino IDE Serial Monitor (sketch refused to start broadcasting until I did this). Open Bluefruit Android app and connect to `Bluefruit52` that's now broadcasting.

4. Select updates and select any update. Devices goes into DFU mode, but then Bluefruit says "Operation Failed" when trying to do the update.

Observations

1. Unlike the nRF52 SDK 15.3 example however, the device _appears_ to be in OTA DFU mode at this point despite the failure from Bluefruit. After the OTA DFU attempt fails, the device is now broadcasting as `AdaDFU`. I can't connect to the board at this point either to attempt to manually send the DFU packets.

2. The applications appears to be wiped once the OTA DFU fails. That's probably expected from a failed flash. Pressing the reset button on the board sends me back to the bootloader and I have to re-upload the sketch and start the process over again.

3. nRF Connect doesn't show the simple "DFU" button like it does in the nRF52 15.3 SDK example. Reading up on SDK11 is looks like legacy DFU mode is used, though implementations seem identical between the SDK versions (`BOOTLOADER_DFU_START` to `GPREGRET0` to initiate).

I don't necessarily expect OTA DFU to work if I'm flashing a new Bootloader or SoftDevice, however I figured I would at least be able to update the application by itself OTA with either a hex or a sketch. If there's sufficient difference between how the bootloader expects SDK11 vs SDK15 calls I can probably port that on my own, I was just hoping to take advantage of y'alls great work on this before also needing to write my own custom bootloader.

Thanks for looking into this.

This is SPOT ON. I have been attempting to perform any type of OTA update over the past 6 months using 5 different Adafruit's nRF52840 Express boards.

I think this should be reopened. There is certainly a bug in the bootloader.

hathach commented 5 years ago

@jewcbox Please open an new issue with more information with step & tools to reproduce the issue with bluefruit nrf52840 board, this topic is totally different issue with SDK + secure DFU on 3rd party hardware.

chrisingis commented 5 years ago

@hathach I think you need to look this over again, because it's not a totally different issue and is an issue pertaining to Adafruit's bootloader.

The resolution was to modify src/sdk_config.h and increase the value of HCI_RX_BUF_QUEUE_SIZE to 16, which resolved the issue.

I traced hci_mem_pool_rx_produce() throwing an error NRF_ERROR_NO_MEM due to m_rx_buffer_queue.free_window_count == 0 In that trace, the value of length, passed to hci_mem_pool_rx_produce() was 14.

Since this is resolved in my environment, I have little interest in the topic. However, I can and will provide sufficient information for your tense and purposes if it helps, let me know.

dsteinman commented 5 years ago

That's great @jewcbox could you make a pull request?

@hathach this is a problem when creating Secure DFU packages from Arduino code running on Adafruit hardware (NRF52832 and NRF52840). The Adafruit mobile app can perform a OTA DFU, but if you generate a secure package and try to get it to perform a DFU using any of Nordic's tools it fails every time. This prevents any secure DFU packages from working with any Adafruit NRF52 product.

hathach commented 5 years ago

@jewcbox if possible, could you make a PR for the changes. Also please provide your setup OS version, iphone/anrdoid model + version, BSP and sketch to test. I will before the test before and after the PR for confrimataion.

@dsteinman secure DFU is not supported by this bootloader. And it is not related to this issue as well. Please open a separated one with detail information on setup/step to reproduce. Though I won't upgrade this repo to support DFU secure any time soon.