// Файл с основными определениями для W25Q16JV. // v 1.0 от 08/10/20 // Автор: Сычев А. // используйте следующие макросы перед подключением этого заголовочного файла // W25Q16JV_APILEVEL - для доступа к структурам и типам низокуровневых функций // W25Q16JV_LOWLEVEL - для доступа ко всем низкоуровневым определениям // // например: # файл c API для работы с флешкой использует // только интерфейсы, ему достаточно только W25Q16JV_APILEVEL // # файл, который реализует низкоуровневые команды требует W25Q16JV_LOWLEVEL // # пользовательский файл высокоуровневой программы вообще не требует этих макросов #ifndef W25Q16JV_H #define W25Q16JV_H // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ ВВЕДЕНИЕ №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // ВНИМАНИЕ! Здесь и далее вводится замена "Сектор" => "Блок" и наоборот, т.к. данный драйвер основан // драйвере для чипа AT45, где под сектором понимается самый большой кусок данных, под блоком - кусок // по меньше, и под страницей - самый меньший. В W25Q под блоком наоборт - самый большой, а под сектором // самый малый, а страниц нет вообще. Для унификации для W25Q вводим замену понятия Блок - в даташите // блок это самый большой кусок, а в драйвере - будет самый малый. В даташите - сектор - самый малый // в данном драйвере - самый большой. // Такая замена необходима для сохранения внутренней структуры драйвера, функций и макросов. // W25Q16JV - чип энергонезависимой памяти емкостью 16 мегабит. // Чип W25Q16JV состоит из 32 секторов, 2 особенных и 30 обычных. Каждый сектор делится на 16 блоков // размером 4KB. Особенность 2 секторов заключается в том, как работает блочная защита от записи. // Особенные сектора расположены: один в начале памяти, один в конце. // Чип обладает 2 программными способами защиты от записи: индивидуальная защита секторов и групповая. // Индивидуальная защита позволяет заблокировать независимо каждый из 30 обычных секторов и независимо // каждый блок из 2 особенных секторов. В итоге есть возможность защитить 62 элемента: 30 по секторам // (все 16 блоков каждого из 30 секторов) и 32 по блокам (16+16 из 2 секторов). Групповая защита // строится на регистре защиты, где выбирается определенная часть защищаемого пространства от начала // памяти или от конца памяти. По умолчанию выбрана групповая схема защиты. // // Защита от записи: // -переходит в состояние сбороса если питание снижено до предела // -разрешает запись только после прошествии защитного итервала после выхода их сброса (либо при подаче питания) // -программная защита от записи активируется после каждой операции записи/стирания // -имеется HW и SW защита регистра статуса // -возможность индивидуальной защиты блока // -возможность защиты по защелке: защита снимается только после Power-up (пробуждения) // -возможность одноразового программирования: OTP // // Производитель обращает внимание на особенность, связанную с защитой от записи при формировании // сигнала выбора (CS): управляющий контроллер должен отслеживать уровень питания чипа с тем, // чтобы выставлять CS только когда уровень питания находится в допустимой зоне после старта, // а также перед выключнием, чтобы исключить выбор устройства вблизи границы напряжения питания. // // Чип позволяет использовать дополнительные линии передачи данных совместно с DO, // а именно Dual-Output и Quad-Output, для чего использутся отдельные команды. // Данная библиотека НЕ ПОДДЕРЖИВАЕТ данные режимы. /* */ #include #include #include "drivers\flash\w25q\config\W25Q16JV_CONF.h" #include "drivers\flash\base\bitbuffer.h" #ifndef W25QXXX_API_TIMEOUT #define W25QXXX_API_TIMEOUT _TIME_FLASHAPI_TIMEOUT #endif /* */ // Библиотека позволяет исключить циклы ожидания после // длительных команд, переложив ожидание ПОСЛЕ команды // в ожидание ПЕРЕД командой - активное ожидание освобождения // устройства через сканирования флага BUSY в статусном регистре. // Библиотека в любом случае использует чтение флага перед // каждой низкоуровневой командой, но делает это обычно 1 раз, // возвращая ошибку после неудачи. Используйте макрос W25QXXX_BKGOPERATIONS=1, // для того, чтобы использовать постоянное сканирование флага // перед командой вместо ожидания в конце команды. Используя данный режим, // будьте внимательны при сохранении данных перед выключением питания. // Библиотека позволяет использовать "умные" задержки после длительных // операций. Это означает, что ожидание после команды представляет собой // периодическое сканирование флага BUSY. Заданная в спецификации задержка // разбивается на квантованные промежутки времени, через которые происходит // опрос занятости устройства. Так предположительно длительная задержка // может быть сокращена при досрочном освобождении устройства. По умолчанию // режим "умных" задержек включен. Для выключения объявите макрос W25Q16JV_DONTUSESMARTDELAY=1 // Режим "умных" задержек используется для обеспечения МИЛЛИСЕКУНДНЫХ задержек более W25QXXX_SMART_WAIT_THRESHOLD миллисекунд #define __FLASH_PAGE_WRITECYCLES 100000 // main datasheet #define __FLASH_STATUSREGISTER_WRITECYCLES 100000 // AN0000016 August 7, 2019 Revision 2.0 /* */ //#define W25Q16JV_DONTUSESMARTDELAY 0 // отключение "умной" задержки //#define W25QXXX_BKGOPERATIONS 0 // отключение задержек операций | ВНИМАНИЕ! Только для ОПЫТНЫХ пользователей (-: !!! /* */ //-------------------------------------------------------------- // Иерархия распределения блоков и секторов // Номера секторов - отнисительно блока секторов //-------------------------------------------------------------- // W25Q16JV // _________ // | // |-[-] Сектор 0 / Специальный сектор, содержит 16 блоков 4КБ // | | _____ // | |___ Блок 0 }-----------------------------------------------+ [ 0] | | // | |___ Блок 1 }-----------------------------------------------+ [ 1] | | // | . | | I | // | . . | N | // | . | | D | // | |___ Блок 15 }-----------------------------------------------+ [15] | I | // | | | V | // | | | I | // |-[-] Сектор 1 / Обычный Сектор, содержит 16 блоков 4КБ }------+ [16] | D | // | | | | U | // | |___ Блок 0 | | A | // | |___ Блок 1 | | L | // | . . | | // | . . | S | // | . . | E | // | |___ Блок 15 | | C | // | | | T | // | | | O | // |-[-] Сектор 2 / Обычный Сектор, содержит 16 блоков 4КБ }------+ [17] | R | // | | | | / | // | |___ Блок 0 | | B | // | |___ Блок 1 | | L | // | . . | O | // | . . | C | // | . . | K | // | |___ Блок 15 | | | // . . | P | // . . | R | // . . | O | // |-[-] Сектор 30 / Обычный Сектор, содержит 16 блоков 4КБ }------+ [58] | T | // | | | | E | // | |___ Блок 0 | | C | // | |___ Блок 1 | | T | // | . . | I | // | . . | O | // | . . | N | // | |___ Блок 15 | | | // | | | R | // | | | E | // |-[-] Сектор 31 / Специальный Сектор, содержит 16 блоков 4КБ | | G | // | | | | I | // | |___ Блок 0 }-----------------------------------------------+ [59] | S | // | |___ Блок 1 }-----------------------------------------------+ [60] | T | // | . . | E | // | . . | R | // | . . | | // | |___ Блок 15 }-----------------------------------------------+ [61] |___| // //---------------------------------------------------------------------------------------------------------- // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ Внутренние определения №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // ##__##__##__##__##__##__##__##__##__##__##__##__##__##__##__## // ## ## // ## Распределение памяти ## // ## ## // ##__##__##__##__##__##__##__##__##__##__##__##__##__##__##__## // размер страницы #define __FULL_PAGE_SIZE 4096 #define __PROG_PAGE_SIZE 256 // размер страницы при программировании // страницы (=сектора) стандартные - каждая страница имеет 4096 байт данных #define __PAGE_SIZE __FULL_PAGE_SIZE // размер страницы: для API #define __PAGE_SIZE_USER __PAGE_SIZE // размер страницы: для пользователя // размер блока #define __PAGES_PER_BLOCK 1 #define __BLOCK_SIZE ( __PAGES_PER_BLOCK * __PAGE_SIZE ) #define __BLOCK_SIZE_USER ( __PAGES_PER_BLOCK * __PAGE_SIZE_USER ) // Количество секторов, блоков #define __SECTORS_TYPICAL 30 // количество обычных секторов #define __SECTORS_SPECIAL 2 // количество особенных секторов #define __SECTORS_FULL (__SECTORS_TYPICAL + __SECTORS_SPECIAL) // полное количество секторов #define __SECTORS __SECTORS_FULL #define __BLOCKS 512 // полное количество блоков #define __BLOCKS_PER_SECTOR 16 // количество блоков в секторе #define __FULL_PAGES (__BLOCKS * __PAGES_PER_BLOCK) #define __PAGES_PER_SECTOR (__BLOCKS_PER_SECTOR * __PAGES_PER_BLOCK ) #define __PROT_SECTOR_FLAGS (__SECTORS_TYPICAL + (__SECTORS_SPECIAL) * (__BLOCKS_PER_SECTOR) ) #define __PROT_SECTOR_TO_ADDRESS(n) W25Q16JV_prot_sector_to_address(n) #define __SECTOR_TO_PROTSECTOR(n,m) W25Q16JV_sector_to_protsector(n,&m) // размеры секторов #define __SECTOR_STD_SIZE 0x10000 // 64K #define __SECTOR0_SIZE __SECTOR_STD_SIZE #define __SECTOR1_SIZE __SECTOR_STD_SIZE #define __SECTOR2_SIZE __SECTOR_STD_SIZE #define __SECTOR3_SIZE __SECTOR_STD_SIZE #define __SECTOR4_SIZE __SECTOR_STD_SIZE #define __SECTOR5_SIZE __SECTOR_STD_SIZE #define __SECTOR6_SIZE __SECTOR_STD_SIZE #define __SECTOR7_SIZE __SECTOR_STD_SIZE #define __SECTOR8_SIZE __SECTOR_STD_SIZE #define __SECTOR9_SIZE __SECTOR_STD_SIZE #define __SECTOR10_SIZE __SECTOR_STD_SIZE #define __SECTOR11_SIZE __SECTOR_STD_SIZE #define __SECTOR12_SIZE __SECTOR_STD_SIZE #define __SECTOR13_SIZE __SECTOR_STD_SIZE #define __SECTOR14_SIZE __SECTOR_STD_SIZE #define __SECTOR15_SIZE __SECTOR_STD_SIZE #define __SECTOR16_SIZE __SECTOR_STD_SIZE #define __SECTOR17_SIZE __SECTOR_STD_SIZE #define __SECTOR18_SIZE __SECTOR_STD_SIZE #define __SECTOR19_SIZE __SECTOR_STD_SIZE #define __SECTOR20_SIZE __SECTOR_STD_SIZE #define __SECTOR21_SIZE __SECTOR_STD_SIZE #define __SECTOR22_SIZE __SECTOR_STD_SIZE #define __SECTOR23_SIZE __SECTOR_STD_SIZE #define __SECTOR24_SIZE __SECTOR_STD_SIZE #define __SECTOR25_SIZE __SECTOR_STD_SIZE #define __SECTOR26_SIZE __SECTOR_STD_SIZE #define __SECTOR27_SIZE __SECTOR_STD_SIZE #define __SECTOR28_SIZE __SECTOR_STD_SIZE #define __SECTOR29_SIZE __SECTOR_STD_SIZE #define __SECTOR30_SIZE __SECTOR_STD_SIZE #define __SECTOR31_SIZE __SECTOR_STD_SIZE #define __FULL_CHIP_SIZE (__BLOCKS * __PAGES_PER_BLOCK * __FULL_PAGE_SIZE) #define __FULL_DATA_SIZE (__FULL_CHIP_SIZE) // переводит НОМЕР защищаемого сектора в адрес // Защищаемый сектор - не всегда сектор 64КБ, для 0 и 31 секторов 64К из них // выводятся биты защиты для каждого блока 4К // // используется для команд индивидуальной защиты секторов/блоков static inline size_t W25Q16JV_prot_sector_to_address(size_t protsector) { size_t w24Address = 0; if( protsector > 0 && protsector < __PROT_SECTOR_FLAGS ) { // проверка на первый специальный сектор, состоящий из __BLOCKS_PER_SECTOR // каждый блок такого сектора представлен отдельным битом защиты // Это сектор 0 if( protsector < __BLOCKS_PER_SECTOR ) { // адрес наращивается для каждого блока 4К в секторе 64К w24Address = (protsector * __BLOCK_SIZE); } else // Это обычные сектора 1..30, каждый сектора представлен одним битом защиты, без разбиения на блоки if( protsector >= __BLOCKS_PER_SECTOR && protsector < __BLOCKS_PER_SECTOR + __SECTORS_TYPICAL ) { w24Address = (__SECTOR0_SIZE) + (protsector - __BLOCKS_PER_SECTOR) * (__SECTOR_STD_SIZE); } // Это опять особенный, последний, сектор, разделенный на защищаемые блоки else { w24Address = (protsector - __BLOCKS_PER_SECTOR - __SECTORS_TYPICAL) * (__BLOCK_SIZE) + (__SECTOR_STD_SIZE)*(__SECTORS - 1); } } return w24Address; } // вычисляет начальный номер protection-sector-block для сектора 64КБ // используется для команд индивидуальной защиты секторов/блоков static inline size_t W25Q16JV_sector_to_protsector(size_t nSector, size_t * pCount ) { size_t nStartProtSector = 0; if( nSector == 0 ) { nStartProtSector = 0; *pCount = __BLOCKS_PER_SECTOR; // количество protsectors в секторе 64КБ = 16 для особенного сектора } else if( nSector == __SECTORS - 1 ) { nStartProtSector = __BLOCKS_PER_SECTOR + __SECTORS_TYPICAL; *pCount = __BLOCKS_PER_SECTOR; // количество protsectors в секторе 64КБ = 16 для особенного сектора } else { nStartProtSector = __BLOCKS_PER_SECTOR + nSector - 1; *pCount = 1; // количество protsectors в секторе 64КБ = 1 для обычного сектора } return nStartProtSector; // начальный номер protsector-а для сектора 64КБ } #include "drivers\flash\base\flash_api_types.h" #ifdef W25Q16JV_LOWLEVEL //--------------------------------------------------------------- // Чип имеет 2 встроенных SRAM буфера по 528 байт для проведения // операций чтения/записи и сравнения. Чип позволяет читать // данные последовательно, страницу за страницей (послед. чтение). // Также возможна запись содержимого буфера в память со стиранием, // при этом стирание происходит автоматически. //--------------------------------------------------------------- // ##__##__##__##__##__##__##__##__##__##__##__##__##__##__##__## // ## ## // ## команды обмена ## // ## ## // ##__##__##__##__##__##__##__##__##__##__##__##__##__##__##__## // чтение #define _RCMD_ARRYREAD 0x03 // последовательное чтение #define _LCMD_ARRYREAD 0x03 // последовательное чтение (до 50MHz) #define _HCMD_ARRYREAD 0x0B // последовательное чтение (до 133MHz) // запись #define _WCMD_PGWRIT 0x02 // Запись страницы // Стирание: Чип позволяет стирать память по-странично, и по-блочно #define _ECMD_PAGERASE 0x20 // Стирание страницы #define _ECMD_BLKERASE32 0x52 // Стирание 8 страниц // по-секторно #define _ECMD_SCTERASE 0xD8 // Стирание сектора // или целиком (последовательность 4 команд-байт) #define _ECMD_CHPERASE 0xC7 // Стрирание чипа // энергосберегающий режим, сброс #define _ACMD_EPWRDOWN 0xB9 // переход в спящий режим #define _ACMD_LPWRDOWN 0xAB // выход их спящего режима #define _ACMD_ENARESET 0x66 // разрешение сброса чипа #define _ACMD_DORESET 0x99 // команда сброса чипа (Требуется предварительная 0x66) // команды чтения/записи "статусных" регистров #define _ACMD_STATREAD_1 0x05 // чтение статусного регистра 1 #define _ACMD_STATREAD_2 0x35 // чтение статусного регистра 2 #define _ACMD_STATREAD_3 0x15 // чтение статусного регистра 3 #define _ACMD_STATWRIT_1 0x01 // запись статусного регистра 1 #define _ACMD_STATWRIT_2 0x31 // запись статусного регистра 2 #define _ACMD_STATWRIT_3 0x11 // запись статусного регистра 3 // команды идентификации #define _ACMD_MFIDREAD 0x9F // чтение информации о производителе и ID микросхемы #define _ACMD_SFDPREAD 0x5A // чтение регистра Serial Flash Discoverable Parameter (Информация о производителе и устройстве) #define _ACMD_UIDRREAD 0x4B // чтение регистра Unique ID // команды защиты #define _SCMD_WRENABLE 0x06 // разрешение записи #define _SCMD_WRDISABLE 0x04 // разрешение записи #define _SCMD_WRENVOL 0x50 // разрешение записи (только для статусных регистров, без сохранения) #define _SCMD_SECRGERS 0x44 // стирание регистра защиты #define _SCMD_SECRGWRT 0x42 // запись регистра защиты #define _SCMD_SECRGRD 0x48 // чтение регистра защиты #define _SCMD_GLBLLK 0x7E // глобальная блокировка блоков #define _SCMD_GLBLUNLK 0x98 // глобальная разблокировка блоков #define _SCMD_BLKLKRD 0x3D // чтение регистра индивидуальной блокировки сектора/блока #define _SCMD_BLKLOCK 0x36 // индивидуальная блокировка сектора/блока #define _SCMD_BLKULOCK 0x39 // индивидуальная разблокировка сектора/блока #define _SCMD_ERPGSUSP 0x75 // заморозить процесс стирания/записи #define _SCMD_ERPGRESM 0x7A // разморозить процесс стирания/записи #endif #if defined(W25Q16JV_APILEVEL) || defined(W25Q16JV_LOWLEVEL) // ##__##__##__##__##__##__##__##__##__##__##__##__##__##__##__## // ## ## // ## максимальные времена ## // ## ## // ##__##__##__##__##__##__##__##__##__##__##__##__##__##__##__## // // из колонки MAX таблицы временных характеристик чипа #define _TIME_CSSET_us 1 // время на установление CS в 1 #define _TIME_CSCLR_us 1 // время на установление CS в 0 #define _TIME_CSHLD_us 1 // минимальное время CS в неактивном состоянии м/у командами #define _TIME_EDPDM_us 3 // вход в спящий режим #define _TIME_RDPDM_us 4 // выход из спящего режима #define _TIME_RSTRC_us 30 // время восстановления после сброса #define _TIME_RSTWD_us 10 // время удержания сигнала сброса #define _TIME_STRUP_us 20 // время готовности после подачи питания (но чип все еще не готов записывать данные) #define _TIME_PGPRG_ms 3 // программирование страницы #define _TIME_STPRG_ms 15 // программирование статусного регистра #define _TIME_START_ms 7 // ожидание запуска чипа до полной готовности #define _TIME_COOLDOWN_ms 20 // ожидание "остывания" чипа после выключения питания #define _TIME_PGERS_ms 400 // стирание страницы (=блока 4KB) #define _TIME_BKERS_ms 400 // стирание блока (=страницы 4KB) #define _TIME_SCERS_ms 2000 // стирание сектора (64KB) #define _TIME_FLASHAPI_TIMEOUT 10 // стандартный таймаут ожидания API-функций #endif #if defined(W25Q16JV_LOWLEVEL) || defined(W25Q16JV_APILEVEL) // ##__##__##__##__##__##__##__##__##__##__##__##__##__##__##__## // ## ## // ## ДРУГИЕ ОПРЕДЕЛЕНИЯ ## // ## ## // ##__##__##__##__##__##__##__##__##__##__##__##__##__##__##__## /* */ #include "drivers\flash\w25q\config\W25Q16JV_CONF.h" /* */ // чтение идентификатора #define __FLASH_WINBOND_ID 0xEF // индентификатор фирмы WINBOND в поле Manufacturer ID #define __FLASH_INVALID_ID 0xFF // неверно прочитанный идентификатор Manufacturer ID #define __FLASH_DENSITY_16MB 0x15 // идентификатор объема накопителя 16МБит #define __FLASH_MEMORYID_Q 0x40 // идентификатор типа чипа W25Q16JV-IQ/JQ #define __FLASH_MEMORYID_M 0x70 // идентификатор типа чипа W25Q16JV-IM*/JM* #endif #if defined(W25Q16JV_APILEVEL) || defined(W25Q16JV_LOWLEVEL) // регистр защиты - байты защиты #define __FLASH_PROTECTION_REG_ENABLE 0xFF // байт регистра защиты - сектор защищен #define __FLASH_PROTECTION_REG_DISABLE 0x00 // байт регистра защиты - сектор НЕ защищен #endif #ifdef W25Q16JV_LOWLEVEL // оперативная память #define __FLASH_LL_COMMAND_MAXSIZE 8 // максимальное количество байт, выделяемое для буфера команд // максимальное количество байт, выделяемое для буфера команд + буфера страницы #define __FLASH_LL_SVCMEM_SIZE ( __FLASH_LL_COMMAND_MAXSIZE + __SECTORS_FULL ) // alloc_place содержит protectbuffer[] байт #endif #if defined(W25Q16JV_APILEVEL) || defined(W25Q16JV_LOWLEVEL) // регистр безопасности #define __FLASH_USER_SECURITY_BYTES 256 // количество байт, доступных для программирования в регистре безопасности #endif // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ структуры и типы №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // #if defined(W25Q16JV_LOWLEVEL) || defined(W25Q16JV_APILEVEL) //------------------------------------------- #pragma pack( push, 1 ) // РЕГИСТРЫ СТАТУСА union __flash_status_register_st_1 { // [W25Q OK] struct { __FLASH_BYTE bBusy : 1; // BUSY бит занятости BUSY: занят(1)/свободен(0), WIP (Write In Progress) __FLASH_BYTE bWrEnLatch: 1; // WEL индикатор возможности записи после Write Enable Instruction: (1) разрешена / (0) запрещена __FLASH_BYTE cBlkProt : 3; // BP индикаторы и установки групповой защиты блоков __FLASH_BYTE bTopBot : 1; // TB бит переключения групповой защиты с начала (bTopBot=0) или конца (bTopBot=1) памяти __FLASH_BYTE bSectBlk : 1; // SEC бит переключения групповой защиты на блоки 4КБ (bSectBlk=1) или 64КБ секторы (bSectBlk=0) [sic!] __FLASH_BYTE bStatProt : 1; // SRP бит аппаратной защиты статусного регистра: (1) - запись возможна если аппаратный сигнал ~WP=0 (asserted), (0) - без защиты }; __FLASH_BYTE status; }; union __flash_status_register_st_2 { // [W25Q OK] struct { __FLASH_BYTE bStatLock : 1; // SRL блокировка стаусного регистра: (1) - заблокировать до следующего цикла подачи питания, (0) - нет блокировки __FLASH_BYTE bQuadEn : 1; // разрешение режима Quad SPI (обмен по 4 линиям IO). (1) - разрешен, (0) - запрещен __FLASH_BYTE bRes1 : 1; // зарезервировано, RO, =0 __FLASH_BYTE bLockSec1 : 1; // LB1 бит защиты Security Register 1: блокировка записи SR1, OTP, не снимается! __FLASH_BYTE bLockSec2 : 1; // LB2 бит защиты Security Register 2: блокировка записи SR2, OTP, не снимается! __FLASH_BYTE bLockSec3 : 1; // LB3 бит защиты Security Register 3: блокировка записи SR3, OTP, не снимается! __FLASH_BYTE bCmpProt : 1; // CMP бит комплиментарности групповой защиты: позволяет проинвертировать признаки групповой защиты блоков, CMP=0 - нет инверсии __FLASH_BYTE bSuspended: 1; // SYS индикатор Suspend State, SYS=1 если одна из команд записи/стирания находится на паузе }; __FLASH_BYTE status; }; union __flash_status_register_st_3 { // [W25Q OK] struct { __FLASH_BYTE cRes_0 : 2; // зарезервировано, RO, =0 __FLASH_BYTE bWPSel : 1; // WPS выбор схемы защиты от записи, WPS=0 групповая защита {CMP, SEC, TB, BP[2:0]}, WPS=1 индивидуальная защита секторов/блоков __FLASH_BYTE cRes_1 : 2; // зарезервировано, RO, =0 __FLASH_BYTE cDrvStr : 2; // DRV настройка тока выходного драйвера: 00 = 100%, 11 = 25% (по умолчанию) __FLASH_BYTE bRes : 1; // зарезервировано, RO, =0 }; __FLASH_BYTE status; }; #define __FLASH_WPS_GROUP_PROTECT 0 // bWPSel=0, групповая защита секторов #define __FLASH_WPS_INDIVIDUAL_PROTECT 1 // bWPSel=1, индивидуальная защита секторов #define __FLASH_DRS_DEFAULT 3 // cDrvStr=11, Driver Strength = 25% #define __FLASH_SRP_WP_ENABLE 1 // bStatProt=1, разрешение аппаратного ~WP #define __FLASH_SRP_WP_DISABLE 0 // bStatProt=0, запрещение аппаратного ~WP #if W25QXXX_HW_WR_PROTECT #define __FLASH_SRP_WP_DEFAULT __FLASH_SRP_WP_ENABLE #else #define __FLASH_SRP_WP_DEFAULT __FLASH_SRP_WP_DISABLE #endif #define __FLASH_SRL_LOCKED 1 // bStatLock=1, запись в статусные регистры запрещена по следующего цикла включения питания #define __FLASH_SRL_UNLOCKED 0 // bStatLock=0, запись в статусные регистры разрешена #define __FLASH_QUAD_ENABLED 1 // bQuadEn=1, разрешен режим Quad SPI #define __FLASH_QUAD_DISABLED 0 // bQuadEn=0, запрещен режим Quad SPI #define __FLASH_SYS_ENABLED 1 // bSuspended=1, задействован режим suspend #define __FLASH_BP_RESET 0 // cBlkProt=0, все индикаторы групповой защиты сброшены #define __FLASH_BP_SET 7 // cBlkProt=7, все индикаторы групповой защиты установлены #define __FLASH_CMP_ENABLE 1 // bCmpProt=1, режим комплиментарной защиты включен #define __FLASH_CMP_DISABLE 0 // bCmpProt=0, режим комплиментарной защиты выключен #pragma pack( pop ) typedef union __flash_status_register_st_1 __flash_status1_t; typedef union __flash_status_register_st_2 __flash_status2_t; typedef union __flash_status_register_st_3 __flash_status3_t; //------------------------------------------- #pragma pack( push, 1 ) // ИНДЕТИФИКАТОР ПРОИЗВОДИТЕЛЯ struct __flash_deviceid_st // [W25Q OK] { __FLASH_BYTE Family; // семейство памяти, в зависимости от модели __FLASH_BYTE Density : 6; // вместимость чипа, для линейки W25Q: значение [10h ... 20h] __FLASH_BYTE Reserved: 2; // }; typedef struct __flash_deviceid_st flash_deviceid_t; struct __flash_manufacturerid_st // [W25Q OK] { union { struct { __FLASH_BYTE LowId; // стандартный байт ID (не расширенный) __FLASH_BYTE Reserved; // зарезервировано, всегда 0. // Поле использовалось под расширенный байт ID, Continuation Code, JEDEC JEP-106, // но семейство W25Q не поддерживает подобный формат. }; __FLASH_WORD FullId; // полный ID }; __FLASH_WORD DevId; // код устройства [flash_deviceid_t] // W25Q не поддерживает расширение поля ID в соответствии с JEDEC JEP-106, // однако поддерживает другой стандарт Serial Flash Discoverable Parameter Structure (JESD216D.01) // Поля ExtLen и pExtBf будут использованы для выдачи информации о чипе в этом формате __FLASH_BYTE ExtLen; // длинна расширенной информации __FLASH_BYTE * pExtBf; // указатель на буфер приемник расширенной информации }; struct __flash_manufacturerid_ex_st // [W25Q OK] { union { struct { __FLASH_BYTE LowId; // стандартный байт ID (не расширенный) __FLASH_BYTE Reserved; // зарезервировано, всегда 0. // Поле использовалось под расширенный байт ID, Continuation Code, JEDEC JEP-106, // но семейство W25Q не поддерживает подобный формат. }; __FLASH_WORD FullId; // полный ID }; flash_deviceid_t DevId; // код устройства // W25Q не поддерживает расширение поля ID в соответствии с JEDEC JEP-106, // однако поддерживает другой стандарт Serial Flash Discoverable Parameter Structure (JESD216D.01) // Поля ExtLen и pExtBf будут использованы для выдачи информации о чипе в этом формате __FLASH_BYTE ExtLen; // длинна расширенной информации __FLASH_BYTE * pExtBf; // указатель на буфер приемник расширенной информации }; struct __flash_manufacturerid_returnvalue_st // [W25Q OK] { union { struct { __FLASH_BYTE LowId; // стандартный байт ID (не расширенный) __FLASH_BYTE HighId; // зарезервировано, всегда 0. }; __FLASH_WORD FullId; // полный ID }; flash_deviceid_t DevId; // код устройства }; typedef struct __flash_manufacturerid_returnvalue_st __flash_rvid_t; typedef struct __flash_manufacturerid_st __flash_id_t; typedef struct __flash_manufacturerid_ex_st __flash_exid_t; #pragma pack( pop ) #pragma pack( push, 1 ) // РЕГИСТРЫ ЗАЩИТЫ/БЛОКИРОВКИ СЕКТОРОВ/БЛОКОВ struct __flash_protect_register_st // [W25Q OK] { // байты защиты секторов 0-62 (__FLASH_PROTECTION_REG_ENABLE / __FLASH_PROTECTION_REG_DISABLE ) __FLASH_BYTE bSectors[ BITBUFFER_SIZE(__PROT_SECTOR_FLAGS) ]; }; typedef struct __flash_protect_register_st __flash_protectionregister_t; struct __flash_protect_sector_register_st // [W25Q OK] { // байты защиты секторов 0-31 (__FLASH_PROTECTION_REG_ENABLE / __FLASH_PROTECTION_REG_DISABLE ) // Группировка по секторам 64К ! __FLASH_BYTE bSectors[ BITBUFFER_SIZE(__SECTORS) ]; }; typedef struct __flash_protect_sector_register_st __flash_sectorprotectionregister_t; #pragma pack( pop ) #define FLASH_PROTECTION_REGISTER_CHECK(bSectors,n) BITBUFFER_CHECK(bSectors,n) #define FLASH_PROTECTION_REGISTER_SET( bSectors,n) BITBUFFER_SET( bSectors,n) #define FLASH_PROTECTION_REGISTER_CLEAR(bSectors,n) BITBUFFER_CLEAR(bSectors,n) //------------------------------------------- // РЕГИСТРЫ БЕЗОПАСНОСТИ ПОЛЬЗОВАТЕЛЯ #pragma pack( push, 1 ) struct __flash_security_register_st // [W25Q OK] { __FLASH_BYTE content[ __FLASH_USER_SECURITY_BYTES ]; // доступные для однократного программирования байты в регистре безопасности }; typedef struct __flash_security_register_st __flash_securityregister_t; #pragma pack( pop ) //------------------------------------------- // РЕГИСТРЫ ИДЕНТИФИКАТОРОВ #pragma pack( push, 1 ) struct __flash_uniqueid_register_st // [W25Q OK] { __FLASH_BYTE uid[8]; // 8-байтовый уникальный идентификатор в пределах модели }; typedef struct __flash_uniqueid_register_st __flash_uniqueidregister_t; #pragma pack( pop ) //------------------------------------------- // ВНУТРЕННИЕ СЛУЖЕБНЫЕ СТРУКТУРЫ И ТИПЫ typedef const __FLASH_BYTE (*__flash_pageprogramptr_t)[ __PROG_PAGE_SIZE ]; typedef enum { fibufSectorFlags, // буфер флагов защиты секторов 64К fibufSectorFlags_2, // буфер флагов защиты секторов 64К (еще один буфер) fibufProtSectorFlags, // буфер флагов защиты секторов/блоков (protSector) fibufPageIO, // буфер ввода/вывода страницы } __flash_internal_buffer_type_t; // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ преобразования адресов №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // #if defined(W25Q16JV_LOWLEVEL) || defined(W25Q16JV_APILEVEL) #define __FLASH_ADDRESS2SECTOR(addr) ((addr)/__SECTOR_STD_SIZE) // __FLASH_ADDRESS2SECTOR - преобразует адрес в номер сектора с учетом используемого размера страницы #define __FLASH_ADDRESS2PAGE(addr) ((addr)/__PAGE_SIZE_USER) // __FLASH_ADDRESS2PAGE - преобразует адрес в номер страницы с учетом используемого размера страницы #define __FLASH_PAGE2ADDRESS(page) ((page)*__PAGE_SIZE_USER) // __FLASH_PAGE2ADDRESS - преобразует номер страницы в адрес с учетом используемого размера страницы #define __FLASH_PAGE2BLOCK(page) ((page)/__PAGES_PER_BLOCK) // __FLASH_PAGE2BLOCK - преобразует номер страницы в номер блока #define __FLASH_PAGE2SECTOR(page) ((page)/__PAGES_PER_SECTOR) // __FLASH_PAGE2SECTOR - преобразует номер страницы в номер сектора #define __FLASH_ADDRESSOFFSETPAGE(addr) ((addr)%__PAGE_SIZE_USER) // __FLASH_ADDRESSOFFSETPAGE - получает смещение адреса относительно начала страницы // __FLASH_DATAREMAININGINPAGE - вычисляет, какое количество байт осталось до конца страницы #define __FLASH_DATAREMAININGINPAGE(addr) ( __PAGE_SIZE_USER - __FLASH_ADDRESSOFFSETPAGE( address ) ) // В линейке чипов Winbind серии W25Q существуют чипы емкостью от 1МБит до 512МБит // Код емкости: 10h - 512KBit, 11h - 1Mbit, 12h - 2Mbit, ..., 19h - 256MBit, и 20h - 512MBit // Чип емкостью 512МБит выбивается из общего правила, т.к. имеет код не 1Ah, а 20h. // __W25Q_density // Возвращает емкость в Мегабитах static inline int __W25Q_density(int density) { if( 0x11 <= density && density <= 0x19 ) return (1 << ((density & 0xF) - 1)); switch( density ) { case 0x10: return 0; // 512KBit case 0x20: return 512; // 512MBit } return 0; // undefined } #define __FLASH_DENSITY2CAPACITY(density) __W25Q_density(density) // __FLASH_PAGESINRANGE - вычисляет, какое количество страниц находится на промежутке длинной size начиная с адреса address #define __FLASH_PAGESINRANGE(address,size) \ ((address+size)/__PAGE_SIZE_USER - \ (address)/__PAGE_SIZE_USER + \ (((address+size)%__PAGE_SIZE_USER)?1:0)) // // __FLASH_PAGE_ARRAGED_BY_BLOCK - проверяет, выровнена ли страница на размер блока #define __FLASH_PAGE_ARRAGED_BY_BLOCK(pg) (!( pg % W25QFLASH_PAGES_PER_BLOCK )) // __FLASH_PAGE_ARRAGED_BY_SECTOR - проверяет, выровнена ли страница на размер сектора #define __FLASH_PAGE_ARRAGED_BY_SECTOR(pg) (!( pg % W25QFLASH_PAGES_PER_SECTOR )) #endif // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ экпортируемые макросы №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // // для экспорта функций используйте заголовочный файл "W25Q16JV_LL_func.h" #define W25QFLASH_WINBOND_ID __FLASH_WINBOND_ID // Winbond' Manufacturer ID #define W25QFLASH_DENSITY_16MB __FLASH_DENSITY_16MB // Winbond' Density for 16Mbit #define W25QFLASH_FAMILYDATAFLASHQ __FLASH_MEMORYID_Q // Winbond' Family code #define W25QFLASH_FAMILYDATAFLASHM __FLASH_MEMORYID_M // Winbond' Family code #define W25QFLASH_CHIP_SIZE __FULL_CHIP_SIZE // полный объем чипа #define W25QFLASH_DATA_SIZE __FULL_DATA_SIZE // полный объем данных (с учетом или без учета сервисных байтов) #define W25QFLASH_SECTORS __SECTORS // количество секторов #define W25QFLASH_PAGE_SIZE __PAGE_SIZE_USER // размер страницы (зависит от использования сервисных секторов) #define W25QFLASH_BLOCKS __BLOCKS // количество блоков #define W25QFLASH_BLOCK_SIZE __BLOCK_SIZE_USER // размер блока (зависит от использования сервисных секторов) #define W25QFLASH_PAGES __FULL_PAGES // количество страниц #define W25QFLASH_BLOCKS_PER_SECTOR __BLOCKS_PER_SECTOR // количество блоков в секторе #define W25QFLASH_PAGES_PER_SECTOR __PAGES_PER_SECTOR // количество страниц в стандартном секторе #define W25QFLASH_PAGES_PER_BLOCK __PAGES_PER_BLOCK //------------------------------------------- // размеры секторов #define W25QFLASH_SECTOR0_SIZE __SECTOR0_SIZE #define W25QFLASH_SECTOR1_SIZE __SECTOR1_SIZE #define W25QFLASH_SECTOR2_SIZE __SECTOR2_SIZE #define W25QFLASH_SECTOR3_SIZE __SECTOR3_SIZE #define W25QFLASH_SECTOR4_SIZE __SECTOR4_SIZE #define W25QFLASH_SECTOR5_SIZE __SECTOR5_SIZE #define W25QFLASH_SECTOR6_SIZE __SECTOR6_SIZE #define W25QFLASH_SECTOR7_SIZE __SECTOR7_SIZE #define W25QFLASH_SECTOR8_SIZE __SECTOR8_SIZE #define W25QFLASH_SECTOR9_SIZE __SECTOR9_SIZE #define W25QFLASH_SECTOR10_SIZE __SECTOR10_SIZE #define W25QFLASH_SECTOR11_SIZE __SECTOR11_SIZE #define W25QFLASH_SECTOR12_SIZE __SECTOR12_SIZE #define W25QFLASH_SECTOR13_SIZE __SECTOR13_SIZE #define W25QFLASH_SECTOR14_SIZE __SECTOR14_SIZE #define W25QFLASH_SECTOR15_SIZE __SECTOR15_SIZE #define W25QFLASH_SECTOR16_SIZE __SECTOR16_SIZE #define W25QFLASH_SECTOR17_SIZE __SECTOR17_SIZE #define W25QFLASH_SECTOR18_SIZE __SECTOR18_SIZE #define W25QFLASH_SECTOR19_SIZE __SECTOR19_SIZE #define W25QFLASH_SECTOR20_SIZE __SECTOR20_SIZE #define W25QFLASH_SECTOR21_SIZE __SECTOR21_SIZE #define W25QFLASH_SECTOR22_SIZE __SECTOR22_SIZE #define W25QFLASH_SECTOR23_SIZE __SECTOR23_SIZE #define W25QFLASH_SECTOR24_SIZE __SECTOR24_SIZE #define W25QFLASH_SECTOR25_SIZE __SECTOR25_SIZE #define W25QFLASH_SECTOR26_SIZE __SECTOR26_SIZE #define W25QFLASH_SECTOR27_SIZE __SECTOR27_SIZE #define W25QFLASH_SECTOR28_SIZE __SECTOR28_SIZE #define W25QFLASH_SECTOR29_SIZE __SECTOR29_SIZE #define W25QFLASH_SECTOR30_SIZE __SECTOR30_SIZE #define W25QFLASH_SECTOR31_SIZE __SECTOR31_SIZE // количество циклов перезаписи регистра статуса #define W25QFLASH_STATREG_WRITECOUNT __FLASH_STATUSREGISTER_WRITECYCLES // количество циклов перезаписи страницы 4К #define W25QFLASH_PAGE_WRITECOUNT __FLASH_PAGE_WRITECYCLES // зарезервированная область в начале адресного пространства #define W25QFLASH_MINIMUM_ADDRESS (0x20000) // указано 128K для совместимости с AT45, но если не требуется => указать 0 // максимально возможный адрес #define W25QFLASH_MAXIMUM_ADDRESS (W25QFLASH_PAGES * __PAGE_SIZE_USER ) //------------------------------------------- #endif #endif