tonyk_av 31 2 февраля, 2023 Опубликовано 2 февраля, 2023 · Жалоба Достучался до W25Q64, прочитал тип и уникальный идентификатор. Пытаюсь стереть и записать сектор- не получается. Судя по тому, что вижу в SR1=0b11111110 после подачи команды 0х06, память заблокирована для записи. Вопрос: какая должна быть цепочка команд для разблокировки, когда запись запрещена? Какая должна быть цепочка команд для разрешения записи? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
makc 192 2 февраля, 2023 Опубликовано 2 февраля, 2023 · Жалоба 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 сказал: разблокировки, когда запись запрещена? Какая должна быть цепочка команд для разрешения записи? Вопрос непонятен в контексте написанного выше. Как именно вы пробовали стирать и писать? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
tonyk_av 31 2 февраля, 2023 Опубликовано 2 февраля, 2023 · Жалоба Пробую так: 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 ); } //////////////////////////////////////////////////////////////////////////////// Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 184 2 февраля, 2023 Опубликовано 2 февраля, 2023 · Жалоба 1 час назад, tonyk_av сказал: Пробую так: Вижу enableWrite() только перед первой writePage() сектора. А где enableWrite() перед последующими записями страниц сектора? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
tonyk_av 31 2 февраля, 2023 Опубликовано 2 февраля, 2023 (изменено) · Жалоба 4 minutes ago, jcxz said: А где enableWrite() перед последующими записями страниц сектора? А нет их. Понял, учту. Но хотя бы первая страница сектора должна была записаться? Ткните пальцем, где почитать-посмотреть на последовательности команд при стирании и записи. Изменено 2 февраля, 2023 пользователем tonyk_av Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 184 2 февраля, 2023 Опубликовано 2 февраля, 2023 · Жалоба 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. Читайте внимательнее! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
tonyk_av 31 2 февраля, 2023 Опубликовано 2 февраля, 2023 · Жалоба 3 minutes ago, jcxz said: Читайте внимательнее! Постараюсь. Но заполночь это сложно. Благодарю за указания на ошибки! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
makc 192 2 февраля, 2023 Опубликовано 2 февраля, 2023 · Жалоба 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(), но поскольку её исходного кода мы не видим, то и выводы насчёт неё сделать невозможно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 184 2 февраля, 2023 Опубликовано 2 февраля, 2023 · Жалоба 6 минут назад, makc сказал: Ещё было бы неплохо перед началом каждой операции дожидаться отсутствия флага BUSY, который может быть вызван ранее запущенной командой записи: Я так понял, что в waitForTheRecordingToComplete() именно это и делается. А в начале или в конце - не важно, если везде одинаково. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
tonyk_av 31 2 февраля, 2023 Опубликовано 2 февраля, 2023 · Жалоба 8 minutes ago, jcxz said: Я так понял, что в waitForTheRecordingToComplete() именно это и делается Да, именно так. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Vasily_ 45 2 февраля, 2023 Опубликовано 2 февраля, 2023 · Жалоба 3 часа назад, tonyk_av сказал: Пытаюсь стереть и записать сектор- не получается. На ноге WP что висит ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
tonyk_av 31 2 февраля, 2023 Опубликовано 2 февраля, 2023 (изменено) · Жалоба 20 minutes ago, Vasily_ said: На ноге WP что висит ? По такой схеме включил: Изменено 2 февраля, 2023 пользователем tonyk_av Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
makc 192 2 февраля, 2023 Опубликовано 2 февраля, 2023 · Жалоба 1 час назад, jcxz сказал: Я так понял, что в waitForTheRecordingToComplete() именно это и делается. А в начале или в конце - не важно, если везде одинаково. Обычно получается эффективнее не ждать завершения (если только не нужно сделать гарантированный коммит изменений перед выключением), а проверять перед началом следующей операции записи/стирания. Таким образом получается, что все эти операции обычно идут в фоне и меньше влияют на время работы. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
tonyk_av 31 2 февраля, 2023 Опубликовано 2 февраля, 2023 · Жалоба 18 minutes ago, makc said: а проверять перед началом следующей операции записи/стирания Кстати, да. Учту. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 184 2 февраля, 2023 Опубликовано 2 февраля, 2023 · Жалоба 55 минут назад, makc сказал: Обычно получается эффективнее не ждать завершения (если только не нужно сделать гарантированный коммит изменений перед выключением), а проверять перед началом следующей операции записи/стирания. Таким образом получается, что все эти операции обычно идут в фоне и меньше влияют на время работы. Да. А ещё эффективнее - проверять периодически, в фоне. Чтобы потом вообще не ждать. В моём последнем драйвере SPI-флешь алгоритм проверки завершения записи/стирания был такой: После завершения любой операции записи/стирания, я запускал таймер задержки на время T1, по истечении которого, стартовал транзакцию чтения регистра состояния флешь (проверки флага BUSY). Если флаг BUSY ещё остался активен - перезапускал таймер на время T2 и повторял так операцию многократно, периодически. Если API записи/стирания было вызвано до момента обнаружения снятия BUSY, то задача ОС, вызвавшая это API ставилась в ожидание BUSY, а время T2 опроса BUSY опционально укорачивалось (если запрос к API был высокоприоритетный). Соответственно - при обнаружении снятия BUSY, все ожидающие доступа к API записи/стирания задачи возобновлялись по их приоритету. Время T1 - выбиралось в зависимости от завершившейся операции - стирания или записи. Выбиралось чуть больше минимальной (по даташиту) длительности соответствующей операции. Таким образом, при произвольных, непрогнозируемых по времени запросов к API записи/стирания от разных задач ОС, в большинстве случаев не нужно было ждать опроса BUSY перед началом транзакции записи/стирания. PS: Это если серьёзно подходить к реализации драйвера FLASH и стараться максимально ускорить работу. 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться