9160dk external flash operation address length issue

The default setting for the external flash chip of 9160dk appears to be 64m, but when used, the log display only shows 8m, and only the part within 8m can be used,

mx25r64: mx25r6435f@1 {
		compatible = "jedec,spi-nor";
		status = "disabled";
		reg = <1>; 
		spi-max-frequency = <8000000>;
		jedec-id = [c2 28 17];
		sfdp-bfp = [
			e5 20 f1 ff  ff ff ff 03  44 eb 08 6b  08 3b 04 bb
			ee ff ff ff  ff ff 00 ff  ff ff 00 ff  0c 20 0f 52
			10 d8 00 ff  23 72 f5 00  82 ed 04 cc  44 83 48 44
			30 b0 30 b0  f7 c4 d5 5c  00 be 29 ff  f0 d0 ff ff
		size = <67108864>;
		t-enter-dpd = <10000>;
		t-exit-dpd = <35000>;
	<inf> spi_nor: mx25r6435f@1: 8 MiBy flash

Then I set the chip size to 8 times that of 64m in order to use all 64m of flash properly

&mx25r64 {
    status = "okay";
	size = <0x20000000>;
    sfdp-bfp = [
			e5 20 f1 ff  ff ff ff 1f  44 eb 08 6b  08 3b 04 bb
			ee ff ff ff  ff ff 00 ff  ff ff 00 ff  0c 20 0f 52
			10 d8 00 ff  23 72 f5 00  82 ed 04 cc  44 83 48 44
			30 b0 30 b0  f7 c4 d5 5c  00 be 29 ff  f0 d0 ff ff

<inf> spi_nor: mx25r6435f@1: 64 MiBy flash

But when I want to read and write data in the 16-64m area (i.e. the address exceeds 3 bytes), it cannot correctly recognize the 4-byte address, but instead truncates the lower 24 bits as the address for reading and writing, resulting in the actual read and write address being different from the one I want to read and write,just like this

char test_data[20];
memset(test_data, 0, sizeof(test_data));
strcpy(test_data, "aaabbbccdd987");

flash_write(flash_dev, 0x1800012, test_data, sizeof(test_data));

I found several variables related to 4-byte addresses in spi_nor.c, but did not find where the problem lies

Parents Reply
  • Hi Hieu

    I am currently debugging the external flash in order to use other external flash chips on our product. I thought using the flash driver directly would also work properly.

    This is the partition report and config file


    What you said about NVS, I took a look and it's a file system similar to LFS, right? If I use NVS, I should mount it to an external flash and use NVS just like using LFS, so I don't need to use a flash driver, right?

  • Hi llly,

    llly said:
    What you said about NVS, I took a look and it's a file system similar to LFS, right? If I use NVS, I should mount it to an external flash and use NVS just like using LFS, so I don't need to use a flash driver, right?

    NVS does somewhat the same job. Instead of storing files with path and content, it just stores elements with ID and content.

    I meant to link the documentation but ended up linking the sample last time. Here is NVS documentation: Non-Volatile Storage (NVS) (nordicsemi.com).

    As you might have known, you can write to a specific flash address, but you cannot clear a small flash region. You need to clear the entire flash page. This makes updating records a little inconvenient.

    NVS is already setup to take care of that and was also implemented with attention to wear leveling. Of course, the wear leveling is only in the region allocated to NVS.

    Would you like to give it a try? Or would you still want to pursue what is wrong with the flash API? If NVS works, I propose putting the flash API topic in low priority right now, as we are quite overloaded at the moment, and that any additional work would slow us from helping you with other questions.

  • Hi Hieu

    I have confirmed that we only need to use Littlefs. After loading LFS in external flash, I want to try saving a file larger than 16mb to test if LFS will encounter the problem of not being able to correctly handle 4-byte addresses (the maximum value corresponding to 3-byte addresses is 16mb) as mentioned earlier. But I found this not feasible because the flash write speed is too slow. I repeatedly write data in a loop and waited for a long time before writing tens of kb. If I want to write 16mb, I may not be able to do so for a day.

    Can you help me test if I still encounter the problem of 4-byte addresses being treated as 3-byte addresses when mounting LFS in external flash? Or my method is incorrect, is there a better testing method? In addition, I am not sure if my operation of changing the external flash capacity to 64MB is correct. I have shown my modification steps above. Perhaps these are two issues, but if necessary, I can issue a new ticket.

  • I have a new discovery.

    After loading LFS from an external flash, I used a logic analyzer to capture SPI data and printed SPI addresses through serial ports in the code. Upon comparison, I found that the addresses in the code were 4 bytes, but the SPI data still showed 3 bytes. It seems that even with the use of a file system, there is still an address length issue

  • I have determined that the issue comes from loading the external flash device's capability into the driver.

    I am honestly not an expert in it, and this is just my rough understanding. I will try to only write about what I am relatively sure of, but I hope you can help me test something to see if it works.

    The external flash capability is stored in Serial Flash Discoverable Parameters (SFDP). There are two Kconfigs that are relevant to the way the flash driver loads the SFDP: CONFIG_FLASH_JESD216_API and CONFIG_SPI_NOR_SFDP.

    CONFIG_FLASH_JESD216_API enable some Flash APIs, one of which is flash_sfdp_read(). It loads the SFDP from the external flash device when called. By default, this is disabled.
    --> Solution 1: enable CONFIG_FLASH_JESD216_API and call flash_sfdp_read() during initialization.

    As for CONFIG_SPI_NOR_SFDP, by default, it is set to CONFIG_SPI_NOR_SFDP_MINIMAL, synthesize a SFDP based on just the jedec-id and size property of the external flash node on the Devicetree (DT). However, this also defaults the flash address mode to 24-bit, and expects that if 32-bit is needed, then the external flash node has to have the property enter-4byte-addr set properly. I haven't looked into how the value should be derived though...

    --> Solution 2: set the enter-4byte-addr property in the external flash node.

    CONFIG_SPI_NOR_SFDP can also be set to CONFIG_SPI_NOR_SFDP_DEVICETREE, which loads the SFDP from the sfdp-bfp of the external flash DT node. This property is already set for the external flash on the nRF9160 DK board file, so it should work.


    Finally, CONFIG_SPI_NOR_SFDP can also be set to CONFIG_SPI_NOR_SFDP_RUNTIME, which loads SFDP from the external flash device itself during runtime. 


    I realize that I am violating the Occam's Razor principle a lot here, but I figure the information might come in handy eventually for readers with different external flash device, and another reason is that I couldn't test any of them at the moment.

    Please consider which solution best suit you.


  • Hi Hieu

    I am currently using Solution 3, and I have tested Solution 4. The information it reads from the flash shows that it is an 8m flash, so I cannot test the 4-byte address. For Solution 2, I couldn't find a way to set a 4-byte address. For Solution 1, I did not conduct any testing and I believe the result should be the same as Solution 4.

    I think Solution 4 is the most convenient solution because it directly reads information from the flash, and replacing the flash chip does not require much modification. But I don't know why the code in spi_nor. c sets the flash size to one eighth of the read size. The flash on 9160dk has 64m, but can only use 8m. I connected a 32m flash externally, which shows that only 4m can be used