Как подключить W25Q16J и использовать её с LittleFS

W25Q16J — энергонезависимая память SPI NOR Flash объёмом 2 Мбайт. Микросхема поддерживает обычный SPI, QSPI и исполнение кода непосредственно из внешней памяти по технологии XIP. Максимальная заявленная частота интерфейса достигает 133 МГц, однако реальная скорость зависит от микроконтроллера, разводки платы и выбранного периферийного интерфейса.
Микросхема выпускается в корпусе с восемью выводами. Для обмена по стандартному SPI используются линии выбора кристалла CS, передачи данных от контроллера DI, приёма данных DO и тактового сигнала CLK. Дополнительные выводы предназначены для удержания микросхемы в активном состоянии и защиты записи. Память рассчитана минимум на 100 000 циклов стирания и программирования каждого сектора, а срок хранения данных заявлен более 20 лет.
Организация памяти и адресация
Объём W25Q16J составляет 2 097 152 байта. Память разделена на 8192 страницы по 256 байт, 512 секторов по 4 Кбайт и 32 блока по 64 Кбайт. Для физической адресации всего объёма достаточно 21 бита, но команды микросхемы используют 24-битные адреса. Поэтому классический SPI-протокол с такой адресацией ограничивает доступный объём 16 777 216 байт, или 16 Мбайт.
Страница является минимальной единицей программирования, а сектор — минимальной областью стирания. При записи необходимо учитывать границы страниц: переход за предел 256 байт не выполняется как единая операция и должен обрабатываться драйвером. Аналогично стирание сектора требует выровненного адреса его начала.
Подключение к STM32F4
W25Q16J встречается на различных отладочных и промышленных платах. В рассматриваемой плате JL_32F4XX память подключена к периферии SPI3 микроконтроллера STM32F4. Линия CS выведена на PB14, MOSI подключён к PB5, MISO — к PB4, а тактовая линия SCK — к PB3.
У такого подключения есть особенность: PB3 одновременно используется как вывод JTDO интерфейса JTAG. Поэтому при работе SPI3 этот контакт занят тактовой линией памяти, а отладку платы приходится выполнять по SWD. Для анализа обмена удобно подключить логический анализатор непосредственно к четырём линиям SPI.
Хотя сама W25Q16J способна работать на частоте до 133 МГц, SPI3 на этой плате тактируется от шины APB1 с частотой до 42 МГц. Минимальный делитель STM32F4 равен двум, поэтому предельная частота SPI3 в данной конфигурации составляет 21 МГц. При проектировании платы для более высокой скорости логичнее было бы использовать SPI1, который в STM32F4 может работать на частоте до 42 МГц.
Основные команды SPI
Внутренний протокол микросхемы включает около 42 команд, но для большинства драйверов достаточно небольшого набора. Данные передаются старшим битом вперёд, а выборка выполняется по положительному перепаду тактового сигнала. Полярность тактирования может настраиваться в соответствии с используемым режимом SPI.
- Read Data, 0x03 — чтение массива байтов начиная с заданного 24-битного адреса.
- Write Enable — установка разрешения на изменение памяти.
- Page Program — программирование страницы или её части.
- Sector Erase, 4 Кбайт — стирание сектора.
- Read Status Register — чтение состояния операций и флага разрешения записи.
- Read JEDEC ID, 0x9F — получение идентификатора производителя и параметров памяти.
Идентифицировать микросхему можно по JEDEC ID. Для W25Q16J в источнике приведены значения производителя 0xEF, типа памяти 0x40 и идентификатора ёмкости 0x15. Кроме того, устройство имеет уникальный 64-битный идентификатор, доступный отдельной командой.
Чтение, стирание и запись
Чтение выполняется проще всего: контроллер передаёт команду 0x03, 24-битный начальный адрес, после чего считывает необходимое количество байт. Для стирания сначала нужно отправить Write Enable и убедиться, что в регистре состояния установлен флаг WEL. Затем передаётся команда стирания с адресом начала сектора. Пока операция выполняется, установлен флаг BUSY; после его сброса результат можно проверить чтением, ожидая значения 0xFF во всей области.
Запись также начинается с установки WEL. Данные передаются командой Page Program, причём адрес и размер операции должны учитывать границу страницы. После отправки команды драйвер опрашивает BUSY до завершения программирования. Для надёжной работы полезно дополнительно прочитать записанный массив и сравнить его с исходными данными.
NOR Flash допускает последовательное уменьшение единичных битов без предварительного стирания: например, значение 0xFE можно изменить на 0xFC. Вернуть нулевые биты в единичное состояние без стирания нельзя. Такая особенность позволяет создавать простые хранилища параметров, но требует контроля износа, распределения записей и корректной обработки сбоев питания.
Зачем нужна файловая система
Непосредственная работа со страницами и секторами быстро усложняется, когда данные пересекают границы блоков. Программисту приходится самостоятельно управлять стиранием, копированием актуальных данных, выравниванием адресов и равномерным использованием памяти. Для решения этих задач поверх низкоуровневого драйвера можно использовать LittleFS — файловую систему для небольших энергонезависимых носителей.
В LittleFS файл представляется именованным массивом байтов, для которого система хранит размер и служебную информацию. В качестве носителя могут использоваться Flash, EEPROM, FRAM, SD-карты и другие устройства. Файловая система берёт на себя размещение данных, обновление метаданных и часть задач по снижению износа, тогда как драйвер микросхемы предоставляет операции чтения, программирования и стирания.
Интеграция LittleFS с W25Q16J
Портирование сводится к заполнению конфигурации LittleFS и реализации четырёх функций блочного устройства: read, prog, erase и sync. Функции чтения и записи переводят логические координаты файловой системы в физический адрес памяти по формуле: базовый адрес плюс номер блока, умноженный на размер блока, плюс смещение внутри блока.
Обработчик erase получает номер блока, вычисляет адрес его начала и вызывает драйвер стирания сектора. Обработчик prog передаёт буфер в функцию программирования страницы, а read использует обычную SPI-команду чтения. Если операция драйвера завершилась ошибкой, адаптер преобразует её в код ошибки LittleFS, например LFS_ERR_CORRUPT.
В конфигурации также задаются размеры чтения и программирования, размер кэша, буфер упреждающего поиска, размер блока и количество блоков. В приведённом варианте размер блока соответствует сектору Flash, а параметр block_cycles установлен в 100 000. При отсутствии динамического выделения памяти буферы read, prog и lookahead можно разместить статически.
Таким образом, W25Q16J подходит для хранения настроек, журналов, калибровочных коэффициентов и других небольших массивов данных. Низкоуровневый SPI-драйвер обеспечивает доступ к микросхеме, а LittleFS скрывает особенности страниц и секторов, предоставляя приложению привычную работу с именованными файлами.


