Adding NVS in zigbee sample

We are making ZigBee product. The base we have took is from nrf connect sdk samples light_switch and coordniator example. everything works fine but we need to keep some information stored in NVS/flash.

Mainly for device list in network so that we can relate mac and short address and update it when rejoins. so that when coordinator  restarts it has network device list.

Issue we are facing is that when we add nvs sample code it gives error 

*** Booting nRF Connect SDK v3.5.99-ncs1-1 ***
[00:00:00.020,416] <err> flash_nrf: invalid address: 0x00100ff8:8
[00:00:00.037,841] <inf> fs_nvs: 3 Sectors of 4096 bytes
[00:00:00.038,604] <inf> fs_nvs: alloc wra: 0, fe8
[00:00:00.039,306] <inf> fs_nvs: data wra: 0, 0
[00:00:00.040,039] <err> flash_nrf: invalid address: 0x00100ff8:8
No address found, adding 192.168.1.1 at id 1
[00:00:00.041,351] <err> flash_nrf: invalid address: 0x00100ff8:8
[00:00:00.042,236] <err> flash_nrf: invalid address: 0x00100ff8:8
No key found, adding it at id 2

After research found its due to multi build 
The nRF Connect SDK build system enables sysbuild by default, while Zephyr build system does not. You can select the build system default or choose to explicitly use --sysbuild or --no-sysbuild for your build configuration. 

I am not sure how to fix it still
Any suggestion idea will be helpful!

Parents
  • Hi,

     

    Can you share how you are reproducing this issue?

    When altering the partition layout, it is important that you re-generate the build (ie. delete the build folder, then re-configure) - this is to ensure that the partitions are generated within the address space of the chosen device.

    Your address space seems to be out-of-bounds.

     

    Kind regards,

    Håkon

Reply
  • Hi,

     

    Can you share how you are reproducing this issue?

    When altering the partition layout, it is important that you re-generate the build (ie. delete the build folder, then re-configure) - this is to ensure that the partitions are generated within the address space of the chosen device.

    Your address space seems to be out-of-bounds.

     

    Kind regards,

    Håkon

Children
  • Hi Hakon 
    I am not sure where to alter partition layout 
    in nvs example it used to be mentioned in device tree but if have used zigbee samples 
    not able to find where to add nvs partition or if it has then how to modify it 


  • Hi,

     

    The layout is generated based on the configuration.

    Can you please share how to recreate this scenario?

     

    Kind regards,

    Håkon

  • Hi,

    I tried to reproduce with sample you can use coordniator example with below prj.conf

    #
    # Copyright (c) 2020 Nordic Semiconductor ASA
    #
    # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
    #

    CONFIG_NCS_SAMPLES_DEFAULTS=y

    CONFIG_SERIAL=y
    CONFIG_GPIO=y

    # Make sure printk is not printing to the UART console
    CONFIG_CONSOLE=y
    CONFIG_UART_CONSOLE=y

    CONFIG_HEAP_MEM_POOL_SIZE=2048
    CONFIG_MAIN_THREAD_PRIORITY=7

    CONFIG_ZIGBEE=y
    CONFIG_ZIGBEE_APP_UTILS=y
    CONFIG_ZIGBEE_ROLE_COORDINATOR=y

    # Enable DK LED and Buttons library
    CONFIG_DK_LIBRARY=y

    # This example requires more workqueue stack
    CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048

    # Enable nRF ECB driver
    CONFIG_CRYPTO=y
    CONFIG_CRYPTO_NRF_ECB=y
    CONFIG_CRYPTO_INIT_PRIORITY=80

    # Networking
    CONFIG_NET_IPV6=n
    CONFIG_NET_IP_ADDR_CHECK=n
    CONFIG_NET_UDP=n
    #
    # Copyright (c) 2020 Nordic Semiconductor ASA
    #
    # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
    #

    CONFIG_NCS_SAMPLES_DEFAULTS=y
    CONFIG_NO_OPTIMIZATIONS=y
    CONFIG_UART_INTERRUPT_DRIVEN=n
    CONFIG_SERIAL=y
    CONFIG_UART_ASYNC_API=y
    CONFIG_UART_1_ASYNC=y
    CONFIG_GPIO=y

    # Make sure printk is not printing to the UART console
    CONFIG_CONSOLE=y
    CONFIG_UART_CONSOLE=y

    CONFIG_HEAP_MEM_POOL_SIZE=2048

    CONFIG_ZIGBEE=y
    CONFIG_ZIGBEE_APP_UTILS=y

    # Enable DK LED and Buttons library
    CONFIG_DK_LIBRARY=y

    # This example requires more workqueue stack
    CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048

    # Enable API for powering down unused RAM parts
    CONFIG_RAM_POWER_DOWN_LIBRARY=y

    # Networking
    CONFIG_NET_IPV6=n
    CONFIG_NET_IP_ADDR_CHECK=n
    CONFIG_NET_UDP=n
    #CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y
    CONFIG_ZIGBEE_SCENES=y
    CONFIG_LOG_MODE_IMMEDIATE=y
    CONFIG_ZIGBEE_CHANNEL=15


    CONFIG_FLASH=y
    CONFIG_FLASH_PAGE_LAYOUT=y

    CONFIG_NVS=y
    CONFIG_LOG=y
    CONFIG_LOG_MODE_IMMEDIATE=y
    CONFIG_NVS_LOG_LEVEL_DBG=y
    CONFIG_REBOOT=y
    CONFIG_MPU_ALLOW_FLASH_WRITE=y


    # choose RTT console
    CONFIG_UART_CONSOLE=n
    CONFIG_USE_SEGGER_RTT=y
    CONFIG_RTT_CONSOLE=y
    CONFIG_MAIN_STACK_SIZE=4096





    and main function from nvs sample with required variables and #defines 

    #include <zephyr/drivers/flash.h>
    #include <zephyr/storage/flash_map.h>
    #include <zephyr/fs/nvs.h>

    static struct nvs_fs fs;

    #define NVS_PARTITION       storage_partition
    #define NVS_PARTITION_DEVICE    FIXED_PARTITION_DEVICE(NVS_PARTITION)
    #define NVS_PARTITION_OFFSET    FIXED_PARTITION_OFFSET(NVS_PARTITION)

    /* 1000 msec = 1 sec */
    #define SLEEP_TIME      100
    /* maximum reboot counts, make high enough to trigger sector change (buffer */
    /* rotation). */
    #define MAX_REBOOT 400

    #define ADDRESS_ID 1
    #define KEY_ID 2
    #define RBT_CNT_ID 3
    #define STRING_ID 4
    #define LONG_ID 5


    int main(void)
    {
        int rc = 0, cnt = 0, cnt_his = 0;
        char buf[16];
        uint8_t key[8], longarray[128];
        uint32_t reboot_counter = 0U, reboot_counter_his;
        struct flash_pages_info info;

        /* define the nvs file system by settings with:
         *  sector_size equal to the pagesize,
         *  3 sectors
         *  starting at NVS_PARTITION_OFFSET
         */
        fs.flash_device = NVS_PARTITION_DEVICE;
        if (!device_is_ready(fs.flash_device)) {
            printk("Flash device %s is not ready\n", fs.flash_device->name);
            return 0;
        }
        fs.offset = NVS_PARTITION_OFFSET;
        rc = flash_get_page_info_by_offs(fs.flash_device, fs.offset, &info);
        if (rc) {
            printk("Unable to get page info\n");
            return 0;
        }
        fs.sector_size = info.size;
        fs.sector_count = 3U;

        rc = nvs_mount(&fs);
        if (rc) {
            printk("Flash Init failed\n");
            return 0;
        }

        /* 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);
        }
        /* KEY_ID is used to store a key, lets see if we can read it from flash
         */
        rc = nvs_read(&fs, KEY_ID, &key, sizeof(key));
        if (rc > 0) { /* item was found, show it */
            printk("Id: %d, Key: ", KEY_ID);
            for (int n = 0; n < 8; n++) {
                printk("%x ", key[n]);
            }
            printk("\n");
        } else   {/* item was not found, add it */
            printk("No key found, adding it at id %d\n", KEY_ID);
            key[0] = 0xFF;
            key[1] = 0xFE;
            key[2] = 0xFD;
            key[3] = 0xFC;
            key[4] = 0xFB;
            key[5] = 0xFA;
            key[6] = 0xF9;
            key[7] = 0xF8;
            (void)nvs_write(&fs, KEY_ID, &key, sizeof(key));
        }
        /* RBT_CNT_ID is used to store the reboot counter, lets see
         * if we can read it from flash
         */
        rc = nvs_read(&fs, RBT_CNT_ID, &reboot_counter, sizeof(reboot_counter));
        if (rc > 0) { /* item was found, show it */
            printk("Id: %d, Reboot_counter: %d\n",
                RBT_CNT_ID, reboot_counter);
        } else   {/* item was not found, add it */
            printk("No Reboot counter found, adding it at id %d\n",
                   RBT_CNT_ID);
            (void)nvs_write(&fs, RBT_CNT_ID, &reboot_counter,
                  sizeof(reboot_counter));
        }
        /* STRING_ID is used to store data that will be deleted,lets see
         * if we can read it from flash, since we don't know the size read the
         * maximum possible
         */
        rc = nvs_read(&fs, STRING_ID, &buf, sizeof(buf));
        if (rc > 0) {
            /* item was found, show it */
            printk("Id: %d, Data: %s\n",
                STRING_ID, buf);
            /* remove the item if reboot_counter = 10 */
            if (reboot_counter == 10U) {
                (void)nvs_delete(&fs, STRING_ID);
            }
        } else   {
            /* entry was not found, add it if reboot_counter = 0*/
            if (reboot_counter == 0U) {
                printk("Id: %d not found, adding it\n",
                STRING_ID);
                strcpy(buf, "DATA");
                (void)nvs_write(&fs, STRING_ID, &buf, strlen(buf) + 1);
            }
        }

        /* LONG_ID is used to store a larger dataset ,lets see if we can read
         * it from flash
         */
        rc = nvs_read(&fs, LONG_ID, &longarray, sizeof(longarray));
        if (rc > 0) {
            /* item was found, show it */
            printk("Id: %d, Longarray: ", LONG_ID);
            for (int n = 0; n < sizeof(longarray); n++) {
                printk("%x ", longarray[n]);
            }
            printk("\n");
        } else   {
            /* entry was not found, add it if reboot_counter = 0*/
            if (reboot_counter == 0U) {
                printk("Longarray not found, adding it as id %d\n",
                       LONG_ID);
                for (int n = 0; n < sizeof(longarray); n++) {
                    longarray[n] = n;
                }
                (void)nvs_write(
                    &fs, LONG_ID, &longarray, sizeof(longarray));
            }
        }

        cnt = 5;
        while (1) {
            k_msleep(SLEEP_TIME);
            if (reboot_counter < MAX_REBOOT) {
                if (cnt == 5) {
                    /* print some history information about
                     * the reboot counter
                     * Check the counter history in flash
                     */
                    printk("Reboot counter history: ");
                    while (1) {
                        rc = nvs_read_hist(
                            &fs, RBT_CNT_ID,
                            &reboot_counter_his,
                            sizeof(reboot_counter_his),
                            cnt_his);
                        if (rc < 0) {
                            break;
                        }
                        printk("...%d", reboot_counter_his);
                        cnt_his++;
                    }
                    if (cnt_his == 0) {
                        printk("\n Error, no Reboot counter");
                    } else {
                        printk("\nOldest reboot counter: %d",
                               reboot_counter_his);
                    }
                    printk("\nRebooting in ");
                }
                printk("...%d", cnt);
                cnt--;
                if (cnt == 0) {
                    printk("\n");
                    reboot_counter++;
                    (void)nvs_write(
                        &fs, RBT_CNT_ID, &reboot_counter,
                        sizeof(reboot_counter));
                    if (reboot_counter == MAX_REBOOT) {
                        printk("Doing last reboot...\n");
                    }
                    sys_reboot(0);
                }
            } else {
                printk("Reboot counter reached max value.\n");
                printk("Reset to 0 and exit test.\n");
                reboot_counter = 0U;
                (void)nvs_write(&fs, RBT_CNT_ID, &reboot_counter,
                  sizeof(reboot_counter));
                break;
            }
        }
        return 0;
    }



  •  
    I found if I comment 

    CONFIG_ZIGBEE_SCENES=y
     it works fine

    but I will need that so how can I fix it any idea?
  • Hi,

     

    Thank you for sharing this, I was able to reproduce the scenario.

    The problem is that ZIGBEE_SCENES uses settings, which uses NVS as the backend.

    The application must then setup a specific storage partition that does not overlap with this settings partition. This can be done by setting a dedicated partition, lets name this "second_storage" here for simplicity:

    // Comment out "original" partition name
    //#define NVS_PARTITION       storage_partition
    #define NVS_PARTITION       second_storage

    Then we adjust the flash by placing this in the myproject/pm_static.yml:

    app:
      address: 0x0
      end_address: 0xf3000
      region: flash_primary
      size: 0xf3000
    settings_storage:
      address: 0xfe000
      end_address: 0x100000
      placement:
        align:
          start: 0x1000
        before:
        - end
      region: flash_primary
      size: 0x2000
    sram_primary:
      address: 0x20000000
      end_address: 0x20040000
      region: sram_primary
      size: 0x40000
    zboss_nvram:
      address: 0xf5000
      end_address: 0xfd000
      placement:
        after:
        - app
        align:
          start: 0x1000
      region: flash_primary
      size: 0x8000
    zboss_product_config:
      address: 0xfd000
      end_address: 0xfe000
      placement:
        after:
        - zboss_nvram
      region: flash_primary
      size: 0x1000
    second_storage:
      address: 0xf3000
      end_address: 0xf5000
      placement:
        align:
          start: 0x1000
        before:
        - end
      region: flash_primary
      size: 0x2000
    

    Ran your on a nrf52840dk_nrf52840 board:

     

    *** Booting nRF Connect SDK v2.8.0-a2386bfc8401 ***
    *** Using Zephyr OS v3.7.99-0bc3393fb112 ***
    I: Starting ZBOSS Light Switch example
    I: 3 Sectors of 4096 bytes
    I: alloc wra: 0, bf8
    I: data wra: 0, 280
    Id: 1, Address: 192.168.1.1
    Id: 2, Key: ff fe fd fc fb fa f9 f8 
    Id: 3, Reboot_counter: 120
    Id: 5, Longarray: 0 1 2 3 4 5 6 7 8 9 a b c d e f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 2 
    Reboot counter history: ...120...119...118...117...116...115...114...113...112...111...110...109...108...107...106...105...0
    Oldest reboot counter: 0
    Rebooting in ...5...4...3...2...1
    

    Remember to delete your build folder and regenerate the project when changing the partition layout.

     

    Could you try this and report back?

     

    Kind regards,

    Håkon

Related