Custom board USB DFU (buttonless)

Trying to add the capability of USB DFU (buttonless, because I forgot to have a button for it) to my custom board (nrf52840, MS88SF31 module). Reading about this process from different places gives different answers and I can't quite wrap my head around it. I have made a custom board and managed to program a LED to blink. For programming I used openocd and ST-link 2. 

If anyone can lead me in the right direction, help would be appreciated. I have read the academy course on it, and some documentation as well but a lot of the terminology is lost on me.

Biggest questions I have with it are:
1. Where do I get the MCUBoot? I have managed to build one through visual studio code with my application, but it didn't seem to work, I don't really know how to test it other than connect the board through USB and look at NRF Connect for Desktop, Programmer. I have also seen a lot of mentions of pca10040 pca10100 etc., but I don't understand what am I suppose to do with the stuff in those folders. All the file types are completly different from the ones that I have seen before.

2. If I manage to get the USB DFU to work, can I program my board through NRF Connect for Desktop, Programmer or do I need something else? 

3. How much, if at all, do I need to change the bootloader? As I understand, I need to add a few lines to make the DFU USB work, but is there something else I need to do aswell? I have read about mcumgr, which I don't really understand the purpose of I this context.

Thanks in advance!

  • Yeah, I remember starting with DFU and MCUboot and having a rough time haha. These aren't complete answers but I think it will get you moving in the right direction. Everything I talk about below can be seen in the SMP Server example built into Zephyr. So you should just be able to build that, flash it with the programmer once, then test DFU.

    1. MCUboot is included in Zephyr, you "get" it by using Kconfig options to include it in your build and make any configuration changes to the bootloader. Testing MCUboot will not involve NRF connect or the programmer; it will only involve a client (like mcumgr) that uses USB in your case. The programmer lets you write anywhere in memory while MCUboot and the DFU process is essentially for making sure you only affect your application binary and not the bootloader binary. Another easy way to test (if you have bluetooth) is to add some extra kconfig to hook mcuboot up to bluetooth and use the NRF Device Manager phone app.

    2. If you want to test DFU and only update your application code it would not involve NRF Connect or the programmer. There are many clients that can talk to mcuboot. One you mentioned is mcumgr command line tool. I've used that to test DFU over USB and it worked fine. MCUboot is expecting something to talk to it with the SMP protocol. mcumgr (and many other programs) already speak SMP protocol so you don't need to learn how to speak it. Another example is the python package SMPClient which can use USB; using this is more involved though and I would recommend mcumgr for quick testing).

    3. You (usually) don't need to "change" the bootloader at all. Virtually any change you need to make can be done with Kconfig statements. In the SMP server example, all you have to do is enable your USB port in your application code and it should work. All the bootloader does is check if there's a pending firmware update, handle it if so, and then point to the first memory address of your application code. Your application code just needs to know to enable the usb port.

    In short, check out the SMP server example and maybe try this video out. Hopefully this helps!

  • Hello (to both of you);

    nordicator_prim3 answers to your questions are correct, but I would also like to inform you of the courses we have on our academy pages at https://academy.nordicsemi.com/ which sole purpose is to bring the learning curve down to a less steep level when it comes to getting started with nRF Connect SDK and Zephyr.

    For both new and intermediate developers I strongly recommend this path when you're getting started (or if you need to repeat something)

    1. Decide which SDK version you're working with. For instance if you're not going to use sysbuild, you will have to stick with NCS v2.6.x. If it doesn't really matter, start with the latest tagged release (currently NCS v3.0.2)
    2. Fundamentals NCS lesson 1, 2, 3, 4 and 5
    3. Intermediate NCS lesson 1, 2, 3, 8, and 9 and then maybe 7
    4. Any other lesson that contains peripherals that you will be using presented within these courses
    5. BLE fundamentals if you intend to have something BLE related on your application or the cellular and/or Wifi fundamentals course(s)

    I will say that at least steps 1-3 are "mandatory" to go through, but solely based on your description I strongly recommend you to at least have a look at lesson 8 and 9 in the intermediate course, which contains theory, links and samples relevant to MCUboot and DFU specifically. All the lessons should link to our official documentation at https://docs.nordicsemi.com/ 

    Kind regards,
    Andreas

  • Thanks for your answer, it has cleared some things up. 

    I have been trying to get SMP server example running, but I haven't had much success. I can build it and upload it to my board, but as I understand it, I should be able to now see the board in device manager. My best guess is that I haven't properly setup my USB in my board files or somewhere else. Don't really know where to look because I am not getting any errors.

  • I have gotten the stuff I need working on an NRF52480 dongle (i2c devices, ble etc.) and I now want to use this stuff on my custom board. 

    I got myself a nrf52dk so I could actually get some info back from the board. I am working with ncs 3.0.2.


    As far as I can see, the SMP server example runs on my board without errors, but I can't seem to get the USB to show up anywhere. My best guesses are I am missing something in prj.conf or something is wrong in the devicetree, but not sure what is wrong.

    # Enable MCUmgr and dependencies.
    CONFIG_NET_BUF=y
    CONFIG_ZCBOR=y
    CONFIG_CRC=y
    CONFIG_MCUMGR=y
    CONFIG_STREAM_FLASH=y
    CONFIG_FLASH_MAP=y
    
    
    # Some command handlers require a large stack.
    CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2304
    CONFIG_MAIN_STACK_SIZE=2176
    
    # Ensure an MCUboot-compatible binary is generated.
    CONFIG_BOOTLOADER_MCUBOOT=y
    
    # Enable flash operations.
    CONFIG_FLASH=y
    
    # Required by the `taskstat` command.
    CONFIG_THREAD_MONITOR=y
    
    # Support for taskstat command
    CONFIG_MCUMGR_GRP_OS_TASKSTAT=y
    
    # Enable statistics and statistic names.
    CONFIG_STATS=y
    CONFIG_STATS_NAMES=y
    
    # Enable most core commands.
    CONFIG_FLASH=y
    CONFIG_IMG_MANAGER=y
    CONFIG_MCUMGR_GRP_IMG=y
    CONFIG_MCUMGR_GRP_OS=y
    CONFIG_MCUMGR_GRP_STAT=y
    
    # Enable logging
    CONFIG_LOG=y
    
    CONFIG_LOG_PRINTK=y
    
    CONFIG_USE_SEGGER_RTT=y
    
    CONFIG_CONSOLE=y
    
    #USB stuff?
    CONFIG_USB_DEVICE_STACK=y
    CONFIG_SERIAL=y
    CONFIG_UART_LINE_CTRL=y
    
    

    /dts-v1/;
    #include <nordic/nrf52840_qiaa.dtsi>
    #include "nrflode_v000-pinctrl.dtsi"
    
    / {
    	model = "NRF Lode";
    	compatible = "trimsense,nrflode-v000";
    
    	chosen {
    		zephyr,sram = &sram0;
    		zephyr,flash = &flash0;
    		zephyr,code-partition = &slot0_partition;
    	};
    
    	gpio-leds {
    		compatible = "gpio-leds";
    		led0: led0 {
    			label = "led0";
    			gpios = <&gpio0 16 0>;
    		};
    	};
    };
    
    &flash0 {
    	partitions {
    		compatible = "fixed-partitions";
    		#address-cells = <1>;
    		#size-cells = <1>;
    
    		boot_partition: partition@0 {
    			label = "mcuboot";
    			reg = <0x00000000 DT_SIZE_K(48)>;
    		};
    
    		slot0_partition: partition@c000 {
    			label = "image-0";
    			reg = <0x0000c000 DT_SIZE_K(472)>;
    		};
    
    		slot1_partition: partition@82000 {
    			label = "image-1";
    			reg = <0x00082000 DT_SIZE_K(472)>;
    		};
    
    		storage_partition: partition@f8000 {
    			label = "storage";
    			reg = <0x000f8000 DT_SIZE_K(32)>;
    		};
    	};
    };
    &gpio0 {
    	status = "okay";
    };
    
    &gpiote {
    	status = "okay";
    };
    
    
    &usbd {
    	cdc_acm_uart: cdc-acm-uart {
    		compatible = "zephyr,cdc-acm-uart";
    		status = "okay";
    	};
    
    	status = "okay";
    };
    

  • I'm on version 2.7.0, but my prj and dts have these things (some of which you may not need). I'll put the stuff I think is important that I dont see in yours at the top of the files.

    MCUBoot_usb.conf

    CONFIG_MCUMGR_TRANSPORT_UART=y
    CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n # This just lets you write less code
    
    CONFIG_USB_DEVICE_STACK=y
    CONFIG_SERIAL=y
    CONFIG_UART_LINE_CTRL=y
    CONFIG_CONSOLE=y
    CONFIG_BASE64=y



    DTS

    /dts-v1/;
    #include <nordic/nrf52840_qiaa.dtsi>
    
    / {
    	model = "optix_bigfoot";
    	compatible = "nordic-semiconductor,optix-bigfoot";
    
    	chosen {
    		zephyr,sram = &sram0;
    		zephyr,flash = &flash0;
    		zephyr,code-partition = &slot0_partition;
    		zephyr,uart-mcumgr = &cdc-acm-uart; // <--------------------------
    		nordic,pm-ext-flash = &mx25r1;
    	};

Related