141 lines
5.4 KiB
C
141 lines
5.4 KiB
C
#ifndef PORTABLE_SPI_NOR_H
|
||
#define PORTABLE_SPI_NOR_H
|
||
|
||
/*
|
||
* Переносимое ядро SPI NOR.
|
||
*
|
||
* Ядро знает только стандартные SPI-команды и callbacks платформы. Оно не
|
||
* включает HAL, регистры MCU, GPIO проекта, Modbus или код приложения. Каждый
|
||
* экземпляр хранит собственное состояние и поэтому не использует глобальные
|
||
* изменяемые переменные.
|
||
*/
|
||
|
||
#include <stddef.h>
|
||
#include <stdint.h>
|
||
|
||
#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 */
|