This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Writing to and reading from flash on nRF5340

Hello,

I am trying to use part of the code from this example https://github.com/zephyrproject-rtos/zephyr/blob/master/samples/subsys/nvs

to write to and read from flash on nRF5340 SoC. However, I am getting the following linking error when building the project in Segger.

I am using Segger v5.34a, NCS v1.5.0-rc1 and Zephyr v2.4.99-ncs1-rc1.

I am including the following header files

#include <zephyr.h>
#include <power/reboot.h>
#include <device.h>
#include <string.h>
#include <drivers/flash.h>
#include <storage/flash_map.h>
#include <fs/nvs.h>

Can you please help ?

1> Linking ‘zephyr_prebuilt.elf’
1> C:\Zypher\v1.5.0-rc1\toolchain\opt/bin/arm-none-eabi-gcc zephyr/CMakeFiles/zephyr_prebuilt.dir/misc/empty_file.c.obj -Wl,-T zephyr/linker.cmd -Wl,-Map=C:/Sandbox/PID4-Firmware/app_core/build_nrf5340pdk_nrf5340_cpuapp_flash/zephyr/zephyr_prebuilt.map -Wl,--whole-archive app/libapp.a zephyr/libzephyr.a zephyr/arch/common/libarch__common.a zephyr/arch/arch/arm/core/aarch32/libarch__arm__core__aarch32.a zephyr/arch/arch/arm/core/aarch32/cortex_m/libarch__arm__core__aarch32__cortex_m.a zephyr/arch/arch/arm/core/aarch32/cortex_m/mpu/libarch__arm__core__aarch32__cortex_m__mpu.a zephyr/arch/arch/arm/core/aarch32/cortex_m/cmse/libarch__arm__core__aarch32__cortex_m__cmse.a zephyr/lib/libc/newlib/liblib__libc__newlib.a zephyr/lib/posix/liblib__posix.a zephyr/soc/arm/common/cortex_m/libsoc__arm__common__cortex_m.a zephyr/boards/boards/arm/nrf5340pdk_nrf5340_cpuapp/libboards__arm__nrf5340dk_nrf5340.a zephyr/drivers/adc/libdrivers__adc.a zephyr/drivers/gpio/libdrivers__gpio.a zephyr/drivers/ipm/libdrivers__ipm.a zephyr/drivers/spi/libdrivers__spi.a modules/nrf/lib/fatal_error/lib..__nrf__lib__fatal_error.a modules/nrf/drivers/hw_cc310/lib..__nrf__drivers__hw_cc310.a modules/hal_nordic/libmodules__hal_nordic.a -Wl,--no-whole-archive zephyr/kernel/libkernel.a zephyr/CMakeFiles/offsets.dir/./arch/arm/core/offsets/offsets.c.obj -Lc:/zypher/v1.5.0-rc1/toolchain/opt/bin/../lib/gcc/arm-none-eabi/9.2.1/thumb/v8-m.main/nofp -LC:/Sandbox/PID4-Firmware/app_core/build_nrf5340pdk_nrf5340_cpuapp_flash/zephyr -lgcc -Wl,--print-memory-usage zephyr/arch/common/libisr_tables.a C:/Zypher/v1.5.0-rc1/nrfxlib/crypto/nrf_cc312_platform/lib/cortex-m33/soft-float/no-interrupts/libnrf_cc312_platform_0.9.7.a -mcpu=cortex-m33 -mthumb -mabi=aapcs -Wl,--gc-sections -Wl,--build-id=none -Wl,--sort-common=descending -Wl,--sort-section=alignment -Wl,-u,_OffsetAbsSyms -Wl,-u,_ConfigAbsSyms -nostdlib -static -no-pie -Wl,-X -Wl,-N -Wl,--orphan-handling=warn -lm -Wl,-lc -LC:/Zypher/v1.5.0-rc1/toolchain/opt/arm-none-eabi/lib/thumb/v8-m.main/nofp -u_printf_float -Wl,-lgcc -lc -specs=nano.specs -o zephyr\zephyr_prebuilt.elf
1> Memory region Used Size Region Size %age Used
1> FLASH: 73512 B 1 MB 7.01%
1> SRAM: 28680 B 448 KB 6.25%
1> c:/zypher/v1.5.0-rc1/toolchain/opt/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld.exe: app/libapp.a(pid4_flash.c.obj): in function `flash_get_page_info_by_offs':
1> C:\Sandbox\PID4-Firmware\app_core\build_nrf5340pdk_nrf5340_cpuapp_flash/zephyr/include/generated/syscalls/flash.h:85: undefined reference to `z_impl_flash_get_page_info_by_offs'
1> c:/zypher/v1.5.0-rc1/toolchain/opt/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld.exe: app/libapp.a(pid4_flash.c.obj): in function `flash_init':
1> C:\Sandbox\PID4-Firmware\app_core\build_nrf5340pdk_nrf5340_cpuapp_flash/../src/flash/pid4_flash.c:45: undefined reference to `nvs_init'
1> collect2.exe: error: ld returned 1 exit status
1> IDT_LIST: 104 B 2 KB 5.08%
Build failed

Kind regards

Mohamed

  • Hi again!

    This is correct. Lets take a look at this function call in context:

    /* ADDRESS_ID is used to store an address, lets see if we can
     * read it from flash, since we don't know the size read the
     * maximum possible
     */
    rc = nvs_read(&fs, ADDRESS_ID, &buf, sizeof(buf));
    if (rc > 0) { /* item was found, show it */
    	printk("Id: %d, Address: %s\n", ADDRESS_ID, buf);
    } else   {/* item was not found, add it */
    	strcpy(buf, "192.168.1.1");
    	printk("No address found, adding %s at id %d\n", buf,
    	       ADDRESS_ID);
    	(void)nvs_write(&fs, ADDRESS_ID, &buf, strlen(buf)+1);
    }

    Here we can see that the application checks if there is anything located at ADDRESS_ID, if not the nvs_read(...) function throws an error. The application then assumes that this means nothing is located at ADDRESS_ID 1, and calls nvs_write(...) with the ID. So ADDRESS_ID is initially not pointing to anything, before it's used by nvs_write(...). This is also described by the comments in the source code.


    Learner said:
    I could not see the source code for this example.

    All Zephyr samples are present in the nRF Connect SDK. Please have a look at <ncs_root>\zephyr\samples\drivers\flash_shell.

    Best regards,
    Carl Richard

  • Hi Carl,

    Thank you for your support.

    Could you also please answer my other questions in my previous post? I edited it late last night.

    With NVS, the user does not even know which flash location is being written to or read from because this is abstracted away from him/her. Maybe this is what I am not comfortable with. 

    "Elements, represented as id-data pairs, are stored in flash using a FIFO-managed circular buffer. Each element is stored in flash as metadata (8 byte) and data. The metadata is written in a table starting from the end of a nvs sector, the data is written one after the other from the start of the sector. The metadata consists of: id, data offset in sector, data length, part (unused) and a crc...."

    If I understood the above description right, each sector in flash will contain metadata starting from the end of the sector and data written at the start of the sector.

    Is the size of the metadata always 8 bytes irrespective of whether I am writing 1 byte or 1 MB of data to flash?

    Or does it grow as the data size grows?

    Diagrams would have been very helpful to explain how NVS stores and retrieves data from flash.

    Kind regards

    Mohamed

  • Hi Carl,

    I am trying to get familiar with NVS using the same example  https://github.com/zephyrproject-rtos/zephyr/blob/master/samples/subsys/nvs

    So, I did three successive writes to flash changing the string address each time, with a reboot between each write. Note, each write is 12 (11 + 1) bytes long.

    Why are we adding +1 to the length?

    strcpy( buf, "192.168.1.1" );
    printk( "No address found, adding %s at id %d\n", buf, ADDRESS_ID );
    (void)nvs_write( &fs, ADDRESS_ID, &buf, strlen( buf )+1 );

    *** reboot ***

    strcpy( buf, "193.168.1.1" );
    printk( "No address found, adding %s at id %d\n", buf, ADDRESS_ID );
    (void)nvs_write( &fs, ADDRESS_ID, &buf, strlen( buf )+1 );

    *** reboot ***

    strcpy( buf, "194.168.1.1" );
    printk( "No address found, adding %s at id %d\n", buf, ADDRESS_ID );
    (void)nvs_write( &fs, ADDRESS_ID, &buf, strlen( buf )+1 );

    *** reboot ***

    After the third write/reboot sequence,

    fs.offset = 0x000fa000

    fs.ate_wra = 0x00000fd8

    fs.data_wra = 0x00000024

    This suggests I end up with all 3 addresses 192.168.1.1 193.168.1.1 194.168.1.1 stored in flash under the same ID ADDRESS_ID.

    However, nvs_read( &fs, ADDRESS_ID, &buf, sizeof( buf ) ) reads only 194.168.1.1 i.e. the last address written despite the fact that fs.ate_wra = 0x00000fd8 and fs.data_wra = 0x00000024. Please can you explain why this is the case.

    Thank you.

    Kind regards

    Mohamed

  • Hi again!

    I will see if I can provide some kind of explanation on the memory layout when using NVS tomorrow. In addition I see that earlier versions of Zephyr imposed a max size on the elements in NVS, but that's not present anymore. I will check if there are any limitations. 

    Just want to note that this is a Zephyr provided API so you're free to report your suggestions through their support channels as well.


    The "+1" when writing is reserved for the metadata I guess, but I'll double check this. From my understanding the NVS fs stores previously written data to some extent, which can be read out using nvs_read_hist(...). They demonstrate this in the NVS sample aswell.

    Best regards,
    Carl Richard

  • Thank you Carl,

    I am looking forward to your answers.

    In addition I see that earlier versions of Zephyr imposed a max size on the elements in NVS, but that's not present anymore.

    Which max size are you referring to?

    The "+1" when writing is reserved for the metadata I guess, but I'll double check this.

    I think the +1 is for the extra NULL  ('\0') string terminator which is not included in the length returned by strlen().

    Kind regards

    Mohamed

Related