This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

No transport to DfuTarg observed after "Enabling DFU Bootloader..."

First attempt at implementing buttonless dfu; assistance would be greatly appreciated. Using SDK v11 + s130 + nRF51822.

Please note that iphone screen captures supporting my observations can be seen here: https://goo.gl/VlYdBY

I wrote a bootloader, and successfully installed it with sd + app. It seems to be operating well and I'm able to debug, so I am capable of execution flow trace.

I created an app-only zip with good start packet using nrfutil, and added it to NRF Toolbox iOS app as a user file.

I start up my device, which is advertising for dfu properly.

In NRF Toolbox I select my file, then select my device as the target. I then tap "Upload".

The ios App begins the process. It quickly says "Starting update" followed by "Enabling DFU Bootloader...", and then it just sits there forever.

In debugging on the device, I can see that I get all the way through dfu_transport_update_start just fine, and at this point I'm in the bootloader.c wait_for_events() loop as I should be. (It eventually times out properly.)

However, oddly, while the phone is sitting there "Enabling DFU Bootloader...", the device never reaches ble_evt_dispatch() in the dfu transport - not a single time - indicating to me that the phone doesn't seem to be connecting into my device to initiate the transport.

When I use nRF Connect to see what's going on, I do see DfuTarg being advertised. When I Connect to it, I see "Legacy DFU Service" as the primary service. When I open the service, I see Legacy DFU Packet, Control Point, and Revision. (See photos for details.)

The encouraging thing is that when I do use nRF Connect to examine these things, I DO nicely get events coming into the handler at ble_evt_dispatch() within dfu_transport_ble.c. However, as I said, I get nothing coming into that handler as triggered by nRF Toolbox's DFU process.

(It is a bit odd that these things are called "Legacy DFU" given that I'm using the up-to-date SDK and the up-to-date nRF Toolbox & Connect apps. Perhaps a better version must be coming in sdkv12?)

In any case, as I said, the DFU seems to be starting nicely, but I'm blocked at this point given that the BLE transport doesn't seem to be being kicked off.

Any thoughts about what to try next would sincerely be appreciated; thanks for your time.

Parents
  • It's not very helpful, but I'm running into this currently too.

    DFUPeripheral.swift just calls connect() which does:

    centralManager.connectPeripheral(peripheral!, options: nil)
    

    from the centralManager didDisconnectPeripheral callback when it is disconnected after jumping into the bootloader.

    iOS however never succeeds at reconnecting to the device (it is advertising and can be connected to however) until the DFU times out and the device resets itself again, restoring the application to running.

    Update 1: Looking at the addresses of the device from nRF Connect from an Android device while running the app vs running the bootloader, the address is changing: xx:xx:xx:xx:xx:xC in the app vs xx:xx:xx:xx:xx:xD in the bootloader. iOS won't be connecting because it thinks it's a different device.

    I did see something in the iOS source about handling this situation for SD updates, but that code was literally "eh the address will have changed, so just use the first device found that exposes a DFU service" - not exactly something I'm willing to put into production code.

    Update 2: Here's some explanations of what is happening and why: devzone.nordicsemi.com/.../ devzone.nordicsemi.com/.../

    Disabling the half-dozen lines from the first link in dfu_transport_update_start() in dfu_transport_ble.c in the bootloader has resolved my issues - DFU is now working on iOS! I'm not using an encrypted link at this stage, so it is not an issue. From those links and the code, it looks like we should use bonded connections and set them up so that the bond information is shared with the bootloader in the long term.

Reply
  • It's not very helpful, but I'm running into this currently too.

    DFUPeripheral.swift just calls connect() which does:

    centralManager.connectPeripheral(peripheral!, options: nil)
    

    from the centralManager didDisconnectPeripheral callback when it is disconnected after jumping into the bootloader.

    iOS however never succeeds at reconnecting to the device (it is advertising and can be connected to however) until the DFU times out and the device resets itself again, restoring the application to running.

    Update 1: Looking at the addresses of the device from nRF Connect from an Android device while running the app vs running the bootloader, the address is changing: xx:xx:xx:xx:xx:xC in the app vs xx:xx:xx:xx:xx:xD in the bootloader. iOS won't be connecting because it thinks it's a different device.

    I did see something in the iOS source about handling this situation for SD updates, but that code was literally "eh the address will have changed, so just use the first device found that exposes a DFU service" - not exactly something I'm willing to put into production code.

    Update 2: Here's some explanations of what is happening and why: devzone.nordicsemi.com/.../ devzone.nordicsemi.com/.../

    Disabling the half-dozen lines from the first link in dfu_transport_update_start() in dfu_transport_ble.c in the bootloader has resolved my issues - DFU is now working on iOS! I'm not using an encrypted link at this stage, so it is not an issue. From those links and the code, it looks like we should use bonded connections and set them up so that the bond information is shared with the bootloader in the long term.

Children
  • I have exactly this behavior also. It times out, and then resets/restores. Sigh.

  • That is truly fascinating. Let me explain something else that I've found, and perhaps you might have an explanation for this:

    I got the most basic hrs app running with identical softdevice/bootloader/etc, and interestingly it got past the Enabling step and well into downloading - which gave me something to A/B test against.

    What I found was that when using the hrs example, in dfu_transport_update_start() in dfu_transport_ble.c, the behavior was different between HRS and my app.

    In HRS, the call to dfu_ble_peer_data_get() returns SUCCESS. The "peer_data" is apparently valid.

    In my app, that call returns an error, and thus, as you say, it falls into the code that bumps the address by one.

    I've never done a DFU app before, and so what I've been trying to do for the past hour or so is to figure out what this "peer data" is, and how it gets initialized.

    Any further thoughts?

  • This is my first time doing a DFU app also unfortunately.

    This page in the docs covers the bonding setup though: infocenter.nordicsemi.com/index.jsp

  • PROBLEM SOLVED - at least for me.

    Simple description: In my app's ble_evt_dispatch(), I neglected to add a call to dm_ble_evt_handler() when I was inserting the DFU code. Here's the longer explanation:

    void ble_evt_dispatch(ble_evt_t *p_ble_evt) {

    // Make sure that we process DM events, else connections won't be registered with DM.  
    // The most significant result of this is that DFU won't work; it won't leave an "Enabling..." state.                                   
    // because the DM needs to be looked up.  Call stack:                                                                                   
    // dfu_app_on_dfu_evt(), when evt_type == BLE_DFU_START                                                                                 
    //  bootloader_start(p_dfu->conn_handle), which is valid                                                                                
    //   dfu_app_peer_data_set(conn_handle), which is supposed to set peer_data                                                             
    //    dm_handle_get(conn_handle, &m_dm_handle), ...                                                                                     
    //      looks up handle in connection table associated with dm_                                                                         
    // ...so where does it get put INTO this connection table?                                                                              
    //  dm_ble_evt_handler(p_ble_evt) is supposed to be called by your own ble_evt_dispatch                                                 
    //   BLE_GAP_EVT_CONNECTED adds it.                                                                                                     
    // The bug was that I failed to have this call to dm_ble_evt_handler() in my ble_evt_dispatch.                                          
    
    dm_ble_evt_handler(p_ble_evt);
    
  • Hi, I was just about to ask a question about this same problem! Looks like it's maybe a recent nuisance??

    I'm using SDK v10 (as my app is part mBed based) and I see the same problem.

    Using nRF Toolbox I start a DFU upload and it hangs at "Enabling DFU bootloader...". I've found that if I then kill & re-launch the nRF Toolbox app and upload to the newly-advertising "DfuTarg" it uploads fine. I guess nRF Toolbox is storing some info on the old DFUService and getting confused when it updates to the DfuTarg version.

    I can also successfully upload after having "manually" started the DFU process by writing a byte to the DFU Control Point (using the iOS app LightBlue Explorer) and then going to nRF Toolbox and uploading to the newly-advertised DFUTarg device...

    @Ray I'll attempt to implement your fix and see if that works if I can

Related