nr52832 + nRF Connect 1.8.0 + External Flash

Hello Team,

We are interfacing nRF52832 with an external flash for data storage. Could you please point to the right document/link/code reference on how to interface external flash (on SPI) with nRF52832 on nRF Connect SDK 1.8.0?

Thanks!

Parents
  • Hi,

     

    You can try with the zephyr/samples/drivers/spi_flash for instance.

    You will need to add a $my_board.conf file and a $my_board.overlay file. I'm assuming that you're using the nRF52-DK as a basis here.

    The nrf52dk_nrf52832.conf should hold:

    CONFIG_SPI_NOR=y

     

    And the .overlay should hold your spi configuration and the spi-nor device that you have.

    Here's an example on how the nRF9160-DK has setup a SPI-NOR flash overlay:

    https://github.com/nrfconnect/sdk-zephyr/blob/v2.7.99-ncs1-1/boards/arm/nrf9160dk_nrf9160/nrf9160dk_nrf9160_common_0_14_0.dtsi#L42-L65

     

    Pin numbering, device name, and spi instance will differ from your wanted setting.

     

    Kind regards,

    Håkon

  • Thanks, Hakon.

    I just tested our Winbond Flash (W25Q80DV) over SPI with basic read and write using SPI APIs. As I check the datasheet, W25Q80DV supports the JEDEC, does that mean we should be able to use the flash APIs if we configure overlay and conf files as you suggested?

    Thanks!

  • Hi,

     

    Yes, you should if configured correctly.

    I was able to find a smaller variant of this flash here:

    https://github.com/nrfconnect/sdk-zephyr/blob/v2.7.99-ncs1-1/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_common.dts#L135-L155

     

    You'll have to adjust the naming, size, and "jedec-id" to match yours.

     

    Kind regards,

    Håkon

  • Hi Hakon,

    Thank you very much for the reference. It helped and I've setup my flash with it. However, I've a couple of issues. Could you please guide?

    1. Wrong page size info:

    Page size I am getting is: 65536. For W25Q80DV, page size is 256 bytes. Chip size is correct.

    W25Q80DV SPI flash testing
    ==========================
    Using W25Q80DV, chip size: 1048576 bytes (page: 65536)

    2. Fails to get the Device in first attempt.

    When I flash the device for the first time using JTAG (I use VS Code so whenever I flash the program it resets the chip), it always fail to get the device.

    W25Q80DV SPI flash testing
    ==========================
    SPI flash driver W25Q80DV was not found!

    However, if I reset my device using reset button it gets the driver and can write/read the chip.

    W25Q80DV SPI flash testing
    ==========================
    Using W25Q80DV, chip size: 1048576 bytes (page: 65536)
    
    Test 1: Flash erase
    Flash erase succeeded!
    
    Test 2: Flash write
    Attempting to write 4 bytes
    Data read matches data written. Good!!

    Reference:

    Overlayfile

    arduino_spi: &spi2 {
    	compatible = "nordic,nrf-spi";
    	status = "okay";
    	sck-pin = <27>;
    	mosi-pin = <26>;
    	miso-pin = <28>;
    	cs-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>;
    
    	w25q80dv: w25q80dv@0 {
    		compatible = "jedec,spi-nor";
    		label = "W25Q80DV";
    		reg = <0>;
    		spi-max-frequency = <40000000>;
    		//wp-gpios = <&gpio0 8 GPIO_ACTIVE_LOW>;
    		//hold-gpios = <&gpio0 10 GPIO_ACTIVE_LOW>;
    		size = <0x800000>;
    		has-dpd;
    		t-enter-dpd = <3000>;
    		t-exit-dpd = <30000>;
    		jedec-id = [ef 40 14];
    	};
    };
    

    SPI flash test Code: (ref: samples/drivers/spi_flash)

    void spi_test_flash_api(void)
    {
    #define FLASH_NAME "W25Q80DV"
    #define FLASH_TEST_REGION_OFFSET (0xff000)
    #define FLASH_SECTOR_SIZE (4096)
    #define FLASH_DEVICE DT_LABEL(DT_INST(0, jedec_spi_nor))
    
            const uint8_t expected[] = {0x55, 0xaa, 0x66, 0x99};
            const size_t len = sizeof(expected);
            uint8_t buf[sizeof(expected)];
            const struct device *flash_dev;
            int rc;
            
            const char *const spiName = "W25Q80DV";
    
            printk("\n" FLASH_NAME " SPI flash testing\n");
    
            printk("==========================\n");
    
            flash_dev = device_get_binding(FLASH_NAME);
            if (!flash_dev)
            {
                    printk("SPI flash driver %s was not found!\n",
                           FLASH_NAME);
                    return;
            }
    
    #ifdef CONFIG_FLASH_PAGE_LAYOUT
            struct flash_pages_info pages_info;
            size_t page_count, chip_size;
            page_count = flash_get_page_count(flash_dev);
            (void)flash_get_page_info_by_idx(flash_dev, 0, &pages_info);
            chip_size = page_count * pages_info.size;
            printk("Using %s, chip size: %u bytes (page: %u)\n",
                   FLASH_NAME, chip_size, pages_info.size);
    
    #endif
    
            /* Write protection needs to be disabled before each write or
             * erase, since the flash component turns on write protection
             * automatically after completion of write and erase
             * operations.
             */
            printk("\nTest 1: Flash erase\n");
    
            rc = flash_erase(flash_dev, FLASH_TEST_REGION_OFFSET,
                             FLASH_SECTOR_SIZE);
            if (rc != 0)
            {
                    printk("Flash erase failed! %d\n", rc);
            }
            else
            {
                    printk("Flash erase succeeded!\n");
            }
    
    
            printk("\nTest 2: Flash write\n");
            printk("Attempting to write %zu bytes\n", len);
            rc = flash_write(flash_dev, FLASH_TEST_REGION_OFFSET, expected, len);
            if (rc != 0)
            {
                    printk("Flash write failed! %d\n", rc);
                    return;
            }
    
            memset(buf, 0, len);
            rc = flash_read(flash_dev, FLASH_TEST_REGION_OFFSET, buf, len);
            if (rc != 0)
            {
                    printk("Flash read failed! %d\n", rc);
                    return;
            }
    
            if (memcmp(expected, buf, len) == 0)
            {
                    printk("Data read matches data written. Good!!\n");
            }
            else
            {
                    const uint8_t *wp = expected;
                    const uint8_t *rp = buf;
                    const uint8_t *rpe = rp + len;
    
                    printk("Data read does not match data written!!\n");
                    while (rp < rpe)
                    {
                            printk("%08x wrote %02x read %02x %s\n",
                                   (uint32_t)(FLASH_TEST_REGION_OFFSET + (rp - buf)),
                                   *wp, *rp, (*rp == *wp) ? "match" : "MISMATCH");
                            ++rp;
                            ++wp;
                    }
            }
    }
    

    Thanks!

Reply
  • Hi Hakon,

    Thank you very much for the reference. It helped and I've setup my flash with it. However, I've a couple of issues. Could you please guide?

    1. Wrong page size info:

    Page size I am getting is: 65536. For W25Q80DV, page size is 256 bytes. Chip size is correct.

    W25Q80DV SPI flash testing
    ==========================
    Using W25Q80DV, chip size: 1048576 bytes (page: 65536)

    2. Fails to get the Device in first attempt.

    When I flash the device for the first time using JTAG (I use VS Code so whenever I flash the program it resets the chip), it always fail to get the device.

    W25Q80DV SPI flash testing
    ==========================
    SPI flash driver W25Q80DV was not found!

    However, if I reset my device using reset button it gets the driver and can write/read the chip.

    W25Q80DV SPI flash testing
    ==========================
    Using W25Q80DV, chip size: 1048576 bytes (page: 65536)
    
    Test 1: Flash erase
    Flash erase succeeded!
    
    Test 2: Flash write
    Attempting to write 4 bytes
    Data read matches data written. Good!!

    Reference:

    Overlayfile

    arduino_spi: &spi2 {
    	compatible = "nordic,nrf-spi";
    	status = "okay";
    	sck-pin = <27>;
    	mosi-pin = <26>;
    	miso-pin = <28>;
    	cs-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>;
    
    	w25q80dv: w25q80dv@0 {
    		compatible = "jedec,spi-nor";
    		label = "W25Q80DV";
    		reg = <0>;
    		spi-max-frequency = <40000000>;
    		//wp-gpios = <&gpio0 8 GPIO_ACTIVE_LOW>;
    		//hold-gpios = <&gpio0 10 GPIO_ACTIVE_LOW>;
    		size = <0x800000>;
    		has-dpd;
    		t-enter-dpd = <3000>;
    		t-exit-dpd = <30000>;
    		jedec-id = [ef 40 14];
    	};
    };
    

    SPI flash test Code: (ref: samples/drivers/spi_flash)

    void spi_test_flash_api(void)
    {
    #define FLASH_NAME "W25Q80DV"
    #define FLASH_TEST_REGION_OFFSET (0xff000)
    #define FLASH_SECTOR_SIZE (4096)
    #define FLASH_DEVICE DT_LABEL(DT_INST(0, jedec_spi_nor))
    
            const uint8_t expected[] = {0x55, 0xaa, 0x66, 0x99};
            const size_t len = sizeof(expected);
            uint8_t buf[sizeof(expected)];
            const struct device *flash_dev;
            int rc;
            
            const char *const spiName = "W25Q80DV";
    
            printk("\n" FLASH_NAME " SPI flash testing\n");
    
            printk("==========================\n");
    
            flash_dev = device_get_binding(FLASH_NAME);
            if (!flash_dev)
            {
                    printk("SPI flash driver %s was not found!\n",
                           FLASH_NAME);
                    return;
            }
    
    #ifdef CONFIG_FLASH_PAGE_LAYOUT
            struct flash_pages_info pages_info;
            size_t page_count, chip_size;
            page_count = flash_get_page_count(flash_dev);
            (void)flash_get_page_info_by_idx(flash_dev, 0, &pages_info);
            chip_size = page_count * pages_info.size;
            printk("Using %s, chip size: %u bytes (page: %u)\n",
                   FLASH_NAME, chip_size, pages_info.size);
    
    #endif
    
            /* Write protection needs to be disabled before each write or
             * erase, since the flash component turns on write protection
             * automatically after completion of write and erase
             * operations.
             */
            printk("\nTest 1: Flash erase\n");
    
            rc = flash_erase(flash_dev, FLASH_TEST_REGION_OFFSET,
                             FLASH_SECTOR_SIZE);
            if (rc != 0)
            {
                    printk("Flash erase failed! %d\n", rc);
            }
            else
            {
                    printk("Flash erase succeeded!\n");
            }
    
    
            printk("\nTest 2: Flash write\n");
            printk("Attempting to write %zu bytes\n", len);
            rc = flash_write(flash_dev, FLASH_TEST_REGION_OFFSET, expected, len);
            if (rc != 0)
            {
                    printk("Flash write failed! %d\n", rc);
                    return;
            }
    
            memset(buf, 0, len);
            rc = flash_read(flash_dev, FLASH_TEST_REGION_OFFSET, buf, len);
            if (rc != 0)
            {
                    printk("Flash read failed! %d\n", rc);
                    return;
            }
    
            if (memcmp(expected, buf, len) == 0)
            {
                    printk("Data read matches data written. Good!!\n");
            }
            else
            {
                    const uint8_t *wp = expected;
                    const uint8_t *rp = buf;
                    const uint8_t *rpe = rp + len;
    
                    printk("Data read does not match data written!!\n");
                    while (rp < rpe)
                    {
                            printk("%08x wrote %02x read %02x %s\n",
                                   (uint32_t)(FLASH_TEST_REGION_OFFSET + (rp - buf)),
                                   *wp, *rp, (*rp == *wp) ? "match" : "MISMATCH");
                            ++rp;
                            ++wp;
                    }
            }
    }
    

    Thanks!

Children
  • embeddedER said:

    Thank you very much for the reference. It helped and I've setup my flash with it. However, I've a couple of issues. Could you please guide?

    1. Wrong page size info:

    Page size I am getting is: 65536. For W25Q80DV, page size is 256 bytes. Chip size is correct.

    I believe the erase sector on your flash is 4k aligned?

    Could you try adding this config?

    CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096

    embeddedER said:

    2. Fails to get the Device in first attempt.

    When I flash the device for the first time using JTAG (I use VS Code so whenever I flash the program it resets the chip), it always fail to get the device.

    Since it works after a reset, it indicates that everything else is running as intended, meaning that the physical setup etc is OK.

    Could you try setting the page size to 4k and see if this issue still happens?

     

    Kind regards,

    Håkon

Related