# Переносимая библиотека SPI NOR `SpiNor` — самостоятельный синхронный драйвер последовательной NOR Flash. Он не зависит от STM32, HAL, `main.c`, GPIO проекта, Modbus, GUI и FlashStorage. Память для контекста предоставляет приложение; `malloc` и глобальное изменяемое состояние не используются. ## Поддержанные микросхемы | Модель | JEDEC | Ёмкость | Program | Erase | |---|---:|---:|---:|---:| | W25Q64 | `EF 40 17` | 8 МиБ | страницы до 256 байт | 4 КиБ | | W25Q128 | `EF 40 18` | 16 МиБ | страницы до 256 байт | 4 КиБ | | SST25VF016B | `BF 25 41` | 2 МиБ | безопасный Byte Program | 4 КиБ | Ядро использует команды с 24-битным адресом и намеренно не принимает микросхемы больше 16 МиБ. Неизвестный JEDEC возвращает `SPI_NOR_E_UNSUPPORTED`; пустая шина `00 00 00` или `FF FF FF` — `SPI_NOR_E_NOT_FOUND`. ## Структура - `Inc/spi_nor.h` — публичные типы, callbacks, конфигурация и API; - `Src/spi_nor.c` — переносимый протокол, JEDEC, bounds, тайм-ауты и verify; - `Port/STM32F4_HAL` — единственное место с зависимостью от STM32F4 HAL; - `Examples/portable_init.c` — минимальная интеграция без имён текущей платы; - `PORTING.md` — пошаговый перенос на другой STM32 или другой MCU; - `Tests` — mock-шина и сценарии без HAL и реального оборудования. - `Diagnostics` — два bounded read-only сервиса без HAL/Modbus/GUI; `spi_nor_read_service` читает физический диапазон через callback, а `spi_nor_command_service` выполняет одну разрешённую сервисную транзакцию. Адаптер журнала находится отдельно в `Libraries/FlashStorage/Adapter/SPI_NOR`: FlashStorage не проникает в ядро SPI NOR, а SPI NOR не знает формат журнала. Диагностический сервис принимает только capacity и callback чтения, ограничивает один пакет 64 байт и не имеет `program`/`erase` API. Приложение может связать его с Modbus, не добавляя GUI или прикладные зависимости в ядро `SpiNor`. ### Сервис коротких SPI-команд `spi_nor_command_service` принимает `spi_nor_t`, request с `sequence`, TX до 4 байт и RX до 64 байт, а response возвращает status, echo TX и RX. Владельцем контекста остаётся приложение; сервис не выделяет память и не хранит историю. Allowlist одинаков для всех трёх поддержанных моделей: | Opcode | Строгая форма | Причина допуска | |---:|---|---| | `9F` | TX 1, RX 3 | JEDEC ID | | `05` | TX 1, RX 1 | status register 1 | | `03` | TX 4 (`03 A2 A1 A0`), RX 1–64 | обычное 24-битное чтение с bounds | Любой другой opcode возвращает `BLOCKED`. В частности, запрещены WREN/WRDI, program, все erase, status/protection writes, power-down/release, reset и неизвестные команды. Это fail-closed read-only API, а не универсальный SPI terminal. Изменяющий сервисный режим не требуется и в библиотеку не включён. Одна операция имеет порядок `CS active -> TX -> dummy RX -> CS inactive`. После ошибки или тайм-аута TX/RX сервис безусловно освобождает CS и очищает частичный RX. Он использует тот же `busy` и необязательные `lock/unlock`, что основной экземпляр `spi_nor_t`. ## Публичный API ```c spi_nor_io_t io; spi_nor_t flash; /* Порт приложения заполняет callbacks и собственный io.context. */ FillPlatformCallbacks(&io); if (spi_nor_init(&flash, &io, NULL) == SPI_NOR_OK && spi_nor_probe(&flash) == SPI_NOR_OK) { uint8_t bytes[16]; (void)spi_nor_read(&flash, 0U, bytes, sizeof(bytes)); } ``` `spi_nor_program()` автоматически делит поток по страницам и проверяет каждый chunk обратным чтением. `spi_nor_erase()` принимает только полные выровненные 4-КиБ секторы и проверяет каждый стёртый байт на `0xFF`. ## Электрическое подключение Нужны `SCK`, `MOSI`, `MISO`, отдельный active-low `CS`, питание и земля. Питание и допустимую частоту следует брать из datasheet конкретной модели. Для текущей платы используются SPI2: `PB10/SCK`, `PC3/MOSI`, `PC2/MISO` и `PE3/CS`, но эти имена находятся только в `app_storage.c`. ## Ограничения выполнения - API синхронный и не предназначен для ISR; - erase может блокировать вызывающий поток до заданного тайм-аута; - один `spi_nor_t` не допускает рекурсивных операций; - при RTOS callbacks `lock/unlock` должны защищать всю составную операцию; - общий SPI bus требует согласованного mutex и корректного управления CS всех подключённых устройств; - DMA callback нельзя считать завершённым до фактического окончания обмена; - библиотека не меняет SPI mode и clock: это обязанность платформенного порта. ## Гарантии ошибок При любой ошибке обмена CS возвращается в неактивное состояние. Ошибка program или erase не маскируется: результат считается успешным только после ожидания BUSY и полного readback verify. Повторять изменяющую операцию автоматически библиотека не будет, потому что политика повторов принадлежит приложению. ## Shared source Canonical source: `templates/c/spi-nor`. Used by `home/climate`; its old paths are compatibility includes. Board-specific ports remain in the application. Change this library, not the forwarding files.