// Файл с основными определениями для 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