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

Parents Reply Children
  • Hi!

    Great that you managed to fix the issue. The flash API is a more low level API used for interacting directly with the flash peripheral. The NVS API uses the flash API for easier organization and usage of storage. What you chose depends on your application, but NVS is commonly used for storing BLE bonding data for example.

    Best regards,
    Carl Richard

  • Thank you Carl.

    I am leaning more towards using flash API. 

    Maybe if you can answer the following questions about the code of the example I referred to at the top of the page, it will help me make a better decision.

    Q1/ I can see the line below is setting an offset from the start of the flash area but What is 'storage', I could not find where it is defined. I was expecting to see fs.offset = some_address.

    fs.offset = FLASH_AREA_OFFSET( storage );       

    Q2/ What is ADDRESS_ID used for in the line of code below?

    nvs_read( &fs, ADDRESS_ID, &buf, sizeof( buf );

    Q3/ What is meant by 'offset' in

    int flash_read(const struct device *dev, off_t offset, void *data, size_t len)

    int flash_write(const struct device *dev, off_t offsetconst void *data, size_t len)

    Is it an offset from the start of the flash area or an offset from a specific page of the flash area?

    How can I specify which page I want to read from or write to?

    An example running Zephyr showing how to use the flash APIs will be very helpful.

    That is all for now. I would appreciate a quick response because I am working to very tight schedule. Thank you.

    Kind regards

    Mohamed

  • Hi!

    Glad to help!

    Learner said:

    Q1/ I can see the line below is setting an offset from the start of the flash area but What is 'storage', I could not find where it is defined. I was expecting to see fs.offset = some_address.

    fs.offset = FLASH_AREA_OFFSET( storage );       

    This refers to the storage partition defined by the device tree structure of the target board. In the case of the nRF5340DK you can find the storage label here. It is indeed an address!

    Learner said:

    Q2/ What is ADDRESS_ID used for in the line of code below?

    nvs_read( &fs, ADDRESS_ID, &buf, sizeof( buf );

    The NVS API works with id-data pairs, where an id points to a specific address (defined by the user) where data is stored. You can read more about this in the NVS API documentation.

    Learner said:

    Q3/ What is meant by 'offset' in

    int flash_read(const struct device *dev, off_t offset, void *data, size_t len)

    int flash_write(const struct device *dev, off_t offsetconst void *data, size_t len)

    Is it an offset from the start of the flash area or an offset from a specific page of the flash area?

    How can I specify which page I want to read from or write to?

    I believe you will find answers to all of this in the Flash API documentation, but here is a short summary: the offset is from the start of the flash area and you can get page start offset and size through API calls. Then flash write/read can be used to alter or read the page. 

    You can have a look at the Flash Shell Sample for reference.

    Hope this answers your questions!

    Best regards,
    Carl Richard

  • Thank you Carl for the quick response.

    The NVS API works with id-data pairs, where an id points to a specific address (defined by the user) where data is stored.

    In the example  https://github.com/zephyrproject-rtos/zephyr/blob/master/samples/subsys/nvs All I can see is

    #define ADDRESS_ID 1

    Then it is used in

    rc = nvs_read(&fs, ADDRESS_ID, &buf, sizeof(buf));

    So, what address is id ADDRESS_ID pointing to?

    ou can have a look at the Flash Shell Sample for reference.

    I could not see the source code for this example.

    The NVS API uses the flash API for easier organization and usage of storage.

    In the nvs_fs structure, data_wra is the address the data is written to but what is ate_wra used for? 

    Also, after calling nvs_init( &fs, DT_CHOSEN_ZEPHYR_FLASH_CONTROLLER_LABEL );

    fs.ate_wra = 0x00000FF0, 0000 meaning sector 0, and 0FF0 is the offset within sector 0.

    Why is the offset within the sector not zero?

    fs.data_wra = 0x00000000

    fs.sector_size = 0x1000

    fs.sector_count = 3

    Is sector 0 at higher address or lower address? sector 0 at 0x000fa000 or at 0x???

    Can you please draw a memory map diagram after the call to nvs_init.

    Thank you.

    Kind regards

    Mohamed

     

    Please help.

    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

Related