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.

  • 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

  • Hi Simon,

    Those "other DFU examples" are related to using external flash, I'm trying to write to the internal flash directly with the new application image.

    What is the point of defining the flash partitions in the board.dts file if they are ignored by the partition manager? I'm assuming I can't just not use the partition manager? This design approach seems to be so over-complicated for what I am trying to do.

    Sorry to complain, but I've been doing this work for well over 30 years and I find that this whole Zephyr approach is not very user friendly and is very time consuming.

    Thanks for your help and regards,

    Pam

Reply
  • Hi Simon,

    Those "other DFU examples" are related to using external flash, I'm trying to write to the internal flash directly with the new application image.

    What is the point of defining the flash partitions in the board.dts file if they are ignored by the partition manager? I'm assuming I can't just not use the partition manager? This design approach seems to be so over-complicated for what I am trying to do.

    Sorry to complain, but I've been doing this work for well over 30 years and I find that this whole Zephyr approach is not very user friendly and is very time consuming.

    Thanks for your help and regards,

    Pam

Children
  • Pamela Keiles said:
    Those "other DFU examples" are related to using external flash, I'm trying to write to the internal flash directly with the new application image.

    Yes, I was just trying to point you to an example that shows how the pm_static.yml file might be used. Sorry for the confusion.

    Pamela Keiles said:
    What is the point of defining the flash partitions in the board.dts file if they are ignored by the partition manager?

    The reason it is set in the dts file is because that's how was done in Zephyr upstream (NCS contains a downstream version of Zephyr). Also if you don't have a multi image build, the DTS files will be used. Nordic created the Partition Manager to handle multi image builds, because DTS must be set before Kconfig (when building the project, it will first go through the DTS file and set the memory layout, then it will look at all the configurations (Kconfig, prj.conf and so on)). If DTS would be used, we would need to have an own dts file for all possible configurations.

    Be aware that Kconfig and the devicetree in Zephyr is inherited from Linux (see the Zephyr Wikipedia page), which was written for computers with more memory and resources. Zephyr is open source and work in progress.

    Hopefully we will soon get the same solution in NCS as Zephyr upstream now uses, the system device tree.

    Pamela Keiles said:
    I'm assuming I can't just not use the partition manager?

    That is correct. You need to use the Partition Manager for now

    Pamela Keiles said:
    This design approach seems to be so over-complicated for what I am trying to do.

    Actually, your project is quite simple. You don't need to add any pm_static.yml file or do anything. Just build your project with CONFIG_BOOTLOADER_MCUBOOT=y in the prj.conf, and then check the generated file <sample>/build/partitions.yml or (<sample>\build\zephyr\include\generated\pm_config.h). Look for two things, the start address of secondary slot(mcuboot_secondary) and the size of secondary slot

    Now you just need to write your new uploaded image to that location. I also think you can just use the generated macros from pm_config.h to get the size and address of the secondary slot. 

    Please get back to me if you encounter any issues with this.

    Pamela Keiles said:
    Sorry to complain, but I've been doing this work for well over 30 years and I find that this whole Zephyr approach is not very user friendly and is very time consuming.

    I understand your frustration. Zephyr is quite different from other approaches. It is more abstract and moves you further away from the bare metal drivers, and it is a lot of new stuff to learn if you're new to this. 

    This texts may be an instersting read: https://www.zephyrproject.org/leveraging-open-source-software-in-your-software-development-kit-nordic-semiconductors-experience-with-the-zephyr-rtos/

    Best regards,

    Simon

  • Hi Simon,

    Thank you so much for the detailed response. I was also working with our local application engineer on investigating an approach to use the serial DFU update within mcuboot directly. The downside of this approach is having to support with one of the mcumgr protocols on the main processor downloading the image (newtmgr or smp possibly). I think that might require more development time than the approach we have already been discussing here.

    What I was struggling with was creating a partition manager yml file from scratch to ensure static addresses. But now I see I can copy the build generated yml file as a starting point and adjust it if needed. I don't like the dynamic approach because if something changes in the future with the bootloader itself (programmed during manufacturing), then I have to worry about any possible addressing changes. I believe it's safer to use a static file and ensure the flash sections remain fixed.

    I'll work with what we've already outlined and use my own very simple protocol or even xmodem to do the UART transfer from the main processor and flash programming.

    The only part that still seems wrong to me is that whatever is specified in the flash data structure within the device tree file is meaningless. However it is still required to do the build (I tried removing it as a test). I suppose though as you say this is still a work in progress.

    Thanks again, hopefully I have enough now to get this design piece working quickly.

    Best regards,

    Pam

  • Pamela Keiles said:
    I was also working with our local application engineer on investigating an approach to use the serial DFU update within mcuboot directly. The downside of this approach is having to support with one of the mcumgr protocols on the main processor downloading the image (newtmgr or smp possibly).

    Actually, you can modify mcuboot serial recovery (perform DFU update within mcuboot directly) to not use the mcumgr protocol, like I explained earlier. Be aware that if you perform DFU through the MCUboot, you put the image directly into the primary slot (not in the secondary slot like you do when performing the DFU through the application), and swapping won't happen. This is because mcuboot acts as the fallback recovery if the update fails.

    Simon said:
    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.

    Pamela Keiles said:
    Thanks again, hopefully I have enough now to get this design piece working quickly.

    Good luck with the implementation!

    Best regards,

    Simon

Related