拓冰建站拓冰建站
首页 / 资讯中心 / 正文

esp-iot-solution AT24C02 EEPROM 驱动指南:从芯片特性、I2C 读写机制到 Espressif 开源驱动 API 详解

esp-iot-solution AT24C02 EEPROM 驱动指南从芯片特性、I2C 读写机制到 Espressif 开源驱动 API 详解【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution本文围绕 esp-iot-solution 仓库中 at24c02 存储组件展开系统讲解 AT24C01A/02/04/08A/16A 系列串行 EEPROM 的设备寻址、页写回绕、随机/顺序读取与写保护等硬件机制并结合仓库中驱动源码 at24c02.c 与官方测试应用 at24c02_test.c给出可直接复用的创建、读写与位操作实战代码帮助你在 ESP32 平台上可靠地管理掉电不丢的存储数据。一、芯片家族概述Espressif 官方的 AT24C02 组件支持 Atmel现 MicrochipAT24C01A/02/04/08A/16A 系列串行电可擦除可编程只读存储器EEPROM它们分别提供1024/2048/4096/8192/16384 位的存储空间组织为128/256/512/1024/2048 个 8 位字。该器件面向工业与商业低功耗、低电压应用场景优化核心特性如下低压/标准压工作低压型VCC 1.8V 至 5.5V标准压型VCC 2.7V 至 5.5V。I2C 总线兼容1.8V 时 100 kHz2.7V/5V 时最高 400 kHz。页写模式1K/2K 型号为 8 字节页4K/8K/16K 型号为 16 字节页。允许部分页写Partial Page Writes Allowed。高可靠性擦写寿命 100 万次数据保持 100 年。驱动组件对整条调用链做了薄封装底层依赖仓库中的 i2c_bus 组件在 at24c02.c 中每个 API 都直接转发到对应的i2c_bus_*函数。二、设备地址Device Address如何挂多个芯片到同一条 I2C 总线I2C 总线上每个设备由 7 位从机地址区分。AT24C02 的地址格式为固定前缀1 0 1 0加 3 位地址引脚输入A2、A1、A0再接 R/W 位。仓库在头文件中给出了默认地址宏定义// components/storage/eeprom/at24c02/include/at24c02.h #define AT24C02_I2C_ADDRESS_DEFAULT (0x50) //1 0 1 0 A2 A1 A0 R/W即 A2A1A0000 时从机地址为0x50。硬件注意事项继承自官方文档AT24C01A 与 AT24C02A2/A1/A0 为硬件接口的地址输入引脚同一条总线最多可挂8 片 1K/2K 设备只需将三个地址引脚接高/低电平组合出 0x500x57 共 8 个地址。AT24C16A不使用地址引脚单条总线只能挂1 片。驱动侧把该地址作为参数传入创建函数支持多片同总线的场景at24c02_handle_t at24c02_create(i2c_bus_handle_t bus, uint8_t dev_addr);三、内存地址Memory Address与页结构芯片内部把存储空间划分为若干页随机访问需要的字地址位宽随容量增加而扩展型号容量页结构随机寻址所需字地址AT24C01A1K16 页 × 8 字节7 位AT24C022K32 页 × 8 字节8 位AT24C16A16K128 页 × 16 字节11 位以本组件主打的AT24C022K为例32 页、每页 8 字节字地址用 8 位表示0x000xFF这正好与驱动 API 中uint8_t start_addr的取值范围吻合。四、写操作机制字节写、页写与“地址回绕”4.1 字节写Byte WriteAT24C02 的字节写流程为先发送器件地址字并得到应答再发送 8 位数据字地址芯片确认后写入 1 个数据字节随后接收 STOP。4.2 页写Page Write与写回绕Roll Over1K/2K EEPROM 支持8 字节页写芯片应答第一个数据字后主控最多可再连续发送 7 个数据字。必须牢记的关键行为是——如果一次页写发送的数据字超过 8 个1K/2K或 16 个4K/8K/16K数据字地址会在页内“回绕roll over”从该页首字节开始覆盖先前写入的数据。也就是说写回绕是“页内回绕”不是跨页连续。驱动在 at24c02_write 中显式对此做了保护性提示esp_err_t at24c02_write(at24c02_handle_t device, uint8_t start_addr, uint8_t write_num, uint8_t *data_buf) { at24c02_dev_t *dev (at24c02_dev_t *) device; if (write_num 8) { ESP_LOGW(TAG, must write_num 8, extra bytes will overwrite from byte 0 in this 8B page); } return i2c_bus_write_bytes(dev-i2c_dev, start_addr, write_num, data_buf); }可以看到当一次请求写入超过 8 字节时驱动打印警告“多出的字节会从该 8 字节页的第 0 字节开始覆盖”然后仍把请求整体交给 I2C 总线层执行。因此实际工程中跨页写需要应用层自己按页拆分每段不超过 8 字节1K/2K且注意对齐页边界避免同一页内先写后段再被前段回绕覆盖。五、读操作机制当前地址读、随机读、顺序读与读回绕AT24C02 内部的数据字地址计数器在每次读或写之后保持最后访问地址并加 1只要不断电该地址一直有效。基于此有三种读模式当前地址读Current Address Read直接在发送器件地址字后发起读芯片从“内部计数器当前值”开始输出数据。读过程中的回绕定义为从最后一个内存页的最后一个字节跳回第一页的第一个字节——这与写回绕页内回绕语义不同官方文档特别强调了两者的区别。随机读Random Read需要一次“哑字节”写序列来装载数据字地址当器件地址字与字地址被时钟打入并应答后主控必须再产生一次起始重复 START条件才能开始读数据。顺序读Sequential Read由当前地址读或随机读发起只要芯片持续收到应答它就不断自增字地址并串行输出连续数据到达存储末端后地址回绕顺序读继续。仓库驱动对这三种模式做了简化取舍at24c02_read/at24c02_read_byte都通过i2c_bus_read_bytes实现即每次都在总线上先“写地址 重复 START 读”的随机读路径因此 API 调用之间不依赖芯片内部地址计数器的隐式状态语义更明确、更不容易出错。六、写保护WP引脚AT24C01A/02/04/08A/16A 都带有一个 Write ProtectWP硬件保护引脚WP 接GND正常读/写操作WP 接VCC启用写保护芯片只读不可写。设计需要“出厂默认数据只读”或防误擦写场景时建议直接把 WP 上拉至电源调试阶段接 GND 以便验证写入逻辑。七、驱动 API 全解析include/at24c02.h 定义了句柄与全部公开接口。所有函数均以esp_err_t返回ESP_OK/ESP_FAIL创建函数返回句柄失败为 NULL函数功能关键参数说明at24c02_create(i2c_bus_handle_t bus, uint8_t dev_addr)在指定 I2C 总线上创建 AT24C02 句柄dev_addr为 7 位从机地址常见 0x50at24c02_delete(at24c02_handle_t *device)销毁句柄并释放资源传句柄指针成功后内部置 NULLat24c02_write_byte(device, addr, data)单字节写Byte Writeaddr为目标字地址at24c02_read_byte(device, addr, *data)单字节读Random Read内部先写地址再重复 STARTat24c02_write(device, start_addr, write_num, data_buf)多字节连续写Page Write1K/2K 建议write_num 8超过会触发页内回绕覆盖at24c02_read(device, start_addr, read_num, data_buf)多字节连续读从start_addr起随机读at24c02_write_bit(device, addr, bit_num, data)写单字节中的 1 个位bit_num0~70 为最低位at24c02_read_bit(device, addr, bit_num, *data)读单字节中的 1 个位返回值规范为 0/1at24c02_write_bits(device, addr, bit_start, length, data)写字节中的连续位段bit_start0~7MSB 为 0length1~8at24c02_read_bits(device, addr, bit_start, length, *data)读字节中的连续位段位号约定同 write_bits7.1 句柄内部结构从 at24c02.c 的源码结构看句柄就是一个对 I2C 总线设备的轻量封装typedef struct { i2c_bus_device_handle_t i2c_dev; uint8_t dev_addr; } at24c02_dev_t; at24c02_handle_t at24c02_create(i2c_bus_handle_t bus, uint8_t dev_addr) { if (bus NULL) { return NULL; } at24c02_dev_t *dev (at24c02_dev_t *) calloc(1, sizeof(at24c02_dev_t)); dev-i2c_dev i2c_bus_device_create(bus, dev_addr, i2c_bus_get_current_clk_speed(bus)); ... }两个值得注意的实现细节创建设备时通过i2c_bus_get_current_clk_speed(bus)继承总线的当前时钟速率即 EEPROM 的传输速度与所在 I2C 总线一致不需要单独配置所有读写最终都收敛到 i2c_bus.c 的i2c_bus_write_reg8/i2c_bus_read_reg8等“8 位内存地址”寄存器访问原语与 AT24C02 的“器件地址 8 位字地址”总线时序一一对应。7.2 位操作是读-改-写Read-Modify-Write*_bit(s)系列接口在 EEPROM 这种纯存储器上没有硬件位操作指令i2c_bus.c 中采用经典的读-改-写实现// i2c_bus_write_bit置位/清零单个位 byte (data ! 0) ? (byte | (1 bit_num)) : (byte ~(1 bit_num)); return i2c_bus_write_byte(dev_handle, mem_address, byte); // i2c_bus_write_bits先清零目标位段再按位号对齐写入新值 uint8_t mask ((1 length) - 1) (bit_start - length 1); data (bit_start - length 1); // shift data into correct position data mask; // zero all non-important bits in data byte ~(mask); // zero all important bits in existing byte byte | data; // combine data with existing byte使用时的关键约定bit_start以 MSB 为 0 编号length表示位段长度数据按左对齐填入。例如要写字节的高 4 位调用at24c02_write_bits(dev, addr, 0, 4, val)写低 4 位则用at24c02_write_bits(dev, addr, 3, 4, val)位段覆盖 bit3~bit0。位号方向不同write_bit/read_bit的bit_num是 0~7 且 0 为 LSBwrite_bits/read_bits的bit_start是 0~7 且 0 为 MSB调用时需注意区分。由于每次位写都会先读后写整字节EEPROM 的 100 万次擦写寿命对位操作同样按“整字节写”消耗频繁位翻转的场景应合并字节级写入。八、实战基于官方测试应用的完整示例仓库自带的测试工程 test_apps/main/at24c02_test.c 展示了完整的初始化、读写验证与清理流程可直接作为工程模板。8.1 硬件连接与初始化测试工程假设 AT24C02 的 SDA 接 GPIO1、SCL 接 GPIO2使用 I2C_NUM_0、100 kHz 时钟#define I2C_MASTER_SCL_IO 2 #define I2C_MASTER_SDA_IO 1 #define I2C_MASTER_NUM I2C_NUM_0 #define I2C_MASTER_FREQ_HZ 100000 void at24c02_init() { i2c_config_t conf { .mode I2C_MODE_MASTER, .sda_io_num I2C_MASTER_SDA_IO, .sda_pullup_en GPIO_PULLUP_ENABLE, .scl_io_num I2C_MASTER_SCL_IO, .scl_pullup_en GPIO_PULLUP_ENABLE, .master.clk_speed I2C_MASTER_FREQ_HZ, }; i2c_bus i2c_bus_create(I2C_MASTER_NUM, conf); at24c02 at24c02_create(i2c_bus, AT24C02_I2C_ADDRESS_DEFAULT); } void at24c02_deinit() { at24c02_delete(at24c02); i2c_bus_delete(i2c_bus); }释放顺序与创建相反先删 EEPROM 设备句柄再删 I2C 总线。8.2 字节写读与多字节写读// 单字节写读写入后延时 50ms 再读回校验 uint8_t data0 cnt; TEST_ASSERT(ESP_OK at24c02_write_byte(at24c02, cnt, data0)); vTaskDelay(50 / portTICK_RATE_MS); uint8_t data0_read 0; TEST_ASSERT(ESP_OK at24c02_read_byte(at24c02, cnt, data0_read)); TEST_ASSERT_EQUAL_UINT8(data0, data0_read); // 多字节写读从地址 cnt 起写 5 字节再读回比较 uint8_t data[5] {0x00}; for (size_t i 0; i 5; i) { data[i] cnt i; } TEST_ASSERT(ESP_OK at24c02_write(at24c02, cnt, sizeof(data), data)); vTaskDelay(50 / portTICK_RATE_MS); uint8_t data_read[5] {0x00}; TEST_ASSERT(ESP_OK at24c02_read(at24c02, cnt, sizeof(data_read), data_read)); TEST_ASSERT_EQUAL_UINT8_ARRAY(data, data_read, 5);注意示例中每次写后都有 50 ms 延时——EEPROM 写入是内部操作写入周期通常在毫秒级写后短暂等待再读能避免读到写入尚未完成的旧值。8.3 位与位段操作// 先清零整字节再逐位写入 data2 的 8 个位 uint8_t data2 cnt 20; TEST_ASSERT(ESP_OK at24c02_write_byte(at24c02, cnt, 0x00)); for (size_t i 0; i 8; i) { TEST_ASSERT(ESP_OK at24c02_write_bit(at24c02, cnt, i, (data2 i) 0x01)); vTaskDelay(50 / portTICK_RATE_MS); uint8_t data2_read 0; TEST_ASSERT(ESP_OK at24c02_read_bit(at24c02, cnt, i, data2_read)); } // 分两次写高低 4 位bit_start 分别取 0 和 3 TEST_ASSERT(ESP_OK at24c02_write_bits(at24c02, cnt, i * 4 3, 4, ((data2 (i * 4)) 0x0f)));测试工程还通过 Unity 框架的setUp/tearDown钩子在每组用例前后统计 8 位/32 位堆空闲量以-400字节为阈值断言无内存泄漏验证了at24c02_delete/i2c_bus_delete的资源回收完整性。九、组件集成与测试运行方式9.1 组件依赖at24c02 的 idf_component.yml 声明了版本与依赖关系version: 0.1.0 description: EEPROM AT24C02 Driver dependencies: i2c_bus: public: true override_path: ../../../i2c_bus idf: 4.4 cmake_utilities: 0.*即该驱动要求ESP-IDF 4.4并自动携带 i2c_bus 组件本仓库内以相对路径覆盖同时依赖cmake_utilities组件。工程侧只需在idf_component.yml中引用espressif/iot_eeprom_at24c02或在本地以EXTRA_COMPONENT_DIRS方式挂载该目录即可。9.2 编译并运行测试应用测试工程 test_apps/CMakeLists.txt 仅靠三行完成挂载set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/tools/unit-test-app/components ../../at24c02) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(at24c02_test)配套 sdkconfig.defaults 关闭了任务看门狗因为 Unity 菜单交互与vTaskDelay需要、将 FreeRTOS 时基设为 1000 Hz 并选择 240 MHz 主频。烧录后应用入口调用unity_run_menu()在终端菜单中逐项运行四个用例at24c02 byte operations—— 单字节写读at24c02 bytes operations—— 多字节连续写读at24c02 bit operations—— 位级写读at24c02 bits operations—— 位段级写读。十、使用要点与注意事项小结页写上限AT24C02 一次页写最多 8 字节超限会页内回绕覆盖旧数据跨页批量写请应用层按页边界自行分段驱动在 at24c02_write 中已给出超限警告。写回绕与读回绕语义不同写在页内回绕读从整个存储末尾跳回 0 地址继续二者不可混用理解。位号约定*_bit以 0 为最低位*_bits以 0 为最高位调用at24c02_write_bits时按 MSB-first 编号计算bit_start。总线速率驱动自动继承所挂 I2C 总线时钟AT24C02 在 1.8V 供电下保证 100 kHz2.7V/5V 下支持 400 kHz选型接线时按实际供电电压设定。多片挂载AT24C02 利用 A2/A1/A0 最多可挂 8 片0x50~0x57AT24C16A 无地址引脚单总线限 1 片。写保护WP 接 GND 可写、接 VCC 只读可用硬件引脚决定存储区是否允许写入。擦写寿命位操作底层为整字节读-改-写每次位写消耗一次擦写次数高频更新场景建议减少写次数或选用更大容量器件做轮转区。至此本文从芯片原理到仓库驱动实现完成了对 at24c02 组件的完整覆盖理解地址与页结构可以规避回绕覆盖类 Bug熟悉 API 与位号约定可以快速上手开发而参考 测试应用 的工程结构则能在硬件就绪后最短路径内完成烧录验证。【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门