- 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;// 初始化iicint 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的地址处写入数据0xAAESP_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