| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315 |
- /*
- * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
- *
- * SPDX-License-Identifier: Unlicense OR CC0-1.0
- */
- /* i2c - Example
- For other examples please check:
- https://github.com/espressif/esp-idf/tree/master/examples
- See README.md file to get detailed usage of this example.
- 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 <stdio.h>
- #include "esp_log.h"
- #include "driver/i2c.h"
- #include "sdkconfig.h"
- static const char *TAG = "i2c-example";
- #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 */
- #if SOC_I2C_NUM > 1
- #define I2C_SLAVE_SCL_IO CONFIG_I2C_SLAVE_SCL /*!< gpio number for i2c slave clock */
- #define I2C_SLAVE_SDA_IO CONFIG_I2C_SLAVE_SDA /*!< gpio number for i2c slave data */
- #define I2C_SLAVE_NUM I2C_NUMBER(CONFIG_I2C_SLAVE_PORT_NUM) /*!< 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 ESP_SLAVE_ADDR CONFIG_I2C_SLAVE_ADDRESS /*!< ESP32 slave address, you can set any 7bit value */
- #endif
- #define I2C_MASTER_SCL_IO CONFIG_I2C_MASTER_SCL /*!< gpio number for I2C master clock */
- #define I2C_MASTER_SDA_IO CONFIG_I2C_MASTER_SDA /*!< gpio number for I2C master data */
- #define I2C_MASTER_NUM I2C_NUMBER(CONFIG_I2C_MASTER_PORT_NUM) /*!< I2C port number for master dev */
- #define I2C_MASTER_FREQ_HZ CONFIG_I2C_MASTER_FREQUENCY /*!< 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 BH1750_SENSOR_ADDR CONFIG_BH1750_ADDR /*!< slave address for BH1750 sensor */
- #define BH1750_CMD_START CONFIG_BH1750_OPMODE /*!< Operation mode */
- #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 */
- SemaphoreHandle_t print_mux = NULL;
- #if SOC_I2C_NUM > 1
- /**
- * @brief test code to read esp-i2c-slave
- * We need to fill the buffer of esp slave device, then master can read them out.
- *
- * _______________________________________________________________________________________
- * | start | slave_addr + rd_bit +ack | read n-1 bytes + ack | read 1 byte + nack | stop |
- * --------|--------------------------|----------------------|--------------------|------|
- *
- * @note cannot use master read slave on esp32c3 because there is only one i2c controller on esp32c3
- */
- 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_PERIOD_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 |
- * --------|---------------------------|----------------------|------|
- *
- * @note cannot use master write slave on esp32c3 because there is only one i2c controller on esp32c3
- */
- static esp_err_t __attribute__((unused)) 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_PERIOD_MS);
- i2c_cmd_link_delete(cmd);
- return ret;
- }
- #endif
- /**
- * @brief test code to operate on BH1750 sensor
- *
- * 1. set operation mode(e.g One time L-resolution 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 |
- * --------|---------------------------|--------------------|--------------------|------|
- */
- static esp_err_t i2c_master_sensor_test(i2c_port_t i2c_num, uint8_t *data_h, uint8_t *data_l)
- {
- int ret;
- 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);
- ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_PERIOD_MS);
- i2c_cmd_link_delete(cmd);
- if (ret != ESP_OK) {
- return ret;
- }
- vTaskDelay(30 / portTICK_PERIOD_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_PERIOD_MS);
- i2c_cmd_link_delete(cmd);
- return ret;
- }
- /**
- * @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,
- // .clk_flags = 0, /*!< Optional, you can use I2C_SCLK_SRC_FLAG_* flags to choose i2c source clock here. */
- };
- 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);
- }
- #if SOC_I2C_NUM > 1
- /**
- * @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 = ESP_SLAVE_ADDR,
- };
- 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);
- }
- /**
- * @brief test function to show buffer
- */
- 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");
- }
- #endif //!CONFIG_IDF_TARGET_ESP32C3
- static void i2c_test_task(void *arg)
- {
- int ret;
- int task_idx = (int)arg;
- #if SOC_I2C_NUM > 1
- int i = 0;
- 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);
- #endif //!CONFIG_IDF_TARGET_ESP32C3
- uint8_t sensor_data_h, sensor_data_l;
- int cnt = 0;
- while (1) {
- ESP_LOGI(TAG, "TASK[%d] test cnt: %d", task_idx, cnt++);
- ret = i2c_master_sensor_test(I2C_MASTER_NUM, &sensor_data_h, &sensor_data_l);
- xSemaphoreTake(print_mux, portMAX_DELAY);
- if (ret == ESP_ERR_TIMEOUT) {
- ESP_LOGE(TAG, "I2C Timeout");
- } else if (ret == ESP_OK) {
- printf("*******************\n");
- printf("TASK[%d] MASTER READ SENSOR( BH1750 )\n", task_idx);
- printf("*******************\n");
- printf("data_h: %02x\n", sensor_data_h);
- printf("data_l: %02x\n", sensor_data_l);
- printf("sensor val: %.02f [Lux]\n", (sensor_data_h << 8 | sensor_data_l) / 1.2);
- } else {
- ESP_LOGW(TAG, "%s: No ack, sensor not connected...skip...", esp_err_to_name(ret));
- }
- xSemaphoreGive(print_mux);
- vTaskDelay((DELAY_TIME_BETWEEN_ITEMS_MS * (task_idx + 1)) / portTICK_PERIOD_MS);
- //---------------------------------------------------
- #if SOC_I2C_NUM > 1
- for (i = 0; i < DATA_LENGTH; i++) {
- data[i] = i;
- }
- xSemaphoreTake(print_mux, portMAX_DELAY);
- size_t d_size = i2c_slave_write_buffer(I2C_SLAVE_NUM, data, RW_TEST_LENGTH, 1000 / portTICK_PERIOD_MS);
- if (d_size == 0) {
- ESP_LOGW(TAG, "i2c slave tx buffer full");
- 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);
- }
- if (ret == ESP_ERR_TIMEOUT) {
- ESP_LOGE(TAG, "I2C Timeout");
- } else if (ret == ESP_OK) {
- 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);
- printf("====TASK[%d] Master read ====\n", task_idx);
- disp_buf(data_rd, d_size);
- } else {
- ESP_LOGW(TAG, "TASK[%d] %s: Master read slave error, IO not connected...\n",
- task_idx, esp_err_to_name(ret));
- }
- xSemaphoreGive(print_mux);
- vTaskDelay((DELAY_TIME_BETWEEN_ITEMS_MS * (task_idx + 1)) / portTICK_PERIOD_MS);
- //---------------------------------------------------
- int size;
- for (i = 0; i < DATA_LENGTH; i++) {
- data_wr[i] = i + 10;
- }
- xSemaphoreTake(print_mux, portMAX_DELAY);
- //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_PERIOD_MS);
- }
- if (ret == ESP_ERR_TIMEOUT) {
- ESP_LOGE(TAG, "I2C Timeout");
- } else if (ret == ESP_OK) {
- 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);
- printf("----TASK[%d] Slave read: [%d] bytes ----\n", task_idx, size);
- disp_buf(data, size);
- } else {
- ESP_LOGW(TAG, "TASK[%d] %s: Master write slave error, IO not connected....\n",
- task_idx, esp_err_to_name(ret));
- }
- xSemaphoreGive(print_mux);
- vTaskDelay((DELAY_TIME_BETWEEN_ITEMS_MS * (task_idx + 1)) / portTICK_PERIOD_MS);
- #endif //!CONFIG_IDF_TARGET_ESP32C3
- }
- vSemaphoreDelete(print_mux);
- vTaskDelete(NULL);
- }
- void app_main(void)
- {
- print_mux = xSemaphoreCreateMutex();
- #if SOC_I2C_NUM > 1
- ESP_ERROR_CHECK(i2c_slave_init());
- #endif
- ESP_ERROR_CHECK(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);
- }
|