基于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);
驗證結果