feat(eeprom-ft24c256): драйвер EEPROM 24Cxx по I2C
Перенесён из KONOR_ds18b20/lib/eeprom; в OpticalTester лежала такая же копия. Запись режется по границам страниц внутри библиотеки: микросхема принимает до 64 байт за транзакцию, но при переходе через границу страницы счётчик адреса заворачивается и затирает уже принятые байты. Вызывающему коду об этом думать не нужно.
This commit is contained in:
65
c/eeprom-ft24c256/README.md
Normal file
65
c/eeprom-ft24c256/README.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# eeprom-ft24c256
|
||||
|
||||
Драйвер последовательной EEPROM **FT24C256** и совместимого семейства
|
||||
24Cxx по шине I²C.
|
||||
|
||||
Ядро на C99: не включает заголовки периферии, не обращается к регистрам,
|
||||
не пользуется прерываниями. Обмен идёт через таблицу `FT24C256_Io`,
|
||||
которую заполняет порт платы.
|
||||
|
||||
```
|
||||
приложение
|
||||
│
|
||||
ft24c256.c нарезка записи по страницам, ожидание цикла записи,
|
||||
двухбайтовый адрес слова, счётчики ошибок
|
||||
│
|
||||
FT24C256_Io write, write_read, delay_ms, set_write_protect
|
||||
│
|
||||
порт платы I2C
|
||||
```
|
||||
|
||||
## Состав
|
||||
|
||||
| Файл | Что делает | Зависимости |
|
||||
|---|---|---|
|
||||
| `ft24c256.h`, `ft24c256.c` | чтение и запись произвольных блоков, стирание, защита записи, опрос готовности | `stdint.h` |
|
||||
|
||||
FT24C256 — 32768 байт (256 кбит), адрес слова двухбайтовый, страница записи
|
||||
64 байта. Микросхема принимает до 64 байт за транзакцию, но только внутри
|
||||
страницы: при переходе через границу счётчик адреса заворачивается на начало
|
||||
той же страницы и затирает уже принятые байты. Поэтому `FT24C256_Write()`
|
||||
сама режет запрос по границам страниц — вызывающему коду об этом думать не надо.
|
||||
|
||||
## Что нужно от платформы
|
||||
|
||||
```c
|
||||
uint8_t write(void *ctx, uint8_t addr, const uint8_t *data, uint16_t size);
|
||||
uint8_t write_read(void *ctx, uint8_t addr, const uint8_t *tx, uint16_t tx_size,
|
||||
uint8_t *rx, uint16_t rx_size); /* с повторным стартом */
|
||||
void delay_ms(void *ctx, uint32_t ms);
|
||||
```
|
||||
|
||||
Адрес передаётся семибитным, без бита направления — сдвиг делает порт.
|
||||
`set_write_protect` необязателен: если вывод WP не разведён, поле оставляется нулём.
|
||||
|
||||
## Быстрый старт
|
||||
|
||||
```c
|
||||
FT24C256 eeprom;
|
||||
FT24C256_Io io = { .write = i2c_write, .write_read = i2c_write_read,
|
||||
.delay_ms = board_delay, .context = &board };
|
||||
FT24C256_Config config;
|
||||
FT24C256_ConfigDefault(&config); /* 32 КБ, страница 64, адрес 0x50 */
|
||||
|
||||
FT24C256_Init(&eeprom, &io, &config);
|
||||
|
||||
uint8_t settings[100];
|
||||
FT24C256_Write(&eeprom, 0x0030, settings, sizeof settings);
|
||||
FT24C256_Read(&eeprom, 0x0030, settings, sizeof settings);
|
||||
```
|
||||
|
||||
До восьми кристаллов на шине: адрес `0x50 + index`, `FT24C256_AddressOf()`.
|
||||
|
||||
## Проверено в проектах
|
||||
|
||||
`KONOR_ds18b20`, `OpticalTester` — I2C1 на STM32F103C8T6.
|
||||
378
c/eeprom-ft24c256/ft24c256.c
Normal file
378
c/eeprom-ft24c256/ft24c256.c
Normal file
@@ -0,0 +1,378 @@
|
||||
/**
|
||||
* @file ft24c256.c
|
||||
* @brief Постраничная запись, сплошное чтение и ожидание готовности FT24C256.
|
||||
*
|
||||
* Реализация не хранит буфера всего массива: единственная крупная переменная —
|
||||
* кадр одной транзакции записи на стеке, длиной адрес слова плюс страница
|
||||
* (@ref FT24C256_ADDRESS_SIZE + @ref FT24C256_PAGE_MAX байт). Времени
|
||||
* библиотека не измеряет: выдержку цикла записи даёт порт, а готовность
|
||||
* определяется откликом самой микросхемы.
|
||||
*/
|
||||
|
||||
#include "ft24c256.h"
|
||||
|
||||
/** Кадр записи: адрес слова и страница данных. */
|
||||
#define FT24C256_FRAME_MAX (FT24C256_ADDRESS_SIZE + FT24C256_PAGE_MAX)
|
||||
|
||||
/** Длина куска, которым FT24C256_Update() сверяет содержимое. */
|
||||
#define FT24C256_COMPARE_MAX 32U
|
||||
|
||||
/**
|
||||
* @brief Проверяет пригодность состояния к обмену.
|
||||
*
|
||||
* @param device Состояние кристалла.
|
||||
* @return 1, если состояние настроено и обратные вызовы на месте, иначе 0.
|
||||
*/
|
||||
static uint8_t ft24c256_valid(const FT24C256 *device)
|
||||
{
|
||||
if (device == 0) {
|
||||
return 0U;
|
||||
}
|
||||
if (device->ready == 0U) {
|
||||
return 0U;
|
||||
}
|
||||
return (uint8_t)((device->io.write != 0) && (device->io.write_read != 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Проверяет, что область целиком помещается в массив.
|
||||
*
|
||||
* @param device Состояние кристалла.
|
||||
* @param address Адрес первого байта.
|
||||
* @param size Число байтов.
|
||||
* @return 1, если область допустима, иначе 0.
|
||||
*/
|
||||
static uint8_t ft24c256_in_range(const FT24C256 *device, uint32_t address,
|
||||
uint32_t size)
|
||||
{
|
||||
if (address >= device->config.size) {
|
||||
return 0U;
|
||||
}
|
||||
return (uint8_t)(size <= (device->config.size - address));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Раскладывает адрес слова в два байта, старший первым.
|
||||
*
|
||||
* @param address Адрес байта в массиве.
|
||||
* @param frame Приёмник кадра длиной не менее @ref FT24C256_ADDRESS_SIZE.
|
||||
*/
|
||||
static void ft24c256_put_address(uint32_t address, uint8_t *frame)
|
||||
{
|
||||
frame[0] = (uint8_t)((address >> 8U) & 0xFFU);
|
||||
frame[1] = (uint8_t)(address & 0xFFU);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Выдерживает паузу, если порт умеет её отсчитывать.
|
||||
*
|
||||
* @param device Состояние кристалла.
|
||||
* @param milliseconds Длительность паузы.
|
||||
*/
|
||||
static void ft24c256_delay(FT24C256 *device, uint32_t milliseconds)
|
||||
{
|
||||
if (device->io.delay_ms != 0) {
|
||||
device->io.delay_ms(device->io.context, milliseconds);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Записывает часть страницы одной транзакцией и ждёт готовности.
|
||||
*
|
||||
* @param device Состояние кристалла.
|
||||
* @param address Адрес первого байта; не пересекает границу страницы.
|
||||
* @param data Записываемые данные.
|
||||
* @param size Число байтов, не больше размера страницы.
|
||||
* @return 1 при успехе, иначе 0.
|
||||
*/
|
||||
static uint8_t ft24c256_write_page(FT24C256 *device, uint32_t address,
|
||||
const uint8_t *data, uint16_t size)
|
||||
{
|
||||
uint8_t frame[FT24C256_FRAME_MAX];
|
||||
uint16_t index;
|
||||
|
||||
if (size > FT24C256_PAGE_MAX) {
|
||||
return 0U;
|
||||
}
|
||||
ft24c256_put_address(address, frame);
|
||||
for (index = 0U; index < size; index++) {
|
||||
frame[FT24C256_ADDRESS_SIZE + index] = data[index];
|
||||
}
|
||||
if (device->io.write(device->io.context, device->config.address, frame,
|
||||
(uint16_t)(FT24C256_ADDRESS_SIZE + size)) == 0U) {
|
||||
device->write_errors++;
|
||||
return 0U;
|
||||
}
|
||||
device->written_bytes += size;
|
||||
return FT24C256_WaitReady(device);
|
||||
}
|
||||
|
||||
void FT24C256_ConfigDefault(FT24C256_Config *config)
|
||||
{
|
||||
if (config == 0) {
|
||||
return;
|
||||
}
|
||||
config->size = FT24C256_SIZE;
|
||||
config->page_size = FT24C256_PAGE_SIZE;
|
||||
config->address = FT24C256_BASE_ADDRESS;
|
||||
config->write_ms = FT24C256_WRITE_MS;
|
||||
config->poll_retries = FT24C256_POLL_RETRIES;
|
||||
}
|
||||
|
||||
uint8_t FT24C256_Init(FT24C256 *device, const FT24C256_Io *io,
|
||||
const FT24C256_Config *config)
|
||||
{
|
||||
if ((device == 0) || (io == 0)) {
|
||||
return 0U;
|
||||
}
|
||||
if ((io->write == 0) || (io->write_read == 0)) {
|
||||
return 0U;
|
||||
}
|
||||
|
||||
device->io = *io;
|
||||
if (config != 0) {
|
||||
device->config = *config;
|
||||
} else {
|
||||
FT24C256_ConfigDefault(&device->config);
|
||||
}
|
||||
if (device->config.size == 0U) {
|
||||
device->config.size = FT24C256_SIZE;
|
||||
}
|
||||
if (device->config.page_size == 0U) {
|
||||
device->config.page_size = FT24C256_PAGE_SIZE;
|
||||
}
|
||||
if (device->config.page_size > FT24C256_PAGE_MAX) {
|
||||
device->config.page_size = FT24C256_PAGE_MAX;
|
||||
}
|
||||
if (device->config.address == 0U) {
|
||||
device->config.address = FT24C256_BASE_ADDRESS;
|
||||
}
|
||||
if (device->config.write_ms == 0U) {
|
||||
device->config.write_ms = FT24C256_WRITE_MS;
|
||||
}
|
||||
/* Без опроса готовности единственная мера времени — выдержка порта. */
|
||||
if ((device->config.poll_retries == 0U) && (device->io.delay_ms == 0)) {
|
||||
return 0U;
|
||||
}
|
||||
|
||||
device->ready = 1U;
|
||||
device->written_bytes = 0U;
|
||||
device->read_bytes = 0U;
|
||||
device->write_errors = 0U;
|
||||
device->read_errors = 0U;
|
||||
return 1U;
|
||||
}
|
||||
|
||||
uint8_t FT24C256_IsPresent(FT24C256 *device)
|
||||
{
|
||||
if (ft24c256_valid(device) == 0U) {
|
||||
return 0U;
|
||||
}
|
||||
return device->io.write(device->io.context, device->config.address, 0, 0U);
|
||||
}
|
||||
|
||||
uint8_t FT24C256_WaitReady(FT24C256 *device)
|
||||
{
|
||||
uint8_t attempt;
|
||||
|
||||
if (ft24c256_valid(device) == 0U) {
|
||||
return 0U;
|
||||
}
|
||||
if (device->config.poll_retries == 0U) {
|
||||
ft24c256_delay(device, device->config.write_ms);
|
||||
return 1U;
|
||||
}
|
||||
for (attempt = 0U; attempt < device->config.poll_retries; attempt++) {
|
||||
if (device->io.write(device->io.context, device->config.address, 0,
|
||||
0U) != 0U) {
|
||||
return 1U;
|
||||
}
|
||||
ft24c256_delay(device, 1U);
|
||||
}
|
||||
device->write_errors++;
|
||||
return 0U;
|
||||
}
|
||||
|
||||
uint8_t FT24C256_Read(FT24C256 *device, uint32_t address, void *buffer,
|
||||
uint16_t size)
|
||||
{
|
||||
uint8_t frame[FT24C256_ADDRESS_SIZE];
|
||||
|
||||
if ((ft24c256_valid(device) == 0U) || (buffer == 0)) {
|
||||
return 0U;
|
||||
}
|
||||
if (size == 0U) {
|
||||
return 1U;
|
||||
}
|
||||
if (ft24c256_in_range(device, address, size) == 0U) {
|
||||
return 0U;
|
||||
}
|
||||
|
||||
ft24c256_put_address(address, frame);
|
||||
if (device->io.write_read(device->io.context, device->config.address, frame,
|
||||
FT24C256_ADDRESS_SIZE, (uint8_t *)buffer,
|
||||
size) == 0U) {
|
||||
device->read_errors++;
|
||||
return 0U;
|
||||
}
|
||||
device->read_bytes += size;
|
||||
return 1U;
|
||||
}
|
||||
|
||||
uint8_t FT24C256_Write(FT24C256 *device, uint32_t address, const void *data,
|
||||
uint16_t size)
|
||||
{
|
||||
const uint8_t *source = (const uint8_t *)data;
|
||||
uint32_t position = address;
|
||||
uint16_t left = size;
|
||||
|
||||
if ((ft24c256_valid(device) == 0U) || (data == 0)) {
|
||||
return 0U;
|
||||
}
|
||||
if (size == 0U) {
|
||||
return 1U;
|
||||
}
|
||||
if (ft24c256_in_range(device, address, size) == 0U) {
|
||||
return 0U;
|
||||
}
|
||||
|
||||
while (left != 0U) {
|
||||
const uint32_t page = device->config.page_size;
|
||||
const uint32_t tail = page - (position % page);
|
||||
uint16_t chunk = (tail < left) ? (uint16_t)tail : left;
|
||||
|
||||
if (ft24c256_write_page(device, position, source, chunk) == 0U) {
|
||||
return 0U;
|
||||
}
|
||||
position += chunk;
|
||||
source += chunk;
|
||||
left = (uint16_t)(left - chunk);
|
||||
}
|
||||
return 1U;
|
||||
}
|
||||
|
||||
uint8_t FT24C256_Update(FT24C256 *device, uint32_t address, const void *data,
|
||||
uint16_t size)
|
||||
{
|
||||
const uint8_t *source = (const uint8_t *)data;
|
||||
uint32_t position = address;
|
||||
uint16_t left = size;
|
||||
|
||||
if ((ft24c256_valid(device) == 0U) || (data == 0)) {
|
||||
return 0U;
|
||||
}
|
||||
if (size == 0U) {
|
||||
return 1U;
|
||||
}
|
||||
if (ft24c256_in_range(device, address, size) == 0U) {
|
||||
return 0U;
|
||||
}
|
||||
|
||||
while (left != 0U) {
|
||||
uint8_t stored[FT24C256_COMPARE_MAX];
|
||||
const uint16_t chunk = (left < FT24C256_COMPARE_MAX)
|
||||
? left
|
||||
: (uint16_t)FT24C256_COMPARE_MAX;
|
||||
uint16_t index;
|
||||
uint8_t differs = 0U;
|
||||
|
||||
if (FT24C256_Read(device, position, stored, chunk) == 0U) {
|
||||
return 0U;
|
||||
}
|
||||
for (index = 0U; index < chunk; index++) {
|
||||
if (stored[index] != source[index]) {
|
||||
differs = 1U;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((differs != 0U)
|
||||
&& (FT24C256_Write(device, position, source, chunk) == 0U)) {
|
||||
return 0U;
|
||||
}
|
||||
position += chunk;
|
||||
source += chunk;
|
||||
left = (uint16_t)(left - chunk);
|
||||
}
|
||||
return 1U;
|
||||
}
|
||||
|
||||
uint8_t FT24C256_ReadByte(FT24C256 *device, uint32_t address, uint8_t *value)
|
||||
{
|
||||
if (value == 0) {
|
||||
return 0U;
|
||||
}
|
||||
return FT24C256_Read(device, address, value, 1U);
|
||||
}
|
||||
|
||||
uint8_t FT24C256_WriteByte(FT24C256 *device, uint32_t address, uint8_t value)
|
||||
{
|
||||
return FT24C256_Write(device, address, &value, 1U);
|
||||
}
|
||||
|
||||
uint8_t FT24C256_Fill(FT24C256 *device, uint32_t address, uint8_t value,
|
||||
uint32_t size)
|
||||
{
|
||||
uint8_t page[FT24C256_PAGE_MAX];
|
||||
uint32_t position = address;
|
||||
uint32_t left = size;
|
||||
uint16_t index;
|
||||
|
||||
if (ft24c256_valid(device) == 0U) {
|
||||
return 0U;
|
||||
}
|
||||
if (size == 0U) {
|
||||
return 1U;
|
||||
}
|
||||
if (ft24c256_in_range(device, address, size) == 0U) {
|
||||
return 0U;
|
||||
}
|
||||
|
||||
for (index = 0U; index < device->config.page_size; index++) {
|
||||
page[index] = value;
|
||||
}
|
||||
while (left != 0U) {
|
||||
const uint32_t tail =
|
||||
device->config.page_size - (position % device->config.page_size);
|
||||
const uint32_t chunk = (tail < left) ? tail : left;
|
||||
|
||||
if (ft24c256_write_page(device, position, page, (uint16_t)chunk) == 0U) {
|
||||
return 0U;
|
||||
}
|
||||
position += chunk;
|
||||
left -= chunk;
|
||||
}
|
||||
return 1U;
|
||||
}
|
||||
|
||||
uint8_t FT24C256_Erase(FT24C256 *device)
|
||||
{
|
||||
if (ft24c256_valid(device) == 0U) {
|
||||
return 0U;
|
||||
}
|
||||
return FT24C256_Fill(device, 0U, 0xFFU, device->config.size);
|
||||
}
|
||||
|
||||
uint8_t FT24C256_Protect(FT24C256 *device, uint8_t enabled)
|
||||
{
|
||||
if (device == 0) {
|
||||
return 0U;
|
||||
}
|
||||
if (device->io.set_write_protect == 0) {
|
||||
return 0U;
|
||||
}
|
||||
device->io.set_write_protect(device->io.context, (uint8_t)(enabled != 0U));
|
||||
return 1U;
|
||||
}
|
||||
|
||||
uint32_t FT24C256_Size(const FT24C256 *device)
|
||||
{
|
||||
if ((device == 0) || (device->ready == 0U)) {
|
||||
return 0U;
|
||||
}
|
||||
return device->config.size;
|
||||
}
|
||||
|
||||
uint8_t FT24C256_AddressOf(uint8_t index)
|
||||
{
|
||||
return (uint8_t)(FT24C256_BASE_ADDRESS + (index & 0x7U));
|
||||
}
|
||||
277
c/eeprom-ft24c256/ft24c256.h
Normal file
277
c/eeprom-ft24c256/ft24c256.h
Normal file
@@ -0,0 +1,277 @@
|
||||
/**
|
||||
* @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 <stdint.h>
|
||||
|
||||
/** Объём 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 */
|
||||
Reference in New Issue
Block a user