How to write data to qspi configuration register?

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

How to write data to qspi configuration register?

Jump to solution
3,632 Views
kevincronn
Contributor III

 I am using the evkmcimx6ull eval board that has a Micron MT25QL256ABA Qspi flash on it. I am trying to write to the non-volatile configuration register inside the Qspi flash. I believe I have the correct command sequence, 0x200404B1, but how do I send the data to program the register with? I have tried using the TX Buffer Data Register, but could not get it to write out the data, the reference manual states the TBDR is for the page programming commands. What buffer is used for register writes?

Labels (1)
1 Solution
2,595 Views
kevincronn
Contributor III

I believe I have answered my own question. I looks like you have to fill the TX FIFO with 16 bytes before it will output. I was only sending 4 bytes. Maybe that's in the reference manual somewhere? I haven't found it yet.

View solution in original post

10 Replies
2,595 Views
kzambrano
Contributor III

Hi,

  Having the same issue on an LS1046, however I am trying to get this going in UBOOT. I added the sequence below in the LUT. I am attempting to set SRWD to control write protection on the same CYPRESS NOR as above:

/* Write Register 0x01 */
lut_base = SEQID_WRR * 4;
qspi_write32(priv->flags, &regs->lut[lut_base],
OPRND0(QSPI_CMD_WRR) | PAD0(LUT_PAD1) | INSTR0(LUT_CMD) |
OPRND1(0x80) | PAD1(LUT_PAD1) | INSTR1(LUT_WRITE));
qspi_write32(priv->flags, &regs->lut[lut_base + 1], 0);  //end of sequence
qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);

The sequence is invoked on a flash write following a WREN sequence, however it does not seem to be setting the bit in the control register. Added the delay as above, but no joy. Any ideas I can try?

0 Kudos
2,595 Views
deniscollis
Contributor V

Hi Keith,

You don't show the code used to load up the TX FIFO and and trigger the execution of the LUT sequence.

Notwithstanding, there appears to be a problem with:  OPRND1(0x80), which means that you expect to send 128 bytes from the TX buffer.  Cypress WRR expects 2 bytes (one for the configuration register and one for the status register), so OPRND1(0x02) is correct.

2,595 Views
kzambrano
Contributor III

Denis,

  Thx a million, I was way off on this. For some reason I thought that the command required the data immediate after the instruction. So now it makes sense, load the data in the buffer then issue the sequence which will use the data.

  Btw, I believe the CYPRESS part comes out of  reset out of QPI mode. So it will only require a single byte. Otherwise you are correct, it would need 2 bytes.

  Again, Much Gras...TGIF!!!

0 Kudos
2,595 Views
kzambrano
Contributor III

In the spirit of helping a brother out, here is the  snippets from UBOOT:

------- Corrected LUT setup

/* Write Register 0x01 */
lut_base = SEQID_WRR * 4;
qspi_write32(priv->flags, &regs->lut[lut_base],
OPRND0(QSPI_CMD_WRR) | PAD0(LUT_PAD1) | INSTR0(LUT_CMD) |
OPRND1(0x1) | PAD1(LUT_PAD1) | INSTR1(LUT_WRITE));                      <<<<  as Denis pointed out
qspi_write32(priv->flags, &regs->lut[lut_base + 1], 0);  //end of sequence
qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);

------ after status register sequence, enabled SRWD

status_reg |= FLASH_STATUS_SRWD;

qspi_write32(priv->flags, &regs->tbdr, qspi_endian_xchg(status_reg));
while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
;

qspi_write32(priv->flags, &regs->ipcr,
(SEQID_WRR << QSPI_IPCR_SEQID_SHIFT) | 1);
while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
;

-----------------------

Now reading back CYPRESS status register-1 shows SRWD set. Now just  have to figure

why the the flash does not follow WP#. With the change above, now write are allowed.

0 Kudos
2,595 Views
deniscollis
Contributor V

I am trying something similar with a Cypress part, using the same driver example as Kevin.  The a bit in the configuration register must be set to enable QUAD mode. The 8-bit Status Register and 8-bit Configuration are set simultaneously with the Write Register command.

This does not work, i.e. quad-enable bit remains unset. Can anyone see why? 

#ifdef BOARD_QSPI_DEVICE_S25FL128S  // Cypress S25FL128S
     QSPI_ClearFifo(BOARD_QSPI_BASE, kQSPI_TxFifo);

     // set the address (always the base address for register writes)
     QSPI_SetIPCommandAddress(BOARD_QSPI_BASE, FSL_FEATURE_QSPI_AMBA_BASE);

     cmd_write_enable();

     QSPI_ExecuteIPCommand(BOARD_QSPI_BASE, QSPI_LUT_SEQ_WRITE_REGISTER);

     // Load Tx FIFO - push at least 16 bytes before it will pop
     for (int i=0; i<4; i++)
     {
          QSPI_WriteData(BOARD_QSPI_BASE, 0x02020202);
     }

     while (QSPI_GetStatusFlags(BOARD_QSPI_BASE) & kQSPI_Busy)
     {
     }
#endif‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍


typedef enum _qspi_lut_seq_index
{
//------CUT------
    QSPI_LUT_SEQ_WRITE_REGISTER = 20, /* !< register write sequence */
//------CUT------
} qspi_lut_seq_index_t;


typedef enum _cypress_flash_command
{
//------CUT------
    C_WRITE_STATUS_REGISTER = 0x01,
//------CUT------
} cypress_flash_command_t;


const uint32_t g_qspi_flash_lookup_table[FSL_FEATURE_QSPI_LUT_DEPTH] =
{
//------CUT------
/* Seq5: Write Status and Config Registers */
    [QSPI_LUT_SEQ_WRITE_REGISTER] = QSPI_LUT_SEQ(
        QSPI_CMD,   QSPI_PAD_1, C_WRITE_REGISTER,
        QSPI_WRITE, QSPI_PAD_1, 2),
//------CUT------
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Thanks,

Denis

0 Kudos
2,595 Views
deniscollis
Contributor V

Okay, I got it!  Added a fixed delay for the Flash to finish. (Just to be safe I did not want to use check_if_finished() as this reads the Status Register - the same register I am writing - and did not want to risk interference.

     while (QSPI_GetStatusFlags(BOARD_QSPI_BASE) & kQSPI_Busy)
     {
     }

    // Give some time for the device to finish.
     for (int i = 0; i < 400; i++)
     {
          __ASM("nop");
     }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
#endif
2,595 Views
igorpadykov
NXP Employee
NXP Employee

Hi Kevin

one can try to follow sect.43.5.3.5 Issuing SFM Commands i.MX6ULL Reference Manual:

For IP Commands not related to specific addresses, the base address of the related
flash need to be programmed.For example, for an instruction which does not require
an address (i.e. write enable instruction) the SFAR should be programmed with the
base address of the memory the command is to be sent to.

http://www.nxp.com/docs/en/reference-manual/IMX6ULRM.pdf


Best regards
igor
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!

0 Kudos
2,595 Views
kevincronn
Contributor III

Igor,

I am following the code in the qspi driver example in the SDK_2.2. The code in the SDK does not provide an example of a register write. The code given does work, the program and erase, I have run it and verified it works. The write enable function does also work and I am using that in my code. I have an oscilloscope connected and can see that the command sequence is being put out onto the qspi interface but I cannot get the data of what I want to program the register to out onto the interface. I am using the IP functions given in the SDK. Here is my code:

void cmd_write_config_reg(void)
{

static uint32_t tx_data = 0x000078FF;


while (QSPI_GetStatusFlags(EXAMPLE_QSPI) & kQSPI_Busy)
{
}
QSPI_ClearFifo(EXAMPLE_QSPI, kQSPI_TxFifo);
QSPI_SetIPCommandAddress(EXAMPLE_QSPI, FSL_FEATURE_QSPI_AMBA_BASE);
cmd_write_enable();

QSPI_ExecuteIPCommand(EXAMPLE_QSPI, 28U);


QSPI_WriteData(EXAMPLE_QSPI, tx_data);
while (QSPI_GetStatusFlags(EXAMPLE_QSPI) & kQSPI_Busy)
{
}
//check_if_finished();
PRINTF("Write config reg complete!\r\n");
}

Again, my command sequence is 0x200404B1 (28U in the LUT), I can see B1 on the qspi interface and that is the correct code for a non-volatile configuration register write, but the tx_data in the QSPI_WriteData is not driven onto the data lines. The QSPI_WriteData() function is one given with the SDK and used in the qspi driver code, it just puts the data into the TX FIFO to be transmitted. I'm guessing for a register write there is something that must be done differently or I am missing a step somewhere.?

0 Kudos
2,596 Views
kevincronn
Contributor III

I believe I have answered my own question. I looks like you have to fill the TX FIFO with 16 bytes before it will output. I was only sending 4 bytes. Maybe that's in the reference manual somewhere? I haven't found it yet.

2,595 Views
deniscollis
Contributor V

Your last PRINTF() has the side-effect of inserting a delay.  (See my reply below, where I used a NOP loop instead) 

0 Kudos