nrf52840 S140 Central DFU Bluetooth Zephyr 2.0.0 nrf52840 peripheral

We have nrf52840 S140 BLE Central device that currently connects to TI based sensors. I have implemented code that can upgrade those TI sensors' firmware using the TI BLE protocol.

Now we are developing our own BLE peripheral sensors also based on the nrf52840 but now using the newly supported Zephyr 2.0.0. RF connect stuff. I can update the sensors using the Nordic Android program (unauthenticated for now) and now need to implement upgrading BLE DFU using our central device which connects to a cellular gateway.

I do not want to reinvent the wheel, writing existing code, like I had to do with the TI sensors.

Could you point me to code that allows a Central device to update a peripheral device BLE DFU?

If not where can I look to reinvent another wheel?

Thanks David

  • Yes, the upload & list commands now return without any reported problem. 

    If I understand you wanted to try the upload, list, confirm(fails) & again list sequence?

    11/02/2023 19:05:19[ami_com.c:  89] MsgReply:a Len:10
    [ami_smp.c: 692] DFU:316800/319026
    [ami_smp.c: 692] DFU:317200/319026
    [ami_smp.c: 692] DFU:317600/319026
    [ami_smp.c: 692] DFU:318000/319026
    [ami_smp.c: 692] DFU:318400/319026
    [ami_smp.c: 692] DFU:318800/319026
    [ami_smp.c: 793] ImageChecksum AF3A0C7A
    [ami_smp.c: 919] SMP UploadOK
    [ami_smp.c:1200] ImageList
    
    -----------PRIMARY IMAGE-----------
          slot: 0
          version: 0.0.0
          hash: 0x3e5866fbd4c56ae99a04f724b513c9e358f13a576d9e9a63b2e41b46f36d43
          bootable: true
          pending: false
          confirmed: true
          active: true
          permanent: false
    
    -----------SECONDARY IMAGE-----------
          slot: 1
          version: 0.0.0
          hash: 0x4165b6dabeb5dfab85e276b4e927b2e32358d38f1ef8d698617c5f449a095
          bootable: true
          pending: false
          confirmed: false
          active: false
          permanent: false
    [ami_smp.c:1203] ImageTest
    
    -----------PRIMARY IMAGE-----------
          slot: 0
          version: 0.0.0
          hash: 0x3e5866fbd4c56ae99a04f724b513c9e358f13a576d9e9a63b2e41b46f36d43
          bootable: true
          pending: false
          confirmed: true
          active: true
          permanent: false
    
    -----------SECONDARY IMAGE-----------
          slot: 1
          version: 0.0.0
          hash: 0x4165b6dabeb5dfab85e276b4e927b2e32358d38f1ef8d698617c5f449a095
          bootable: true
          pending: true
          confirmed: false
          active: false
          permanent: false
    [ami_smp.c:1209] ImageConfirm
    Decoding error, start_decode images->list  (err: 10)
    [ami_smp.c:1200] ImageList
    
    -----------PRIMARY IMAGE-----------
          slot: 0
          version: 0.0.0
          hash: 0x3e5866fbd4c56ae99a04f724b513c9e358f13a576d9e9a63b2e41b46f36d43
          bootable: true
          pending: false
          confirmed: true
          active: true
          permanent: false
    
    -----------SECONDARY IMAGE-----------
          slot: 1
          version: 0.0.0
          hash: 0x4165b6dabeb5dfab85e276b4e927b2e32358d38f1ef8d698617c5f449a095
          bootable: true
          pending: true
          confirmed: false
          active: false
          permanent: false
    11/02/2023 19:05:22[ami_ble.c: 861] Disconnected: D4:FD:9F:BF:4A:27 (random) (reason 22)
    [ami_ble.c:2639] DFUConnectFinishedErr:105
    11/02/2023 19:05:22[ami_ble.c:1545] ret:0 atomic_ev:32768 index:15
    11/02/2023 19:05:22[ami_ble.c:1545] ret:0 atomic_ev:1 index:0

    When I do a upload, list, test, reset sequence no problems are reported but the image is not updated after reset, but from my phone DFU works.

    [ami_smp.c: 690] DFU:318000/319026
    [ami_smp.c: 690] DFU:318400/319026
    [ami_smp.c: 690] DFU:318800/319026
    [ami_smp.c: 791] ImageChecksum AF3A0C7A
    [ami_smp.c: 917] SMP UploadOK
    [ami_smp.c:1198] ImageList
    
    -----------PRIMARY IMAGE-----------
          slot: 0
          version: 0.0.0
          hash: 0x8711f5297221c184e2f0a9a65d2ad3985be5bba9877fc829834c276a0986263
          bootable: true
          pending: false
          confirmed: true
          active: true
          permanent: false
    
    -----------SECONDARY IMAGE-----------
          slot: 1
          version: 0.0.0
          hash: 0x4165b6dabeb5dfab85e276b4e927b2e32358d38f1ef8d698617c5f449a095
          bootable: true
          pending: false
          confirmed: false
          active: false
          permanent: false
    [ami_smp.c:1201] ImageTest
    
    -----------PRIMARY IMAGE-----------
          slot: 0
          version: 0.0.0
          hash: 0x8711f5297221c184e2f0a9a65d2ad3985be5bba9877fc829834c276a0986263
          bootable: true
          pending: false
          confirmed: true
          active: true
          permanent: false
    
    -----------SECONDARY IMAGE-----------
          slot: 1
          version: 0.0.0
          hash: 0x4165b6dabeb5dfab85e276b4e927b2e32358d38f1ef8d698617c5f449a095
          bootable: true
          pending: true
          confirmed: false
          active: false
          permanent: false
    [ami_smp.c:1204] ImageReset
    11/02/2023 21:03:24[ami_ble.c: 861] Disconnected: D4:FD:9F:BF:4A:27 (random) (reason 8)
    [ami_ble.c:2639] DFUConnectFinishedErr:0
    11/02/2023 21:03:24[ami_ble.c:1545] ret:0 atomic_ev:32768 index:15
    11/02/2023 21:03:24[ami_ble.c:1545] ret:0 atomic_ev:1 index:0

    Like I wrote I calculated a checksum on the data buffers sent with the bt_dfu_smp_command() function and verified it was correct.

    I also used the "nrfjprog --family nRF52 --readcode code.hex" command so I could try to compare part of the code with the app_update.bin or merged.hex.

    I see in my sensor bootloader map that it does not have the littlefs mapped.

    Should this matter since if the phone app works ours should too?

    Central's map:
    #define PM_APP_DEV_NAME "NRF_FLASH_DRV_NAME"
    #define PM_MCUBOOT_PRIMARY_APP_OFFSET 0xc200
    #define PM_MCUBOOT_PRIMARY_APP_ADDRESS 0xc200
    #define PM_MCUBOOT_PRIMARY_APP_END_ADDRESS 0x80000
    #define PM_MCUBOOT_PRIMARY_APP_SIZE 0x73e00
    #define PM_MCUBOOT_PRIMARY_APP_NAME mcuboot_primary_app
    #define PM_MCUBOOT_PRIMARY_APP_ID 4
    #define PM_mcuboot_primary_app_ID PM_MCUBOOT_PRIMARY_APP_ID
    #define PM_mcuboot_primary_app_IS_ENABLED 1
    #define PM_4_LABEL MCUBOOT_PRIMARY_APP
    #define PM_MCUBOOT_PRIMARY_APP_DEV_NAME "NRF_FLASH_DRV_NAME"
    #define PM_MCUBOOT_SECONDARY_OFFSET 0x80000
    #define PM_MCUBOOT_SECONDARY_ADDRESS 0x80000
    #define PM_MCUBOOT_SECONDARY_END_ADDRESS 0xf4000
    #define PM_MCUBOOT_SECONDARY_SIZE 0x74000
    #define PM_MCUBOOT_SECONDARY_NAME mcuboot_secondary
    #define PM_MCUBOOT_SECONDARY_ID 5
    #define PM_mcuboot_secondary_ID PM_MCUBOOT_SECONDARY_ID
    #define PM_mcuboot_secondary_IS_ENABLED 1
    #define PM_5_LABEL MCUBOOT_SECONDARY
    #define PM_MCUBOOT_SECONDARY_DEV_NAME "NRF_FLASH_DRV_NAME"
    #define PM_LITTLEFS_STORAGE_OFFSET 0xf4000
    #define PM_LITTLEFS_STORAGE_ADDRESS 0xf4000
    #define PM_LITTLEFS_STORAGE_END_ADDRESS 0xfa000
    #define PM_LITTLEFS_STORAGE_SIZE 0x6000
    #define PM_LITTLEFS_STORAGE_NAME littlefs_storage
    #define PM_LITTLEFS_STORAGE_ID 6
    #define PM_littlefs_storage_ID PM_LITTLEFS_STORAGE_ID
    #define PM_littlefs_storage_IS_ENABLED 1
    
    Sensor's map:
    #define PM_MCUBOOT_PRIMARY_APP_OFFSET 0xc200
    #define PM_MCUBOOT_PRIMARY_APP_ADDRESS 0xc200
    #define PM_MCUBOOT_PRIMARY_APP_END_ADDRESS 0x80000
    #define PM_MCUBOOT_PRIMARY_APP_SIZE 0x73e00
    #define PM_MCUBOOT_PRIMARY_APP_NAME mcuboot_primary_app
    #define PM_MCUBOOT_PRIMARY_APP_ID 4
    #define PM_mcuboot_primary_app_ID PM_MCUBOOT_PRIMARY_APP_ID
    #define PM_mcuboot_primary_app_IS_ENABLED 1
    #define PM_4_LABEL MCUBOOT_PRIMARY_APP
    #define PM_MCUBOOT_PRIMARY_APP_DEV flash_controller
    #define PM_MCUBOOT_PRIMARY_APP_DEFAULT_DRIVER_KCONFIG CONFIG_SOC_FLASH_NRF
    #define PM_MCUBOOT_SECONDARY_OFFSET 0x80000
    #define PM_MCUBOOT_SECONDARY_ADDRESS 0x80000
    #define PM_MCUBOOT_SECONDARY_END_ADDRESS 0xf4000
    #define PM_MCUBOOT_SECONDARY_SIZE 0x74000
    #define PM_MCUBOOT_SECONDARY_NAME mcuboot_secondary
    #define PM_MCUBOOT_SECONDARY_ID 5
    #define PM_mcuboot_secondary_ID PM_MCUBOOT_SECONDARY_ID
    #define PM_mcuboot_secondary_IS_ENABLED 1
    
    

    By the way do you know if there were any changes to power management from v2.0.2 to v2.2.0?

    It seems that v2.2.0 consumes more current for some reason.

    Thanks David

  • DavidKaplan said:
    If I understand you wanted to try the upload, list, confirm(fails) & again list sequence?

    Yes.

    DavidKaplan said:
    Like I wrote I calculated a checksum on the data buffers sent with the bt_dfu_smp_command() function and verified it was correct.

    Thanks, it is nice to know this, for reference.

    DavidKaplan said:
    When I do a upload, list, test, reset sequence no problems are reported but the image is not updated after reset

    When doing "list", we can see that "pending: true". If an image is set as "pending", MCUboot should swap the image into the primary slot on reboot.
    It is odd that MCUboot does not do so.

    As I do not have your devices, I can not replicate this exactly.
    However, it worked on nRF52840DKs for me.
    Do you have 2x nRF52840DKs by chance? (Or other nordic developement kits?)
    I am thinking that if you can try on the DKs VS you custom board, we can find if it is the hardware or the software which is the issue here.

    DavidKaplan said:
    Like I wrote I calculated a checksum on the data buffers sent with the bt_dfu_smp_command() function and verified it was correct.

    This reinforces my "this should work, why does it not?" thoughts.

    DavidKaplan said:

    I also used the "nrfjprog --family nRF52 --readcode code.hex" command so I could try to compare part of the code with the app_update.bin or merged.hex.

    I see in my sensor bootloader map that it does not have the littlefs mapped.

    Should this matter since if the phone app works ours should too?

    Good thinking!

    It is likely not app_update.bin itself, as the phone app works.

    But maybe it is a difference to which address the application is uploaded to?
    In that case, the "test" tag could maybe be in the wrong place for MCUboot to find it?

    Can you try to see if there is any difference to the code if you upload it using a mobile and the SMP Client?
    To get the image into secondary slot using mobile, upload it and "test only". Then restart twice to make it swap back into the secondary slot.

    After reading out the code, can you try to list the mobile-uploaded image using the SMP Client?
    Then also try to "confirm" the mobile-uploaded image using the SMP client?
    That way we can learn if it is the "upload" or "test" that fails.

    DavidKaplan said:

    By the way do you know if there were any changes to power management from v2.0.2 to v2.2.0?

    It seems that v2.2.0 consumes more current for

    I might ask you to open a new ticket on this.
    But I want to give it a try first.
    Do you have numbers on the current draw before and after?

    Regards,
    Sigurd Hellesvik

  • I have a nRF9160-DK which has a nRF52480 chip on it and according to the documentation, one of its uarts is always routed to the board's virtual com port. I wanted to use it as my Central device while writing a PC program that would simulate our host for streaming the image. I could see the messages coming from the DK on my PC but nothing I sent arrived at the Central. I selected the nrf9160dk_nrf52840 Nordic board for this build. I guess something is wrong with my hardware, so I could not write and debug the host simulator.

     I also have a nRF52840-DK which it nRF USB does not work (no recognition now on PC but previously had worked) so I could not also use it for the Central.

     I can send you the sensor (peripheral) code in a private session in which I remarked the hardware stuff.

    As for the current drain when compiled with V2.2.0 I will have to recheck the comparison, since I remember that management wanted to up the default tx power.

    Currently I manipulate only the I2C & SPI interfaces. Our LC512 EEPROM is I2C and the LSM6DSL sensor is connected by SPI. I also use the ADC which is used only every 5 to 15 minutes which taking a vibration sample. I use the code below pm_device_action_run() & pm_device_busy_set() & pm_device_busy_clear()

    //-----------------------------------------------------------------------------
    // ami_boardPMActivate
    //  Description
    //    Changes the  I2C's or SPI's PM activate state 
    //  Parameters
    //   which
    //   bActivate  -
    //  Returns
    //    true if OK
    //-----------------------------------------------------------------------------
    bool ami_boardPMActivate(unsigned char which,bool bActivate)
    {
    #ifdef CONFIG_PM_DEVICE
      int err = 1;
      enum pm_device_action action = bActivate?PM_DEVICE_ACTION_TURN_ON:PM_DEVICE_ACTION_TURN_OFF;
      switch (which){
        case AMI_BOARD_DEV_SPI1:
          err = pm_device_action_run((const struct device*)spi_dev,action);
          if (err!=-EALREADY && err!=-ENOTSUP){
              d_printf(LINE_INFO,kDbg_Error|kDbg_Display,"SPI state Err:%d",err);
          }
          break;
        case AMI_BOARD_DEV_I2C0:
          err = pm_device_action_run((const struct device*)i2c_dev,action);
          if (err!=-EALREADY && err!=-ENOTSUP){
              d_printf(LINE_INFO,kDbg_Error|kDbg_Display,"I2C state Err:%d",err);
          }
          break;
      } // switch
      return (err==0 || (err==-EALREADY));
    #endif       
    } // ami_boardPMActivate
    
    //-----------------------------------------------------------------------------
    // ami_boardChangeBusyState
    //  Description
    //    Changes the  I2C's or SPI's PM Busy state 
    //  Parameters
    //   which
    //   bSetBusy  -
    //  Returns
    //-----------------------------------------------------------------------------
    void ami_boardChangeBusyState(unsigned char which,bool bSetBusy)
    {
    #ifdef CONFIG_PM_DEVICE
      switch (which){
        case AMI_BOARD_DEV_SPI1:
          //-------------------------------------------------------------------
          // Mark a device as busy.
          // Devices marked as busy will not be suspended when the system goes into low-power states. 
          // This can be useful if, for example, the device is in the middle of a transaction.
          //-------------------------------------------------------------------
          if (bSetBusy){
            pm_device_busy_set(spi_dev);
          }else{
                pm_device_busy_clear(spi_dev);
          }
          break;
        case AMI_BOARD_DEV_I2C0:
          //-------------------------------------------------------------------
          // Mark a device as busy.
          // Devices marked as busy will not be suspended when the system goes into low-power states. 
          // This can be useful if, for example, the device is in the middle of a transaction.
          //-------------------------------------------------------------------
          if (bSetBusy){
            pm_device_busy_set(i2c_dev);
          }else{
                pm_device_busy_clear(i2c_dev);
          }
          break;
        case AMI_BOARD_DEV_GPIO0:
          if (bSetBusy){
            pm_device_busy_set(gpio_0_dev);
          }else{
                pm_device_busy_clear(gpio_0_dev);
          }
          break;
        case AMI_BOARD_DEV_GPIO1:
          if (bSetBusy){
            pm_device_busy_set(gpio_1_dev);
          }else{
                pm_device_busy_clear(gpio_1_dev);
          }
          break;
      } // switch
       
    #endif
    } // ami_boardChangeBusyState
    

    After not really getting anywhere yesterday on the BLE DFU issue, this morning I had some interesting findings. It seems that the DFU upload reports OK but the code is NOT written anywhere, assuming that readcode reads the whole internal code flash.

    1) Tool Chain V2.2.0 Update SDK
    2) Erase board with programmer
    3) Flash LastUpdate ={"14-Feb-2023 v1.0.0"}; merged file with programmer EraseAll Erase&Write
    4) nrfjprog --family nRF52 --readcode code1.hex
    5) DFU with gateway
    	00> [ami_smp.c: 690] DFU:316800/319026
    	00> [ami_smp.c: 690] DFU:317200/319026
    	00> [ami_smp.c: 690] DFU:317600/319026
    	00> [ami_smp.c: 690] DFU:318000/319026
    	00> [ami_smp.c: 690] DFU:318400/319026
    	00> [ami_smp.c: 690] DFU:318800/319026
    	00> [ami_smp.c: 791] ImageChecksum AF3A0C7A
    	00> [ami_smp.c: 917] SMP UploadOK
    	00> [ami_smp.c:1198] ImageList
    	00>
    	00> -----------PRIMARY IMAGE-----------
    	00>       slot: 0
    	00>       version: 0.0.0
    	00>       hash: 0xb34a6ec0abb87ccee95d838d9dbe4e5c33fae249c4ce955adc9a5297a8655d
    	00>       bootable: true
    	00>       pending: false
    	00>       confirmed: true
    	00>       active: true
    	00>       permanent: false
    	00>
    	00> -----------SECONDARY IMAGE-----------
    	00>       slot: 1
    	00>       version: 0.0.0
    	00>       hash: 0x4165b6dabeb5dfab85e276b4e927b2e32358d38f1ef8d698617c5f449a095
    	00>       bootable: true
    	00>       pending: false
    	00>       confirmed: false
    	00>       active: false
    	00>       permanent: false
    	00> [ami_smp.c:1201] ImageTest
    	00>
    	00> -----------PRIMARY IMAGE-----------
    	00>       slot: 0
    	00>       version: 0.0.0
    	00>       hash: 0xb34a6ec0abb87ccee95d838d9dbe4e5c33fae249c4ce955adc9a5297a8655d
    	00>       bootable: true
    	00>       pending: false
    	00>       confirmed: true
    	00>       active: true
    	00>       permanent: false
    	00>
    	00> -----------SECONDARY IMAGE-----------
    	00>       slot: 1
    	00>       version: 0.0.0
    	00>       hash: 0x4165b6dabeb5dfab85e276b4e927b2e32358d38f1ef8d698617c5f449a095
    	00>       bootable: true
    	00>       pending: true
    	00>       confirmed: false
    	00>       active: false
    	00>       permanent: false
    	00> [ami_smp.c:1204] ImageReset
    	00> 14/02/2023 19:17:31[ami_ble.c: 861] Disconnected: D4:FD:9F:BF:4A:27 (random) (reason 8)
    	00> [ami_ble.c:2639] DFUConnectFinishedErr:0
    6) nrfjprog --family nRF52 --readcode code2.hex
     code1.hex & code2.hex are exactly the same.
     This means that the SMP upload reported OK but did not write anything.
    5) Phone Test only (which works)
     In the sensor code after reset, I confirm the image, so test is like confirm, if the code runs.
      //---------------------------------------------------------------------------
      // DFU upgraded and not confirmed, confirm
      //---------------------------------------------------------------------------
      if (!boot_is_img_confirmed()){
        err = boot_write_img_confirmed();
    	  if (err) {
    		  d_printf(LINE_INFO,kDbg_Error|kDbg_Display,"BootConfirmErr:%d",err);
        }else{
              d_printf(LINE_INFO,kDbg_Error|kDbg_Display,"BootConfirmed");
        }
      }
    4) nrfjprog --family nRF52 --readcode code3.hex
      code3.hex is entirely different from code1.hex and code2.hex which were the same.
    
    

    Thanks

    David

  • This morning I programmed my nRF9160-DK with our sensor code with the hardware specific code commented out. I performed a nRF52840 BLE DFU by SMP which reported that all went well but the unit was not updated. I suggest, if possible, I send the sensor code which runs on the nRF9160-DK and you build two images with different Device Information, one which you flash by the programmer and the other that you program to your Central's flash as you did in the Generic SMP BLE DFU test you performed.

    This way we could pinpoint if the problem is in my Central or Sensor code.

    Using the nRF Connect phone app you can verify the DFU and see in my code if the problem exists in my peripheral sensor code or not. 

    My code uses ncs V2.2.0 with a local ms88sf2 board definition which should run on any nRF52840 board.

    I can only upload my code in a private session.

    Thanks David

    static int settings_runtime_load(void)
    {
      char sTemp[32];	
      eight_bytes unique_64;
      
    #if defined(CONFIG_BT_DIS_SETTINGS)
    #ifdef TBD
    	settings_runtime_set("bt/dis/model",
    			     "Zephyr Model",
    			     sizeof("Zephyr Model"));
    	settings_runtime_set("bt/dis/manuf",
    			     "Zephyr Manufacturer",
    			     sizeof("Zephyr Manufacturer"));
    #endif				 
    #if defined(CONFIG_BT_DIS_SERIAL_NUMBER)
        //-------------------------------------------------------------------------
        // Use nRF52840's DeviceID as serial number
        //-------------------------------------------------------------------------
        unique_64.u32[0] = NRF_FICR->DEVICEID[0];
        unique_64.u32[1] = NRF_FICR->DEVICEID[1];
        sprintf(sTemp,"%08X%08X",unique_64.u32[1],unique_64.u32[0]);
    	settings_runtime_set("bt/dis/serial",
    			     sTemp,
    			     strlen(sTemp));
    #endif
    #if defined(CONFIG_BT_DIS_SW_REV)
        //-------------------------------------------------------------------------
    	// Set the software version
        //-------------------------------------------------------------------------
        sprintf(sTemp,"%u.%u %u.%u",
                AMI_VERSION_MAJOR,AMI_VERSION_MINOR,
                AQUA_DEVEL_VERSION_MAJOR,AQUA_DEVEL_VERSION_MINOR);
    	settings_runtime_set("bt/dis/sw",
    			     sTemp,
    			     strlen(sTemp));
    #endif
    #if defined(CONFIG_BT_DIS_FW_REV)
        //-------------------------------------------------------------------------
    	// Set Date as the Firmware version
        //-------------------------------------------------------------------------
        sprintf(sTemp,"%s",__DATE__);
    	settings_runtime_set("bt/dis/fw",
    			     sTemp,
    			     strlen(sTemp));
    #endif
    #if defined(CONFIG_BT_DIS_HW_REV)
    	settings_runtime_set("bt/dis/hw",
    			     CONFIG_BT_DIS_HW_REV_STR,
    			     sizeof(CONFIG_BT_DIS_HW_REV_STR));
    #endif
    #endif
    	return 0;
    } // settings_runtime_load
    
    

  • Hi David,

    That sounds good to me!

    Please create a new private ticket to upload your project and tag me with in the new ticket.

    Regards,
    Sigurd Hellesvik

Related