/* i2c - Example For other examples please check: https://github.com/espressif/esp-idf/tree/master/examples This example code is in the Public Domain (or CC0 licensed, at your option.) Unless required by applicable law or agreed to in writing, this software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ #include #include "driver/i2c.h" /** * TEST CODE BRIEF * * This example will show you how to use I2C module by running two tasks on i2c bus: * * - read external i2c sensor, here we use a BH1750 light sensor(GY-30 module) for instance. * - Use one I2C port(master mode) to read or write the other I2C port(slave mode) on one ESP32 chip. * * Pin assignment: * * - slave : * GPIO25 is assigned as the data signal of i2c slave port * GPIO26 is assigned as the clock signal of i2c slave port * - master: * GPIO18 is assigned as the data signal of i2c master port * GPIO19 is assigned as the clock signal of i2c master port * * Connection: * * - connect GPIO18 with GPIO25 * - connect GPIO19 with GPIO26 * - connect sda/scl of sensor with GPIO18/GPIO19 * - no need to add external pull-up resistors, driver will enable internal pull-up resistors. * * Test items: * * - read the sensor data, if connected. * - i2c master(ESP32) will write data to i2c slave(ESP32). * - i2c master(ESP32) will read data from i2c slave(ESP32). */ #define DATA_LENGTH 512 /*! 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; } /** * @brief Test code to write esp-i2c-slave * Master device write data to slave(both esp32), * the data will be stored in slave buffer. * We can read them out from slave buffer. * * ___________________________________________________________________ * | start | slave_addr + wr_bit + ack | write n bytes + ack | stop | * --------|---------------------------|----------------------|------| * */ esp_err_t i2c_master_write_slave(i2c_port_t i2c_num, uint8_t* data_wr, size_t size) { i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, ( ESP_SLAVE_ADDR << 1 ) | WRITE_BIT, ACK_CHECK_EN); i2c_master_write(cmd, data_wr, size, ACK_CHECK_EN); 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; } /** * @brief test code to write esp-i2c-slave * * 1. set mode * _________________________________________________________________ * | start | slave_addr + wr_bit + ack | write 1 byte + ack | stop | * --------|---------------------------|---------------------|------| * 2. wait more than 24 ms * 3. read data * ______________________________________________________________________________________ * | start | slave_addr + rd_bit + ack | read 1 byte + ack | read 1 byte + nack | stop | * --------|---------------------------|--------------------|--------------------|------| */ esp_err_t i2c_master_sensor_test(i2c_port_t i2c_num, uint8_t* data_h, uint8_t* data_l) { i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, BH1750_SENSOR_ADDR << 1 | WRITE_BIT, ACK_CHECK_EN); i2c_master_write_byte(cmd, BH1750_CMD_START, ACK_CHECK_EN); i2c_master_stop(cmd); int ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS); i2c_cmd_link_delete(cmd); if (ret == ESP_FAIL) { return ret; } vTaskDelay(30 / portTICK_RATE_MS); cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, BH1750_SENSOR_ADDR << 1 | READ_BIT, ACK_CHECK_EN); i2c_master_read_byte(cmd, data_h, ACK_VAL); i2c_master_read_byte(cmd, data_l, NACK_VAL); i2c_master_stop(cmd); ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS); i2c_cmd_link_delete(cmd); if (ret == ESP_FAIL) { return ESP_FAIL; } return ESP_OK; } /** * @brief i2c master initialization */ void i2c_master_init() { int i2c_master_port = I2C_MASTER_NUM; i2c_config_t conf; conf.mode = I2C_MODE_MASTER; conf.sda_io_num = I2C_MASTER_SDA_IO; conf.sda_pullup_en = GPIO_PULLUP_ENABLE; conf.scl_io_num = I2C_MASTER_SCL_IO; conf.scl_pullup_en = GPIO_PULLUP_ENABLE; conf.master.clk_speed = I2C_MASTER_FREQ_HZ; i2c_param_config(i2c_master_port, &conf); i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0); } /** * @brief i2c slave initialization */ void i2c_slave_init() { int i2c_slave_port = I2C_SLAVE_NUM; i2c_config_t conf_slave; conf_slave.sda_io_num = I2C_SLAVE_SDA_IO; conf_slave.sda_pullup_en = GPIO_PULLUP_ENABLE; conf_slave.scl_io_num = I2C_SLAVE_SCL_IO; conf_slave.scl_pullup_en = GPIO_PULLUP_ENABLE; conf_slave.mode = I2C_MODE_SLAVE; conf_slave.slave.addr_10bit_en = 0; conf_slave.slave.slave_addr = ESP_SLAVE_ADDR; i2c_param_config(i2c_slave_port, &conf_slave); i2c_driver_install(i2c_slave_port, conf_slave.mode, I2C_SLAVE_RX_BUF_LEN, I2C_SLAVE_TX_BUF_LEN, 0); } /** * @brief test function to show buffer */ 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 i2c_test_task(void* arg) { int i = 0; int ret; uint32_t task_idx = (uint32_t) arg; uint8_t* data = (uint8_t*) malloc(DATA_LENGTH); uint8_t* data_wr = (uint8_t*) malloc(DATA_LENGTH); uint8_t* data_rd = (uint8_t*) malloc(DATA_LENGTH); uint8_t sensor_data_h, sensor_data_l; while (1) { ret = i2c_master_sensor_test( I2C_MASTER_NUM, &sensor_data_h, &sensor_data_l); xSemaphoreTake(print_mux, portMAX_DELAY); printf("*******************\n"); printf("TASK[%d] MASTER READ SENSOR( BH1750 )\n", task_idx); printf("*******************\n"); if (ret == ESP_OK) { printf("data_h: %02x\n", sensor_data_h); printf("data_l: %02x\n", sensor_data_l); printf("sensor val: %f\n", ( sensor_data_h << 8 | sensor_data_l ) / 1.2); } else { printf("No ack, sensor not connected...skip...\n"); } xSemaphoreGive(print_mux); vTaskDelay(( DELAY_TIME_BETWEEN_ITEMS_MS * ( task_idx + 1 ) ) / portTICK_RATE_MS); //--------------------------------------------------- for (i = 0; i < DATA_LENGTH; i++) { data[i] = i; } size_t d_size = i2c_slave_write_buffer(I2C_SLAVE_NUM, data, RW_TEST_LENGTH, 1000 / portTICK_RATE_MS); if (d_size == 0) { printf("i2c slave tx buffer full\n"); ret = i2c_master_read_slave(I2C_MASTER_NUM, data_rd, DATA_LENGTH); } else { ret = i2c_master_read_slave(I2C_MASTER_NUM, data_rd, RW_TEST_LENGTH); } xSemaphoreTake(print_mux, portMAX_DELAY); printf("*******************\n"); printf("TASK[%d] MASTER READ FROM SLAVE\n", task_idx); printf("*******************\n"); printf("====TASK[%d] Slave buffer data ====\n", task_idx); disp_buf(data, d_size); if (ret == ESP_OK) { printf("====TASK[%d] Master read ====\n", task_idx); disp_buf(data_rd, d_size); } else { printf("Master read slave error, IO not connected...\n"); } xSemaphoreGive(print_mux); vTaskDelay(( DELAY_TIME_BETWEEN_ITEMS_MS * ( task_idx + 1 ) ) / portTICK_RATE_MS); //--------------------------------------------------- int size; for (i = 0; i < DATA_LENGTH; i++) { data_wr[i] = i + 10; } //we need to fill the slave buffer so that master can read later ret = i2c_master_write_slave( I2C_MASTER_NUM, data_wr, RW_TEST_LENGTH); if (ret == ESP_OK) { size = i2c_slave_read_buffer( I2C_SLAVE_NUM, data, RW_TEST_LENGTH, 1000 / portTICK_RATE_MS); } xSemaphoreTake(print_mux, portMAX_DELAY); printf("*******************\n"); printf("TASK[%d] MASTER WRITE TO SLAVE\n", task_idx); printf("*******************\n"); printf("----TASK[%d] Master write ----\n", task_idx); disp_buf(data_wr, RW_TEST_LENGTH); if (ret == ESP_OK) { printf("----TASK[%d] Slave read: [%d] bytes ----\n", task_idx, size); disp_buf(data, size); } else { printf("TASK[%d] Master write slave error, IO not connected....\n", task_idx); } xSemaphoreGive(print_mux); vTaskDelay(( DELAY_TIME_BETWEEN_ITEMS_MS * ( task_idx + 1 ) ) / portTICK_RATE_MS); } } void app_main() { print_mux = xSemaphoreCreateMutex(); i2c_slave_init(); i2c_master_init(); xTaskCreate(i2c_test_task, "i2c_test_task_0", 1024 * 2, (void* ) 0, 10, NULL); xTaskCreate(i2c_test_task, "i2c_test_task_1", 1024 * 2, (void* ) 1, 10, NULL); }