Files
templates/c/spi-nor/PORTING.md

124 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Портирование SPI NOR на другую платформу
## 1. Добавить переносимое ядро
В сборку новой цели включите `Src/spi_nor.c`, а `Inc` добавьте в include path.
Это единственные обязательные файлы. Они используют только C99-заголовки
`stddef.h`, `stdint.h` и `string.h`.
## 2. Реализовать platform callbacks
Создайте собственный контекст шины и заполните `spi_nor_io_t`:
- `transfer` — полный синхронный SPI-обмен при уже активном CS;
- `chip_select` — `active=1` опускает CS, `active=0` поднимает его;
- `tick_ms` — монотонный 32-битный счётчик миллисекунд;
- `delay_ms` — задержка выхода из power-down и пауза BUSY polling;
- `lock/unlock` — необязательная пара для RTOS, оба либо заданы, либо `NULL`.
`transfer` должен поддерживать следующие варианты:
| `tx` | `rx` | Действие |
|---|---|---|
| не `NULL` | `NULL` | передать command или payload |
| `NULL` | не `NULL` | передавать dummy и сохранить входящие байты |
| не `NULL` | не `NULL` | full-duplex обмен, допустим для порта |
Callback не должен самостоятельно переключать CS. Ядро может вызвать transfer
дважды под одним CS: сначала command, затем data. Ошибка должна возвращаться как
`SPI_NOR_IO_ERROR` или `SPI_NOR_IO_TIMEOUT`.
## 3. Настроить SPI
Для W25Q/SST25 используйте master, 8 бит, MSB first и режим, разрешённый
datasheet. Частота не должна превышать предел микросхемы и возможности разводки.
CS перед `spi_nor_init()` должен быть настроен output push-pull и находиться в 1.
Проверьте питание, общую землю и отсутствие конфликта MISO с другими CS.
## 4. Инициализировать и выполнить probe
```c
spi_nor_t device;
spi_nor_io_t io = MakeMyPlatformIo();
spi_nor_config_t config = spi_nor_default_config();
config.erase_timeout_ms = 10000U; /* Пример для медленной микросхемы. */
if (spi_nor_init(&device, &io, &config) != SPI_NOR_OK) {
HandleConfigurationError();
}
if (spi_nor_probe(&device) != SPI_NOR_OK) {
HandleAbsentOrUnsupportedFlash();
}
```
До успешного probe read/program/erase отклоняются. Для диагностики неизвестной
памяти вызовите `spi_nor_get_last_jedec()` после неуспешного probe.
## 5. Подключить FlashStorage при необходимости
Добавьте в сборку:
- `Libraries/FlashStorage/Src/flash_storage.c`;
- `Libraries/FlashStorage/Adapter/SPI_NOR/Src/flash_storage_spi_nor_adapter.c`;
- include paths `FlashStorage/Inc` и `FlashStorage/Adapter/SPI_NOR/Inc`.
После probe создайте `flash_storage_spi_nor_adapter_t`, вызовите
`flash_storage_spi_nor_adapter_init()` и передайте `flash_storage_spi_nor_ops`
в `flash_storage_init()` или `eeprom_store_init()`. Layout должен лежать внутри
фактической `capacity_bytes` и быть выровнен по 4096 байтам.
## 6. STM32 HAL
Для другого STM32 можно использовать существующий порт, если семейство имеет
совместимый HAL API. Подключите `spi_nor_stm32f4_hal.c`, замените HAL include на
заголовок нужного семейства и переименуйте порт. Имена конкретных `hspi`, GPIO
и pin передавайте из приложения; не добавляйте их как `extern` в библиотеку.
Если используется DMA или RTOS, простой STM32F4 порт следует заменить:
- transfer обязан дождаться завершения DMA до возврата;
- lock/unlock должны использовать mutex, не semaphore из ISR;
- mutex должен быть общим для всех устройств на одной SPI-шине;
- callback delay должен освобождать CPU через RTOS delay, если это допустимо.
## 7. Приёмочные проверки
1. На пустой шине получить `SPI_NOR_E_NOT_FOUND` и CS=1.
2. Прочитать ожидаемый JEDEC.
3. Проверить чтение первого и последнего адреса.
4. В тестовом секторе выполнить erase и полный verify `0xFF`.
5. Записать данные через границу страницы и сравнить readback.
6. Имитировать SPI error/timeout и убедиться, что CS поднят.
7. Проверить отказ для диапазона за концом памяти и невыровненного erase.
8. При RTOS параллельно запустить два клиента и проверить mutex-анализатором.
Для текущего репозитория host mock запускается через
`python -m unittest tests.test_spi_nor_host` и не требует STM32 HAL.
## 8. Перенос read-only command service
Если нужен сервисный просмотр команд, добавьте в сборку
`Diagnostics/Src/spi_nor_command_service.c` и include path `Diagnostics/Inc`.
Передавайте ему уже успешно probed `spi_nor_t`; отдельный HAL-порт не нужен:
```c
spi_nor_command_service_request_t request = {0};
spi_nor_command_service_response_t response;
request.sequence = 1U;
request.tx_length = 1U;
request.rx_length = 3U;
request.tx[0] = 0x9FU;
(void)spi_nor_command_service_process(&device, &request, &response);
```
Не расширяйте существующий allowlist ради записи. Если продукту когда-нибудь
потребуются изменяющие операции, они должны иметь отдельный API, threat model,
защиту диапазонов и аппаратные тесты. Текущий сервис не содержит compile-time
или runtime переключателя, снимающего блокировку.
Проверьте mock-тестом своей платформы: TX/RX порядок под одним CS, освобождение
CS при timeout каждого transfer, общий mutex SPI bus, строгие максимумы 4/64 и
отказ для `06`, `02`, всех erase, status/protection writes, power/reset и
неизвестных opcode.