基于RT-Thread驱动EEPROM_AD24C02
前言
- 存储容量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 pin
rt_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_ENABLE
rt_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 10
extern 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 1
rt_kprintf("eeprom check data [0x%02X] not equal read data [0x%02X].\n", data, temp);
#endif
return 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 eeprom
for(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 eeprom
for(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 eeprom
for(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 eeprom
for(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]);
}
//free
rt_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 EEPROM
for (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 data
uint8_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 EEPROM
for (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;
// 初始化 EEPROM
if (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);
验证结果