Help with I2C communication between 2 ESP32
Posted: Sun Jan 08, 2023 1:59 pm
Hello,
My project is to measure water level of tanks. As I'm using more than 3 UARTs I want to use 2 ESP32s.
Slave ESP32: Get data from the water level sensor and send it to the Master ESP32 using I2C.
Master ESP32: Collect that data and pass it on to NodeRED for processing and Visualisation.
My issue: I'm not able to get I2C communication working between ESP32s.
My basic code is here:
Slave Code:
Master Code:
My project is to measure water level of tanks. As I'm using more than 3 UARTs I want to use 2 ESP32s.
Slave ESP32: Get data from the water level sensor and send it to the Master ESP32 using I2C.
Master ESP32: Collect that data and pass it on to NodeRED for processing and Visualisation.
My issue: I'm not able to get I2C communication working between ESP32s.
My basic code is here:
Slave Code:
Code: Select all
#include <stdio.h>
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2c.h"
#include "driver/gpio.h"
static const char *TAG = "i2c-slave";
#define _I2C_NUMBER(num) I2C_NUM_##num
#define I2C_NUMBER(num) _I2C_NUMBER(num)
#define DATA_LENGTH 512 /*!< Data buffer length of test buffer */
#define RW_TEST_LENGTH 128 /*!< Data length for r/w test, [0,DATA_LENGTH] */
#define DELAY_TIME_BETWEEN_ITEMS_MS 1000 /*!< delay time between different test items */
#define I2C_SLAVE_SCL_IO 14 /*!< gpio number for i2c slave clock */
#define I2C_SLAVE_SDA_IO 12 /*!< gpio number for i2c slave data */
#define I2C_SLAVE_NUM I2C_NUMBER(0) /*!< I2C port number for slave dev */
#define I2C_SLAVE_TX_BUF_LEN (2 * DATA_LENGTH) /*!< I2C slave tx buffer size */
#define I2C_SLAVE_RX_BUF_LEN (2 * DATA_LENGTH) /*!< I2C slave rx buffer size */
#define I2C_SLAVE_ADDR 0x45 /*!< I2C slave address */
typedef struct tankData
{
int tankID;
int waterLevel;
} tankData;
tankData tankOne;
/**
* @brief i2c slave initialization
*/
static esp_err_t i2c_slave_init(void)
{
int i2c_slave_port = I2C_SLAVE_NUM;
i2c_config_t conf_slave = {
.sda_io_num = I2C_SLAVE_SDA_IO,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_io_num = I2C_SLAVE_SCL_IO,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.mode = I2C_MODE_SLAVE,
.slave.addr_10bit_en = 0,
.slave.slave_addr = I2C_SLAVE_ADDR,
.slave.maximum_speed = 100000,
};
esp_err_t err = i2c_param_config(i2c_slave_port, &conf_slave);
if (err != ESP_OK)
{
return err;
}
return i2c_driver_install(i2c_slave_port, conf_slave.mode, I2C_SLAVE_RX_BUF_LEN, I2C_SLAVE_TX_BUF_LEN, 0);
}
void app_main(void)
{
int counter = 0;
int i2c_data = 0;
ESP_ERROR_CHECK_WITHOUT_ABORT(i2c_slave_init());
while (true)
{
tankOne.tankID = counter++;
tankOne.waterLevel = (counter % 100);
ESP_LOGI(TAG, "Tank ID: %d | Water Level: %d", tankOne.tankID, tankOne.waterLevel);
i2c_data = i2c_slave_write_buffer(I2C_SLAVE_NUM, (uint8_t *)&tankOne, sizeof(tankOne), (1000 / portTICK_RATE_MS));
if (i2c_data != ESP_FAIL)
{
ESP_LOGI(TAG, "I2C Data Length: %d Bytes", i2c_data);
}
else
{
ESP_LOGE(TAG, "Failed to generate data");
}
vTaskDelay(10000 / portTICK_RATE_MS);
}
}
Code: Select all
#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2c.h"
static const char *TAG = "i2c-master";
#define _I2C_NUMBER(num) I2C_NUM_##num
#define I2C_NUMBER(num) _I2C_NUMBER(num)
#define DATA_LENGTH 512 /*!< Data buffer length of test buffer */
#define RW_TEST_LENGTH 128 /*!< Data length for r/w test, [0,DATA_LENGTH] */
#define DELAY_TIME_BETWEEN_ITEMS_MS 1000 /*!< delay time between different test items */
#define I2C_MASTER_SCL_IO 25 /*!< gpio number for I2C master clock */
#define I2C_MASTER_SDA_IO 27 /*!< gpio number for I2C master data */
#define I2C_MASTER_NUM I2C_NUMBER(0) /*!< I2C port number for master dev */
#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 ESP_SLAVE_ADDR 0x45 /*!< I2C slave address */
#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */
#define READ_BIT I2C_MASTER_READ /*!< I2C master read */
#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */
#define ACK_VAL 0x0 /*!< I2C ack value */
#define NACK_VAL 0x1 /*!< I2C nack value */
typedef struct tankData
{
int tankID;
int waterLevel;
} tankData;
tankData tankOne;
/**
* @brief i2c master initialization
*/
static esp_err_t i2c_master_init(void)
{
int i2c_master_port = I2C_MASTER_NUM;
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = I2C_MASTER_SDA_IO,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_io_num = I2C_MASTER_SCL_IO,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = I2C_MASTER_FREQ_HZ,
};
esp_err_t err = i2c_param_config(i2c_master_port, &conf);
if (err != ESP_OK)
{
return err;
}
return i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
}
static esp_err_t __attribute__((unused)) i2c_master_read_slave(i2c_port_t i2c_num, uint8_t *data_rd, size_t size)
{
if (size == 0) {
return ESP_OK;
}
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (ESP_SLAVE_ADDR << 1) | READ_BIT, ACK_CHECK_EN);
if (size > 1) {
i2c_master_read(cmd, data_rd, size - 1, ACK_VAL);
}
i2c_master_read_byte(cmd, data_rd + size - 1, NACK_VAL);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
return ret;
}
void app_main(void)
{
uint8_t *data = (uint8_t *)malloc(DATA_LENGTH);
esp_err_t i2c_read_err;
ESP_ERROR_CHECK_WITHOUT_ABORT(i2c_master_init());
while (true)
{
// i2c_read_err = i2c_master_read_from_device(I2C_MASTER_NUM, ESP_SLAVE_ADDR, data, sizeof(data), (1000 / portTICK_RATE_MS));
i2c_read_err = i2c_master_read_slave(I2C_NUM_0, data, DATA_LENGTH);
if (i2c_read_err == ESP_OK)
{
memcpy(&tankOne, data, sizeof(tankOne));
ESP_LOGI(TAG, "tankID: %d", tankOne.tankID);
ESP_LOGI(TAG, "waterLevel: %d", tankOne.waterLevel);
}
else
{
ESP_LOGE(TAG, "[%d] I2C Error: %s", i2c_read_err, esp_err_to_name(i2c_read_err));
}
vTaskDelay(10000 / portTICK_RATE_MS);
}
}