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

DFU control point write, app not restarting into bootloader, gcc, SDK 8.0.0

I've followed the instructions for adding the DFU service to my app to the letter and can see the DFU service from the central and can enable notifications on the control point and write a 01 04 to it to kick off DFU OTA for the application. The application does NOT restart into the bootloader, however. I have some debug LEDs on my board that tell me so.

I'm using SDK 8.0.0 on the whole but for GCC, the bootloader_util_gcc.c StartApplication() assembler appears to broken in 8.0.0, from what I read here, so I've pulled that source into my project and used the implementation from SDK 8.1.1.

On a normal reset I can see my bootloader running properly and starting the application. I'm writing to the control point characteristic both from an Android app and from the MCP on Windows. Neither works. I can't connect to the device using the MCP on Android (no CONNECT button on the UI next to the device).

Here's the code for the Android app (central), anyway. There is no error on writing the characteristic value.

    // nordicDfuControlPoint is the characteristic, from discovery.
    final BluetoothGattDescriptor descriptor =
            nordicDfuControlPoint.getDescriptor(BleCharacteristic.CCCD);

    if (descriptor == null) {
        Log.e(TAG, "Can't write descriptor for Nordic DFU control point." +
                " BluetoothGattCharacteristic.getDescriptor() returned null.");
        return;
    }

    Log.d(TAG, "Enabling notifications on characteristic for Nordic DFU control point.");

    descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); // {0x01, 0x00}

    if (!gatt.writeDescriptor(descriptor)) {
        Log.e(TAG, "Can't write descriptor for Nordic DFU control point for enable."
                + " BluetoothGatt.writeDescriptor() returned false.");

        // See BluetoothGatt.java L1020. If either of these are null, we get false back.
        Log.e(TAG, "descriptor.getCharacteristic(): " + descriptor.getCharacteristic());
        Log.e(TAG, "characteristic.getService(): "
                + descriptor.getCharacteristic().getService());
    }

    new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
        @Override
        public void run() {
            nordicDfuControlPoint.setValue(NORDIC_DFU_UPDATE_APPLICATION, // Integer, 0x0104.
                    BluetoothGattCharacteristic.FORMAT_UINT32, 0);

            if (!gatt.writeCharacteristic(nordicDfuControlPoint)) {
                Log.e(TAG, "Can't write value for Nordic DFU control point for update application."
                        + " BluetoothGatt.writeDescriptor() returned false.");

                // See BluetoothGatt.java L1020. If either of these are null, we get false back.
                Log.e(TAG, "descriptor.getCharacteristic(): " + descriptor.getCharacteristic());
                Log.e(TAG, "characteristic.getService(): "
                        + descriptor.getCharacteristic().getService());
            }
        }
    }, 2000); // 2s

My bootloader code has been modified from the example to remove the button stuff and turn some of my LEDs on, not much else.

How do I debug this?

[EDIT]

StartApplication() implementation: bootloader_util_gcc_bike.c

[EDIT]

Before dfu_app_handler.c calls dfu_ble_svc_set_peer_data(), the key_set passed in looks like this to gdb:

		{
		  keys_periph = {enc_key = {p_enc_key = 0x20003d88}, p_id_key = 0x20002a80 <m_local_id_info>, p_sign_key = 0x0},
		  keys_central = {enc_key = {p_enc_key = 0x0}, p_id_key = 0x200029f0 <m_peer_table>, p_sign_key = 0x0}
		}

I can't see any more detail than that in gdb.

Parents
  • If the SVC_Handler is implemented incorrectly it could make the bootlaoder fail to enter DFU mode. My suggestion would be to use the official GCC bootloader from SDK 8.1.0 if possible. Alternatively import the df_ble_svc.c (adds support for GCC) file from this release to see if it solves the problem.

    You were right that the SDK doc was lacking information regarding the service changed characteristic. In addition to implementing the load app context function as you mentioned, you also need to make sure to allocate space for the app context in device_manager_cnfg.h. I will report this internally, sorry for the inconvenience.

    Attached bug fixed linker script as the one provided in the SDK was missing the NOLOAD directive for the .noinit and .bootsettings sections: dfu_gcc_nrf51.ld This issue caused the linker to ("try") place init data in the bootsettings page and .noinit section in RAM.

Reply
  • If the SVC_Handler is implemented incorrectly it could make the bootlaoder fail to enter DFU mode. My suggestion would be to use the official GCC bootloader from SDK 8.1.0 if possible. Alternatively import the df_ble_svc.c (adds support for GCC) file from this release to see if it solves the problem.

    You were right that the SDK doc was lacking information regarding the service changed characteristic. In addition to implementing the load app context function as you mentioned, you also need to make sure to allocate space for the app context in device_manager_cnfg.h. I will report this internally, sorry for the inconvenience.

    Attached bug fixed linker script as the one provided in the SDK was missing the NOLOAD directive for the .noinit and .bootsettings sections: dfu_gcc_nrf51.ld This issue caused the linker to ("try") place init data in the bootsettings page and .noinit section in RAM.

Children
Related