This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

52840 dfu with firmware stored in external flash

Hello,

I am trying to use the dfu library to update the nrf52840 with a firmware stored in a littlefs file in an external qspi flash. I can successfully read the entire firmware and store it in a buffer and then update the application with the dfu library, but it does corrupt my file system. It seems to me that the dfu library tried to store the firmware in the qspi external flash (at the same place that the file system). In fact, if I read the firmware file chunk by chunk, and pass each chunk to the dfu library, my file system is corrupted in the middle of the update. If I do not use the dfu library, I am able to read and write in the file system without any problem. This problem happened only when using the dfu library.

Below is the part of the device tree where I include the qspi flash:

 

&qspi {
	status = "okay";
	sck-pin = <19>;
	io-pins = <20>, <21>, <22>, <23>;
	csn-pins = <17>;
	mx25r32_qspi: mx25r3235fm2il0@0 {
		compatible = "nordic,qspi-nor";
		reg = <0>;
		/* MX25R64 supports only pp and pp4io */
		writeoc = "pp4io";
		/* MX25R64 supports all readoc options */
		readoc = "read4io";
		sck-frequency = <8000000>;
		label = "MX25R32";
		jedec-id = [c2 28 16];
		sfdp-bfp = [
			e5 20 f1 ff  ff ff ff 03  44 eb 08 6b  08 3b 04 bb
			ee ff ff ff  ff ff 00 ff  ff ff 00 ff  0c 20 0f 52
			10 d8 00 ff  23 72 f5 00  82 ed 04 cc  44 83 68 44
			30 b0 30 b0  f7 c4 d5 5c  00 be 29 ff  f0 d0 ff ff
		];
		size = <33554432>;
		has-dpd;
		t-enter-dpd = <10000>;
		t-exit-dpd = <30000>;
	};
};

&mx25r32_qspi {
	partitions {
		compatible = "fixed-partitions";
		#address-cells = <1>;
		#size-cells = <1>;
		partition@0 {
			label = "storage_qspi";
			reg = <0x00000000 0x00050000>;
		};
	};
};


Below is the part where I defined the file system:

FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(storage);
static struct fs_mount_t lfs_storage_mnt = {
    .type = FS_LITTLEFS,
    .fs_data = &storage,
    .storage_dev = (void *)DT_FIXED_PARTITION_ID(DT_NODE_BY_FIXED_PARTITION_LABEL(storage_qspi)), 
    .mnt_point = MOUNT_POINT,
};

Finally, the relevant part in my prj.conf:

# DFU Target
CONFIG_DFU_TARGET=y

# Image manager
CONFIG_IMG_MANAGER=y
CONFIG_FLASH=y
CONFIG_IMG_ERASE_PROGRESSIVELY=y

CONFIG_DFU_TARGET_MCUBOOT=y
CONFIG_BOOTLOADER_MCUBOOT=y

CONFIG_SPI=y
CONFIG_SPI_NOR=n
CONFIG_NORDIC_QSPI_NOR=y
CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096

CONFIG_FLASH=y

CONFIG_FILE_SYSTEM=y
CONFIG_FLASH_MAP=y
CONFIG_FLASH_PAGE_LAYOUT=y

CONFIG_FILE_SYSTEM_LITTLEFS=y

To read the file system, I use the littlefs library, and to write to the dfu, I use the dfu_target library.

Do you have maybe some hints as to why this problem can occur ?

Kind regards

Parents
  • Hi,

    In fact, if I read the firmware file chunk by chunk, and pass each chunk to the dfu library, my file system is corrupted in the middle of the update.

    By DFU library you mean the DFU Target library, right? There must be some writing involved as you see corruption. Can you explain in more detail and perhaps show relevant parts of your implementation?  Also, what does your flash memory layout look like (can you share your pm_static.yml)?

    By the way, what is the reason you use DFU Target library and transfer the image to litlefs first instead of directly storing the image in S1 on external flash without the DFU Target library, which is supported? (It does not have to be a bad idea, but I am curious).

  • Hello,


    By DFU library you mean the DFU Target library, right ?

    Yes.

    Can you explain in more detail

    For the needs of our project, we have a nrf9160, a nrf52840 and multiples devices. The nrf52840 is the gateway between our devices and internet (it uses the project serial_lte_modem to communicate with the modem of the nrf9160).

    The role of the gateway is to check if there are updates available for the devices or itself, download them (with AT commands), store them onto our file system, and send them to the appropriate target. It also needs to get the data reported by the devices and upload them on a server.

    We have implemented a custom AT command to download a firmware with HTTPS and store it into the file system. This command is used to download the firmware update for the nrf52840. But once we have download this file, we would like to use the dfu target library to update the firmware with the firmware downloaded. And that is when we have the error.

    show relevant parts of your implementation ?

    I don't think there is much to show that is relevant to the problem. Below is the part where we read the file containing the firmware chunk by chunk and put them in the dfu library.

        do
        {
            // Read <chunk_size> number of bytes from the offset <chunk_idx * chunk_size> in the file <filename> and store it in the buffer <read_chunk> 
            number_of_bytes_read = fs_handle_read_chunk_in_file(filename, read_chunk, chunk_size, chunk_idx * chunk_size);
    
    		total_read += number_of_bytes_read;
    
    		if (number_of_bytes_read < 0)
    		{
    			LOG_ERR("Error when trying to read bytes in file: %d", number_of_bytes_read);
    			break;
    		}
    		chunk_idx++;
    
    		LOG_INF("Read chunk idx: %d -> number bytes read: %d (total: %d)", chunk_idx, number_of_bytes_read, total_read);
    
    		err = dfu_target_write(read_chunk, number_of_bytes_read);
    		if (err != 0)
    		{
    		 	LOG_ERR("dfu_target_write error %d", err);
    		 	int res = dfu_target_done(false);
    
    		    if (res != 0)
    		    {
    			    LOG_ERR("Unable to free DFU target resources");
    		    }
    		    return err;
    		}
        } while (number_of_bytes_read > 0);




    But I do think, there is some incomprehension of my part on how to configure the external flash as a storage partition. When I mount the partition, I see this log:

    00> [00:00:00.000,488] <inf> file_system_handle: Area 5 at 0x83000 on NRF_FLASH_DRV_NAME for 487424 bytes
    00> 
    00> [00:00:00.000,518] <inf> littlefs: LittleFS version 2.2, disk version 2.0
    00> [00:00:00.000,732] <inf> littlefs: FS at NRF_FLASH_DRV_NAME:0x83000 is 119 0x1000-byte blocks with 512 cycle
    00> [00:00:00.000,762] <inf> littlefs: sizes: rd 16 ; pr 16 ; ca 64 ; la 32
    00> [00:00:00.001,342] <inf> littlefs: /lfs mounted
    00> [00:00:00.001,373] <inf> file_system_handle: /lfs mount: 0

    When the partition on the device tree specify this region:

    &mx25r32_qspi {
    	partitions {
    		compatible = "fixed-partitions";
    		#address-cells = <1>;
    		#size-cells = <1>;
    		partition@0 {
    			label = "storage_qspi";
    			reg = <0x00000000 0x00050000>;
    		};
    	};
    };


    And I did not have created a pm_static.yml file which is probably the mistake because, If I check the file partition.yml generated when building the application, I do not see anything related to the storage_qspi defined in the device tree... But even after having looking at the documentation, it is still not very clear to me. Is this file mandatory to create if we use an external flash? And in this case, why the application is able to compile when I specify the storage_qspi in the littlefs definition without having created this file ?

    By the way, what is the reason you use DFU Target library and transfer the image to litlefs first instead of directly storing the image in S1 on external flash without the DFU Target library, which is supported?

    Well, It seems to us that it was more generic to use the same function and callback to download any file (firmware for our devices and our gateway, configuration files, ...) on our server and store everything on the external qspi flash, and then, use a custom behavior depending on the type of the file downloaded.

  • Hi,

    I need to look more at this tomorrow and get back to you then. In the mean time, can you upload the partitions.yml file from your build folder?

  • Hello,

    Thank you. Here is my partition.yml file:

    app:
      address: 0xc200
      end_address: 0x83000
      region: flash_primary
      size: 0x76e00
    littlefs_storage:
      address: 0xfa000
      end_address: 0x100000
      placement:
        before:
        - end
      region: flash_primary
      size: 0x6000
    mcuboot:
      address: 0x0
      end_address: 0xc000
      placement:
        before:
        - mcuboot_primary
      region: flash_primary
      size: 0xc000
    mcuboot_pad:
      address: 0xc000
      end_address: 0xc200
      placement:
        align:
          start: 0x1000
        before:
        - mcuboot_primary_app
      region: flash_primary
      size: 0x200
    mcuboot_primary:
      address: 0xc000
      end_address: 0x83000
      orig_span: &id001
      - mcuboot_pad
      - app
      region: flash_primary
      sharers: 0x1
      size: 0x77000
      span: *id001
    mcuboot_primary_app:
      address: 0xc200
      end_address: 0x83000
      orig_span: &id002
      - app
      region: flash_primary
      size: 0x76e00
      span: *id002
    mcuboot_secondary:
      address: 0x83000
      end_address: 0xfa000
      placement:
        after:
        - mcuboot_primary
        align:
          start: 0x1000
      region: flash_primary
      share_size:
      - mcuboot_primary
      size: 0x77000
    sram_primary:
      address: 0x20000000
      end_address: 0x20040000
      region: sram_primary
      size: 0x40000

Reply
  • Hello,

    Thank you. Here is my partition.yml file:

    app:
      address: 0xc200
      end_address: 0x83000
      region: flash_primary
      size: 0x76e00
    littlefs_storage:
      address: 0xfa000
      end_address: 0x100000
      placement:
        before:
        - end
      region: flash_primary
      size: 0x6000
    mcuboot:
      address: 0x0
      end_address: 0xc000
      placement:
        before:
        - mcuboot_primary
      region: flash_primary
      size: 0xc000
    mcuboot_pad:
      address: 0xc000
      end_address: 0xc200
      placement:
        align:
          start: 0x1000
        before:
        - mcuboot_primary_app
      region: flash_primary
      size: 0x200
    mcuboot_primary:
      address: 0xc000
      end_address: 0x83000
      orig_span: &id001
      - mcuboot_pad
      - app
      region: flash_primary
      sharers: 0x1
      size: 0x77000
      span: *id001
    mcuboot_primary_app:
      address: 0xc200
      end_address: 0x83000
      orig_span: &id002
      - app
      region: flash_primary
      size: 0x76e00
      span: *id002
    mcuboot_secondary:
      address: 0x83000
      end_address: 0xfa000
      placement:
        after:
        - mcuboot_primary
        align:
          start: 0x1000
      region: flash_primary
      share_size:
      - mcuboot_primary
      size: 0x77000
    sram_primary:
      address: 0x20000000
      end_address: 0x20040000
      region: sram_primary
      size: 0x40000

Children
Related