feat(i2c_eeprom): Add new example for I2C eeprom with new API

This commit is contained in:
Cao Sen Miao 2023-08-03 12:32:18 +08:00
parent b6cbeeae01
commit d9d1c87e56
8 changed files with 320 additions and 0 deletions

View File

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(i2c_eeprom)

View File

@ -0,0 +1,54 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |
# I2C EEPROM example
This code demonstrates how to use the I2C master mode to read/write I2C EEPROM.
## Overview
This example demonstrates basic usage of I2C driver by reading and writing from a I2C connected eeprom:
If you have a new I2C application to go (for example, read the temperature data from external sensor with I2C interface), try this as a basic template, then add your own code.
## How to use example
### Hardware Required
To run this example, you should have one ESP32, ESP32-S, ESP32-C or ESP32-H based development board as well as EEPROM(s). I2C bus allow use several EEPROMs, and some of the EEPROMs' address are configurable. Some are not, for which you can use 74LS138 to set different EEPROM different slave address(It is also can be used on other types of I2C slaves).
For some I2C EEPROM slaves, they have A0, A1, A2 pins for address configuration.
For some I2C slaves, They don't have address configuration pins but have enable pins. For these kind of slave, you can use GPIO pins and external decoder to select which slave you are using.
#### Pin Assignment:
**Note:** The following pin assignments are used by default, you can change these in the `menuconfig` .
| | SDA | SCL |
| ---------------- | -------------- | -------------- |
| ESP I2C Master | I2C_MASTER_SDA | I2C_MASTER_SCL |
| EEPROM1 | SDA | SCL |
| EEPROMn | SDA | SCL |
For the actual default value of `I2C_MASTER_SDA` and `I2C_MASTER_SCL` see `Example Configuration` in `menuconfig`.
**Note:** There's no need to add an external pull-up resistors for SDA/SCL pin, because the driver will enable the internal pull-up resistors.
### Build and Flash
Enter `idf.py -p PORT flash monitor` to build, flash and monitor the project.
(To exit the serial monitor, type ``Ctrl-]``.)
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
## Example Output
```bash
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
10 11 12 13 14 15 16 17 18
```
## Troubleshooting
(For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.)

View File

@ -0,0 +1,3 @@
idf_component_register(SRCS "i2c_eeprom.c"
INCLUDE_DIRS "."
PRIV_REQUIRES driver)

View File

@ -0,0 +1,87 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <string.h>
#include <stdio.h>
#include "sdkconfig.h"
#include "esp_types.h"
#include "esp_log.h"
#include "esp_check.h"
#include "driver/i2c_master.h"
#include "i2c_eeprom.h"
#include "esp_check.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#define I2C_EEPROM_MAX_TRANS_UNIT (48)
// Different EEPROM device might share one I2C bus
static const char TAG[] = "i2c-eeprom";
esp_err_t i2c_eeprom_init(i2c_master_bus_handle_t bus_handle, const i2c_eeprom_config_t *eeprom_config, i2c_eeprom_handle_t *eeprom_handle)
{
esp_err_t ret = ESP_OK;
i2c_eeprom_handle_t out_handle;
out_handle = (i2c_eeprom_handle_t)calloc(1, sizeof(i2c_eeprom_handle_t));
ESP_GOTO_ON_FALSE(out_handle, ESP_ERR_NO_MEM, err, TAG, "no memory for i2c eeprom device");
i2c_device_config_t i2c_dev_conf = {
.scl_speed_hz = eeprom_config->eeprom_device.scl_speed_hz,
.device_address = eeprom_config->eeprom_device.device_address,
};
if (out_handle->i2c_dev == NULL) {
ESP_GOTO_ON_ERROR(i2c_master_bus_add_device(bus_handle, &i2c_dev_conf, &out_handle->i2c_dev), err, TAG, "i2c new bus failed");
}
out_handle->buffer = (uint8_t*)calloc(1, eeprom_config->addr_wordlen + I2C_EEPROM_MAX_TRANS_UNIT);
out_handle->addr_wordlen = eeprom_config->addr_wordlen;
out_handle->write_time_ms = eeprom_config->write_time_ms;
*eeprom_handle = out_handle;
return ESP_OK;
err:
if (out_handle) {
free(out_handle);
}
if (out_handle->i2c_dev) {
i2c_master_bus_rm_device(out_handle->i2c_dev);
}
return ret;
}
esp_err_t i2c_eeprom_write(i2c_eeprom_handle_t eeprom_handle, uint32_t address, const uint8_t *data, uint32_t size)
{
ESP_RETURN_ON_FALSE(eeprom_handle, ESP_ERR_NO_MEM, TAG, "no mem for buffer");
esp_err_t ret = ESP_OK;
for (int i = 0; i < eeprom_handle->addr_wordlen; i++) {
eeprom_handle->buffer[i] = (address & (0xff << ((eeprom_handle->addr_wordlen - 1 - i) * 8))) >> ((eeprom_handle->addr_wordlen - 1 - i) * 8);
}
memcpy(eeprom_handle->buffer + eeprom_handle->addr_wordlen, data, size);
ret = i2c_master_transmit(eeprom_handle->i2c_dev, eeprom_handle->buffer, eeprom_handle->addr_wordlen + size, -1);
return ret;
}
esp_err_t i2c_eeprom_read(i2c_eeprom_handle_t eeprom_handle, uint32_t address, uint8_t *data, uint32_t size)
{
ESP_RETURN_ON_FALSE(eeprom_handle, ESP_ERR_NO_MEM, TAG, "no mem for buffer");
esp_err_t ret = ESP_OK;
for (int i = 0; i < eeprom_handle->addr_wordlen; i++) {
eeprom_handle->buffer[i] = (address & (0xff << ((eeprom_handle->addr_wordlen - 1 - i) * 8))) >> ((eeprom_handle->addr_wordlen - 1 - i) * 8);
}
ret = i2c_master_transmit_receive(eeprom_handle->i2c_dev, eeprom_handle->buffer, eeprom_handle->addr_wordlen, data, size, -1);
return ret;
}
void i2c_eeprom_wait_idle(i2c_eeprom_handle_t eeprom_handle)
{
// This is time for EEPROM Self-Timed Write Cycle
vTaskDelay(pdMS_TO_TICKS(eeprom_handle->write_time_ms));
}

View File

@ -0,0 +1,73 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdint.h>
#include "driver/i2c_master.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
i2c_device_config_t eeprom_device; /*!< Configuration for eeprom device */
uint8_t addr_wordlen; /*!< block address wordlen */
uint8_t write_time_ms; /*!< eeprom write time, typically 10ms*/
} i2c_eeprom_config_t;
struct i2c_eeprom_t {
i2c_master_dev_handle_t i2c_dev; /*!< I2C device handle */
uint8_t addr_wordlen; /*!< block address wordlen */
uint8_t *buffer; /*!< I2C transaction buffer */
uint8_t write_time_ms; /*!< I2C eeprom write time(ms)*/
};
typedef struct i2c_eeprom_t i2c_eeprom_t;
/* handle of EEPROM device */
typedef struct i2c_eeprom_t *i2c_eeprom_handle_t;
/**
* @brief Init an EEPROM device.
*
* @param[in] bus_handle I2C master bus handle
* @param[in] eeprom_config Configuration of EEPROM
* @param[out] eeprom_handle Handle of EEPROM
* @return ESP_OK: Init success. ESP_FAIL: Not success.
*/
esp_err_t i2c_eeprom_init(i2c_master_bus_handle_t bus_handle, const i2c_eeprom_config_t *eeprom_config, i2c_eeprom_handle_t *eeprom_handle);
/**
* @brief Write data to EEPROM
*
* @param[in] eeprom_handle EEPROM handle
* @param[in] address Block address inside EEPROM
* @param[in] data Data to write
* @param[in] size Data write size
* @return ESP_OK: Write success. Otherwise failed, please check I2C function fail reason.
*/
esp_err_t i2c_eeprom_write(i2c_eeprom_handle_t eeprom_handle, uint32_t address, const uint8_t *data, uint32_t size);
/**
* @brief Read data from EEPROM
*
* @param eeprom_handle EEPROM handle
* @param address Block address inside EEPROM
* @param data Data read from EEPROM
* @param size Data read size
* @return ESP_OK: Read success. Otherwise failed, please check I2C function fail reason.
*/
esp_err_t i2c_eeprom_read(i2c_eeprom_handle_t eeprom_handle, uint32_t address, uint8_t *data, uint32_t size);
/**
* @brief Wait eeprom finish. Typically 5ms
*
* @param eeprom_handle EEPROM handle
*/
void i2c_eeprom_wait_idle(i2c_eeprom_handle_t eeprom_handle);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,4 @@
set(srcs "i2c_eeprom_main.c")
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS ".")

View File

@ -0,0 +1,23 @@
menu "Example Configuration"
menu "I2C Master"
config I2C_MASTER_SCL
int "SCL GPIO Num"
default 4
help
GPIO number for I2C Master clock line.
config I2C_MASTER_SDA
int "SDA GPIO Num"
default 5
help
GPIO number for I2C Master data line.
config I2C_MASTER_FREQUENCY
int "Master Frequency"
default 400000
help
I2C Speed of Master device.
endmenu
endmenu

View File

@ -0,0 +1,70 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <string.h>
#include <stdio.h>
#include "sdkconfig.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2c_master.h"
#include "i2c_eeprom.h"
#define SCL_IO_PIN CONFIG_I2C_MASTER_SCL
#define SDA_IO_PIN CONFIG_I2C_MASTER_SDA
#define MASTER_FREQUENCY CONFIG_I2C_MASTER_FREQUENCY
#define PORT_NUMBER -1
#define LENGTH 48
static void disp_buf(uint8_t *buf, int len)
{
int i;
for (i = 0; i < len; i++) {
printf("%02x ", buf[i]);
if (( i + 1 ) % 16 == 0) {
printf("\n");
}
}
printf("\n");
}
void app_main(void)
{
i2c_master_bus_config_t i2c_bus_config = {
.clk_source = I2C_CLK_SRC_DEFAULT,
.i2c_port = PORT_NUMBER,
.scl_io_num = SCL_IO_PIN,
.sda_io_num = SDA_IO_PIN,
};
i2c_master_bus_handle_t bus_handle;
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_config, &bus_handle));
i2c_eeprom_config_t eeprom_config = {
.eeprom_device.scl_speed_hz = MASTER_FREQUENCY,
.eeprom_device.device_address = 0x50,
.addr_wordlen = 2,
.write_time_ms = 10,
};
i2c_eeprom_handle_t eeprom_handle;
uint32_t block_addr = 0x0010;
uint8_t buf[LENGTH];
for (int i = 0; i < LENGTH; i++) {
buf[i] = i;
}
uint8_t read_buf[LENGTH];
ESP_ERROR_CHECK(i2c_eeprom_init(bus_handle, &eeprom_config, &eeprom_handle));
while(1) {
ESP_ERROR_CHECK(i2c_eeprom_write(eeprom_handle, block_addr, buf, LENGTH));
// Needs wait for eeprom hardware done, referring from datasheet
i2c_eeprom_wait_idle(eeprom_handle);
ESP_ERROR_CHECK(i2c_eeprom_read(eeprom_handle, block_addr, read_buf, LENGTH));
disp_buf(read_buf, LENGTH);
vTaskDelay(50);
}
}