Problems with QSPI device initialization

Hi all,
My project uses nRF52840 microcontroller and nRF5_SDK_17.1.0.
My project uses AT25SF161B flash memory and The little filesystem to store data and everything works fine.
Now I need to use S25FL064L flash memory and I have some problems.

This is my QSPI configuration:

#define QSPI_ENABLED 1
#define QSPI_CONFIG_SCK_DELAY 1
#define QSPI_CONFIG_XIP_OFFSET 0
#define QSPI_CONFIG_READOC 4		// <4=> Read4IO 
#define QSPI_CONFIG_WRITEOC 2		// <2=> PP4O 
#define QSPI_CONFIG_ADDRMODE 0		// <0=> 24bit 
#define QSPI_CONFIG_MODE 0			// <0=> Mode 0 
#define QSPI_CONFIG_FREQUENCY 15	// <15=> 32MHz/16

#define BSP_QSPI_SCK_PIN    	    	NRF_GPIO_PIN_MAP(0, 19)
#define BSP_QSPI_CSN_PIN    	    	NRF_GPIO_PIN_MAP(0, 17)
#define BSP_QSPI_IO0_PIN    	    	NRF_GPIO_PIN_MAP(0, 20)
#define BSP_QSPI_IO1_PIN    	    	NRF_GPIO_PIN_MAP(0, 21)
#define BSP_QSPI_IO2_PIN    	    	NRF_GPIO_PIN_MAP(0, 22)
#define BSP_QSPI_IO3_PIN    	    	NRF_GPIO_PIN_MAP(0, 23)

The first problem is that sometimes the QSPI device initialization fails, that is, the instruction

err_code = nrf_drv_qspi_init(&config, NULL, NULL);
APP_ERROR_CHECK(err_code); 

returns the following error:

<error> app: ERROR 13 [NRF_ERROR_TIMEOUT] at C:\[my project folder]\Flash.cpp:266
PC at: 0x0004ED0B
<error> app: End of error report

The problem persists despite numerous restart commands. To clear the error, you must remove power from the microcontroller.

If the QSPI device initialization is OK, the second problem occurs when executing the nrf_drv_qspi_read or nrf_drv_qspi_write function. What happens is that the firmware gets stuck inside the while loop of the qspi_task_perform function.

static nrfx_err_t qspi_task_perform(nrf_qspi_task_t task)
{
    // Wait for peripheral
    if (m_cb.is_busy)
    {
        return NRFX_ERROR_BUSY;
    }

    nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY);

    if (m_cb.handler)
    {
        m_cb.is_busy = true;
        nrf_qspi_int_enable(NRF_QSPI, NRF_QSPI_INT_READY_MASK);
    }

    nrf_qspi_task_trigger(NRF_QSPI, task);

    if (m_cb.handler == NULL)
    {
        while (!nrf_qspi_event_check(NRF_QSPI, NRF_QSPI_EVENT_READY))   // the firmware gets stuck here
        {};
    }
    return NRFX_SUCCESS;
}

Can anyone help me understand and solve my problems?

Below is the code to initialize the memory

uint8_t Configure(void)
{
	uint8_t jedecId[3];
	uint32_t err_code;

	nrf_qspi_cinstr_conf_t cinstr_cfg = {
		.opcode    = 0x66,
		.length    = NRF_QSPI_CINSTR_LEN_1B,
		.io2_level = true,
		.io3_level = true,
		.wipwait   = true,
		.wren      = true
	};

	// Send reset enable
	err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);
	APP_ERROR_CHECK(err_code);

	// Send reset command
	cinstr_cfg.opcode = 0x99;
	err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);
	APP_ERROR_CHECK(err_code);

	// Read JEDEC ID
	cinstr_cfg.opcode = READ_JEDEC_ID;
	cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_4B;
	cinstr_cfg.wren   = false;
	err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, jedecId);
	APP_ERROR_CHECK(err_code);

	FLASH_DEBUG("JEDEC ID: %02X %02X %02X", jedecId[0], jedecId[1], jedecId[2]);

	if (memcmp(jedecId, AT25SF161B_JEDEC_ID, sizeof(jedecId)) == 0)
	{
		// AT25SF161B flash management
		// This part of the code enables communication with 4 data bits.
	}
	else if (memcmp(jedecId, S25FL064L_JEDEC_ID, sizeof(jedecId)) == 0)
	{
		FLASH_DEBUG("S25FL064L flash detected");

		FLASH_SECTOR_SIZE        = 0x10000U;					// 64 kBytes
		FLASH_BLOCK_SIZE         = 0x1000U;						// 4 kBytes

		uint8_t SR1V;
		uint8_t CR1V;
		uint8_t data[2];

		// The code below enables writing the flash.
		
		// Read Status Register 1 (SR1V)
		cinstr_cfg.opcode = 0x05;			    // RDSR1
		cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_2B;
		cinstr_cfg.wren   = false;
		err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, &SR1V);
		APP_ERROR_CHECK(err_code);

		if ((SR1V & 0x02) != 0x02)
		{
			// Write Enable.
			cinstr_cfg.opcode = 0x06;		    // WREN
			cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_1B;
			cinstr_cfg.wren   = true;
			err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);
			APP_ERROR_CHECK(err_code);
		}
		
		// The following code allows communication with 4 bits of data.

		// Read Configuration Register 1 Volatile (CR1V)
		cinstr_cfg.opcode = 0x35;			    // RDCR1
		cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_2B;
		cinstr_cfg.wren   = false;
		err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, &CR1V);
		APP_ERROR_CHECK(err_code);

		if ((CR1V & 0x02) != 0x02)
		{
			data[0] = SR1V | 0x02;
			data[1] = CR1V | 0x02;

			// Write Registers (Status Register 1 and Configuration Register 1)
			cinstr_cfg.opcode = 0x01;		    // WRR
			cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_3B;
			cinstr_cfg.wren = true;
			err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, data, NULL);
			APP_ERROR_CHECK(err_code);
		}
	}
	else
	{
		FLASH_DEBUG("Memory not supported");
		return EXIT_FAILURE;
	}
	return EXIT_SUCCESS;
}

I would like to point out that I currently use a custom electronic board created to host the AT25SF161B flash. In order to mount a S25FL064L flash I had to make a very difficult manual modification because the devices are small (while waiting for the final board that mounts the S25FL064L to arrive).
Can the errors I detect be due to incorrect electrical connections? The JEDEC code reads it correctly anyway.
Thanks.

  • Hi

    From what I can see looking at the S25FL064FL datasheet it doesn't support QSPI, but rather QPI which is not the same, so I think you need to use normal SPI to get the S25FL flash reading/writing correctly.

    Best regards,

    Simon

  • Hi Simon,

    Are you sure of what you say?

    I'm reporting a piece of text taken from the memory datasheet:

    Single bit wide commands start with an instruction and may provide an address or data, all sent only on the SI signal. Data may be sent back to the host serially on the SO signal. This is referenced as a 1-1-1 command protocol for single bit width instruction, single bit width address and modifier, single bit data.
    Dual-output or quad-output commands provide an address sent from the host as serial on SI (IO0) then followed by dummy cycles. Data is returned to the host as bit pairs on IO0 and IO1 or, four bit (nibble) groups on IO0, IO1, IO2, and IO3. This is referenced as 1-1-2 for Dual-O and 1-1-4 for Quad-O command protocols.
    Dual or quad input / output (I/O) commands provide an address sent from the host as bit pairs on IO0 and IO1 or, four bit (nibble) groups on IO0, IO1, IO2, and IO3 then followed by dummy cycles. Data is returned to the host similarly as bit pairs on IO0 and IO1 or, four bit (nibble) groups on IO0, IO1, IO2, and IO3. This is referenced as 1-2-2 for dual I/O and 1-4-4 for quad I/O command protocols.
    The FL-L family also supports a QPI mode in which all information is transferred in 4 bit width, including the instruction, address, modifier, and data. This is referenced as a 4-4-4 command protocol.

    The 1-4-4 is a QSPI protocol.

    Thanks for your time.

    Stefano

  • Hi

    I agree with your description here, but I still mean that QSPI needs to be specifically supported by a flash memory, and that QPI support doesn't necessarily mean QSPI is supported and the other way around, so are you sure the S25FL064L supports QSPI? Since the error code refers to a timeout during init it seems to me like the nRF isn't able to communicate correctly with the flash device which I assume is because the flash doesn't recognize the instructions coming from the nRF52.

    Best regards,

    Simon

  • Thanks Simon, I solved it. All I had to do was set bit 6 of the CR1NV register to zero. Thanks.

Related