nRF51822 & Zephyr - OTA DFU

Hello, everyone!

We have nRF51822 SoC running Zephyr OS. We would like to have the ability to perform OTA DFU. Given the fact that nRF51822 has only 256KB of flash memory, we have separated the Zephyr part from the application code so that we can update only the application part and leave the Zephyr part intact. Here is how our memory is partitioned:

As you can see, App Slots 1 and 2 are used for storing the application code. Scratch partition helps during the image swap process (link). We flash the Zephyr partition just once and don't touch it during the OTA DFU process.

It seems that we can successfully perform OTA DFU only if the new image is very similar to the one running on the Heart device. For example, if we just change the content in one line of the debug log and create a .bin file for OTA DFU, we can successfully update the FW and a new version of it will run properly.

On the other side, if we add a new function in the code, or if we add some additional small CPU activity in the existing function, a new version of the FW will cause HardFaults after OTA DFU. We can transfer the image over BLE, detect it on the device side, confirm it, and restart the device, but the new version of the FW will cause the HardFaults.

Do you have any idea about what we are missing here?

Thanks in advance for your time and efforts.

Sincerely,
Bojan.

Parents
  • Hi Bojan, 


    Could you give us more information on how you separate Zephyr from the app and how you locate Zephyr in a different partition  ?

    Which bootloader did you use ? I assume it's MCUBoot ? 

    If you try to DFU update with very simple application , for example blinking LED, do you see the same issue ?

    Please be aware that we don't support nRF51 in our nRF Connect SDK. You can use it with Zephyr but it's pretty much on your own. For new development we suggest to go with nRF52 or nRF53. 

  • Hello, !

    Sorry for the delayed reply.

    Could you give us more information on how you separate Zephyr from the app and how you locate Zephyr in a different partition  ?

    In our custom .dts file, we have defined our memory layout in the following way:

    &flash0 {
    	partitions {
    		compatible = "fixed-partitions";
    		#address-cells = <1>;
    		#size-cells = <1>;
    
    		boot_partition: partition@0 {
    			label = "mcuboot";
    			reg = <0x00000000 0x6000>;
    		};
    		slot0_partition: partition@6000 {
    			label = "image-0";
    			reg = <0x00006000 0x6000>;
    		};
    		slot1_partition: partition@c000 {
    			label = "image-1";
    			reg = <0x0000c000 0x6000>;
    		};
    		scratch_partition: partition@12000 {
    			label = "image-scratch";
    			reg = <0x00012000 0x1000>;
    		};
    		zephyr_partition: partition@13000 {
    			label = "zephyr";
    			reg = <0x000013000 0x2C000>;
    		};
    
    		storage_partition: partition@3f000 {
    			label = "storage";
    			reg = <0x0003f000 0x00001000>;
    		};
    	};
    };

    We separate Zephyr from the app by using the arm-none-eabi-objcopy executable from the compiler:

                    // Extract app section to bin
                    "${config:TOOLCHAIN_PATH}/bin/arm-none-eabi-objcopy -O binary --only-section=rom_start --only-section=app_flash ${workspaceFolder}/build/zephyr/zephyr.elf ${workspaceFolder}/images/${config:BOARD_NAME}.bin;",
                    // Extract app section to hex
                    "${config:TOOLCHAIN_PATH}/bin/arm-none-eabi-objcopy -O ihex --only-section=rom_start --only-section=app_flash ${workspaceFolder}/build/zephyr/zephyr.elf ${workspaceFolder}/images/${config:BOARD_NAME}.hex;",
                    // Extract Zephyr section to bin
                    "${config:TOOLCHAIN_PATH}/bin/arm-none-eabi-objcopy -O binary --remove-section=rom_start --remove-section=app_flash ${workspaceFolder}/build/zephyr/zephyr.elf ${workspaceFolder}/images/ZephyrOS.bin;",
                    // Extract Zephyr section to hex
                    "${config:TOOLCHAIN_PATH}/bin/arm-none-eabi-objcopy -O ihex --remove-section=rom_start --remove-section=app_flash ${workspaceFolder}/build/zephyr/zephyr.elf ${workspaceFolder}/images/ZephyrOS.hex;",

    Here is what we have noticed recently:

    Once we change the application code, compile it, and separate Zephyr from the app, ZephyrOS.hex file is different compared to the ZephyrOS.hex file we get after compilation of the initial version of the code. We found ~26 lines of difference between the two ZephyrOS.hex files. This might be the reason for HardFault after DFU.

    How can we get consistent/deterministic content of the ZephyrOS.hex file? We don't change anything related to the Zephyr when we update our application code. Consequently, we expect ZephyrOS.hex part to always be the same.

    Which bootloader did you use ? I assume it's MCUBoot ? 

    Yes, we are using the MCUBoot bootloader.

    Best,
    Bojan.

  • Hi Bojan, 

    I'm not aware of a way to seperate zephyr OS from application. I don't think by defining a "zephyr_partition" you would be able to put the OS into a separate partition that you can split it using arm-none-eabi-objcopy. 

    My understanding is that when you build a Zephyr application, the OS and the application is mixed and there is no easy way to separate them. 

    What you see as zephyr.hex is the mixture of the Zephyr OS and the application. 


    This may also explain why when you change anything in the application, the zephyrOS.hex also change.

    My suggestion, if the internal flash is too small, you may want to think of either using external flash to receive new image, or use our nRF5 SDK solution (Bootloader + Softdevice) and then have the zephyr application running as a NRF5 SDK application.

    But i'm not so sure if you have enough space. 

  • FWIW I tried to get the same outcome with a different approach. After some study of CONFIG_CODE_DATA_RELOCATION (only works for different regions it seems, not within a region) and flash_map (only suited for storage, not XIP code) I went down the custom-sections.ld linker script route. Things were looking good, separating out the app segments from the Zephyr segments, thanks to this trick that allows segments to be specified by library. Alas I hit a brick wall because there's some symbols in the app library (eg. _static_thread_data* that by default get grouped with some Zephyr symbols. If I try to move them, the app silently hangs, so I assume there's some address arithmetic going on that relies on them being grouped together.

    I gather this might be the class of challenge that have led others to conclude that OS and app cannot be separated, and I have, very reluctantly, come to the same conclusion. I'd love to hear otherwise! Prior to hitting the brick wall, I had 5kB of application code isolated from >600kB of Zephyr library, and the Zephyr library was not changing as I made meaningful changes to the application. You can imagine the benefits this could bring for OTA, including opening the door to a two-stage upgrade strategy - OTA for incremental updates and cabled for OS or major updates.

Reply
  • FWIW I tried to get the same outcome with a different approach. After some study of CONFIG_CODE_DATA_RELOCATION (only works for different regions it seems, not within a region) and flash_map (only suited for storage, not XIP code) I went down the custom-sections.ld linker script route. Things were looking good, separating out the app segments from the Zephyr segments, thanks to this trick that allows segments to be specified by library. Alas I hit a brick wall because there's some symbols in the app library (eg. _static_thread_data* that by default get grouped with some Zephyr symbols. If I try to move them, the app silently hangs, so I assume there's some address arithmetic going on that relies on them being grouped together.

    I gather this might be the class of challenge that have led others to conclude that OS and app cannot be separated, and I have, very reluctantly, come to the same conclusion. I'd love to hear otherwise! Prior to hitting the brick wall, I had 5kB of application code isolated from >600kB of Zephyr library, and the Zephyr library was not changing as I made meaningful changes to the application. You can imagine the benefits this could bring for OTA, including opening the door to a two-stage upgrade strategy - OTA for incremental updates and cabled for OS or major updates.

Children
No Data
Related