SerialFlash: can erase command have lower precedence than write?

Status
Not open for further replies.

Sandro

Well-known member
Hi all,
reading SerialFlash official description I undestand that I can read the flash chip while erasing a (createErasable) file without any interruption; but (anyone know if) is there any possibility to write a file without interruption while erasing another file? This should be a very important feature in order to realize a LIFO file-area on a flash chip for my audio project.

I created (createErasable) a bunch of 1packet (64KB) files: file_0, file_1 and so on; a file-write function is called inside an AudioStream-class object. I verified that write process is interrupted when a file_x.erase function is called: and it is interrupted by the erase call even if erase is called in the main/Arduino code.
The eraseBlock function (called once by erase function) seems (to me) to be executed within __disable_irq() and __enable_irq(), since audio interrupt does not stop it... But in the official code (see below) there is nothing about it ... So the audio-interrupt should suspend it!! :confused:
Code:
void SerialFlashFile::erase()
{
	uint32_t i, blocksize;

	blocksize = SerialFlash.blockSize();
	if (address & (blocksize - 1)) return; // must begin on a block boundary
	if (length & (blocksize - 1)) return;  // must be exact number of blocks
	for (i=0; i < length; i += blocksize) {
		SerialFlash.eraseBlock(address + i);
	}
}


void SerialFlashChip::eraseBlock(uint32_t addr)
{
    uint8_t f = flags;
    if (busy) wait();
    SPIPORT.beginTransaction(SPICONFIG);
    CSASSERT();
    SPIPORT.transfer(0x06); // write enable command
    CSRELEASE();
    delayMicroseconds(1);
    CSASSERT();
    if (f & FLAG_32BIT_ADDR)
    {
        SPIPORT.transfer(0xD8);
        SPIPORT.transfer16(addr >> 16);
        SPIPORT.transfer16(addr);
    }
    else
    {
        SPIPORT.transfer16(0xD800 | ((addr >> 16) & 255));
        SPIPORT.transfer16(addr);
    }
    CSRELEASE();
    SPIPORT.endTransaction();
    busy = 2;
}

Maybe the solution could be found by explicitly suspending the erase command execution while audio-interrupt is active... I guess is this the right way?

Thanks in advance for any suggestions..
 
Maybe I found the answer : noway (at least with my Winbond chip)...

1) On the datasheet of the flash chip W25Q512 it is repeatedly written that Erase operation disables both read and write operations... This explains why write process is interrrupted.

2) Since SerialFlash allows reading even while erasing, I've looked into read function, in SerialFlshChip.cpp. The read function uses command 75h; datasheet says:

"The Erase/Program Suspend instruction “75h”, allows the system to interrupt a Sector or Block Erase operation or a Page Program operation and then read from or program/erase data to, any other sectors or blocks"
So... datasheet doesn't even mention "write" ... :( :(

Code:
void SerialFlashChip::read(uint32_t addr, void *buf, uint32_t len)
{
    uint8_t *p = (uint8_t *)buf;
    uint8_t b, f, status, cmd;

    memset(p, 0, len);
    f = flags;
    SPIPORT.beginTransaction(SPICONFIG);
    b = busy;
    if (b)
    {
        // read status register ... chip may no longer be busy
        CSASSERT();
        if (flags & FLAG_STATUS_CMD70)
        {
            SPIPORT.transfer(0x70);
            status = SPIPORT.transfer(0);
            if ((status & 0x80)) b = 0;
        }
        else
        {
            SPIPORT.transfer(0x05);
            status = SPIPORT.transfer(0);
            if (!(status & 1)) b = 0;
        }
        CSRELEASE();
        if (b == 0)
        {
            // chip is no longer busy :-)
            busy = 0;
        }
        else if (b < 3)
        {
            // TODO: this may not work on Spansion chips
            // which apparently have 2 different suspend
            // commands, for program vs erase
            CSASSERT();
            SPIPORT.transfer(0x06); // write enable (Micron req'd)
            CSRELEASE();
            delayMicroseconds(1);
            [B]cmd = 0x75[/B]; //Suspend program/erase for almost all chips
            // but Spansion just has to be different for program suspend!
            if ((f & FLAG_DIFF_SUSPEND) && (b == 1)) cmd = 0x85;
            CSASSERT();
            SPIPORT.transfer(cmd); // Suspend command
            CSRELEASE();
            if (f & FLAG_STATUS_CMD70)
            {
                // Micron chips don't actually suspend until flags read
                CSASSERT();
                SPIPORT.transfer(0x70);
                do
                {
                    status = SPIPORT.transfer(0);
                }
                while (!(status & 0x80));
                CSRELEASE();
            }
            else
            {
                CSASSERT();
                SPIPORT.transfer(0x05);
                do
                {
                    status = SPIPORT.transfer(0);
                }
                while ((status & 0x01));
                CSRELEASE();
            }
        }
        else
        {
            // chip is busy with an operation that can not suspend
            SPIPORT.endTransaction();	// is this a good idea?
            wait();			// should we wait without ending
            b = 0;			// the transaction??
            SPIPORT.beginTransaction(SPICONFIG);
        }
    }
    do
    {
        uint32_t rdlen = len;
        if (f & FLAG_MULTI_DIE)
        {
            if ((addr & 0xFE000000) != ((addr + len - 1) & 0xFE000000))
            {
                rdlen = 0x2000000 - (addr & 0x1FFFFFF);
            }
        }
        CSASSERT();
        // TODO: FIFO optimize....
        if (f & FLAG_32BIT_ADDR)
        {
            SPIPORT.transfer(0x03);
            SPIPORT.transfer16(addr >> 16);
            SPIPORT.transfer16(addr);
        }
        else
        {
            SPIPORT.transfer16(0x0300 | ((addr >> 16) & 255));
            SPIPORT.transfer16(addr);
        }
        SPIPORT.transfer(p, rdlen);
        CSRELEASE();
        p += rdlen;
        addr += rdlen;
        len -= rdlen;
    }
    while (len > 0);
    if (b)
    {
        CSASSERT();
        SPIPORT.transfer(0x06); // write enable (Micron req'd)
        CSRELEASE();
        delayMicroseconds(1);
        [B]cmd = 0x7A[/B];
        if ((f & FLAG_DIFF_SUSPEND) && (b == 1)) cmd = 0x8A;
        CSASSERT();
        SPIPORT.transfer(cmd); // Resume program/erase
        CSRELEASE();
    }
    SPIPORT.endTransaction();
}
 
Status
Not open for further replies.
Back
Top