Using the DFU Target Library

We use a custom board implementation based on nrf52840 that makes use of a proprietary host transport protocol.

I am trying to implement  FOTA using our transport. We can successfully download the app_update.bin file that is created when using NCS to create the boot images.

I would like to confirm that by using the DFU Target Library I can update the image slot and reboot to the new image.

Is there anything special I need in order to do this?

Second question:

The app_update.bin image is downloaded to external flash. Could you possibly provide me with suggestions as to the external flash configuration should I wish to specify the secondary slot for DFU. We are using QSPI with an MX25R6435FM2IL0 flash chip. The image is downloaded to an offset of 0x300000.

Thank you

  • Hi Francois, 
    I would suggest to take a look at some of our example, for example \nrf\subsys\net\lib\fota_download, \nrf\subsys\zigbee\lib\zigbee_fota\src to see how dfu_target is used. 

    But yes, this is correct:

    I would like to confirm that by using the DFU Target Library I can update the image slot and reboot to the new image.

    I did make an example on how to configure the board to receive image on external flash. Could you take a look at : https://devzone.nordicsemi.com/f/nordic-q-a/84025/changes-in-bootloader--saving-image-in-external-flash-and-transferring-in-internal-via-bootloader/352191#352191

  • Hi - I have started this implementation. I have included the DFU TARGET in prj.conf. It seems that there is more require as CONFIG_DFU_TARGET_MCUBOOT does ot get set to 1, so the whole thing fails.

    Can you tell me apart from CONFIG_DFU_TARGET=y, what else must be set for me to be able to use DFU Traget with my custom DFU implementation.

    See attached prj.conf and my code for DFU.At the time I start the process, the latest image has already been downloaded into the external flash.

    572725.prj.conf

    /********************************************************************
    FileName:     	mydfu.c
    Dependencies: 	See INCLUDES section
    ********************************************************************
    File Description:
    
    performs dfu update
    
    Change History:
    Rev   Date         Description
    1.0   Aug 2023    Initial release
    
    ********************************************************************/
    #include <zephyr/kernel.h>
    #include <zephyr/drivers/flash.h>
    #include <zephyr/device.h>
    #include <zephyr/devicetree.h>
    #include <stdio.h>
    #include <string.h>
    #include "besecure.h"
    #include "storage.h"
    #include "mydfu.h"
    #include "statled.h"
    #include "events.h"
    #include "watchdog.h"
    #include "dfu/dfu_target.h"
    #include <zephyr/logging/log.h>
    #include <dfu/dfu_target_mcuboot.h>
    
    #define LOG_MODULE_NAME MyDFU
    LOG_MODULE_REGISTER(LOG_MODULE_NAME);
    
    #define CONFIG_DFU_TARGET_MCUBOOT
    
    typedef enum
    {
      d_init,
      d_loop,
      d_err,
      d_done
    } dfuState;
    
    /** V A R I A B L E S */
    
    static enum dfu_target_image_type img_type;
    dfuState dstate;
    const struct device *flash_dv = DEVICE_DT_GET(DT_ALIAS(spi_flash0));
    int rcod;
    uint32_t dfuaddr;
    uint32_t fragsiz;
    int32_t dfutot;
    char dfubuff[2048];
    
    extern uint32_t FWTotal;         // total size of fw
    
    static void dfu_target_callback_handler(enum dfu_target_evt_id evt)
    {
    	switch (evt) {
    	case DFU_TARGET_EVT_TIMEOUT:
    		break;
    	case DFU_TARGET_EVT_ERASE_DONE:
    		break;
    	}
    }
    
    //
    //	Main entry point for the user interface state machine
    //
    void dfuMac(void)
    {
     	int err;
       
      switch (dstate)
      {
        case d_init:                  // we get here at startup
        {
          if (sysStat.rdSOFT == 1)
          {
            dfuaddr = 0x300000;
            // read in first block
            rcod = flash_read(flash_dv, dfuaddr, (char*)&dfubuff, (size_t)2048);
            dfuaddr = dfuaddr + 2048;
            if (rcod != 0)
            {
              dstate = d_err;
            }
            else
            {
              // get image type
              fragsiz = 2048;
              img_type = dfu_target_img_type((char*)&dfubuff,	fragsiz);
              // init
              err = dfu_target_init(img_type, 0, FWTotal, dfu_target_callback_handler);
              if (err == -EFBIG) {
                LOG_ERR("%s", "Image too big");
                dstate = d_err;
              } else if (err < 0) {
                LOG_ERR("dfu_target_init error %d", err);
                dstate = d_err;
              }
              dfutot = FWTotal;       // size we have to process
              fragsiz = 2048;         // first fragment is always 2K
              dstate = d_loop;
            }        
          }
          break;
        }
    
        case d_loop:        // process fragment
        {
          err = dfu_target_write(&dfubuff, fragsiz);
          if (err && err == -EINVAL) {
            LOG_INF("%s", "Image refused");
            dstate = d_err;
          } else if (err != 0) {
            LOG_ERR("dfu_target_write error %d", err);
            dstate = d_err;
          }
          // update our total
          dfutot = dfutot - fragsiz;
    
          // see if we are done
          if (dfutot == 0)
          {
            dstate = d_done;
          }
          else
          {
            if (dfutot <= 2048)
            {
              fragsiz = dfutot;
            }
    
            // read in next block
            rcod = flash_read(flash_dv, dfuaddr, (char*)&dfubuff, fragsiz);
            if (rcod != 0)
            {
              dstate = d_err;
            }
          }
          break;
        }
    
        case d_err:
        {
          err = dfu_target_reset();
          if (err != 0) {
            LOG_ERR("Unable to reset DFU target, err: %d", err);
          }      
          sysStat.rdSOFT = 0;
          break;
        }
    
       case d_done:
       {
    		err = dfu_target_done(true);
    		if (err == 0) {
    			err = dfu_target_schedule_update(0);
          sysStat.rdSOFT = 0;
    		}
        break;
       }
    
       
      }  // end switch
    } // end dfumac
    
    

  • Hi Francois, 
    Which issue do you have when you set CONFIG_DFU_TARGET_MCUBOOT=y ?

    I don't see that in your prj.conf. 

    Normally I would double check in the \build\zephyr\include\generated\autoconfig.h to see if the configuration is set to 1 or 0. VSCode may give wrong interpretation. 


    Could you try taking a look at the \modules\lib\memfault-firmware-sdk\examples\nrf-connect-sdk\nrf9160\memfault_demo_app sample ? 
    The sample uses fota_download library (which in turn uses dfu_target) to receive image. 

Related