need help to get S25FL064L operate in quad-spi mode

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
user_2847636
Level 2
Level 2

Hi,

I was working on a modified nordic nRF52840 custom board. Its memory will be based on S25FL064L , I tried write a set of random data and read it back, the result is the read request doesn't end with data send back to the nrf52840 chip.

Datasheet:

http://www.cypress.com/file/316661/download

Here is the step I followed to enable the Quad-SPI mode but it doesn't work for me.

Change S25FL064L from Default Serial SDR Mode to Quad or QPI Mode - KBA222445

Step:

1) write RSTEN (0x66)

2) write RST (0x99)

3) write WREN (0x06) <---the reason I use 0x06 instead of 0x05 is because the datasheet stated WREN address is 0x06 (I did tried 0x05 but it endup quad-spi not working as well)

4) write WRR (0x01) + SR1NV (0x02) + CR1NV (0x02) + CR2NV(0x68) + CR3NV(0x78)

Example configure Code:

static void configure_memory()

{

    uint8_t temporary[4] = {0x02,0x02,0x68,0x78};

    uint32_t err_code;

    nrf_qspi_cinstr_conf_t cinstr_cfg = {

        .opcode    = QSPI_STD_CMD_RSTEN,

        .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 = QSPI_STD_CMD_RST;

    err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);

    APP_ERROR_CHECK(err_code);

    // Send WREN

    cinstr_cfg.opcode = 0x06;

    err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);

    APP_ERROR_CHECK(err_code);

    // Switch to qspi mode

    cinstr_cfg.opcode = QSPI_STD_CMD_WRR;

    cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_5B;

    err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, &temporary, NULL);

    APP_ERROR_CHECK(err_code);

}

Example write/read code:

int main(void)

{

    uint32_t i;

    ret_code_t err_code;

    srand(0);

    for (i = 0; i < QSPI_TEST_DATA_SIZE; ++i)

    {

        m_buffer_tx = (uint8_t)rand();

    }

      nrf_drv_qspi_config_t config = NRF_DRV_QSPI_DEFAULT_CONFIG;

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

    APP_ERROR_CHECK(err_code);

    NRF_LOG_INFO("QSPI example started.");

    configure_memory();

    m_finished = false;

    err_code = nrf_drv_qspi_erase(NRF_QSPI_ERASE_LEN_64KB, 0);

    APP_ERROR_CHECK(err_code);

    WAIT_FOR_PERIPH();

    NRF_LOG_INFO("Process of erasing first block start");

    err_code = nrf_drv_qspi_write(m_buffer_tx, QSPI_TEST_DATA_SIZE, 0);

    APP_ERROR_CHECK(err_code);

    WAIT_FOR_PERIPH();

    NRF_LOG_INFO("Process of writing data start");

    err_code = nrf_drv_qspi_read(m_buffer_rx, QSPI_TEST_DATA_SIZE, 0);

    WAIT_FOR_PERIPH();

    NRF_LOG_INFO("Data read");

    NRF_LOG_INFO("Compare...");

    if (memcmp(m_buffer_tx, m_buffer_rx, QSPI_TEST_DATA_SIZE) == 0)

    {

        NRF_LOG_INFO("Data consistent");

    }

    else

    {

        NRF_LOG_INFO("Data inconsistent");

    }

}

0 Likes
15 Replies
SudheeshK
Moderator
Moderator
Moderator
250 sign-ins First question asked 750 replies posted

Hello,

I need a clarification about your query. Are you using Quad-SPI mode or QPI mode in your application? Please see the explanation for QUAD an QPI modes from datasheet below.

Quad Data Width (QUAD) CR1V[1]: When set to 1, this bit switches the data width of the device to 4 bit - Quad mode. That is, WP# becomes IO2 and IO3 / RESET# becomes an active I/O signal when CS# is low or the RESET# input when CS# is high. The WP# input is not monitored for its normal function and is internally set to high (inactive). The commands for Serial, and Dual I/O Read still function normally but, there is no need to drive the WP# input for those commands when switching between commands using different data path widths. Similarly, there is no requirement to drive the IO3 / RESET# during those commands (while CS# is low). The QUAD bit must be set to one when using the Quad Output Read, Quad I/O Read, DDR Quad I/O Read. The volatile register write for QIO mode has a short and well defined time (tQEN) to switch the device interface into QIO mode and (tQEX) to switch the device back to SPI mode. Following commands can then be immediately sent in QIO protocol. While QPI mode is entered or exited by the QPIEN and QPIEX commands, or by setting the CR2V[3] bit to 1, the Quad data width mode is in use whether the QUAD bit is set or not.

QPI CR2V[3]: This bit controls the expected instruction width for all commands. This volatile QPI configuration bit enables the device to enter and exit QPI mode during normal operation. When this bit is set to QPI mode, the QUAD mode is active, independent of the setting of QIO mode (CR1V[1]). When this bit is cleared to legacy SPI mode, the QUAD bit is not affected. The QPI CR2V[3] bit can also be set to “1” by the QPIEN (38h) command and set to “0” by the QPIEX (F5h) command.

If you need to use only QUAD mode, it is not required to set QPI bit (CR2[3]). QPI mode expects data width of 4 for instruction, address and data transfers.

Thanks and Regards,

Sudheesh

0 Likes

Hi Sudheesh,

Thanks for the quick reply. I wanted Quad-spi and I just tested with the following step, I still not able to get any data out from the memory chip.

Step:

1) write RSTEN (0x66)

2) write RST (0x99)

3) write WREN (0x06) <---the reason I use 0x06 instead of 0x05 is because the datasheet stated WREN address is 0x06 (I did tried 0x05 but it endup quad-spi not working as well)

4) write WRR (0x01) + SR1NV (0x02) + CR1NV (0x02)

Example configure Code:

static void configure_memory()

{

    uint8_t temporary[2] = {0x02,0x02};

    uint32_t err_code;

    nrf_qspi_cinstr_conf_t cinstr_cfg = {

        .opcode    = QSPI_STD_CMD_RSTEN,

        .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 = QSPI_STD_CMD_RST;

    err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);

    APP_ERROR_CHECK(err_code);

    // Send WREN

    cinstr_cfg.opcode = 0x06;

    err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);

    APP_ERROR_CHECK(err_code);

    // Switch to qspi mode

    cinstr_cfg.opcode = QSPI_STD_CMD_WRR;

    cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_3B;

    err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, &temporary, NULL);

    APP_ERROR_CHECK(err_code);

}

Example write/read code:

int main(void)

{

    uint32_t i;

    ret_code_t err_code;

    srand(0);

    for (i = 0; i < QSPI_TEST_DATA_SIZE; ++i)

    {

        m_buffer_tx = (uint8_t)rand();

    }

      nrf_drv_qspi_config_t config = NRF_DRV_QSPI_DEFAULT_CONFIG;

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

    APP_ERROR_CHECK(err_code);

    NRF_LOG_INFO("QSPI example started.");

    configure_memory();

    m_finished = false;

    err_code = nrf_drv_qspi_erase(NRF_QSPI_ERASE_LEN_64KB, 0);

    APP_ERROR_CHECK(err_code);

    WAIT_FOR_PERIPH();

    NRF_LOG_INFO("Process of erasing first block start");

    err_code = nrf_drv_qspi_write(m_buffer_tx, QSPI_TEST_DATA_SIZE, 0);

    APP_ERROR_CHECK(err_code);

    WAIT_FOR_PERIPH();

    NRF_LOG_INFO("Process of writing data start");

    err_code = nrf_drv_qspi_read(m_buffer_rx, QSPI_TEST_DATA_SIZE, 0);

    WAIT_FOR_PERIPH();

    NRF_LOG_INFO("Data read");

    NRF_LOG_INFO("Compare...");

    if (memcmp(m_buffer_tx, m_buffer_rx, QSPI_TEST_DATA_SIZE) == 0)

    {

        NRF_LOG_INFO("Data consistent");

    }

    else

    {

        NRF_LOG_INFO("Data inconsistent");

    }

}

0 Likes

Hello,

For the Quad SPI commands to work, you have to reset the QPI bit in CR2NV. Command WREN = 0x06 is to update the non-volatile versions of status and configuration registers. Our device S25FL064L uses volatile versions of status and configuration registers during run time. But, they are initialized from non-volatile registers during power up. So, you have to reset the QPI bit by sending commands in QPI mode (4-4-4). If your controller can send commands, address and data in this format, then you can reset QPI bit in CR2NV to 0. Otherwise, please use a fresh device.

Please feel free to ask if you need any clarifications.


Thanks and Regards,

Sudheesh

0 Likes
user_2847636
Level 2
Level 2

Hi Sudheesh,

Thanks for the input.

Questions 1:

Its there ways to hard reset the chip to factory mode?

And may I know what happened if I set the below setting? The chip will by default use QPI as highest priorities?

  • CR1V  =  02h (Quad I/O mode bit-1 = 1)
  • CR2V  =  68h (QPI bit-3 =1 : QPI 4-4-4 protocol is enabled)

we don;t have any qpi implemented code available.

Questions 2:

We have tried using new memory chip and use the following configuration. We still not able to read matching data from the chip. Do we need to feed in all Phase? Instruction, Input Status Register-1, Input Conf Register-1, Input Conf Register-2, Input Conf Register-3? Or we can input just instruction + input status register-1 + input conf register-1?

  • SR1NV  =  02h  (programs WEL_D bit-1 = 1)
  • CR1NV  =  02h  (programs Quad_NV bit-1 = 1)

static void configure_memory()

{

    uint8_t temporary[2] = {0x02,0x02};

    uint32_t err_code;

    nrf_qspi_cinstr_conf_t cinstr_cfg = {

        .opcode    = QSPI_STD_CMD_RSTEN,

        .length    = NRF_QSPI_CINSTR_LEN_1B,

        .io2_level = true,

        .io3_level = true,

        .wipwait   = true,

        .wren      = false

    };

    // 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 = QSPI_STD_CMD_RST;

    err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);

    APP_ERROR_CHECK(err_code);

    // Send WREN

    cinstr_cfg.opcode = 0x06;

    err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);

    APP_ERROR_CHECK(err_code);

    // Switch to quad spi mode

    cinstr_cfg.opcode = QSPI_STD_CMD_WRSR;

    cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_2B;

    err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, &temporary, NULL);

    APP_ERROR_CHECK(err_code);

}

Question 3:

Do you have any open example code on getting this chip operate in Quad spi mode?

Please advice.

0 Likes
lock attach
Attachments are accessible only for community members.

Hello,

1. Once the QPI mode is enabled, our device will expect all SPI transactions to be in 4-4-4 (opcode-address-data) format. QPI mode should be disabled to use normal SPI commands. Unfortunately, there is no other ways to change the device to factory settings.

2. You can update only SR1 and CR1 using WRR command. There is no need to send data to all the registers. Please see the information from datasheet below.

"CS# must be driven to the logic high state after the eighth, sixteenth, twenty-fourth, or thirty-second bit of data has been latched. If not, the Write Registers (WRR) command is not executed. If CS# is driven high after the:

  • eighth cycle then only the Status Register 1 is written
  • sixteenth cycle both the Status 1 and Configuration 1 Registers are written;
  • twenty-fourth cycle Status 1 and Configuration 1 and 2 Registers are written;
  • thirty-second cycle Status 1 and Configuration 1, 2 and 3 Registers are written."

Can you send us the logic analyzer waveform for write and read operations?

3. I am attaching the low level driver for our SPI devices with this response. You can use it as a reference to write your application.

Thanks and Regards,

Sudheesh

0 Likes
lock attach
Attachments are accessible only for community members.

Hi Sudheesh,


Thanks for the code. I will provide the logic analzyer waveform once I get it, for the time been I have some question for the following code. Its seem that the WRR operation is limited to

1) I will need to execute WREN before execute WRR

2) Once after WRR command must follow in this sequence SR1V, CR1V, SR2V(the result I guess its write into volatile register is because SR2V only available in volatile mode). Which means I cannot use WRR? When I want to write into SR1NV and CR1NV I need to use WRAR and another challenge is SR1V and CR1V is using 800000 and 800002 addressing value whereby my nordic QSPI api doesn't support uint16_t input.  I not sure the sequence of the data.

SLLD_STATUS slld_WRROp

(

        BYTE       *status_val,          /* variable containing data to program the status register */

        BYTE       *config_val,          /* variable containing data to program the config register */

        BYTE       *status2_val,         /* variable containing data to program the status register2 */

        DEVSTATUS  *dev_status_ptr       /* variable to store device status */

)

{

    SLLD_STATUS status = SLLD_OK;

    status = slld_WRENCmd();

    if(status != SLLD_OK)

        return(status);

    status = slld_WRRCmd(status_val, config_val,status2_val);

    if(status != SLLD_OK)

        return(status);

    status = slld_Poll(dev_status_ptr);

    if(status != SLLD_OK)

        return(status);

    status = slld_WRDICmd();       /* just in case WRROp is operated on protected area */

    return(status);

}

0 Likes

Hi,

I tried using the WRAR to write the non volatile register and conclusion is I was not able to get the cr1nv updated with the correct setting. Please advice. But take note I was able to read the value of RDID register.PI write (0x66 reset_en)

  1. SPI write (0x99 reset)
  2. SPI write (0x06 wren, 0x71 wrar, 0x02 cr1nv address, 0x02 cr1nv setting)
  3. SPI read (0x65 RDAR, 0x02 cr1nv address)

Conclusion, I the cr1nv address still shown 0x00 rather than the 0x02 value setting which I set using the wrar

2018-11-30 11_43_40-Photos.png

2018-11-30 11_47_53-Photos.png

0 Likes

Hi,

I analyzed the waveform that you provided. Please find my comments below.

A. I found that you are sending both WREN and WRR command sequence in the same CS# cycle. You have to make CS# pin HIGH after sending WREN command. Please see the sequence below.

  1. CS# -> LOW
  2. WREN(0x06) command
  3. CS# -> HIGH
  4. CS# -> LOW
  5. WRR command
  6. SR1NV value
  7. CR1NV value
  8. CR2NV value
  9. CS# -> HIGH

In the waveform that you attached, CS# signal is not going HIGH after WREN command. Please correct this and test again.

B. WRR command updates SR1NV, CR1NV, CR2NV and CR3NV registers. SR2V does not get updated using WRR command. Please refer page 68 of datasheet for more details.

Thanks and Regards,

Sudheesh

0 Likes

Hi Sudheesh,

Thanks. I have tried your suggest and its not working either, now I have a new set of problems. I cannot read the RDID value, I want confirmation on how to read RDID value from the chip via SPI

  1. Please advise the right step to read RDID. Here is my step
  • Execute RSTEN
  • Execute RST
  • Wait for 50ms
  • Write RDID and wait for receive buffer of for 3 bytes of data.
0 Likes

Hi,

Could you please send the waveform after making the changes that I suggested? (For WREN and WRR commands)

Please send the waveform for RDID also. I hope the initial state of CS# pin is HIGH after power up. Please confirm.

Thanks and Regards,

Sudheesh

0 Likes

Hi Sudheesh,

I didn't managed to capture the image and I cannot provide any more waveform, we have burn/cause malfunction for several memory chip we have. The memory chip itself cannot resist soldering. Do you have other alternative method? We cannot afford to further damage more board as our chip supply drop low. I would hope to have clear step on the read/write sequence for the chip.

1) Based on the provided sample code, the step for reading RDID is:

-> send 0x9F

-> read 3 bytes from the rx buffer

2) for configure the chip into QSPI mode.

-> send WREN (0x06)

-> sent WRR(0x01)+SR1NV(0x02)+CR1NV(0x02)+CR2NV(0x00)

3) Possible to help check with the cypress hardware team? We notice the memory chip cannot resist hand soldering and we already have 3 memory chip malfunction when we try to solder pin for waveform capture, and I never see memory chip are so sensitive to heat.

0 Likes

Hi,

We would like to see the waveform for different operations to assist you further. Could you please attach waveform for below sequence?

  • Execute RSTEN
  • Execute RST
  • Wait for 50ms
  • Write RDID and wait for receive buffer of for 3 bytes of data.

Thanks and Regards,

Sudheesh

0 Likes

Hi,

We managed to read the RDID, its our circuit connection issue. But we still not able to communicate in Quad I/O mode. Please advice the similiar step for us to simulate.

Kindly refer to the attachment (CS:yellow,SCLK:blue,SI:purple,SO:green)

RSTEN

pastedImage_0.png

RST

pastedImage_1.png

RDID

pastedImage_2.png

Thanks for your help.

0 Likes

Hi,

Could you please read back the configuration register 1 and make sure that the QUAD bit is set?

Thanks and Regards,

Sudheesh

0 Likes

Hi,

WRR(0x01) + SR1NV(0x02) + CR1NV (0x02) + CR2NV (0x00)

pastedImage_1.png

RDCR1

pastedImage_2.png

CR1V is not 0x02 after I reset the device.

0 Likes