External 32MB QSPI NOR Flash fails over 0x1800000 (24 MB)

dear all,

We are fighting with a problem that defied every effort to solve it so far, so we are asking for help. Our custom board is based on the nrf5340 SoC connected via QSPI to an external flash, specifically the mt25qu256 from Micron. Everything works perfectly if we stay in the lower 24 MBytes, but any write operation on address 0x1800000 or higher will silently fail. The driver reports no errors (return code is 0) but the data is not written and a subsequent read gives a series of 0xFFs.

The code runs on sdk 2.7.0 but I also tried v3.0.2 with the same results. This is the devicetree entry:

&qspi {
    status = "okay";
    pinctrl-0 = <&qspi_default>;
    pinctrl-1 = <&qspi_sleep>;
    pinctrl-names = "default", "sleep";
    mt25qu256: mt25qu256@0 {
        compatible = "nordic,qspi-nor";
        reg = <0>;
        writeoc = "pp4io";
        readoc = "read4o";
        // requires-ulbpr; // Is this needed?
        sck-frequency = <DT_SIZE_M(48)>;
        jedec-id = [20 bb 19];
        size = <DT_SIZE_M(256)>; // bits, = 32 MiB
        has-dpd;
        t-enter-dpd = <10000>; // Chek value, this was taken from a different device
        t-exit-dpd = <35000>; // Chek value, this was taken from a different device
        enter-4byte-addr = <0xB7>; // Enter 4 byte command
        address-size-32; // Force address size to 32 bit
        partitions {
            compatible = "fixed-partitions";
            #address-cells = <1>;
            #size-cells = <1>;

            littlefs_partition: littlefs_partition@0 {
                label = "external_flash";
                reg = <0x00000000 0x01800000>;
                // reg = <0x00000000 0x02000000>;
            };
        };
    };
};
And this is the relevant snippet of pm_static.yml

external_flash:
  device: MT25QU256
  address: 0x00000000
  size:    0x02000000       # 32 MiB
  region:  external_flash
I tried measuring the erase operation and noted that it seems to be much faster (half of the time more or less) after 24 megabytes, this is of course quit suspect.

The code used to test the flash is here:


const int START_BLOCK_TEST = 0;

void test_flash_32m()
{
    int rc = 0;
    uint8_t buffer[SPI_FLASH_SECTOR_SIZE / 4];
    uint8_t check[SPI_FLASH_SECTOR_SIZE / 4];
   
    const int FLASH_ERASE_LARGE_BLOCK_SIZE = 64 * 1024;

    memset(check, 0xFF, sizeof(check));

    printk("Testing flash, please be patient it will take a while...\n");
   
    unsigned int num_sectors = 0x2000000 / FLASH_ERASE_LARGE_BLOCK_SIZE;
    unsigned long time = k_uptime_get();
    for(size_t i = 384; i < 0x2000000 / (64 * 1024); i++) {
        size_t block_address =  i * FLASH_ERASE_LARGE_BLOCK_SIZE;
        rc += flash_erase(qspi_flash, block_address, FLASH_ERASE_LARGE_BLOCK_SIZE);
        // Check pattern
        for(int j=0; j < 4 * FLASH_ERASE_LARGE_BLOCK_SIZE / SPI_FLASH_SECTOR_SIZE; j++) {
            size_t address = block_address + j * SPI_FLASH_SECTOR_SIZE / 4;
            rc = flash_read(qspi_flash, address, buffer, sizeof(buffer));
           
            if (memcmp(check, buffer, sizeof(check)) != 0) {
                printk("Flash erase failed at address 0x%X, error %d", address, rc);
                return;
            }
        }
       
        if(i % 8 == 0) {
            printk("Erased block %X, time %u", block_address, k_uptime_get() - time);
            time = k_uptime_get();
            // printk(".\n");
        }
    }
   
    printk("\n");
    printk("Flash erase succeeded, writing test data\n");
   
    // prepare test data
    for(size_t i=0; i < sizeof(check); i++) {
        check[i] = sys_rand8_get();
    }
                   
    num_sectors = 0x2000000 / SPI_FLASH_SECTOR_SIZE; // 8192 blocks

    for(size_t i = START_BLOCK_TEST; i < num_sectors; i++) {
        size_t block_address =  i * SPI_FLASH_SECTOR_SIZE;

        // Write and check pattern
        for(int j=0; j<4; j++) {
            size_t address = block_address + j * SPI_FLASH_SECTOR_SIZE / 4;
            int rcw = flash_write(qspi_flash, address, check, sizeof(check));
            rc = flash_read(qspi_flash, address, buffer, sizeof(buffer));

            if (memcmp(check, buffer, sizeof(check)) != 0) {
                printk("Flash write failed at address 0x%X, error %d", address, rcw);
                return;
            }
            else {
                printk("Flash write successful at address 0x%X", address);
            }
        }

        if(i % 128 == 0) {
            cm_print(".\n");
        }
    }

    printk("\n");
    printk("Flash test succeeded on all 32 MB range\n");
}
Following the driver operation with debugger did not give any clue, to me at least, everything seems to be operating correctly but obviously it does not.
Thank you in advance to anybody that will be able to help.
Best regards
Davide
Parents Reply Children
  • The flash is working in 32 bits addressing mode because the addresses from 16M to 24M (-1) are correctly written to. Up to 0x17FF000 everything works as expected, from 0x1800000 onwards there are no errors but data is never written (and I suspect the erase operation fails too but that cannot be verified since the flash has 0xFFs from factory. If there is something that I can do on my side to debug let me know.

    Did anybody manage to write on a large QSPI? I think so... may be the problem is with my particular device (the Micron 32MB)

    Regards
    Davide

  • Hi Davide,

    The nRF5340 DK has an 8-megabyte external flash and has been tested before. While that is not 32MB, the address that we are having issue with, 0x01800000, is within that range.

    I have been trying to get your code to run on the JESD216 sample, but was still unsuccessful. I lost a lot of time to an insufficient main stack issue, after which I have got trouble getting 32-bit addressing mode to work...

    As for whether the Micron device is the problem, unless you have seen the issue with multiple units and can cross check with another MCU, I am hesitant to make any conclusion.

    I am out of office now, but will return to office next week and resume getting a working test running on the nRF5340 DK. If you have a nRF5340 DK, can you give it a try also? Your test code should work with it.

    Regards,

    Hieu

Related