基于RT-Thread驱动EEPROM_AD24C02
- 前言
- 一、硬件设计
- 二、软件设计
- 三、测试
- 1、eeprom_test()测试
- 2、基础操作字节实验
- 3、多字节读写
前言
- 存储容量2048位,内部组织256x8(2K),即256个字节的存储单元;分为16页,每页16个字节。
- 具有写保护,擦写寿命1,000,000次,数据保存期限100年。
- 写操作可按字节写,也可按页写。
- I2C通信,器件从机写地址0x50, 从机读地址0x51
一、硬件设计
- WP引脚上拉,这个引脚是写保护引脚,低电平解开保护,可以读写。高电平写保护,
- 通过IIC即可与之通信。
二、软件设计
-
创建工程
-
打开RT-Thread Settings
-
打开I2C设备驱动程序
-
使能I2C模块
-
进入board.h打开I2C1的的宏定义,SCL跟SDA引脚的绑定需要根据你实际硬件连接去修改。
-
主函数中这么写
-
在applications文件夹下新建一个system_deal文件夹,然后再在system_deal文件夹下新建一个system_deal.c和system_deal.h文件,这个文件夹里我放一个给板子闪灯的程序,判断板子是否跑起来
-
在system_deal.c文件里这么写
/** Copyright (c) 2006-2021, RT-Thread Development Team** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date Author Notes* 2025-04-18 Administrator the first version*/#include "system_deal.h"/*********************************************************************************************************** Function name: SystemLedRun** Descriptions: System Led Run** input parameters: NONE** output parameters: NONE** Returned value: NONE*********************************************************************************************************/
static void SystemLedRun(void)
{static uint8_t l_ucmode = 0;if (l_ucmode == 0){rt_pin_write(SYS_LED, PIN_HIGH);l_ucmode = 1;}else if (l_ucmode == 1){rt_pin_write(SYS_LED, PIN_LOW);l_ucmode = 0;}
}/*********************************************************************************************************** Function name: SysDeal_thread** Descriptions: SysDeal thread** input parameters: parameter** output parameters: NONE** Returned value: NONE*********************************************************************************************************/
static void SysDeal_thread(void* parameter)
{// set pinrt_pin_mode(SYS_LED, PIN_MODE_OUTPUT);rt_pin_write(SYS_LED, PIN_HIGH);while(1){SystemLedRun(); //闪个灯rt_thread_mdelay(500);}}/*********************************************************************************************************** Function name: SystemDealTaskInit** Descriptions: System Task Init** input parameters: NONE** output parameters: NONE** Returned value: NONE*********************************************************************************************************/
void SystemDealTaskInit(void)
{rt_thread_t SysDeal_tid;SysDeal_tid = rt_thread_create("sys_ctl", SysDeal_thread, RT_NULL, SYS_THREAD_STACK, SYS_THREAD_PRO, SYS_THREAD_TICK);if (SysDeal_tid != RT_NULL){rt_thread_startup(SysDeal_tid);}else{
#if DEBUG_LOG_ENABLErt_kprintf("/--> SysDeal create failed!\n");
#endif}
}/*********************************************************************************************************** Function name: SystemTaskInit** Descriptions: System Task Init** input parameters: NONE** output parameters: NONE** Returned value: NONE*********************************************************************************************************/
static void SystemTaskInit(void)
{SystemDealTaskInit(); // 15}/*********************************************************************************************************** Function name: SystemStartInit** Descriptions: System Start Init** input parameters: NONE** output parameters: NONE** Returned value: NONE*********************************************************************************************************/
void SystemStartInit(void)
{SystemTaskInit();
}
- 在system_deal.h文件里这么写
/** Copyright (c) 2006-2021, RT-Thread Development Team** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date Author Notes* 2025-04-18 Administrator the first version*/
#ifndef APPLICATIONS_SYSTEM_DEAL_SYSTEM_DEAL_H_
#define APPLICATIONS_SYSTEM_DEAL_SYSTEM_DEAL_H_#include <rtdevice.h>
#include <rtthread.h>
#include "board.h"
#include "stdio.h"/* system io */
#define SYS_LED GET_PIN(G, 13)/* thread information */
#define SYS_THREAD_STACK 1024
#define SYS_THREAD_PRO 15
#define SYS_THREAD_TICK 10extern void SystemStartInit(void);#endif /* APPLICATIONS_SYSTEM_DEAL_SYSTEM_DEAL_H_ */
- 在applications文件夹下新建drv_ad24c02文件夹,再在drv_ad24c02文件夹下新建drv_ad24c02.c和drv_ad24c02.h文件,这个文件夹里写的是ad24c02的驱动
- 在drv_ad24c02.c文件里这么写
/** Copyright (c) 2006-2021, RT-Thread Development Team** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date Author Notes* 2025-04-18 Administrator the first version*/
#include "drv_ad24c02.h"static struct rt_i2c_bus_device *i2c_bus = RT_NULL;
/*** eeprom write byte* @note This operation is write one bye to eeprom.** @param addr: the data address to write* data: the data write to the address** @return >= 0: successful* -1: error**/
rt_err_t eeprom_write_byte(uint8_t addr, uint8_t data)
{struct rt_i2c_msg msg;uint8_t buffer[2];buffer[0] = addr;buffer[1] = data;msg.addr = EEPROM_I2C_ADDR;msg.flags = RT_I2C_WR;msg.buf = buffer;msg.len = 2;if(rt_i2c_transfer(i2c_bus, &msg, 1) != 1){rt_kprintf("eeprom i2c data write error.\n");return RT_ERROR;}rt_thread_mdelay(5);return RT_EOK;
}
/*** eeprom read byte* @note This operation is read one bye from eeprom.** @param addr: the data address to read** @return data: the data read from the address***/
uint8_t eeprom_read_byte(uint8_t addr)
{struct rt_i2c_msg msg;uint8_t buffer[2];uint8_t data;msg.addr = EEPROM_I2C_ADDR;msg.flags = RT_I2C_WR;buffer[0] = addr;msg.buf = buffer;msg.len = 1;rt_i2c_transfer(i2c_bus, &msg, 1);msg.flags = RT_I2C_RD;msg.buf = &data;rt_i2c_transfer(i2c_bus, &msg, 1);return data;
}
/*** eeprom check* @note This operation is check eeprom.** @param** @return >= 0: successful* -1: error**/
static rt_err_t eeprom_check(uint8_t data)
{uint8_t temp;temp = eeprom_read_byte(EEPROM_SIZE - 1);if(temp != data){eeprom_write_byte(EEPROM_SIZE - 1, data);rt_thread_mdelay(5);temp = eeprom_read_byte(EEPROM_SIZE - 1);if(temp != data){
#if 1rt_kprintf("eeprom check data [0x%02X] not equal read data [0x%02X].\n", data, temp);
#endifreturn RT_ERROR;}rt_kprintf("eeprom check data [0x%02X] equal read data [0x%02X].\n", data, temp);}return RT_EOK;
}/*** eeprom init* @note This operation is eeprom init.** @param** @return >= 0: successful* -1: error**/
rt_err_t eeprom_init(void)
{i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(EEPROM_I2C_BUS_NAME);if (i2c_bus == RT_NULL){rt_kprintf("eeprom i2c bus find error.\n");return RT_ERROR;}rt_pin_mode(EEPROM_WP_PIN, PIN_MODE_OUTPUT);rt_pin_write(EEPROM_WP_PIN, PIN_LOW);if(eeprom_check(EEPROM_CHECK_VALUE) != RT_EOK){rt_kprintf("eeprom check error.\n");return RT_ERROR;}else {rt_kprintf("eeprom check success.\n");}return RT_EOK;
}/*** eeprom test* @note This operation is test eeprom.** @param** @return >= 0: successful* -1: error**/
static int eeprom_test(void)
{rt_uint8_t *rw_buf = RT_NULL;rw_buf = (rt_uint8_t *)rt_malloc(EEPROM_SIZE); //分配一个256字节大小的空间eeprom_init();//erase eepromfor(rt_uint16_t addr = 0; addr < EEPROM_SIZE; addr++){if(RT_EOK == eeprom_write_byte(addr, 0)){rt_kprintf("address [0x%02X] erase OK.\n", addr);}else{rt_kprintf("address [0x%02X] erase failed.\n", addr);}}rt_kprintf("\n");rt_thread_mdelay(1000);//read eepromfor(rt_uint16_t addr = 0; addr < EEPROM_SIZE; addr++){rw_buf[addr] = eeprom_read_byte(addr);rt_kprintf("address [0x%02X] data is [%d].\n", addr, rw_buf[addr]);}rt_kprintf("\n");rt_thread_mdelay(1000);//write eepromfor(rt_uint16_t addr = 0; addr < EEPROM_SIZE; addr++){if(RT_EOK == eeprom_write_byte(addr, 0XFF)){rt_kprintf("address [0x%02X] write OK.\n", addr);}else{rt_kprintf("address [0x%02X] write failed.\n", addr);}}rt_kprintf("\n");rt_thread_mdelay(1000);//read eepromfor(rt_uint16_t addr = 0; addr < EEPROM_SIZE; addr++){rw_buf[addr] = eeprom_read_byte(addr);rt_kprintf("address [0x%02X] data is [%d].\n", addr, rw_buf[addr]);}//freert_free(rw_buf);return RT_EOK;
}
MSH_CMD_EXPORT(eeprom_test, eeprom test);static void basic_test(int argc, char** argv)
{if (argc != 3){rt_kprintf("Usage: basic_test [addr(0-255)] [data(0-255)]\n");return;}uint8_t addr = atoi(argv[1]);uint8_t wr_data = atoi(argv[2]);// 写入并验证eeprom_write_byte(addr, wr_data);uint8_t rd_data = eeprom_read_byte(addr);rt_kprintf("Immediate read: Addr 0x%02X => Wr:0x%02X Rd:0x%02X %s \r\n",addr, wr_data, rd_data, (wr_data == rd_data) ? "OK" : "FAIL");// 重启后验证rt_kprintf("Power cycle device and run again to check persistence");
}
MSH_CMD_EXPORT(basic_test, basic single-byte test);static void read_test(int argc, char** argv)
{if(argc != 2){rt_kprintf("Usage: read_test [addr(0-255)]\n");return;}uint8_t addr = atoi(argv[1]);uint8_t rd_data = eeprom_read_byte(addr);rt_kprintf("Immediate read: Addr %d => Rd:%d \r\n",addr, rd_data);}
MSH_CMD_EXPORT(read_test, read single-byte test);
- 在drv_ad24c02.h文件里这么写
/** Copyright (c) 2006-2021, RT-Thread Development Team** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date Author Notes* 2025-04-18 Administrator the first version*/
#ifndef APPLICATIONS_DRV_AD24C02_DEAL_DRV_AD24C02_H_
#define APPLICATIONS_DRV_AD24C02_DEAL_DRV_AD24C02_H_#include <rtdevice.h>
#include <rtthread.h>
#include "board.h"
#include "stdio.h"
#include "stdlib.h"#define EEPROM_I2C_BUS_NAME "i2c1"
#define EEPROM_I2C_ADDR 0x50 //0xA0 << 1
#define EEPROM_SIZE 256 //Byte
#define EEPROM_CHECK_VALUE 0x5A/*********************************eeprom**************************************************/
#define EEPROM_WP_PIN GET_PIN(B, 4)extern rt_err_t eeprom_init(void); //ad24c02初始化
#endif /* APPLICATIONS_DRV_AD24C02_DEAL_DRV_AD24C02_H_ */
- 包含头文件
- 找个位置进行ad24c02初始化
- 包含一下ad24c02驱动头文件
- 编译通过
三、测试
1、eeprom_test()测试
在MSH中使用命令行敲出eeprom_test进行测试。
-
先打help可以看到目前有什么指令,然后输入eeprom_test进行测试,按TAB键可以自动补齐。
-
该测试函数首先会往eeprom的256个字节中写0,一个字节一个字节的写,每写成功一个都会返回erase OK
-
写完后,又会再读出来,可以看到我们写进去是0,那读出来也是0
-
然后又往这256个字节里面写,不过这回写的是0XFF
-
然后再读,0XFF对应十进制就是255。
-
检查打印,看是否都写成功,然后读出来是否是前面一次是0,后面这次是255。如果符合预期,说明咱的eeprom驱动写得没问题了。
2、基础操作字节实验
步骤:
- 在指定地址写入特定值
- 立即读取验证
- 断电重启再次读取验证持久性
在MSH中敲出命令行,使用basic_test ,第一个参数写地址,第二个参数写数据
可以看到有返回,当然我们写进去的地址跟数据使用的是十进制,返回的使用的是十六进制,所以看起来不一样,自己换算一下可以发现是一样的。
我们再用read_test去读这个23地址,我们刚刚就在这个23地址中写入了66
可以发现读出来的是66
进行一次重启(即掉电),可以发现读出来的还是66,说明eeprom是起作用的
3、多字节读写
新增这两个函数,这两个函数可以进行多字节读写
int16_t eeprom_write_params(uint8_t *buf, int16_t start_index, int16_t buf_len)
{static int write_count = 0;rt_kprintf("[EEPROM] write count : %d, write len : %d\n", ++write_count, buf_len);if (start_index + buf_len >= EEPROM_SIZE){rt_kprintf("EEPROM write params assert\n");return RT_ERROR;}// Write data to EEPROMfor (int16_t i = 0; i < buf_len; i++){if (eeprom_write_byte(start_index + i, buf[i]) != RT_EOK){rt_kprintf("EEPROM write error at address %d\n", start_index + i);return RT_ERROR;}}// Verify the written datauint8_t tmp_mem[buf_len];for (int16_t i = 0; i < buf_len; i++){tmp_mem[i] = eeprom_read_byte(start_index + i);if (tmp_mem[i] != buf[i]){rt_kprintf("EEPROM write verify failed at address %d\n", start_index + i);return RT_ERROR;}else{rt_kprintf("EEPROM write verify success at address %d\n", start_index + i);}}return RT_EOK;
}//eeprom read
int16_t eeprom_read_params(uint8_t *buf, int16_t start_index, int16_t buf_len)
{if (start_index + buf_len >= EEPROM_SIZE || buf == RT_NULL){rt_kprintf("EEPROM read params assert\n");return RT_ERROR;}// Read data from EEPROMfor (int16_t i = 0; i < buf_len; i++){buf[i] = eeprom_read_byte(start_index + i);}return RT_EOK;
}
再新加这个测试函数,用于验证
void eeprom_tes2(void)
{uint8_t write_buf[TEST_DATA_SIZE] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};uint8_t read_buf[TEST_DATA_SIZE] = {0};int16_t start_index = 0;// 初始化 EEPROMif (eeprom_init() != RT_EOK){rt_kprintf("EEPROM initialization failed\n");return;}// 向 EEPROM 写入数据if (eeprom_write_params(write_buf, start_index, TEST_DATA_SIZE) != RT_EOK){rt_kprintf("EEPROM write params failed\n");return;}rt_thread_mdelay(100); // 适当延时,确保写入完成// 从 EEPROM 读取数据if (eeprom_read_params(read_buf, start_index, TEST_DATA_SIZE) != RT_EOK){rt_kprintf("EEPROM read params failed\n");return;}// 验证写入和读取的数据是否一致for (int16_t i = 0; i < TEST_DATA_SIZE; i++){if (write_buf[i] != read_buf[i]){rt_kprintf("Data verification failed at index %d: write %d, read %d\n", i, write_buf[i], read_buf[i]);return;}}rt_kprintf("EEPROM read and write test passed\n");
}MSH_CMD_EXPORT(eeprom_tes2, EEPROM read and write test);
验证结果