Example For Using UART DFU on NRF52832 on both sides of communications

Hello,

I am trying to figure out which example is the closest fit for our design. We are using a 2 processor solution in our product, and the firmware for the NRF52832 has to be able to be upgraded via the UART connection to the main processor. I have found some examples here, but usually it's using a PC application or over the air which does not apply to our design. Also, I'm confused abut some of the examples on the side of the NRF52832 in terms of performing the update. There are references to a "full modem" update, but what is meant by modem? This will be a simple direct UART communication update, is this done via the application on the Nordic chip or can it be done via the bootloader directly?

This has to be a common approach, I'm just unsure where to start. Note I am using the latest SDK release 1.9.1.

Thanks for your help.

Regards,

Pam

Parents
  • Hi Again,

    Forget the question related to using the UART, I can figure that out myself by referencing the serial drivers directly in my SDK.

    I think I need to focus my question on the usage of the bootloader to directly update the image. I would prefer to have all of the update support handled within the bootloader image. If this requires the usage of the mcumgr/smp protocol, then I can incorporate that within my main processor controlling the upgrade process.

    Can I include all support for the firmware image update via the UART within the bootloader code? And if so, is the smp protocol the only option?

    Thanks,

    Pam

  • Pamela Keiles said:
    Can I include all support for the firmware image update via the UART within the bootloader code? And if so, is the smp protocol the only option?

    Yes, you can do this. If you want to perform a UART DFU through mcuboot you need to use smp/mcumgr protocol. However, only a limited set of commands are supported, as you see here: https://github.com/nrfconnect/sdk-mcuboot/blob/v1.8.99-ncs1/boot/boot_serial/src/boot_serial.c#L502-L527 

    If you want to drop the smp/mcumgr, you need to modify MCUboot, which might require less work that using the smp/mcumgr protocol (where you need to implement the protocol on the client side).

    The modification of mcuboot, will happen to the function boot_serial_input(), and instead of parsing the incoming messages as mcumgr commands, you simply store the image blocks right into flash where it belongs.

    Please let me know what approach you prefer, and I will assist you with the implementation.

  • Hi Simon,

    Another option is to not rely on the bootloader for the update itself but perform the flash programming within my application. Since there are 2 slots, the current running application can do the flash write directly to the other slot. Then after it confirms the programming is correct (via a checksum or header/tail data check?), call the correct routines within the bootloader to mark the new image as active and execute the reset. Does that sound doable? I'm assuming the flash driver routines can just be called directly?

    Thanks,

    Pam

  • Yes this is absolutely possible.

    Pamela Keiles said:
    Then after it confirms the programming is correct (via a checksum or header/tail data check?),

    This is actually done by the bootloader, all you need from the current running application, is to place the image into the secondary slot. Then on reset, the mcuboot will check if there is a valid image present in secondary slot and swap it with the image in the primary slot if that's the case. Then, it will boot the new image.

    Pamela Keiles said:
    call the correct routines within the bootloader to mark the new image as active and execute the reset.

    This should be done from within the image itself, like it's done in the https_update sample, so mcuboot won't revert back to the old image on the next reet.

    The reason it mcuboot will revert back the images on the next reset is to prevent the product from being bricked, for example if the new firmware is faulty, and causes the device to crash.

    Let me create a detailed list of how things happen (when performing a dfu through the application)

    1. Application receives the image, and places it in the secondary slot
    2. The device resets
      1. This can be done externally by pressing a button, or within the application itself using sys_reboot() (see \zephyr\lib\os\reboot.c)
    3. MCUboot will run first after a reboot and it can see that there is a new image in secondary slot. It will then check if the image is valid (see MCUboot-->Integrity check)
    4. If a valid image is present in the secondary slot, mcuboot wil swap it with the image in the primary slot
    5. MCUboot will then boot the new update that are now present in the primary slot
    6. The new update will run, and needs to confirm itself ( like it's done in the https_update sample), so MCUboot won't revert back on the next reset
    Pamela Keiles said:
    I'm assuming the flash driver routines can just be called directly?

    Yes, you can. Check out the flash API: https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.0/zephyr/reference/peripherals/flash.html#overview. Take a look at the example \zephyr\samples\drivers\soc_flash_nrf to see how to use this API. The http_update sample uses the Stream Flash API (through \nrf\include\dfu\dfu_target_stream.h), so that might be worth taking a look at.

    Good luck and best regards,

    Simon

  • Hi Simon,

    I'm going to try and work with the flash erase/write routines directly for the firmware update. I do remember seeing an API to call within I think mcuboot which can be used to set the newly downloaded image as valid and switch the active image slot. Do you know where this is described or an example of its usage?

    Thanks,

    Pam

  • Are you referring to boot_write_img_confirmed()? This is present inside a file named mcuboot.h, but it is located inside the zephyr repository, not mcuboot. This will not perform any validation checks or do any swapping, but just mark it as "confirmed". It should be run from the application.

    You don't need to care about the validation or swapping of the image. This will happen automatically in mcuboot when it's booted:

    Best regards,

    Simon

Reply Children
  • Hi Simon,

    I will be performing the second slot flash update from the app, which receives it via the UART directly. So it sounds like all I have to do after programming the flash with the new image, is call the "boot_write_img_confirmed() routine and force a reboot, is that correct?

    Thanks,

    Pam

  • You do it in the opposite way. After you've programmed the secondary flash with the new image, you force a reboot, then you call boot_write_img_confirmed() routine from the new image (now present in the primary slot).

    Like I explained in this answer: https://devzone.nordicsemi.com/support-private/support/288653#permalink=757710 

  • Hi Simon,

    Great, I think I got the sequence from your explanations. I'll be working on this part of the design the next couple of days and I'll let you know if I have any other questions. I will also be trying to "break" the bootloader to make sure it recovers nicely, such as only a partial image being present in the second bank.

    Thanks for all your detailed help.

    Best regards,

    Pam

  • Hi Simon,

    I'm struggling with accessing the flash partition area directly using the partition manager defines and the device tree specification for my board. I was referencing the "soc_flash_nrf" example, but it doesn't seem to incorporate the partition manager, which I believe is automatic when using "mcuboot" correct?

    I have also been looking at the resultant defines in the "pm_config.h" file, and they are not what I would expect from my board.dts file.

    Specifically the sizes and start addresses seem wrong. Here is how the flash is defined in my device tree file:

    &flash0 {

        partitions {
            compatible = "fixed-partitions";
            #address-cells = <1>;
            #size-cells = <1>;

            boot_partition: partition@0 {
                label = "mcuboot";
                reg = <0x00000000 0xc000>;
            };
            slot0_partition: partition@c000 {
                label = "image-0";
                reg = <0x0000C000 0x32000>;
            };
            slot1_partition: partition@3e000 {
                label = "image-1";
                reg = <0x0003E000 0x32000>;
            };
            scratch_partition: partition@70000 {
                label = "image-scratch";
                reg = <0x00070000 0xa000>;
            };
            storage_partition: partition@7a000 {
                label = "storage";
                reg = <0x0007a000 0x00006000>;
            };
        };
    };
     
    However when I look at the resultant "pm_config.h" file, the values do not match. Maybe this is effected by this unexpected "PM_MCUBOOT_PAD_SIZE" added which messes up the defined starting locations of the slots?
    I'll keep plugging away at this, but any help you can provide would be great.
    Thanks,
    Pam
  • When your project contains child images (like mcuboot), the Partition Manager will be used to partition the images instead of the device tree. It will go through the pm.yml files from all the child images and dynamically place the images, and eventually it will place the app where it's room left. Read the documentation for more information: https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/nrf/scripts/partition_manager/partition_manager.html 

    You can also set the partitions statically using a pm_static.yml file, for example like it's done in Other DFU samples, or in the maching learning application

    Please let me know if anything is unclear

    Best regards,

    Simon

Related