diff --git a/examples/peripherals/i2c/i2c_eeprom/components/i2c_eeprom/i2c_eeprom.c b/examples/peripherals/i2c/i2c_eeprom/components/i2c_eeprom/i2c_eeprom.c index a57f9ec15a..e69614e501 100644 --- a/examples/peripherals/i2c/i2c_eeprom/components/i2c_eeprom/i2c_eeprom.c +++ b/examples/peripherals/i2c/i2c_eeprom/components/i2c_eeprom/i2c_eeprom.c @@ -1,11 +1,12 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ #include #include +#include #include "sdkconfig.h" #include "esp_types.h" #include "esp_log.h" @@ -16,11 +17,22 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#define I2C_EEPROM_MAX_TRANS_UNIT (48) +/* Smallest EEPROMs have a page size of 8 bytes */ +#define I2C_EEPROM_MINIMUM_PAGE_SIZE (8) +/* Biggest EEPROMs have a page size of 256 bytes (24CM01/24CM02) */ +#define I2C_EEPROM_MAX_PAGE_SIZE (256) // Different EEPROM device might share one I2C bus static const char TAG[] = "i2c-eeprom"; +struct i2c_eeprom_t { + i2c_master_dev_handle_t i2c_dev; /*!< I2C device handle */ + uint8_t addr_wordlen; /*!< block address wordlen */ + uint8_t page_size; /*!< eeprom page size */ + uint8_t *buffer; /*!< I2C transaction buffer */ + uint8_t write_time_ms; /*!< I2C eeprom write time(ms)*/ +}; + 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; @@ -37,11 +49,15 @@ esp_err_t i2c_eeprom_init(i2c_master_bus_handle_t bus_handle, const i2c_eeprom_c 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->buffer = (uint8_t*)calloc(1, eeprom_config->addr_wordlen + I2C_EEPROM_MAX_PAGE_SIZE); ESP_GOTO_ON_FALSE(out_handle->buffer, ESP_ERR_NO_MEM, err, TAG, "no memory for i2c eeprom device buffer"); out_handle->addr_wordlen = eeprom_config->addr_wordlen; out_handle->write_time_ms = eeprom_config->write_time_ms; + + /* Page size cannot exceed the maximum since it is encoded on 8-bit */ + out_handle->page_size = MAX(eeprom_config->page_size, I2C_EEPROM_MINIMUM_PAGE_SIZE); + *eeprom_handle = out_handle; return ESP_OK; @@ -54,23 +70,44 @@ err: return ret; } -esp_err_t i2c_eeprom_write(i2c_eeprom_handle_t eeprom_handle, uint32_t address, const uint8_t *data, uint32_t size) +static void i2c_eeprom_prepare_address(i2c_eeprom_handle_t eeprom_handle, uint32_t address) { - ESP_RETURN_ON_FALSE(eeprom_handle, ESP_ERR_NO_MEM, TAG, "no mem for buffer"); 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); +} - return i2c_master_transmit(eeprom_handle->i2c_dev, eeprom_handle->buffer, eeprom_handle->addr_wordlen + size, -1); +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"); + + /* We cannot write more than page size at once, so we have to write in chunks */ + uint8_t *chunk_data = eeprom_handle->buffer + eeprom_handle->addr_wordlen; + esp_err_t err = ESP_OK; + while (size > 0) { + uint32_t chunk_size = MIN(size, eeprom_handle->page_size); + i2c_eeprom_prepare_address(eeprom_handle, address); + memcpy(chunk_data, data, chunk_size); + err = i2c_master_transmit(eeprom_handle->i2c_dev, eeprom_handle->buffer, eeprom_handle->addr_wordlen + chunk_size, -1); + if (err != ESP_OK) { + break; + } + size -= chunk_size; + address += chunk_size; + data += chunk_size; + /* Do not wait for completion for the last chunk (let the caller do it) */ + if (size > 0) { + i2c_eeprom_wait_idle(eeprom_handle); + } + } + + return err; } 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"); - 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); - } + i2c_eeprom_prepare_address(eeprom_handle, address); return i2c_master_transmit_receive(eeprom_handle->i2c_dev, eeprom_handle->buffer, eeprom_handle->addr_wordlen, data, size, -1); } diff --git a/examples/peripherals/i2c/i2c_eeprom/components/i2c_eeprom/i2c_eeprom.h b/examples/peripherals/i2c/i2c_eeprom/components/i2c_eeprom/i2c_eeprom.h index 0dc4597e16..15db5ada5c 100644 --- a/examples/peripherals/i2c/i2c_eeprom/components/i2c_eeprom/i2c_eeprom.h +++ b/examples/peripherals/i2c/i2c_eeprom/components/i2c_eeprom/i2c_eeprom.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -13,20 +13,13 @@ extern "C" { typedef struct { i2c_device_config_t eeprom_device; /*!< Configuration for eeprom device */ + uint8_t page_size; /*!< eeprom page size */ 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_t; typedef struct i2c_eeprom_t *i2c_eeprom_handle_t; /**