Skip to content

nrf_qspi_nor: Inconsistent state of HOLD and WP for QSPI command execution causes hang on startup for some flash chips #46285

@jeremyherbert

Description

@jeremyherbert

Describe the bug

In drivers/flash/nrf_qspi_nor.c, the function qspi_send_cmd by default sets the IO2 and IO3 pins on the QSPI bus to high:

	nrf_qspi_cinstr_conf_t cinstr_cfg = {
		.opcode = cmd->op_code,
		.length = xfer_len,
		.io2_level = true,
		.io3_level = true,
		.wipwait = false,
		.wren = wren,
	};

ref:

.io2_level = true,

Later in this file, the function qspi_device_uninit calls the function nrfx_qspi_mem_busy_check to execute a status register read on the flash to see if the WIP bit is set. It then waits in an idle loop while the bit is set

qspi_device_uninit:

while (nrfx_qspi_mem_busy_check() != NRFX_SUCCESS) {

nrfx_qspi_mem_busy_check: https://github.com/NordicSemiconductor/nrfx/blob/55305292a2a8e4149869951451311452f4566e9a/drivers/src/nrfx_qspi.c#L478

The problem I have found is that in this nrfx function, the qspi configuration is initialised to have io2_level and io3_level as false through the NRFX_QSPI_DEFAULT_CINSTR macro which is defined as such:

/** @brief QSPI custom instruction helper with the default configuration. */
#define NRFX_QSPI_DEFAULT_CINSTR(opc, len) \
{                                          \
    .opcode    = (opc),                    \
    .length    = (len),                    \
    .io2_level = false,                    \
    .io3_level = false,                    \
    .wipwait   = false,                    \
    .wren      = false                     \
}

here: https://github.com/NordicSemiconductor/nrfx/blob/55305292a2a8e4149869951451311452f4566e9a/drivers/include/nrfx_qspi.h#L124

--

I have discovered this because I am working on a device which has a Puya Semiconductor P25Q16H which appears to have an undocumented issue where the HOLD pin behaviour is unusual - I am not exactly sure where this behaviour is standardised, but in most devices HOLD pin is supposed to be ignored for status commands I think. However, for this device it is not, so the MISO pin is held high when HOLD is low, causing the status register to always read as 0xFF. The LSB of this read is the Write In Progress (WIP) bit, and so the qspi_device_uninit hangs forever because the device never reads the WIP bit as 0.

My suggestions to fix the problem are (either would solve this):

  1. Remove calls to nrfx_qspi_mem_busy_check and instead call qspi_send_cmd with the ReaD Status Register (RDSR) command
  2. Change nrfx library to default both IO2 and IO3 lines to high

Expected behavior
QSPI peripheral should hold IO2 and IO3 high (ie, deasserted) during all QSPI operations that do not use those pins.

Additional context
I patched my local nrfx library to set IO2 and IO3 to high in NRFX_QSPI_DEFAULT_CINSTR and the P25Q16H flash chip started working fine. I ran the samples/subsys/fs/littlefs sample and everything worked great.

The board is a custom one (seeedstudio_xiao_ble with the nrf52840 and P25Q16H)

Metadata

Metadata

Assignees

Labels

area: QSPIQuad SPIbugThe issue is a bug, or the PR is fixing a bugplatform: nRFNordic nRFxpriority: lowLow impact/importance bug

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions