- AT24C32或AT24C64两款芯片容量不一样,其他都一样。程序无法动态识别容量
- AT24C32容量32K,地址范围0x~0x7FFF.
- AT24C64容量64K,地址范围0x~0xFFFF
电气参数
-
电压2.7V-5.5V
-
IIC通信
-
有引脚控制数据保护
-
有引脚可以配置IIC的地址。
-
每个page 32字节
-
1百万次写入
-
100年存放
-
容量有两个型号AT24C32/64 提供32,768/65,536 bits ,也就是4096字节(4k字节)或8192字节(8K字节)
-
使用16bit来确定存储的地址
-
设备地址,如果引脚A0~A2都接地,则IIC地址为0x50.
操作步骤
写入
分为两种
- 按字节写入
- 按page写入,一次最多写入32字节
读取
分为3种
- 当前地址读取
- 随机地址读取
- 连续读取,连续读取可以一直读
EEPROM和flash有个最大的区别:
EEPROM在写入前不需要擦除page,直接写入就行
Flash 在写入前,需要擦除,且擦除是按照page进行的。比如spi flash。
时序
写入时序
按1个字节写入时序
按page写入时序
读取时序
在当前位置读取时序
随机读取时序
顺序读取时序
附上完整代码
AT24CXX_driver.c
#include <stdio.h>
#include "esp_log.h"
#include "AT24CXX_driver.h"
#include "driver/i2c.h"
#include <string.h>
static const char *TAG = "AT24CXX-driver";
#define I2C_MASTER_SCL_IO CONFIG_I2C_MASTER_SCL /*!< GPIO number used for I2C master clock */
#define I2C_MASTER_SDA_IO CONFIG_I2C_MASTER_SDA /*!< GPIO number used for I2C master data */
#define I2C_MASTER_NUM 0 /*!< I2C master i2c port number, the number of i2c peripheral interfaces available will depend on the chip */
#define I2C_MASTER_FREQ_HZ 100000 /*!< I2C master clock frequency */
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
#define I2C_MASTER_TIMEOUT_MS 1000
#define AT24CXX_I2C_ADDR 0x50 /*!< Slave address of the MPU9250 sensor */
esp_err_t at24cxx_init(void)
{
int ret;
// 初始化iic
int i2c_master_port = I2C_MASTER_NUM;
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = I2C_MASTER_SDA_IO,
.scl_io_num = I2C_MASTER_SCL_IO,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = I2C_MASTER_FREQ_HZ,
};
i2c_param_config(i2c_master_port, &conf);
ret = i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
ESP_LOGI(TAG, "I2C initialized successfully");
return ret;
}
/**
* 读取当前位置的数据
*/
esp_err_t at24cxx_read_current(uint8_t *data, uint32_t len)
{
int ret;
// 开始读取数据
ret = i2c_master_read_from_device(I2C_MASTER_NUM, AT24CXX_I2C_ADDR, data, len, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
ESP_LOGI(TAG, "READ current DATA:");
for (uint32_t i = 0; i < len; i++)
{
printf("%x ", data[i]);
}
return ret;
}
/**
* 随机读取一个字节
*
*/
esp_err_t at24cxx_random_read_byte(uint16_t address, uint8_t *data)
{
int ret;
uint8_t write_buf[2] = {address >> 8, address & 0xff};
// 开始读取数据
ret = i2c_master_write_read_device(I2C_MASTER_NUM, AT24CXX_I2C_ADDR, write_buf, 2,
data, 1, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
ESP_LOGI(TAG, "at24cxx_random_read_byte:%x", *data);
return ret;
}
/**
* 随机读取一个字节
*
*/
esp_err_t at24cxx_random_read(uint16_t address, uint8_t *data, uint32_t len)
{
int ret;
if (len == 0)
{
return 0;
}
// 开始读取数据
at24cxx_random_read_byte(address, data);
vTaskDelay(30 / portTICK_PERIOD_MS);
if (len > 1)
{
at24cxx_read_current(data + 1, len - 1);
}
ESP_LOGI(TAG, "random READ DATA:");
for (uint32_t i = 0; i < len; i++)
{
printf("%x ", data[i]);
}
return ret;
}
void at24cxx_dump(void)
{
uint8_t data[4096], write_buf[2] = {0, 0};
// 开始读取数据
i2c_master_write_read_device(I2C_MASTER_NUM, AT24CXX_I2C_ADDR, write_buf, 2,
data, 4096, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
ESP_LOGI(TAG, "READ DATA:");
printf(" ");
for (uint8_t i = 0; i < 16; i++)
{
printf("%2x ", i);
}
printf("\r\n00 ");
for (uint32_t i = 0; i < 4096; i++)
{
printf("%2x ", data[i]);
if (((i + 1) % 16 == 0) && (i != 0))
{
printf("\r\n%2lx ", i / 16);
}
}
}
/**
* @brief 按字节写入
*/
esp_err_t at24cxx_write_byte(uint16_t address, uint8_t data)
{
int ret = 0;
uint8_t write_buf[3] = {address >> 8, address & 0xFF, data};
ret = i2c_master_write_to_device(I2C_MASTER_NUM, AT24CXX_I2C_ADDR, write_buf, 3, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
return ret;
}
/**
* @brief 按字节写入
* @param page_index 第几个page
*/
esp_err_t at24cxx_write_page(uint16_t page_index, at24c_page pg)
{
int ret = 0;
// 算出page对应的地址
uint16_t address = page_index * 32;
uint8_t write_buf[2 + 32] = {address >> 8, address & 0xFF};
memcpy(write_buf + 2, &pg, 32);
ret = i2c_master_write_to_device(I2C_MASTER_NUM, AT24CXX_I2C_ADDR, write_buf, 2 + 32, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
return ret;
}
AT24CXX_driver.h
#ifndef __DS1307_H_
#define __DS1307_H_
#include "driver/i2c.h"
typedef struct
{
union
{
uint8_t value[32];
uint32_t value_32[32 / 4];
};
} at24c_page; // 秒
esp_err_t at24cxx_init(void);
esp_err_t at24cxx_write_byte(uint16_t address, uint8_t data);
esp_err_t at24cxx_write_page(uint16_t page_index, at24c_page pg);
esp_err_t at24cxx_read_current(uint8_t *data, uint32_t len);
esp_err_t at24cxx_random_read_byte(uint16_t address, uint8_t *data);
esp_err_t at24cxx_random_read(uint16_t address, uint8_t *data, uint32_t len);
void at24cxx_dump(void);
#endif
AT24CXX_main.c
#include <stdio.h>
#include "esp_log.h"
#include "AT24CXX_driver.h"
static const char *TAG = "AT24CXX_main";
void app_main(void)
{
at24c_page pg;
uint8_t eeprom_data[10], *p = (uint8_t *)&pg;
ESP_ERROR_CHECK(at24cxx_init());
/* Read the MPU9250 WHO_AM_I register, on power up the register should have the value 0x71 */
for (uint8_t i = 0; i < 32; i++)
{
p[i] = i;
}
ESP_LOGI(TAG, "test at24cxx_write_byte");
at24cxx_write_byte(9,0xAA);//在下标9的地址处写入数据0xAA
ESP_LOGI(TAG, "test at24cxx_write_page");
at24cxx_write_page(1, pg);
vTaskDelay(300 / portTICK_PERIOD_MS);
//这个函数可能会造成爆栈,主要是里面有个很大的数组。实际代码要优化这个位置,比如边读变输出,或使用动态内存
// at24cxx_dump();
ESP_LOGI(TAG, "test at24cxx_read_current");
ESP_ERROR_CHECK(at24cxx_read_current(eeprom_data, 10));
ESP_LOGI(TAG, "test at24cxx_random_read");
ESP_ERROR_CHECK(at24cxx_random_read(1,eeprom_data,5));
ESP_LOGI(TAG, "test finish");
}
i2cget -c 0x50 -r 0 -l 10