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

DFU and Serial communication over USB

I am trying to enable DFU over USB with the nRF52480, while keeping the possibility for Serial communication. I got a working example with both separate, however when I try to combine the examples I get a lot problems.

As of my understanding I have to use the nrf_dfu_trigger_usb.h library, however I can't seem to figure out how. The documentation says to call "nrf_dfu_trigger_usb_init()" after USB is initialized but before it is enabled. Do you have an example of how to do this, i.e. how to use DFU over USB while still using the USB for something else (Serial communication)?

I guess my main problem is that the DFU library initialises the variable "m_app_cdc_acm" and thus I cannot use do that myself for the Serial communication. Should I access this variable through something like: "extern const app_usbd_cdc_acm_t m_app_cdc_acm", or am I missing some basic understanding of how this works Slight smile

Also when compiling I get a lot of undefined reference to f.x. `slip_decode_add_byte' and `crc32_compute'. I have added the files containing these functions to my makefile, but I am wondering if the order of the includes makes a difference? 

Thanks Smiley

  • MrSolidGeek,

    As of my understanding I have to use the nrf_dfu_trigger_usb.h library, however I can't seem to figure out how. The documentation says to call "nrf_dfu_trigger_usb_init()" after USB is initialized but before it is enabled. Do you have an example of how to do this, i.e. how to use DFU over USB while still using the USB for something else (Serial communication)?

    Unfortunately, we have not tried the combo to work together ourselves. So I am not sure what are the efforts and challenges involved to integrate them. Sorry that this answer is not much of any help. Lets wait out to see if any other forum members experimented with it. 

  • Thanks for your answer Susheel!

    EDIT:

    I now understand how the bootloader works, and must admit I had it all wrong, and learned a lot from: https://devzone.nordicsemi.com/nordic/short-range-guides/b/software-development-kit/posts/getting-started-with-nordics-secure-dfu-bootloader

    I have now build the "open bootloader" and flashed that AND my application containing my project. The bootloader works, and I can enter the bootloader by pressing the RESET button. I can also succesfully flash new firmware using the nRF Connect app. SO far so good! 

    Next, I have been trying to get the USB DFU Trigger to work, however with no success. I have added to my sdk_config:

    // <q> APP_USBD_NRF_DFU_TRIGGER_ENABLED
    #ifndef APP_USBD_NRF_DFU_TRIGGER_ENABLED
    #define APP_USBD_NRF_DFU_TRIGGER_ENABLED 1
    #endif
    
    // <q> NRF_USB_DFU_TRIGGER_USB_SHARED  - Flag indicating whether USB is used for other purposes in the application.
    #ifndef NRF_DFU_TRIGGER_USB_USB_SHARED
    #define NRF_DFU_TRIGGER_USB_USB_SHARED 1
    #endif
    
    // <o> NRF_USB_DFU_TRIGGER_INTERFACE_NUM - The USB interface to use for the DFU Trigger library.  <0-255>
    
    // <i> According to the USB Specification, interface numbers cannot have
    // <i> gaps. Tailor this value to adhere to this limitation.
    #ifndef NRF_DFU_TRIGGER_USB_INTERFACE_NUM
    #define NRF_DFU_TRIGGER_USB_INTERFACE_NUM 1
    #endif

    And my USB init function looks like (called in beginning of main):

    void usb_init()
    {
        ret_code_t ret;
        static const app_usbd_config_t usbd_config = {
            .ev_state_proc = usbd_user_ev_handler
        };
    
        ret = nrf_drv_clock_init();
        APP_ERROR_CHECK(ret);
        
        nrf_drv_clock_lfclk_request(NULL);
    
        // Wait for the LFCLK
        while(!nrf_drv_clock_lfclk_is_running()){}
    
        // Initiate the USB 
        app_usbd_serial_num_generate();
    
        ret = app_usbd_init(&usbd_config);
        APP_ERROR_CHECK(ret);
    
        app_usbd_class_inst_t const * class_cdc_acm = app_usbd_cdc_acm_class_inst_get(&m_app_cdc_acm);
        ret = app_usbd_class_append(class_cdc_acm);
        APP_ERROR_CHECK(ret);
    
        nrf_dfu_trigger_usb_init();
    
        ret = app_usbd_power_events_enable();
        APP_ERROR_CHECK(ret);
    }

    I have inserted the nrf_dfu_trigger_usb_init() before I enable the USB bus, however I see that nrf_dfu_trigger_usb_init does most of this by it self. How should I approach this?

    If anyone has an example of how to use the USB DFU Trigger library, I would be very glad Smiley

  • Finally, I got it working! The "nRF Connect DFU Trigger" now shows in the device manager, and the nRF Connect tool recognizes and triggers the DFU correctly. 

    For anyone in the future who might need to do the same I will try to document my findings as good as possible. This issue on Github gave me a lot of clues: https://github.com/NordicSemiconductor/pc-nrfconnect-programmer/issues/116

    I used the example USBD_CDC_ACM ("\examples\peripheral\usbd_cdc_acm") as a starting point, as this has most of the configuration already. I added/changed a few things to the sdk_config:

    // <s> APP_USBD_PID - Product ID.
    #ifndef APP_USBD_PID
    #define APP_USBD_PID 0xC00A
    #endif
    
    // <q> APP_USBD_CONFIG_SELF_POWERED  - Self-powered device, as opposed to bus-powered.
    #ifndef APP_USBD_CONFIG_SELF_POWERED
    #define APP_USBD_CONFIG_SELF_POWERED 0
    #endif
    
    // <q> APP_USBD_NRF_DFU_TRIGGER_ENABLED
    #ifndef APP_USBD_NRF_DFU_TRIGGER_ENABLED
    #define APP_USBD_NRF_DFU_TRIGGER_ENABLED 1
    #endif
    
    // <q> NRF_USB_DFU_TRIGGER_USB_SHARED  - Flag indicating whether USB is used for other purposes in the application.
    #ifndef NRF_DFU_TRIGGER_USB_USB_SHARED
    #define NRF_DFU_TRIGGER_USB_USB_SHARED 1
    #endif
    
    // <o> NRF_USB_DFU_TRIGGER_INTERFACE_NUM - The USB interface to use for the DFU Trigger library.  <0-255>
    #ifndef NRF_DFU_TRIGGER_USB_INTERFACE_NUM
    #define NRF_DFU_TRIGGER_USB_INTERFACE_NUM 0
    #endif

    And changed the interface numbers for the actual USB:

    // As DFU Trigger uses interface 0, CDC must use 1 and 2
    #define CDC_ACM_COMM_INTERFACE  1
    #define CDC_ACM_DATA_INTERFACE  2

    I added the function usb_init which is called just at the beginning of main:

    void usb_init()
    {
        ret_code_t ret;
        static const app_usbd_config_t usbd_config = {
            .ev_state_proc = usbd_user_ev_handler
        };
    
        ret = nrf_drv_clock_init();
        APP_ERROR_CHECK(ret);
        
        nrf_drv_clock_lfclk_request(NULL);
    
        while(!nrf_drv_clock_lfclk_is_running()){}
    
        ret = app_timer_init();
        APP_ERROR_CHECK(ret);
    
        app_usbd_serial_num_generate();
    
        ret = app_usbd_init(&usbd_config);
        APP_ERROR_CHECK(ret);
    
        // Enable DFU Trigger library over USB (should happen right after usbd_init)
        nrf_dfu_trigger_usb_init();
    
        // USBD CDC ACM example started
        app_usbd_class_inst_t const * class_cdc_acm = app_usbd_cdc_acm_class_inst_get(&m_app_cdc_acm);
        ret = app_usbd_class_append(class_cdc_acm);
        APP_ERROR_CHECK(ret);
    
        if (USBD_POWER_DETECTION)
        {
            ret = app_usbd_power_events_enable();
            APP_ERROR_CHECK(ret);
        }
        else
        {
            // No USB power detection enabled. Starting USB now
            app_usbd_enable();
            app_usbd_start();
        }
    }

    And of course, imported the needed libraries:

    INC_FOLDERS += \
      $(SDK_ROOT)/components/libraries/bootloader/dfu \
      $(SDK_ROOT)/components/libraries/usbd/class/nrf_dfu_trigger \
      $(SDK_ROOT)/components/libraries/block_dev \
    
    SRC_FILES += \
      $(SDK_ROOT)/components/libraries/usbd/class/nrf_dfu_trigger/app_usbd_nrf_dfu_trigger.c \
      $(SDK_ROOT)/components/libraries/bootloader/dfu/nrf_dfu_trigger_usb.c \

    I guess it was quite easy after all, it was just hard to find the documentation needed to do so. An example added to the SDK would be a good way to go in the future :D 

Related