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

nRF5 DFU over serial

We are implementing a DFU controller to perform DFU over serial for the nRF52832.

Our reference is the nRF5 SDK v15.3.0 DFU Serial documentation (Nordic/SDK/nRF_SDK_15.3.0_docs/nrf5/lib_dfu_transport_serial.html).

The documentation has a message sequence chart that describes Transfer of an Init Packet, and Transfer of a firmware Image.

I'm find the description regarding transfer of a firmware image a bit ambiguous. It says the firmware image is split up into several data objects that are transferred consecutively.  For example if the image is 10k and the maximum object size is 4k, then 3 data objects must be transferred.   Presumably two 4k objects followed by a 2k object.

1) Is the Select command required at the start of each data object, or just once when the firmware image transfer is started?

2) Is the execute command sent at the end of each data object, or just once at the end of the entire firmware image transfer?

2) Once all the data has been transferred (3 data objects in the example) is it necessary to do one more Select command immediately followed by an execute command?

3) At what point does the boot-loader know the entire image has been downloaded and start the application.  Does it attempt to do this on every execute command?

In our case we have found the Select response returns a maximum object size of 4096 bytes.  Our firmware image is not a multiple of 4096 bytes, so I my difficulty is understanding what happens when the last data object, which is less than the maximum object size,  is transferred.

  • Furthermore after some trial and error, I found I couldn't send a CREATE data object command with a size less than the max_size returned by the SELECT data object command.

    For example SELECT data object returns max_size 0x1000 (4096)

    If the firmware image size is 0x3200, this requires 3 data objects of 0x1000 and 1 data object of 0x200

    When command CREATE data object of size 0x1000,  [01 02 00 10 00 00] is sent the response is [01] success. After that the data object is sent Ok and the EXECUTE command also returns success.

    When sending the last 512 bytes the command CREATE data object of size 0x0200, [01 02 00 02 00 00] , returns status code [03] NRF_DFU_RES_CODE_INVALID_PARAMETER..  Then it doesn't accept any write commands.

    It seems the only size that is valid for the Create Data Object command is the max_size returned by the Select data object request.

    How do we send the last data block of 512 bytes in this example?

  • Hi Phil, 

    I actually made an example of DFU controller running on nRF52 that you can have a look: https://devzone.nordicsemi.com/nordic/short-range-guides/b/software-development-kit/posts/getting-started-with-nordics-secure-dfu-bootloader#h108sjziaxo3m81rkgr1has5r1d72qtu

    I would suggest to test the example and review the code. If you still have any question, please let me know. 

  • Thanks Hung.  We do all the steps in your guide.

    I had a look at your DFUMaster_UART code.  The DFU message sequence diagram in SDK15.3.0 says to send a SELECT command [06 01] to select the Init object before the transfer of the Init packet.   Then also send a SELECT command [06 02] to select a data object before transferring the firmware image.

    I can't see where you send any SELECT command in your code.  Does that mean it is not strictly necessary?

    Also I notice you send the EXECUTE command at the end of each data object during the firmware image transfer.  That answers one of my questions.

  • I've narrowed my problem down to a specific issue.  I cannot send a Create data object command with size other than 0x1000 (4096).  This size is the max_size returned by the SELECT data object request.

    Create data object: size = 512:    [01 02 00 02 00 00].  Response [60 01 03]: status = missing or invalid parameter

    Create data object: size = 4096:  [01 02 00 10 00 00].  Response [60 01 01]:  status = success

    I notice in your example code that you send a Create data object command at the start of each data object transfer.  Each one, except the last, has size=4096. The size of the last one is the length of the remaining bytes of the firmware image.  This is exactly what we intend to do.  I also notice you are never checking the response to the Create data object command (or any commands).  Does this actually work?

    Does the number of bytes transferred for each data object have to equal the size in the Create data object command?  Could we just always create a data object of max_size and just send fewer bytes where necessary before sending the EXECUTE command?

  • Hi Phil, 

    The firmware I made was quite a long time ago so I don't remember all the detail. 

    But the way it works in our bootloader is that you only set the data object size once, for all packets. And the last packet is the only exception. You don't need to set the data object size for the last packet. The bootloader detect that automatically because the size of the image is sent at the beginning already. 

    If you have a look at the on_data_obj_create_request() function in nrf_dfu_req_handler.c you can find an error log "NRF_LOG_ERROR("Object size must be page aligned");" Data object size need to be page aligned, so either 4096 or 8192 and so on. 

Related