Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 2 of 2

Thread: SerialFlash: can erase command have lower precedence than write?

  1. #1
    Senior Member Sandro's Avatar
    Join Date
    Nov 2016
    Location
    Rimini - Italy
    Posts
    144

    SerialFlash: can erase command have lower precedence than write?

    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!!
    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..

  2. #2
    Senior Member Sandro's Avatar
    Join Date
    Nov 2016
    Location
    Rimini - Italy
    Posts
    144
    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);
                cmd = 0x75; //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);
            cmd = 0x7A;
            if ((f & FLAG_DIFF_SUSPEND) && (b == 1)) cmd = 0x8A;
            CSASSERT();
            SPIPORT.transfer(cmd); // Resume program/erase
            CSRELEASE();
        }
        SPIPORT.endTransaction();
    }

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •