Is it possible to access a QSPI flash from nrf5340 as 'direct' memory access?

I have a custom board, with nrf5340 and a external QPSI flash (this is exactly like the nrf5340 DK).

I use the external flash for multiple partitions (mcuboot slots, FAT-FS file system, etc), and would like to use a partition as a "memory mapped file system" ie have blocks of data in the flash partition and allow code to access them as though it was data in the internal flash (ie just with a pointer in the 0x100000000 region). This lets me use this const data as though it was in my main application build but without having to use up space in the (limited) internal nrf5340 flash...

I can use the flash_open/read/write()  interface driver api to set up the partition data just fine.

However, when the code attempts to access the memory space directly (as a pointer access for example), it faults...

eg:

// the QPSI flash should be mapped at 0x10000000 and my partition starts at offset 0x780000 in my pm_static.yml

uint32_t* aptr = (uint32_t*)(0x10000000 + 0x780000); 

uint32_t val = *aptr;    // fault!

Your AI says there is no DTS or linker magic required to let the code read from this area, and I have checked that the flash initialisation priority (41 for the driver and 50 for flash) mean it should be initialised before my application starts running (priority 90).

The code also accesses the partition with flash_area_open() so that it can write to it via this api : could this cause an issue?

thanks!

Brian

  • not explicitly, but it has

    #define CONFIG_XIP 1
    in the autoconf.h si I guess yes!
    Also, I use this external flash for the nrf70 firmware which I think requires XIP to be enabled?
  • Does this mean that XIP must be enabled to allow this kind of read access? 

    I don't think it is, as if I enable it programmatically:

    nrf_qspi_nor_xip_enable(_ctx.flash_device, true);
    then all the QPSI flash accesses FAIL due to the ERRATA_159 workaround, which requires a specific HCLK (192MHz) and processor clock (64MHz) to access the QSPI...
    This implies that accessing the QSPI flash for XIP or data storage will not let me run at 128MHz???
    that shows such fast access?!
    What is the correct setup to get both performance and extended data storage from the QSPI?
  • BrianW said:
    Also, I use this external flash for the nrf70 firmware which I think requires XIP to be enabled?

    Been a while since I looked into that, but from my memory it depends on what mode you choose for the firmware patch. https://nrfconnectdocs.nordicsemi.com/ncs/latest/nrf/app_dev/device_guides/nrf70/fw_patches_ext_flash.html mentions two methods, one with xip and one with non-xip. I assume that you're using https://nrfconnectdocs.nordicsemi.com/ncs/latest/kconfig/index.html#SB_CONFIG_WIFI_PATCHES_EXT_FLASH_XIP since it enables it in autoconf.

    BrianW said:
    Does this mean that XIP must be enabled to allow this kind of read access? 

    That is at least my understanding of it. 

    The nRF5340 can read QSPI flash through a pointer at 0x10000000, but only while the QSPI peripheral is held in XIP mode. Errata 159 also requires the CPU clock (HCLK) to be 64 MHz for every QSPI transfer, and XIP fetches count. So with the workaround in place, you can't memory-map the flash and keep the CPU at 128 MHz at the same time. Without XIP, nrf_qspi_nor.c deactivates QSPI after every API call  qspi_release() calls nrfx_qspi_deactivate()). With PM it can also send the flash into deep power-down and uninit QSPI. A pointer read in that state gives a bus fault.

    I tried mirroring your setup with a nRF5340DK + 7002-EK shield, Wi-Fi fw patch in external flash and to read from the same range of addresses as you did. 

    Pointer reads into external flash work when all three of these are true:

    1. XIP is enabled with nrf_qspi_nor_xip_enable(dev, true) before the pointer read, and stays enabled while the pointer is used.
    2. The errata 43 workaround is turned back on in the application CMakeLists.txt.
    3. The CPU runs at 64 MHz while XIP is enabled.

    With these, pointer reads and flash_area_read() both returned correct data in every test, including after XIP was turned off again. For 128 MHz, also turn on the errata 159 workaround and never raise the clock while XIP is on.

    # Application CMakeLists.txt, after find_package(Zephyr) zephyr_compile_definitions(NRF53_ERRATA_43_ENABLE_WORKAROUND=1) zephyr_compile_definitions(NRF53_ERRATA_159_ENABLE_WORKAROUND=1) # only needed for 128 MHz

    nrf_qspi_nor_xip_enable(qspi_dev, true); uint32_t val = *(const volatile uint32_t *)(0x10000000 + 0x780000); nrf_qspi_nor_xip_enable(qspi_dev, false); /* when pointer access is done */


    Might be a bit hard to read the matrix below, but these are the configurations I tested on bench.

    TL;DR: XIP is required for pointer read and the order of enabling vs reading is important.

    I can share the heavily LLM assisted bench sample I used to validate if you wish to test it on your end as well. Happy to be challenged if you think I'm wrong on the XIP requirement + CLK frequency + order of enabling peripheral vs reading.

    Kind regards,
    Andreas

Related