#ifndef PORTABLE_SPI_NOR_H #define PORTABLE_SPI_NOR_H /* * Переносимое ядро SPI NOR. * * Ядро знает только стандартные SPI-команды и callbacks платформы. Оно не * включает HAL, регистры MCU, GPIO проекта, Modbus или код приложения. Каждый * экземпляр хранит собственное состояние и поэтому не использует глобальные * изменяемые переменные. */ #include #include #ifdef __cplusplus extern "C" { #endif /* Поддерживаемые микросхемы ограничены устройствами с 24-битной адресацией. */ typedef enum { SPI_NOR_MODEL_NONE = 0, SPI_NOR_MODEL_W25Q64, SPI_NOR_MODEL_W25Q128, SPI_NOR_MODEL_SST25VF016B } spi_nor_model_t; /* Ошибки протокола не зависят от кодов конкретного HAL. */ typedef enum { SPI_NOR_OK = 0, SPI_NOR_E_ARGUMENT = -1, SPI_NOR_E_IO = -2, SPI_NOR_E_TIMEOUT = -3, SPI_NOR_E_NOT_FOUND = -4, SPI_NOR_E_UNSUPPORTED = -5, SPI_NOR_E_BOUNDS = -6, SPI_NOR_E_ALIGNMENT = -7, SPI_NOR_E_VERIFY = -8, SPI_NOR_E_BUSY = -9 } spi_nor_status_t; /* Callback SPI возвращает только переносимый результат физического обмена. */ typedef enum { SPI_NOR_IO_OK = 0, SPI_NOR_IO_ERROR = -1, SPI_NOR_IO_TIMEOUT = -2 } spi_nor_io_status_t; /* Геометрия и JEDEC доступны приложению только как копируемая диагностика. */ typedef struct { spi_nor_model_t model; uint8_t manufacturer_id; uint8_t memory_type; uint8_t capacity_code; uint32_t capacity_bytes; uint32_t sector_size; uint16_t page_size; } spi_nor_info_t; /* * Контракт платформы описывает одну SPI-шину и один сигнал CS. * * transfer выполняется при уже активном CS. NULL в tx означает передачу * dummy-байтов, NULL в rx — игнорирование принятого потока. lock/unlock * необязательны; RTOS-порт может ими сериализовать полную read/program/erase * операцию, а не отдельный SPI пакет. */ typedef struct { void *context; spi_nor_io_status_t (*transfer)(void *context, const uint8_t *tx, uint8_t *rx, size_t size, uint32_t timeout_ms); void (*chip_select)(void *context, uint8_t active); uint32_t (*tick_ms)(void *context); void (*delay_ms)(void *context, uint32_t delay_ms); spi_nor_io_status_t (*lock)(void *context, uint32_t timeout_ms); void (*unlock)(void *context); } spi_nor_io_t; /* Тайм-ауты вынесены в конфигурацию для медленных шин и разных RTOS. */ typedef struct { uint32_t io_timeout_ms; uint32_t lock_timeout_ms; uint32_t program_timeout_ms; uint32_t erase_timeout_ms; uint32_t ready_poll_delay_ms; } spi_nor_config_t; /* Контекст полностью принадлежит вызывающему коду и не требует malloc. */ typedef struct { spi_nor_io_t io; spi_nor_config_t config; spi_nor_info_t info; uint8_t initialized; uint8_t detected; uint8_t busy; } spi_nor_t; /* Возвращает документированные безопасные тайм-ауты библиотеки. */ spi_nor_config_t spi_nor_default_config(void); /* Инициализация только копирует callbacks и не обращается к физической шине. */ spi_nor_status_t spi_nor_init(spi_nor_t *device, const spi_nor_io_t *io, const spi_nor_config_t *config); /* Probe будит память, читает JEDEC и разрешает работу известной геометрии. */ spi_nor_status_t spi_nor_probe(spi_nor_t *device); /* Операции используют физические смещения микросхемы, начиная с нуля. */ spi_nor_status_t spi_nor_read(spi_nor_t *device, uint32_t address, void *data, size_t size); spi_nor_status_t spi_nor_program(spi_nor_t *device, uint32_t address, const void *data, size_t size); spi_nor_status_t spi_nor_erase(spi_nor_t *device, uint32_t address, size_t size); /* Информация выдаётся только после успешного распознавания поддержанной модели. */ spi_nor_status_t spi_nor_get_info(const spi_nor_t *device, spi_nor_info_t *info); /* Последний JEDEC доступен и для различения пустой шины и неизвестной модели. */ spi_nor_status_t spi_nor_get_last_jedec(const spi_nor_t *device, uint8_t jedec[3]); /* Read-only диагностика возвращает status register 1 под общей блокировкой. */ spi_nor_status_t spi_nor_read_status_register(spi_nor_t *device, uint8_t *status); #ifdef __cplusplus } #endif #endif /* PORTABLE_SPI_NOR_H */