Перейти к содержанию
    

W25Q64, алгоритм разблокировки и записи

Достучался до W25Q64, прочитал тип и уникальный идентификатор. Пытаюсь стереть и записать сектор- не получается. Судя по тому, что вижу в SR1=0b11111110 после подачи команды 0х06, память заблокирована для записи.

Вопрос: какая должна быть цепочка команд для разблокировки, когда запись запрещена?  Какая должна быть цепочка команд для разрешения записи?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

40 минут назад, tonyk_av сказал:

Судя по тому, что вижу в SR1=0b11111110 после подачи команды 0х06, память заблокирована для записи.

Судя по содержимому регистра эта команда отработала успешно и бит WEL установлен:

11.1.2 Write Enable Latch (WEL) Write Enable Latch (WEL) is a read only bit in the status register (S1) that is set to a 1 after executing a Write Enable Instruction. The WEL status bit is cleared to a 0 when the device is write disabled. A write disable state occurs upon power-up or after any of the following instructions: Write Disable, Page Program, Sector Erase, Block Erase, Chip Erase and Write Status Register.

42 минуты назад, tonyk_av сказал:

разблокировки, когда запись запрещена?  Какая должна быть цепочка команд для разрешения записи?

Вопрос непонятен в контексте написанного выше. Как именно вы пробовали стирать и писать?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Пробую так:

        memset( msg, 0, sizeof( msg ) );
        strcpy( msg, "123" );
        w25q -> enableWrite();
        w25q -> eraseSector( 0 );
        w25q -> enableWrite();
        w25q -> writeSector( 0, ( uint8* )msg );
        memset( msg, 0, sizeof( msg ) );
        w25q -> readSector( 0, ( uint8* )msg );
Spoiler
bool
W25Q::enableWrite( void )
{
    *cs_pin = ON;
    {
        SPI_writeByte( W25_WRITE_ENABLE );
    }
    *cs_pin = OFF;

    return( true );
}

 

Spoiler
bool
W25Q::eraseSector( int32 _sector )
{
    waitForTheRecordingToComplete();

    int32
        addr = _sector * sector_size;

    *cs_pin = ON;
    {
        if( getChipId() >= W25Q256 )
        {
            SPI_writeByte( W25_SECTOR_ERASE1 );
            SPI_writeByte( ( addr & 0xFF000000 ) >> 24 );
        }
        else
        {
            SPI_writeByte( W25_SECTOR_ERASE );
        }

        SPI_writeByte( ( addr & 0xFF0000 ) >> 16 );
        SPI_writeByte( ( addr & 0xFF00   ) >> 8  );
        SPI_writeByte(   addr & 0xFF             );
    }
    *cs_pin = OFF;

    waitForTheRecordingToComplete( );

    Task::mdelay( 1 );

    return( true );
}
Spoiler
////////////////////////////////////////////////////////////////////////////////

int32
W25Q::writePage
(
    int32   _page,
    uint8*  _buff
)
{
    if
    (
        ( _page < 0 )                               ||
        ( _page > getIndexOfLastPageForWriting() )  ||
        ( _buff == 0 )
    )
    {
        return( 0 );
    }

    int32
        n = 0;

    *cs_pin = ON;
    {
        int32
            addr = _page * page_size;

        if( getChipId() >= W25Q256 )
        {
            SPI_writeByte( W25_PROGRAM_PAGE1 );
            SPI_writeByte( ( addr & 0xFF000000 ) >> 24 );
        }
        else
        {
            SPI_writeByte( W25_PROGRAM_PAGE1 );
        }

        SPI_writeByte( ( addr & 0xFF0000 ) >> 16 );
        SPI_writeByte( ( addr & 0x00FF00 ) >> 8  );
        SPI_writeByte(   addr & 0x0000FF         );
        n = SPI_writeBytes ( _buff, getSizeOfPage( _page ) );
    }
    *cs_pin = OFF;

    waitForTheRecordingToComplete();

    return( n );
}

////////////////////////////////////////////////////////////////////////////////

int32
W25Q::writeSector
(
    int32   _sector,
    uint8*  _buff
)
{
    if
    (
        ( _sector < 0 )             ||
        ( _sector >= sector_count ) ||
        ( page_size <= 0 )          ||
        ( _buff == 0 )
    )
    {
        return( 0 );
    }

    int32
        page =
            convertSectorToPage( _sector ),
        was_written = 0,
        pcnt = getSizeOfSector( _sector) / page_size;

    while( pcnt > 0 )
    {
        was_written += writePage( page, _buff );
        _buff += was_written;
        page++;
        pcnt--;
    }

    Task::mdelay( 1 );

    return( was_written );
}

////////////////////////////////////////////////////////////////////////////////
Spoiler
////////////////////////////////////////////////////////////////////////////////

int32
W25Q::readPage
(
    int32   _page,
    uint8*  _buff
)
{
    if
    (
        ( _page < 0 )                               ||
        ( _page > getIndexOfLastPageForReading() )  ||
        ( _buff == 0 )
    )
    {
        return( 0 );
    }

    int32
        n = 0;

    *cs_pin = ON;
    {
        int32
            addr = _page * page_size;

        if( chip_id >= W25Q256 )
        {
            SPI_writeByte( W25_FAST_READ1 );
            SPI_writeByte( ( addr & 0xFF000000 ) >> 24 );
        }
        else
        {
            SPI_writeByte( W25_FAST_READ1 );
        }

        SPI_writeByte( ( addr & 0xFF0000 ) >> 16 );
        SPI_writeByte( ( addr & 0x00FF00 ) >> 8  );
        SPI_writeByte(   addr & 0x0000FF         );
        SPI_writeByte( 0 );

        n = SPI_readBytes( _buff, page_size );
    }
    *cs_pin = OFF;

    return( n );
}

////////////////////////////////////////////////////////////////////////////////

int32
W25Q::readSector
(
    int32   _sector,
    uint8*  _buff
)
{
    if
    (
        ( _sector < 0 )                                 ||
        ( _sector < getIndexOfFirstSectorForReading() ) ||
        ( _sector > getIndexOfLastSectorForReading() )  ||
        ( page_size <= 0 )                              ||
        ( _buff == 0 )
    )
    {
        return( 0 );
    }

    int32
        was_read = 0,
        i = getSizeOfSector( _sector ) / page_size;

    while( i > 0 )
    {
        was_read += readPage( i, _buff );
        _buff += was_read;
        i--;
    }

    return( was_read );
}

////////////////////////////////////////////////////////////////////////////////

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, tonyk_av сказал:

Пробую так:

Вижу enableWrite() только перед первой writePage() сектора. А где enableWrite() перед последующими записями страниц сектора?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 minutes ago, jcxz said:

А где enableWrite() перед последующими записями страниц сектора?

А нет их. Понял, учту. Но хотя бы первая страница сектора должна была записаться?

Ткните пальцем, где почитать-посмотреть на последовательности команд при стирании и записи.

Изменено пользователем tonyk_av

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 минут назад, tonyk_av сказал:

А нет их. Понял, учту. Но хотя бы первая страница сектора должна была записаться?

Если нет других ошибок - видимо да.

5 минут назад, tonyk_av сказал:

Ткните пальцем, где почитать-посмотреть на последовательности команд при стирании и записи.

В мануале же описано. И ув. makc выше даже процитировал нужное место мануала:

1 час назад, makc сказал:

A write disable state occurs upon power-up or after any of the following instructions: Write Disable, Page Program, Sector Erase, Block Erase, Chip Erase and Write Status Register.

Читайте внимательнее!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 minutes ago, jcxz said:

Читайте внимательнее!

Постараюсь. Но заполночь это сложно.

Благодарю за указания на ошибки!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 минуты назад, jcxz сказал:

Если нет других ошибок - видимо да.

Ещё было бы неплохо перед началом каждой операции дожидаться отсутствия флага BUSY, который может быть вызван ранее запущенной командой записи:

Цитата

7.1.1 Erase/Write In Progress (BUSY) – Status Only
BUSY is a read only bit in the status register (S0) that is set to a 1 state when the device is executing a
Page Program, Quad Page Program, Sector Erase, Block Erase, Chip Erase, Write Status Register or
Erase/Program Security Register instruction. During this time the device will ignore further instructions
except for the Read Status Register and Erase/Program Suspend instruction (see tW, tPP, t SE, tBE, and
tCE in AC Characteristics). When the program, erase or write status/security register instruction has
completed, the BUSY bit will be cleared to a 0 state indicating the device is ready for further instructions.

Вполне возможно это реализовано в waitForTheRecordingToComplete(), но поскольку её исходного кода мы не видим, то и выводы насчёт неё сделать невозможно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 минут назад, makc сказал:

Ещё было бы неплохо перед началом каждой операции дожидаться отсутствия флага BUSY, который может быть вызван ранее запущенной командой записи:

Я так понял, что в waitForTheRecordingToComplete() именно это и делается. А в начале или в конце - не важно, если везде одинаково.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

8 minutes ago, jcxz said:

Я так понял, что в waitForTheRecordingToComplete() именно это и делается

Да, именно так.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 часа назад, tonyk_av сказал:

Пытаюсь стереть и записать сектор- не получается.

На ноге WP что висит ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

20 minutes ago, Vasily_ said:

На ноге WP что висит ?

По такой схеме включил:

image.thumb.png.86699bcad267884cc1322d4db752ac30.png

Изменено пользователем tonyk_av

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, jcxz сказал:

Я так понял, что в waitForTheRecordingToComplete() именно это и делается. А в начале или в конце - не важно, если везде одинаково.

Обычно получается эффективнее не ждать завершения (если только не нужно сделать гарантированный коммит изменений перед выключением), а проверять перед началом следующей операции записи/стирания. Таким образом получается, что все эти операции обычно идут в фоне и меньше влияют на время работы.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

18 minutes ago, makc said:

а проверять перед началом следующей операции записи/стирания

Кстати, да. Учту.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

55 минут назад, makc сказал:

Обычно получается эффективнее не ждать завершения (если только не нужно сделать гарантированный коммит изменений перед выключением), а проверять перед началом следующей операции записи/стирания. Таким образом получается, что все эти операции обычно идут в фоне и меньше влияют на время работы.

Да. А ещё эффективнее - проверять периодически, в фоне. :wink: Чтобы потом вообще не ждать.

В моём последнем драйвере SPI-флешь алгоритм проверки завершения записи/стирания был такой: После завершения любой операции записи/стирания, я запускал таймер задержки на время T1, по истечении которого, стартовал транзакцию чтения регистра состояния флешь (проверки флага BUSY). Если флаг BUSY ещё остался активен - перезапускал таймер на время T2 и повторял так операцию многократно, периодически. Если API записи/стирания было вызвано до момента обнаружения снятия BUSY, то задача ОС, вызвавшая это API ставилась в ожидание BUSY, а время T2 опроса BUSY опционально укорачивалось (если запрос к API был высокоприоритетный). Соответственно - при обнаружении снятия BUSY, все ожидающие доступа к API записи/стирания задачи возобновлялись по их приоритету.

Время T1 - выбиралось в зависимости от завершившейся операции - стирания или записи. Выбиралось чуть больше минимальной (по даташиту) длительности соответствующей операции.

Таким образом, при произвольных, непрогнозируемых по времени запросов к API записи/стирания от разных задач ОС, в большинстве случаев не нужно было ждать опроса BUSY перед началом транзакции записи/стирания.

 

PS: Это если серьёзно подходить к реализации драйвера FLASH и стараться максимально ускорить работу.  :wink:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...