--- ## `main/main.c` ```c #include #include "esp_log.h" #include "driver/i2c.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" // For mutex static const char *TAG = "I2C_SHARED_BUS"; // --- I2C Configuration --- #define I2C_MASTER_SCL_IO GPIO_NUM_22 /*!< GPIO number for I2C master clock */ #define I2C_MASTER_SDA_IO GPIO_NUM_21 /*!< GPIO number for I2C master data */ #define I2C_MASTER_NUM I2C_NUM_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 tx buffer size */ #define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master rx buffer size */ #define I2C_MASTER_TIMEOUT_MS 1000 /*!< I2C master timeout in ms */ // --- Sensor Addresses (Replace with your actual sensor addresses) --- #define SENSOR_A_SLAVE_ADDR 0x68 // Example address for Sensor A #define SENSOR_B_SLAVE_ADDR 0x76 // Example address for Sensor B // --- FreeRTOS Mutex for I2C Bus --- SemaphoreHandle_t xI2CMutex; /** * @brief Initialize the I2C master bus. */ 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, .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, }; 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); } /** * @brief Generic function to read data from an I2C sensor. * This function acquires and releases the I2C mutex. * @param slave_addr I2C slave address of the sensor. * @param reg_addr Register address to read from. * @param data Buffer to store the read data. * @param len Length of data to read. * @return ESP_OK on success, otherwise an error code. */ esp_err_t i2c_sensor_read(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, size_t len) { esp_err_t ret = ESP_FAIL; if (xSemaphoreTake(xI2CMutex, portMAX_DELAY) == pdTRUE) { i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, (slave_addr << 1) | I2C_MASTER_WRITE, true); i2c_master_write_byte(cmd, reg_addr, true); i2c_master_start(cmd); // Repeated start for reading i2c_master_write_byte(cmd, (slave_addr << 1) | I2C_MASTER_READ, true); if (len > 1) { i2c_master_read(cmd, data, len - 1, I2C_MASTER_ACK); } i2c_master_read_byte(cmd, data + len - 1, I2C_MASTER_NACK); i2c_master_stop(cmd); ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); xSemaphoreGive(xI2CMutex); } else { ESP_LOGE(TAG, "Failed to acquire I2C mutex for read from 0x%02X", slave_addr); } return ret; } /** * @brief Generic function to write data to an I2C sensor. * This function acquires and releases the I2C mutex. * @param slave_addr I2C slave address of the sensor. * @param reg_addr Register address to write to. * @param data Data to write. * @param len Length of data to write. * @return ESP_OK on success, otherwise an error code. */ esp_err_t i2c_sensor_write(uint8_t slave_addr, uint8_t reg_addr, const uint8_t *data, size_t len) { esp_err_t ret = ESP_FAIL; if (xSemaphoreTake(xI2CMutex, portMAX_DELAY) == pdTRUE) { i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, (slave_addr << 1) | I2C_MASTER_WRITE, true); i2c_master_write_byte(cmd, reg_addr, true); i2c_master_write(cmd, (uint8_t *)data, len, true); i2c_master_stop(cmd); ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); xSemaphoreGive(xI2CMutex); } else { ESP_LOGE(TAG, "Failed to acquire I2C mutex for write to 0x%02X", slave_addr); } return ret; } /** * @brief Task for Sensor A. */ void sensor_a_task(void *pvParameters) { uint8_t sensor_a_data[2]; // Example: reading 2 bytes uint8_t sensor_a_reg = 0x00; // Example register while (1) { ESP_LOGI(TAG, "Sensor A: Attempting to read data..."); esp_err_t ret = i2c_sensor_read(SENSOR_A_SLAVE_ADDR, sensor_a_reg, sensor_a_data, sizeof(sensor_a_data)); if (ret == ESP_OK) { ESP_LOGI(TAG, "Sensor A: Read successful. Data: 0x%02X 0x%02X", sensor_a_data[0], sensor_a_data[1]); } else { ESP_LOGE(TAG, "Sensor A: Read failed (0x%X)", ret); } vTaskDelay(pdMS_TO_TICKS(2000)); // Read every 2 seconds } } /** * @brief Task for Sensor B. */ void sensor_b_task(void *pvParameters) { uint8_t sensor_b_data[4]; // Example: reading 4 bytes uint8_t sensor_b_reg = 0x10; // Example register uint8_t write_data = 0x55; // Example data to write while (1) { // Example: Write to Sensor B ESP_LOGI(TAG, "Sensor B: Attempting to write data..."); esp_err_t ret_write = i2c_sensor_write(SENSOR_B_SLAVE_ADDR, sensor_b_reg, &write_data, 1); if (ret_write == ESP_OK) { ESP_LOGI(TAG, "Sensor B: Write successful."); } else { ESP_LOGE(TAG, "Sensor B: Write failed (0x%X)", ret_write); } vTaskDelay(pdMS_TO_TICKS(500)); // Small delay between write and read // Example: Read from Sensor B ESP_LOGI(TAG, "Sensor B: Attempting to read data..."); esp_err_t ret_read = i2c_sensor_read(SENSOR_B_SLAVE_ADDR, sensor_b_reg, sensor_b_data, sizeof(sensor_b_data)); if (ret_read == ESP_OK) { ESP_LOGI(TAG, "Sensor B: Read successful. Data: 0x%02X 0x%02X 0x%02X 0x%02X", sensor_b_data[0], sensor_b_data[1], sensor_b_data[2], sensor_b_data[3]); } else { ESP_LOGE(TAG, "Sensor B: Read failed (0x%X)", ret_read); } vTaskDelay(pdMS_TO_TICKS(3000)); // Read/Write every 3 seconds } } void app_main(void) { ESP_LOGI(TAG, "Initializing I2C master"); ESP_ERROR_CHECK(i2c_master_init()); ESP_LOGI(TAG, "I2C master initialized successfully"); // Create the I2C mutex xI2CMutex = xSemaphoreCreateMutex(); if (xI2CMutex == NULL) { ESP_LOGE(TAG, "Failed to create I2C mutex"); return; } // Create tasks for each sensor xTaskCreate(&sensor_a_task, "sensor_a_task", 4096, NULL, 5, NULL); xTaskCreate(&sensor_b_task, "sensor_b_task", 4096, NULL, 5, NULL); }