/** * @file ft24c256.h * @brief Портируемый драйвер последовательной EEPROM FT24C256 и её семейства. * * Библиотека не привязана к микроконтроллеру: она не включает заголовки * периферии, не обращается к регистрам и не пользуется прерываниями. Обмен * идёт через таблицу обратных вызовов FT24C256_Io, которую заполняет порт * платы (для этой сборки — @c src/eeprom.c поверх I2C1 STM32F103C8T6). * * FT24C256 — 32768 байт (256 кбит) с двухбайтовым адресом слова и страницей * записи 64 байта. Запись выполняется постранично: микросхема принимает до * 64 байт в одной транзакции, но только внутри страницы — при переходе через * её границу счётчик адреса заворачивается на начало той же страницы и * затирает уже принятые байты. Поэтому FT24C256_Write() сама режет запрос по * границам страниц: * * @code * запись 100 байт с адреса 0x0030 * * 0x0000 0x0040 0x0080 0x00C0 * | страница 0 | страница 1 | страница 2 | * +---------------+---------------+---------------+ * [ 16 ][ 64 ][ 20 ] * 1-я 2-я 3-я транзакция * @endcode * * После каждой транзакции кристалл уходит во внутренний цикл записи (до 5 мс) * и не отвечает на шину. Готовность определяется опросом подтверждения * (ACK polling): библиотека шлёт адресный байт без данных, пока микросхема не * ответит. Порт, который не умеет передавать транзакцию нулевой длины, * выставляет @c poll_retries в ноль — тогда используется выдержка * @c write_ms. * * Кристалл выбирается тремя адресными выводами A0...A2, поэтому на одной шине * живут до восьми микросхем с адресами 0x50...0x57. Задавая @c size и * @c page_size, тем же кодом обслуживаются младшие члены семейства с * двухбайтовым адресом: FT24C32 (4 КБ, страница 32), FT24C64 (8 КБ, 32), * FT24C128 (16 КБ, 64), FT24C512 (64 КБ, 128). Микросхемы до FT24C16 * включительно адресуют слово одним байтом и этой библиотекой не * поддерживаются. */ #ifndef FT24C256_H #define FT24C256_H #include /** Объём FT24C256 в байтах (256 кбит). */ #define FT24C256_SIZE 32768UL /** Размер страницы записи FT24C256 в байтах. */ #define FT24C256_PAGE_SIZE 64U /** Предельная страница семейства (FT24C512); задаёт размер буфера транзакции. */ #define FT24C256_PAGE_MAX 128U /** Базовый адрес на шине при A0 = A1 = A2 = 0. */ #define FT24C256_BASE_ADDRESS 0x50U /** Число микросхем семейства на одной шине. */ #define FT24C256_MAX_DEVICES 8U /** Длительность внутреннего цикла записи по даташиту, мс. */ #define FT24C256_WRITE_MS 5U /** Число опросов подтверждения после записи по умолчанию. */ #define FT24C256_POLL_RETRIES 20U /** Длина адреса слова в байтах: FT24C32 и старше адресуют двумя байтами. */ #define FT24C256_ADDRESS_SIZE 2U /** * @brief Доступ библиотеки к шине I2C. * * Обязательны @c write и @c write_read. Адрес в вызовах — семибитный, без * бита направления: сдвиг и добавление бита выполняет порт. */ typedef struct { /** * Передаёт транзакцию «старт, адрес, данные, стоп». * Вызов с @c size, равным нулю, передаёт один адресный байт и применяется * для опроса готовности; 1 — микросхема ответила подтверждением. */ uint8_t (*write)(void *context, uint8_t address, const uint8_t *data, uint16_t size); /** * Передаёт @c tx_size байт, затем без освобождения шины (повторный старт) * читает @c rx_size байт; 1 — обмен завершён подтверждениями. */ uint8_t (*write_read)(void *context, uint8_t address, const uint8_t *tx, uint16_t tx_size, uint8_t *rx, uint16_t rx_size); /** Выдержка в миллисекундах; обязателен, если @c poll_retries равен нулю. */ void (*delay_ms)(void *context, uint32_t milliseconds); /** Управление выводом WP: 1 — запись запрещена. Допускает значение 0. */ void (*set_write_protect)(void *context, uint8_t enabled); void *context; /**< Контекст порта, передаётся вызовам без изменений. */ } FT24C256_Io; /** * @brief Параметры кристалла. * * Нулевые поля заменяются значениями по умолчанию вызовом * FT24C256_ConfigDefault() или самой FT24C256_Init(). */ typedef struct { uint32_t size; /**< Объём в байтах; 0 — @ref FT24C256_SIZE. */ uint16_t page_size; /**< Страница записи; 0 — @ref FT24C256_PAGE_SIZE. */ uint8_t address; /**< Семибитный адрес; 0 — @ref FT24C256_BASE_ADDRESS. */ uint8_t write_ms; /**< Выдержка цикла записи; 0 — @ref FT24C256_WRITE_MS. */ uint8_t poll_retries; /**< Опросов готовности; 0 — только выдержка. */ } FT24C256_Config; /** * @brief Состояние кристалла: настройки, обратные вызовы и счётчики обмена. */ typedef struct { FT24C256_Io io; /**< Обратные вызовы порта. */ FT24C256_Config config; /**< Параметры кристалла. */ uint8_t ready; /**< 1, если FT24C256_Init() прошла успешно. */ uint32_t written_bytes; /**< Байтов, отправленных на запись. */ uint32_t read_bytes; /**< Байтов, полученных чтением. */ uint32_t write_errors; /**< Транзакций записи, оставшихся без ответа. */ uint32_t read_errors; /**< Транзакций чтения, оставшихся без ответа. */ } FT24C256; /** * @brief Заполняет параметры значениями FT24C256 с адресными выводами на GND. * * @param config Параметры, принадлежащие вызывающему коду. */ void FT24C256_ConfigDefault(FT24C256_Config *config); /** * @brief Готовит кристалл к работе. * * Обмена с шиной не выполняет: наличие микросхемы проверяется отдельно * вызовом FT24C256_IsPresent(). * * @param device Состояние, принадлежащее вызывающему коду. * @param io Обратные вызовы порта; копируются внутрь состояния. * @param config Параметры либо 0 для значений по умолчанию. * @return 1 при успешной настройке, 0 при неполных аргументах. */ uint8_t FT24C256_Init(FT24C256 *device, const FT24C256_Io *io, const FT24C256_Config *config); /** * @brief Проверяет отклик микросхемы на её адрес. * * @param device Состояние кристалла. * @return 1, если получено подтверждение, иначе 0. */ uint8_t FT24C256_IsPresent(FT24C256 *device); /** * @brief Ожидает завершения внутреннего цикла записи. * * При ненулевом @c poll_retries шлёт адресные байты, пока микросхема не * ответит; иначе выдерживает паузу @c write_ms. * * @param device Состояние кристалла. * @return 1, если микросхема готова, иначе 0. */ uint8_t FT24C256_WaitReady(FT24C256 *device); /** * @brief Читает произвольное число байтов подряд. * * Чтение границами страниц не ограничено: счётчик адреса проходит весь * массив, поэтому запрос выполняется одной транзакцией. * * @param device Состояние кристалла. * @param address Адрес первого байта. * @param buffer Приёмник данных. * @param size Число байтов. * @return 1 при успехе; 0 при выходе за границы массива или отказе шины. */ uint8_t FT24C256_Read(FT24C256 *device, uint32_t address, void *buffer, uint16_t size); /** * @brief Записывает произвольное число байтов, разрезая запрос по страницам. * * После каждой страницы выполняется ожидание готовности, поэтому вызов * блокирующий: запись всего массива занимает около 2.6 с. * * @param device Состояние кристалла. * @param address Адрес первого байта. * @param data Записываемые данные. * @param size Число байтов. * @return 1 при успехе; 0 при выходе за границы массива или отказе шины. */ uint8_t FT24C256_Write(FT24C256 *device, uint32_t address, const void *data, uint16_t size); /** * @brief Записывает только те страницы, содержимое которых отличается. * * Ресурс кристалла — миллион циклов записи на страницу, поэтому сохранение * настроек, которые меняются редко, выгоднее вести этой функцией: неизменные * страницы не переписываются. * * @param device Состояние кристалла. * @param address Адрес первого байта. * @param data Записываемые данные. * @param size Число байтов. * @return 1 при успехе, иначе 0. */ uint8_t FT24C256_Update(FT24C256 *device, uint32_t address, const void *data, uint16_t size); /** * @brief Читает один байт. * * @param device Состояние кристалла. * @param address Адрес байта. * @param value Приёмник значения. * @return 1 при успехе, иначе 0. */ uint8_t FT24C256_ReadByte(FT24C256 *device, uint32_t address, uint8_t *value); /** * @brief Записывает один байт. * * @param device Состояние кристалла. * @param address Адрес байта. * @param value Записываемое значение. * @return 1 при успехе, иначе 0. */ uint8_t FT24C256_WriteByte(FT24C256 *device, uint32_t address, uint8_t value); /** * @brief Заполняет область одинаковым значением. * * @param device Состояние кристалла. * @param address Адрес первого байта. * @param value Записываемое значение. * @param size Число байтов. * @return 1 при успехе, иначе 0. */ uint8_t FT24C256_Fill(FT24C256 *device, uint32_t address, uint8_t value, uint32_t size); /** * @brief Заполняет весь массив значением 0xFF. * * @param device Состояние кристалла. * @return 1 при успехе, иначе 0. */ uint8_t FT24C256_Erase(FT24C256 *device); /** * @brief Включает или снимает аппаратную защиту записи выводом WP. * * @param device Состояние кристалла. * @param enabled 1 — запись запрещена, 0 — разрешена. * @return 1, если порт управляет выводом WP, иначе 0. */ uint8_t FT24C256_Protect(FT24C256 *device, uint8_t enabled); /** * @brief Возвращает объём кристалла. * * @param device Состояние кристалла. * @return Число байтов; 0 для ненастроенного состояния. */ uint32_t FT24C256_Size(const FT24C256 *device); /** * @brief Возвращает адрес кристалла на шине для указанных выводов A0...A2. * * @param index Значение адресных выводов, 0...7. * @return Семибитный адрес 0x50...0x57. */ uint8_t FT24C256_AddressOf(uint8_t index); #endif /* FT24C256_H */