This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

SPI Flash N25Q00AA interfacing with MSP430 Read/Write problem

Other Parts Discussed in Thread: MSP430F5438

Hi,

I am interfacing Micron SPI NOR flash N25Q00AA to MSP430, Currently I am able to read Device ID successfully from SPI flash which is 0x20BA21, which shows the SPI configuration that i have done is corret. But I am not able to write/read from the SPI flash every time I am getting 0 as read result. Following are the code snippets. 

void FlashTest(void)
{

uint8_t uReadByte=0;

for (int i=0; i<3; i++)
{
// printf("ID = %X\r\n",sFLASH_ReadID());

if(sFLASH_ReadID() == sFLASH_N25Q00_ID)
printf("N25Q00AA Flash Found\r\n");

else
printf("ERROR Flash not found\r\n");
}
__delay_cycles(10);

//printf("sFLASH_ReadReg() = %X\r\n",sFLASH_ReadReg(sFLASH_CMD_RDSR));


#if 1
//Test two bytes read/write
sFLASH_CS_LOW();
sFLASH_SendByte(sFLASH_CMD_WREN);
// __delay_cycles(10);
sFLASH_CS_HIGH();


sFLASH_CS_LOW();
sFLASH_SendByte(sFLASH_CMD_WRITE);
sFLASH_SendByte(0);
sFLASH_SendByte(0);
sFLASH_SendByte(0);
sFLASH_SendByte(0xAA);
//__delay_cycles(10);
sFLASH_CS_HIGH();


sFLASH_CS_LOW();
sFLASH_SendByte(sFLASH_CMD_WRITE);
sFLASH_SendByte(0);
sFLASH_SendByte(0);
sFLASH_SendByte(1);
sFLASH_SendByte('B');
//__delay_cycles(10);
sFLASH_CS_HIGH();

sFLASH_CS_LOW();
sFLASH_SendByte(sFLASH_CMD_READ);
sFLASH_SendByte(0);
sFLASH_SendByte(0);
sFLASH_SendByte(0);
printf("First byte %X\r\n",sFLASH_SendByte(sFLASH_DUMMY_BYTE));
// uReadByte = sFLASH_SendByte(0);
//__delay_cycles(10);
sFLASH_CS_HIGH();



sFLASH_CS_LOW();
sFLASH_SendByte(sFLASH_CMD_READ);
sFLASH_SendByte(0);
sFLASH_SendByte(0);
sFLASH_SendByte(1);
printf("2nd byte %X\r\n",sFLASH_SendByte(sFLASH_DUMMY_BYTE));
// uReadByte = sFLASH_SendByte(sFLASH_DUMMY_BYTE);
__delay_cycles(10);
sFLASH_CS_HIGH();

#endif
}

void ConfigureSPIFlash(void)

{

//Configure SPI GPIO
P3DIR |= FLASH_nCS; // Chip select for flash //0x40;
P3SEL |= FLASH_MOSI; // Peripheral module function is selected as UCB1SIMO MOSI on SPI
P5SEL |= FLASH_MISO | FLASH_SCK; //Select Port 5 Alternate function UCB1SOMI and UCB1CLK

//Configure SPI for Flash
//data present at serial data inputs are latched on the rising edge of the clock. Data is shifted out on the falling edge of the clock.
UCB1CTL1 |= UCSWRST; // Enabled. USCI logic held in reset state.
UCB1CTL0 = UCMST + UCMSB + UCSYNC + UCCKPH ; //3-Pin SPI with 8 bit SPI master, Clock Ideally Low, and MSB first,
//UCCKPH=1:Data is captured on the first UCLK edge and changed on the following edge.
//TODO Check Clock source once Crystal works
UCB1CTL1 |= UCSSEL_2; //Select SMCLK SubSystemCLOCK

UCB1BR0 = 0x00 ; 
UCB1BR1 = 0;

// UCB1IE |= UCRXIE + UCTXIE; // Enable USCI_A0 RX interrupt

UCB1CTL1 &= ~UCSWRST; //Disable Reset

}

uint8_t sFLASH_SendByte(uint8_t uData)
{

UCB1TXBUF = uData; // write

while ((UCB1IFG & UCTXIFG)== 0);

while ((UCB1IFG & UCRXIFG) == 0); // wait for transfer to complete
return(UCB1RXBUF);

}

Can someone give me some pointers what I would be missing? 

  • Which command do you actually define as 'sFLASH_CMD_WRITE'? Is it 'PAGE PROGRAM' command of NS25Q00 chip (code = 0x02)?

    You write 0xAA to the flash, then without even waiting for the write cycle to be completed you immediately write 'B'.

    If you want to write 2 bytes (in fact, any number of bytes from 1 up to 256), you'd better do it this way:

    sFLASH_CS_LOW();
    sFLASH_SendByte(sFLASH_CMD_WRITE);
    sFLASH_SendByte(0);
    sFLASH_SendByte(0);
    sFLASH_SendByte(0);
    sFLASH_SendByte(0xAA);
    sFLASH_SendByte('B');
    //__delay_cycles(10);
    sFLASH_CS_HIGH();

    Otherwise you have to wait till previous write operation is completed, either by bit polling, or by some dummy delay, and only after that you can issue the next write command.

    Remember, once you set #CS line high at the end of program sequence, you start internal flash write cycle, and it could be lengthy operation. Modern flash chips are very complex devices, they have h/w finite state machine inside, own oscillator, shadow registers etc. When all this stuff starts working it takes some time to finish.

    Also after your writes you have to make sure that internal write cycle of flash is over and only after that you are allowed to read your data back. Again, it could be done either by bit polling or dummy delay tPP. 

    NOTE: Address pointer in flash chip is auto-incrementing, so there is no need to explicitly specify the address for every byte after the first one when you read/write several bytes in a row.

    Besides, your SPI write routine looks a bit redundant. You may change it as follows:

    uint8_t sFLASH_SendByte(uint8_t uData)
    {
        // Clear Rx interrupt flag
        UCB1IFG &= UCRXIFG
        // Transmit data
        UCB1TXBUF = uData;
        // Wait for transfer to complete
        while ((UCB1IFG & UCRXIFG) == 0);
        // Receive data
        uData = UCB1RXBUF;
        return uData;
    }

  • Hi Thanks for quick reply,

    Yes the sFLASH_CMD_WRITE is Page Program command which is 0x02. I tried giving delay tPP=.5-5ms. And also tried polling Write In Progress Bit from Status Register, but still no success getting 0 as result.

    Following is the code

    sFLASH_CS_LOW();
    sFLASH_SendByte(sFLASH_CMD_WRITE);
    sFLASH_SendByte(0);
    sFLASH_SendByte(0);
    sFLASH_SendByte(0);
    sFLASH_SendByte(0xAA);
    // sFLASH_WaitForWriteEnd();
    sFLASH_SendByte('B');
    delay_ms(1);
    // sFLASH_WaitForWriteEnd();

    sFLASH_CS_HIGH();

    sFLASH_CS_LOW();
    sFLASH_SendByte(sFLASH_CMD_READ);
    sFLASH_SendByte(0);
    sFLASH_SendByte(0);
    sFLASH_SendByte(0);
    printf("First byte %X\r\n",sFLASH_SendByte(sFLASH_DUMMY_BYTE));
    printf("2nd byte %X\r\n",sFLASH_SendByte(sFLASH_DUMMY_BYTE));
    // uReadByte = sFLASH_SendByte(0);
    //__delay_cycles(10);
    sFLASH_CS_HIGH();

    void sFLASH_WaitForWriteEnd(void)
    {
    uint8_t flashstatus = 0;

    /*!< Select the FLASH: Chip Select low */
    sFLASH_CS_LOW();

    /*!< Send "Read Status Register" instruction */
    sFLASH_SendByte(sFLASH_CMD_RDSR);

    /*!< Loop as long as the memory is busy with a write cycle */
    do
    {
    /*!< Send a dummy byte to generate the clock needed by the FLASH
    and put the value of the status register in FLASH_Status variable */
    flashstatus = sFLASH_SendByte(sFLASH_DUMMY_BYTE);

    }
    while ((flashstatus & sFLASH_WIP_FLAG)); /* Write in progress */

    /*!< Deselect the FLASH: Chip Select high */
    sFLASH_CS_HIGH();
    }

    Here sFLASH_WIP_FLAG==0x01,

    But no success :(

    Regards,

    Shrenik.

  • You should put your delay AFTER setting #CS high. Otherwise, it does not make any sense... The internal flash write cycle starts when #CS goes high.

  • I tried giving delay after #CS high. Now I am getting 0xFF as read result. Currently I am writing 5 bytes in one WRITE command and thereafter after #CS goes high, I am giving delay. For reading also I am giving READ Command with 0x000000 address and reading 5 bytes in one read command, but getting 0xFF for all read.

  • Well, it sounds much better :-)

    Now, tell me about pins of your flash chip, where are these connected. Especially #W pin.

  • Its not connected. Floating.

  • Not sure about the particular chip you are using, but for many flash chips this pin enables write protection. Try to connect it to high level.

  • No Luck, I tried pulling up the #WP pin but still result is 0xFF, sometimes it comes 0x00.

  • What other pins are floating? You should connect #HOLD to Hi, #RESET to some output pin of your MSP430. You should apply low pulse to #RESET as a part of your system start-up sequence.

  • Did you manage to get your code working? The next code should work OK:

    // Write enable
    sFLASH_CS_LOW();
    sFLASH_SendByte(sFLASH_CMD_WREN);
    sFLASH_CS_HIGH();
    
    // Write 3 bytes: 0xAA, 0xBB, 0xCC to address 0x000000
    sFLASH_CS_LOW();
    sFLASH_SendByte(sFLASH_CMD_WRITE);
    sFLASH_SendByte(0);
    sFLASH_SendByte(0);
    sFLASH_SendByte(0);
    sFLASH_SendByte(0xAA);
    sFLASH_SendByte(0xBB);
    sFLASH_SendByte(0xCC);
    sFLASH_CS_HIGH();
    sFLASH_WaitForWriteEnd();
    
    // Read 3 bytes from address 0x000000
    sFLASH_CS_LOW();
    sFLASH_SendByte(sFLASH_CMD_READ);
    sFLASH_SendByte(0);
    sFLASH_SendByte(0);
    sFLASH_SendByte(0);
    b1 = sFLASH_SendByte(sFLASH_DUMMY_BYTE);
    b2 = sFLASH_SendByte(sFLASH_DUMMY_BYTE);
    b3 = sFLASH_SendByte(sFLASH_DUMMY_BYTE);
    sFLASH_CS_HIGH();
    
    printf("B1:B2:B3 = %X %X %X\r\n", b1, b2, b3);
    
    
    
    void sFLASH_WaitForWriteEnd(void)
    {
        uint8_t flashstatus = 0;
    	
        // Loop as long as the memory is busy with
        do
        {	// Select the FLASH: Chip Select low
            sFLASH_CS_LOW();
            // Send "Read Status Register" instruction
            sFLASH_SendByte(sFLASH_CMD_RDSR);
            // Send a dummy byte to generate the clock needed by the FLASH
            // and put the value of the status register in FLASH_Status variable
            flashstatus = sFLASH_SendByte(sFLASH_DUMMY_BYTE);
            // Deselect the FLASH: Chip Select high
            sFLASH_CS_HIGH();
        }
        while (flashstatus & sFLASH_WIP_FLAG);
    }
    

  • This is pin diagram for N25Q00AA in which currently I pulled high W#/Vpp/DQ2 and HOLD#/DQ3 pins. 

    I tried the program you gave but result is same 0 or FF. I have doubt about Status register. I put print in "do" loop which always give me 0 value for "flashstatus". I guess its not reading status register at all.

  • Yes, you did it right. You can not leave inputs floating.

    Can you confirm that when you send READ ID command you actually read the next 3 bytes back: 0x20, 0xBA, 0x21?

  • Yes I do read three bytes read back as 0x20, 0xBA, 0x21. And then I check it and give print as Flash detected.

  • Can you send WRITE ENABLE command followed by READ STATUS REGISTER to make sure WREN bit in status register is actually set? Make sure the codes for these commands are 0x06 and 0x05.

  • sFLASH_CS_LOW();
    sFLASH_SendByte(sFLASH_CMD_WREN);
    sFLASH_SendByte(sFLASH_CMD_RDSR);
    printf("Write enable check = %X\r\n",sFLASH_SendByte(sFLASH_DUMMY_BYTE));
    sFLASH_CS_HIGH();

    after doing this, I am getting status register 0 only. Now what could be problem, is it that I am not reading status register properly or the Write Enable command is not working properly.

  • Hi Actually i do get logs like this


    N25Q00AA Flash Found
    Write enable check = FF
    FlashStatus = 0
    B1:B2:B3 = 0 0 0

    N25Q00AA Flash Found
    Write enable check = FF
    FlashStatus = 0
    B1:B2:B3 = 0 0 0

    N25Q00AA Flash Found
    Write enable check = 0
    FlashStatus = 0
    B1:B2:B3 = 0 0 0

    N25Q00AA Flash Found
    Write enable check = FF
    FlashStatus = 0
    B1:B2:B3 = 0 0 0

    N25Q00AA Flash Found
    Write enable check = FF
    FlashStatus = 0
    B1:B2:B3 = 0 0 0

  • You still didn't get it right:

    The WRITE ENABLE operation sets the write enable latch bit. To execute a WRITE ENABLE command, S# is driven LOW and held LOW until the eighth bit of the command code has been latched in, after which it must be driven HIGH. The command code is input on DQ0 for extended SPI protocol, on DQ[1:0] for dual SPI protocol, and on DQ[3:0] for quad SPI protocol.

    The write enable latch bit must be set before every PROGRAM, ERASE, WRITE, ENTER 4-BYTE ADDRESS MODE, and EXIT 4-BYTE ADDRESS MODE command. If S# is not driven HIGH after the command code has been latched in, the command is not executed

     

    That's why your code:

    sFLASH_CS_LOW();
    sFLASH_SendByte(sFLASH_CMD_WREN);
    sFLASH_SendByte(sFLASH_CMD_RDSR);
    printf("Write enable check = %X\r\n",sFLASH_SendByte(sFLASH_DUMMY_BYTE));
    sFLASH_CS_HIGH();

    is not going to work properly. Change it as 

    sFLASH_CS_LOW();
    sFLASH_SendByte(sFLASH_CMD_WREN);
    sFLASH_CS_HIGH();
    
    sFLASH_CS_LOW();
    sFLASH_SendByte(sFLASH_CMD_RDSR);
    printf("Write enable check = %X\r\n",sFLASH_SendByte(sFLASH_DUMMY_BYTE));
    sFLASH_CS_HIGH();

     

  • Yes sorry for that, I am able to get WRITE command execution properly. In reply i do get status register as 0x02 which shows write is enabled. 

  • OK. Try to write some data to flash memory again, and afterwards read Flag Status Register, it shows what errors happened during write.

  • I do get 0x80 value for Flag register which says Program or erase controller ready.

    erase controller
    0 = Busy 1 = Ready
    Status bit: Indicates whether one of the following command cycles is in progress: WRITE STATUS REGISTER, WRITE NONVOLATILE CONFIGURATION REGISTER, PROGRAM, or ERASE

    and other bits are 0 in which 4th bit shows that program operation has succeeded.

     

    Also Why the Status register gets cleared after write operation. When i complete write operation and immediately checked status register it gives me 0, but before it is 0x02 after write enable. what could be the reason?

  • Looks OK. Are you sure you use codes 0x02 as PAGE PROGRAM and 0x03 as READ?

  • Yes 100% sure I am using 0x02 for sFLASH_CMD_WRITE and 0x03 for sFLASH_CMD_READ.

    This is what my current code look like

    void FlashTest(void)
    {
    uint8_t b1,b2,b3;
    for (int i=0; i<3; i++)
    {
    // printf("ID = %X\r\n",sFLASH_ReadID());
    if(sFLASH_ReadID() == sFLASH_N25Q00_ID)
    {
    printf("N25Q00AA Flash Found\r\n");
    break;
    }
    else
    printf("ERROR Flash not found\r\n");
    }
    __delay_cycles(100000);
    // / Write enable
    sFLASH_CS_LOW();
    sFLASH_SendByte(sFLASH_CMD_WREN);
    sFLASH_CS_HIGH();
    __delay_cycles(100);


    printf("sFLASH_ReadReg() = %X\r\n",sFLASH_ReadReg(sFLASH_CMD_RDSR));

    // Write 3 bytes: 0xAA, 0xBB, 0xCC to address 0x000000
    sFLASH_CS_LOW();
    sFLASH_SendByte(sFLASH_CMD_WRITE);
    sFLASH_SendByte(0);
    sFLASH_SendByte(0);
    sFLASH_SendByte(0);
    sFLASH_SendByte(0xAA);
    sFLASH_SendByte(0xBB);
    sFLASH_SendByte(0xCC);
    sFLASH_CS_HIGH();
    __delay_cycles(1000);

    //sFLASH_WaitForWriteEnd();

    printf("sFLASH_ReadReg() = %X\r\n",sFLASH_ReadReg(sFLASH_CMD_RDSR));


    printf("sFLASH_FlagReg() = %X\r\n",sFLASH_ReadReg(sFLASH_CMD_RD_FLAG));


    // Read 3 bytes from address 0x000000
    sFLASH_CS_LOW();
    sFLASH_SendByte(sFLASH_CMD_READ);
    sFLASH_SendByte(0);
    sFLASH_SendByte(0);
    sFLASH_SendByte(0);
    b1 = sFLASH_SendByte(sFLASH_DUMMY_BYTE);
    b2 = sFLASH_SendByte(sFLASH_DUMMY_BYTE);
    b3 = sFLASH_SendByte(sFLASH_DUMMY_BYTE);
    sFLASH_CS_HIGH();

    printf("B1:B2:B3 = %X %X %X\r\n", b1, b2, b3);
    }

  • Can you insert  __delay_cycles(1000); line after each sFLASH_CS_LOW();  line and before each sFLASH_CS_HIGH(); line and see if it makes any difference?

  • No success.

    N25Q00AA Flash Found
    sFLASH_ReadStatusReg() = 2
    sFLASH_ReadStatusAfterWriteReg() = 0
    sFLASH_FlagReg() = 80
    B1:B2:B3 = 0 0 0

    This is whats the result. I doubt why the status register is 0 after write operation. Do you think any reason behind it?

  • Well, the WIP bit stays high only for duration of internal write cycle. If you can not detect it, it means that either this cycle was very short or haven't been started at all.

    Did I get it right that now you read 0 from programmed cells consistently? It may mean that while playing with the chip you did write 0 to these cells and before writing something to it you must first do erase.

    So try execute erase first (either full-chip bulk erase or sector erase) before any further write tests.

    Also check if the voltage supplied to flash chip is within 2.7-3.6V

  • Hi I tried Sector erase command, after that I can see that I was getting WIP bit high showing that erase is in progress. In that case the flashstatus i was getting during WIP period was 0x03 which is WREN and WIP is set. But it doesn't clear Status register in for sector erase command but it clears status register after executing Page Program command. This is what i have doubt about. At least it must give 0x02 as result after Page program as I am not Disabling write enable bit.

    Now after sector erase command i get 0xFF after reading. 

  • > Hi I tried Sector erase command, after that I can see that I was getting WIP bit high showing that erase is in progress. In that case the flashstatus i was getting during WIP period was 0x03 which is WREN and WIP is set. But it doesn't clear Status register in for sector erase command but it clears status register after executing Page Program command. This is what i have doubt about. At least it must give 0x02 as result after Page program as I am not Disabling write enable bit.

    SA: I don't quite understand what do you mean. The sequence should be the next:

    1. You send WREN command;

    2. You send sector erase command;

    3. You read in a loop Status Register while its WIP bit = 1. You can not proceed further to the next operation until WIP = 0;

    4. Internal erase operation is finished -> WIP and WREN bits are both reset to 0 by internal flash state machine;

    5. You send WREN command again;

    6. You program 3 bytes to flash - 0xAA, 0xBB, 0xCC.

    7. You read in a loop Status Register while its WIP bit = 1. You can not proceed further to the next operation until WIP = 0;

    8. Internal flash write is finished -> WIP and WREN bits are both reset to 0 by internal flash state machine;

    9. You read these 3 bytes and get 0xFF, 0xFF, 0xFF - for some reason, instead of 0xAA, 0xBB, 0xCC.

    Is this how you get it?

  • Hi I got it working. I tried to write at different sector from 0x00FF00 and reading back. And its working now. I guess the first sector was having some problem. It seems hardware problem. What can you comment on this.

    I will also check with new flash chip for same program to make it sure. Anyway I really appreciate your continuous and quick replies for my queries. Hope to get same support if require. 

    Thank you very much again.

    Shrenik.

  • You are welcome.

    If your chip is brand new, it is very unlikely the hardware problem. Usually sector should last for at least 100,000 erase cycles. Though it is possible. If the firmware is malfunctioning doing infinite consecutive erase cycles, then a sector could be destroyed within several hours.

    Try new chip and write how it goes.

    Good luck!

  • Before setting CS high, ensure that the last SPI transfer is completed. Many people write a byte to TXBUF and then de-assert CS, while the last (and probably even the byte before) is still sending.

  • Jens-Michael Gross said:

    Before setting CS high, ensure that the last SPI transfer is completed. Many people write a byte to TXBUF and then de-assert CS, while the last (and probably even the byte before) is still sending.

    I also considered this as a main culprit, but here it is not the case as sFLASH_SendByte() function has this line at the end:

    while ((UCB1IFG & UCRXIFG) == 0); // wait for transfer to complete

    I believe when UCRXIFG flag is set to 1, it is safe to set #CS = 1. Normally flash chips allow clock-to-cs-unactive delay in a magnitude of 10 nanoseconds, which for sure is satisfied in MSP430 even if it runs at max clock 25MHz. Though I could not find waveforms in data manual which show when exactly UCRXIFG is set relatively to the 8th clock pulse.

  • Serge,

    TXIFG indicates that TXBUF is empty. But that means, the moment TXIFG gets set, the content of TXBUF has been just moved to the output shift register and has started shifting out.
    To be sure (in SPI mode) that TXBUF and output shift register are empty is sent is by checking the UCBUSY bit. (In UART mode, it will also be set when the UART is receiving, and in I2C mode, it is set until the stop condition is sent)

    So before clearing CS, it must be checked whether UCBUSY is clear.

  • Jens-Michael Gross said:

    Serge,

    TXIFG indicates that TXBUF is empty. But that means, the moment TXIFG gets set, the content of TXBUF has been just moved to the output shift register and has started shifting out.
    To be sure (in SPI mode) that TXBUF and output shift register are empty is sent is by checking the UCBUSY bit. (In UART mode, it will also be set when the UART is receiving, and in I2C mode, it is set until the stop condition is sent)

    So before clearing CS, it must be checked whether UCBUSY is clear.

    Jens-Michael,

    Totally agree with you. TXIFG can not be checked as a condition for de-activating #CS line. But I mentioned RXIFG. I would assume that once it is set, it is safe to do so. I am not sure wether there is any difference between RXIFG and UCBUSY flags usage for end of TX-RX transaction detection in SPI mode. Unfortunately there are no wave forms in the documentation showing the relation between clock, data and any of IFGs for serial comms module. Which is very unusual comparing with other manufacturers (Renesas, NEC, for example).

  • Serge A said:
    But I mentioned RXIFG.

    In need new eyeglasses :)
    You’re right, with RXIFG it should work – depending on clock phase. I believe, with the ‘wrong’ settings, RXIFG is set 1/2 clock cycle before TX is complete. Which of course doesn’t make a difference if SPI clock isn’t too much slower than MCLK :)

    However, there are waveforms in the users guide – look in the section about clock phase and polarity (IIRC).

  • hi i am also using same using same flash , i tried to read and write operation it 's working but Sector erase is not working Please share your experience.
  • Hello Everybody,

    I 'm developping a system that uses the same SPI NOR Flash that you have been talking about, N25Q00A.
    And I have found the same problems as you. I can read the device ID, but I cannot read data in memory. I don't know whether is because a bad writting or a bad reading.

    I think you solved the problem, can you tell me how do you get. Can you give me a example of use?

    Thank you very much for your help
    Carmen
  • Hey! I am new to SPI on MSP430 and i am struggling to get Micron N25Q512A13GSF40G chip working with MSP430F5438. I cannot get the Device ID back. Would you able to give me the code of how to get the Device ID including all the necessary functions? I looked at the code above but some functions you called are missing. I will change the pins to work with my MCU.

    Thanks for your help.
    Shahid
  • Hello,
    I am able to read manufacture ID , device ID using read ID command but I am not able to read data. Can you please share your code so that I can see where I am doing wrong. I will really appreciate your support.
    Thanks in advance!
  • I had this same problem with this Flash and resolved it by reading the Flash status register after the ERASE and WRITE commands, essentially reading the Flash Status register in a loop while its program or erase controller bit = 0

    From spec doc:
    The flag status register must be read any time a PROGRAM, ERASE, or SUSPEND/
    RESUME command is issued, or after a RESET command while device is busy. The cycle
    is not complete until bit 7 of the flag status register outputs 1. Refer to Command Definitions
    for more information.

**Attention** This is a public forum