Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Accessing QSPI flash simultaneously in nRF52840 program and as a USB block device

Has anyone (tried to) simultaneously use the same QSPI Flash memory directly from an nRF52840 program and as a USB block device?

We have both functions running in the same hardware when used alternatively: can either read/write the QSPI memory with nrf_drv_qspi_init(), nrfx_qspi_read() and nrfx_qspi_write or disable that and use the same memory as a USB MSC block device with NRF_BLOCK_DEV_QSPI_DEFINE(), etc.

I'm trying to figure out if it is worth the effort to try to combine these. Probably should

  • Let the block device library initialize the QSPI and the flash memory
  • Starting read/write operations (externally to the block device) could be quite simple - may need to fetch come pointer from inside the block device library
  • Should add a flag showing if a read/write is from "our app" or "block device", modify the QSPI event handler to pass the read/write results accordingly either to the block device library or to our own code.

I suppose this is not possible without modifying the block device library code? But the modifications needed might be reasonably small?

Setup: nRF52840 on our own board, MX25R6435F, SDK16.0, SoftDevice 7.0.1, FreeRTOS.

Pertti

  • This functionality could have been relatively easy to add if the QSPI handler would get a pointer to the RAM address used in the operation that completed. We could just check from the buffer used what type of event handling is required. But the event handler does not even know wast it a read, write or erase operation that completed.

    Is it possible to read that information directly from the QSPI peripheral registers: would the registers READ.DST and WRITE.SRC of QSPI be always valid at the time of the competition handler call? Or would it require some mutex that prevents another QSPI command from being issued before the event handling completes?

    Is it possible to read from the QSPI registers the type of the operation (a read, write or erase) that completed? The SDK block device code seems to keep track of that in it's on structs.

  • Hi Pertti

    Sorry about the delayed reply, but I had to forward this issue to our development team in hopes of a good and exact reply to your requests, as I don't know if this has been tried/done before or if it will be possible. I still haven't heard back, but I will update you as soon as I hear something. Thank you for your patience.

    Best regards,

    Simon

  • No problem. It will be interesting to hear an insider opinion on how to best implement this.

    I managed to write a test version for the double functionality. We need to build some test cases on top of it and test the robustness of the implementation. In an initial test, it seems to be working - tested with reading >10MB data from QSPI over USB while the other functions seemed to work as before.

    The current implementation depends on FreeRTOS and is somewhat dependent on our other code framework. The basic method:

    1. Bypass the QSPI init calls in nrfx_block_dev_qspi.c if QSPI has been already initialized from our own code
    2. Added a function call that is called always before QSPI read/write/erase, both in our modified copy of nrfx_block_dev_qspi.c and our own QSPI access functions
    3. The function takes a "mutex" semaphore and sets a variable marking the caller - which QSPI handler should be called when a QSPI event occurs
    4. The QSPI event handler takes note of which event handler needs to be called, then releases the above semaphore. Makes a call to the handler that is waiting for the QSPI task completion.
    5. Modified the block device event handler to use a fixed reference to m_active_qspi_dev instead of *p_context when in this dual-mode
    6. The bit tricky part in the FreeRTOS context was setting the semaphores right (we have two other related semaphores in addition to the above). The same QSPI read/write functions get called both in ISR context and non-ISR. That needs some planning in the FreeRTOS setup to get it working right with "binary" type (not "mutex") semaphores. 

    The current implementation reads about 215000 bytes/s from USB MSC with Mac command line dd-command. That is about half of the speed I recall seeing when running as a block device only. A not too bad penalty from the added semaphores - good enough for the current need.

Related