diff --git a/README.md b/README.md index 448b39c..29967d3 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,70 @@ -# Driver_M24Cxx -通过I2C读取M24Cxx系列EEPROM的可移植驱动 +# Driver_M24Cxx(可移植 EEPROM 驱动) + +这是一个面向 M24Cxx / AT24Cxx 系列 EEPROM 的可移植驱动模块。 + +核心特性: + +- 不依赖特定 MCU/SDK(不绑定 STM32 HAL) +- 支持页写自动拆分 +- 通过回调适配底层总线 + +## 目录结构 + +- `module/Int_EEPROM24xx.h`:驱动接口定义 +- `module/Int_EEPROM24xx.c`:驱动实现 +- `examples/adapter_template.c`:适配层模板 + +## 你需要实现的 3 个函数 + +移植时,你只需要实现这三个底层函数,然后在配置结构体里挂接: + +1. `bus_read`:从 EEPROM 读数据 +2. `bus_write`:向 EEPROM 写数据 +3. `delay_ms`:毫秒延时 + +> 这也是本仓库提交信息里的重点:**需要自己实现读、写、延时这三个函数**。 + +## 快速接入 + +### 1) 将模块加入工程 + +把以下文件加入你的工程: + +- `module/Int_EEPROM24xx.h` +- `module/Int_EEPROM24xx.c` + +### 2) 实现底层适配函数 + +参考 `examples/adapter_template.c`,按你的平台替换 I2C 读写与延时实现。 + +### 3) 初始化设备描述并调用 API + +```c +static const IntEEPROM24xx_t g_eeprom = { + .ctx = your_bus_context, + .dev_addr = (0x50u << 1), + .page_size = 8u, + .mem_addr_size = 1u, + .write_cycle_ms = 6u, + .timeout_ms = 100u, + .bus_read = your_bus_read, + .bus_write = your_bus_write, + .delay_ms = your_delay_ms, +}; + +Int_EEPROM24xx_Read(&g_eeprom, 0x00, rx_buf, sizeof(rx_buf)); +Int_EEPROM24xx_Write(&g_eeprom, 0x00, tx_buf, sizeof(tx_buf)); +``` + +## 参数说明 + +- `dev_addr`:设备地址(7bit 或左移后地址,取决于你的底层驱动规范) +- `page_size`:页大小(必须与芯片手册一致) +- `mem_addr_size`:地址字节数(1 或 2) +- `write_cycle_ms`:每次页写后的写周期等待 + +## 常见问题 + +- 写入失败:优先检查 `page_size` 和 `write_cycle_ms` +- 读写偏移错乱:检查 `mem_addr_size`(1 字节 / 2 字节) +- 跨平台报错:说明底层回调未按目标 SDK 正确实现 diff --git a/examples/adapter_template.c b/examples/adapter_template.c new file mode 100644 index 0000000..9d7bcd5 --- /dev/null +++ b/examples/adapter_template.c @@ -0,0 +1,75 @@ +#include "Int_EEPROM24xx.h" + +/* + * 这是移植模板:请把这 3 个函数替换为你的平台实现。 + */ + +static IntEEPROM_Result_t your_bus_read(void *ctx, + uint16_t dev_addr, + uint32_t mem_addr, + uint8_t mem_addr_size, + uint8_t *buf, + uint16_t len, + uint32_t timeout_ms) +{ + (void)ctx; + (void)dev_addr; + (void)mem_addr; + (void)mem_addr_size; + (void)buf; + (void)len; + (void)timeout_ms; + + /* TODO: 替换为平台 I2C 读函数 */ + return INT_EEPROM_ERR_IO; +} + +static IntEEPROM_Result_t your_bus_write(void *ctx, + uint16_t dev_addr, + uint32_t mem_addr, + uint8_t mem_addr_size, + const uint8_t *buf, + uint16_t len, + uint32_t timeout_ms) +{ + (void)ctx; + (void)dev_addr; + (void)mem_addr; + (void)mem_addr_size; + (void)buf; + (void)len; + (void)timeout_ms; + + /* TODO: 替换为平台 I2C 写函数 */ + return INT_EEPROM_ERR_IO; +} + +static void your_delay_ms(void *ctx, uint32_t delay_ms) +{ + (void)ctx; + (void)delay_ms; + + /* TODO: 替换为平台 delay 实现 */ +} + +/* 示例:设备描述 */ +static const IntEEPROM24xx_t g_eeprom = { + .ctx = 0, + .dev_addr = (0x50u << 1), + .page_size = 8u, + .mem_addr_size = 1u, + .write_cycle_ms = 6u, + .timeout_ms = 100u, + .bus_read = your_bus_read, + .bus_write = your_bus_write, + .delay_ms = your_delay_ms, +}; + +void eeprom_example(void) +{ + uint8_t tx[8] = {1,2,3,4,5,6,7,8}; + uint8_t rx[8] = {0}; + + (void)Int_EEPROM24xx_Write(&g_eeprom, 0x00, tx, sizeof(tx)); + (void)Int_EEPROM24xx_Read(&g_eeprom, 0x00, rx, sizeof(rx)); +} diff --git a/module/Int_EEPROM24xx.c b/module/Int_EEPROM24xx.c new file mode 100644 index 0000000..bd178a8 --- /dev/null +++ b/module/Int_EEPROM24xx.c @@ -0,0 +1,59 @@ +#include "Int_EEPROM24xx.h" + +/* 直接透传到用户提供的总线读回调。 */ +IntEEPROM_Result_t Int_EEPROM24xx_Read(const IntEEPROM24xx_t *dev, uint32_t mem_addr, uint8_t *buf, uint16_t len) +{ + if (dev == NULL || buf == NULL || len == 0u || dev->bus_read == NULL) + { + return INT_EEPROM_ERR_ARG; + } + + return dev->bus_read(dev->ctx, dev->dev_addr, mem_addr, dev->mem_addr_size, buf, len, dev->timeout_ms); +} + +/* 按页拆分写入,避免跨页写导致 EEPROM 数据回卷或写失败。 */ +IntEEPROM_Result_t Int_EEPROM24xx_Write(const IntEEPROM24xx_t *dev, uint32_t mem_addr, const uint8_t *buf, uint16_t len) +{ + uint16_t written = 0; + uint16_t chunk; + uint32_t cur_addr; + uint16_t page_off; + uint16_t room; + IntEEPROM_Result_t st; + + if (dev == NULL || buf == NULL || len == 0u || dev->page_size == 0u || dev->bus_write == NULL) + { + return INT_EEPROM_ERR_ARG; + } + + while (written < len) + { + /* 计算当前页内偏移和本次最多可写长度。 */ + cur_addr = mem_addr + written; + page_off = (uint16_t)(cur_addr % dev->page_size); + room = (uint16_t)(dev->page_size - page_off); + chunk = (uint16_t)(((len - written) < room) ? (len - written) : room); + + /* 实际总线写由平台适配层完成。 */ + st = dev->bus_write(dev->ctx, + dev->dev_addr, + cur_addr, + dev->mem_addr_size, + (const uint8_t *)(buf + written), + chunk, + dev->timeout_ms); + if (st != INT_EEPROM_OK) + { + return st; + } + + if (dev->delay_ms != NULL && dev->write_cycle_ms > 0u) + { + /* EEPROM 页写后通常需要写周期时间。 */ + dev->delay_ms(dev->ctx, dev->write_cycle_ms); + } + written = (uint16_t)(written + chunk); + } + + return INT_EEPROM_OK; +} diff --git a/module/Int_EEPROM24xx.h b/module/Int_EEPROM24xx.h new file mode 100644 index 0000000..4bda80d --- /dev/null +++ b/module/Int_EEPROM24xx.h @@ -0,0 +1,60 @@ +#ifndef INT_EEPROM24XX_H +#define INT_EEPROM24XX_H + +#include +#include + +typedef int32_t IntEEPROM_Result_t; + +#define INT_EEPROM_OK 0 +#define INT_EEPROM_ERR_ARG -1 +#define INT_EEPROM_ERR_IO -2 + +/* 底层总线读回调: + * ctx : 用户上下文(可传 I2C 句柄、驱动实例等) + * dev_addr : 器件地址(格式由你的平台驱动决定) + * mem_addr : EEPROM 内存地址 + * mem_addr_size : 地址字节数(1 或 2) + * timeout_ms : 访问超时(毫秒) + */ +typedef IntEEPROM_Result_t (*IntEEPROM_BusRead_t)(void *ctx, + uint16_t dev_addr, + uint32_t mem_addr, + uint8_t mem_addr_size, + uint8_t *buf, + uint16_t len, + uint32_t timeout_ms); + +/* 底层总线写回调,参数含义同读回调 */ +typedef IntEEPROM_Result_t (*IntEEPROM_BusWrite_t)(void *ctx, + uint16_t dev_addr, + uint32_t mem_addr, + uint8_t mem_addr_size, + const uint8_t *buf, + uint16_t len, + uint32_t timeout_ms); + +typedef void (*IntEEPROM_DelayMs_t)(void *ctx, uint32_t delay_ms); + +typedef struct +{ + void *ctx; /* 用户上下文 */ + uint16_t dev_addr; /* 器件地址 */ + uint16_t page_size; /* 页大小(字节) */ + uint8_t mem_addr_size; /* 地址字节数:1 或 2 */ + uint32_t write_cycle_ms; /* 每次页写后等待时间(ms) */ + uint32_t timeout_ms; /* 总线访问超时(ms) */ + IntEEPROM_BusRead_t bus_read; + IntEEPROM_BusWrite_t bus_write; + IntEEPROM_DelayMs_t delay_ms; +} IntEEPROM24xx_t; + +/* 读取 EEPROM。 + * 返回 INT_EEPROM_OK 表示成功。 + */ +IntEEPROM_Result_t Int_EEPROM24xx_Read(const IntEEPROM24xx_t *dev, uint32_t mem_addr, uint8_t *buf, uint16_t len); + +/* 写入 EEPROM(内部会自动按页拆分写入)。 */ +IntEEPROM_Result_t Int_EEPROM24xx_Write(const IntEEPROM24xx_t *dev, uint32_t mem_addr, const uint8_t *buf, uint16_t len); + +#endif