I2C Pins

Typically you can use any GPIO: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/i2c.html

To confirm, see the S# series datasheet for the ESP device you are using > Peripheral Pin Configurations

Resources

https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/i2c.html

https://github.com/espressif/esp-idf/tree/master/examples/peripherals/i2c

I2C Address

Set as normal byte address including RW at bit 0.
So 0b01101000 is set as 0x68, not (0x68 >> 1)

I2C Master Example

#include "driver/i2c.h"
#include <string.h>			//Required for memset()


#define EXAMPLE_I2C_PORT_NUMBER				I2C_NUM_1		//I2C port number
#define EXAMPLE_I2C_SCL_GPIO				16				//GPIO pin
#define EXAMPLE_I2C_SDA_GPIO				17				//GPIO pin
#define EXAMPLE_I2C_FREQ_HZ					100000			//!< I2C master clock frequency
#define EXAMPLE_I2C_ADDR					0x98
#define EXAMPLE_I2C_WRITE_BIT				I2C_MASTER_WRITE
#define EXAMPLE_I2C_READ_BIT				I2C_MASTER_READ
#define EXAMPLE_I2C_ACK_CHECK_EN			0x1
#define EXAMPLE_I2C_ACK_CHECK_DIS			0x0
#define EXAMPLE_I2C_ACK_VAL					0x0
#define EXAMPLE_I2C_NACK_VAL				0x1


    //----- CREATE THE I2C PORT -----
	int i2c_master_port = EXAMPLE_I2C_PORT_NUMBER;
	i2c_config_t conf;
	conf.mode = I2C_MODE_MASTER;
	conf.sda_io_num = EXAMPLE_I2C_SDA_GPIO;
	conf.sda_pullup_en = GPIO_PULLUP_DISABLE;
	conf.scl_io_num = EXAMPLE_I2C_SCL_GPIO;
	conf.scl_pullup_en = GPIO_PULLUP_DISABLE;
	conf.master.clk_speed = EXAMPLE_I2C_FREQ_HZ;		//I2C frequency is the clock speed for a complete high low clock sequence
	i2c_param_config(i2c_master_port, &conf);
	i2c_driver_install(i2c_master_port, conf.mode, 0, 0, 0);		//(i2c_num, mode, slv_rx_buf_len, slv_tx_buf_len, intr_alloc_flags)
	//i2c_driver_install(i2c_port, i2c_config.mode, 0, 0, ESP_INTR_FLAG_LOWMED);		//<<< Alternative version using non dedicated level 1 interrupt (if you have issues running out of level 1 interrupts)

	esp_err_t i2c_ret = ESP_OK;
	uint8_t data_h;
	uint8_t data_l;

	i2c_cmd_handle_t OurI2cCmdHandle = i2c_cmd_link_create();

	//----- WRITE BYTES -----
	i2c_master_start(OurI2cCmdHandle);
	i2c_master_write_byte(OurI2cCmdHandle, EXAMPLE_I2C_ADDR | EXAMPLE_I2C_WRITE_BIT, EXAMPLE_I2C_ACK_CHECK_EN);
	i2c_master_write_byte(OurI2cCmdHandle, 0x02, EXAMPLE_I2C_ACK_CHECK_EN);
	i2c_master_write_byte(OurI2cCmdHandle, 0x7f, EXAMPLE_I2C_ACK_CHECK_EN);
	i2c_master_stop(OurI2cCmdHandle);
	//Send queued commands
	i2c_ret = i2c_master_cmd_begin(EXAMPLE_I2C_PORT_NUMBER, OurI2cCmdHandle, (100 / portTICK_PERIOD_MS));	//"(# / portTICK_PERIOD_MS)"=maximum wait time. This task will be blocked until all the commands have been sent (not thread-safe - if you want to use one I2C port in different tasks you need to take care of multi-thread issues)

	i2c_cmd_link_delete(OurI2cCmdHandle);

	//If you want to know if the device returned NACK:
	//if (i2c_ret == ESP_FAIL)
	//{
	//	//NACK returned
	//}


	if (i2c_ret == ESP_OK)
	{
		//READ BYTES
		printf("I2C Write OK\n");

		OurI2cCmdHandle = i2c_cmd_link_create();

		i2c_master_start(OurI2cCmdHandle);
		i2c_master_write_byte(OurI2cCmdHandle, EXAMPLE_I2C_ADDR | EXAMPLE_I2C_READ_BIT, EXAMPLE_I2C_ACK_CHECK_EN);
		i2c_master_read_byte(OurI2cCmdHandle, &data_h, EXAMPLE_I2C_ACK_VAL);
		i2c_master_read_byte(OurI2cCmdHandle, &data_l, EXAMPLE_I2C_NACK_VAL);
		i2c_master_stop(OurI2cCmdHandle);
		//Send queued commands
		i2c_ret = i2c_master_cmd_begin(EXAMPLE_I2C_PORT_NUMBER, OurI2cCmdHandle, 100 / portTICK_PERIOD_MS);	//"(# / portTICK_PERIOD_MS)"=maximum wait time. This task will be blocked until all the commands have been sent (not thread-safe - if you want to use one I2C port in different tasks you need to take care of multi-thread issues)

		i2c_cmd_link_delete(OurI2cCmdHandle);
	}
	else
	{
		printf("I2C FAILED\n");
	}
write, restart, read
	i2c_cmd_handle_t OurI2cCmdHandle = i2c_cmd_link_create();

	//----- WRITE & READ BYTES -----
	i2c_master_start(OurI2cCmdHandle);
	i2c_master_write_byte(OurI2cCmdHandle, EXAMPLE_I2C_ADDR | EXAMPLE_I2C_WRITE_BIT, EXAMPLE_I2C_ACK_CHECK_EN);
	i2c_master_write_byte(OurI2cCmdHandle, 0x02, EXAMPLE_I2C_ACK_CHECK_EN);
	i2c_master_start(OurI2cCmdHandle);
	i2c_master_write_byte(OurI2cCmdHandle, EXAMPLE_I2C_ADDR | EXAMPLE_I2C_READ_BIT, EXAMPLE_I2C_ACK_CHECK_EN);
	i2c_master_read_byte(OurI2cCmdHandle, &data_h, EXAMPLE_I2C_ACK_VAL);
	i2c_master_read_byte(OurI2cCmdHandle, &data_l, EXAMPLE_I2C_NACK_VAL);
	i2c_master_stop(OurI2cCmdHandle);
	//Send queued commands
	i2c_ret = i2c_master_cmd_begin(EXAMPLE_I2C_PORT_NUMBER, OurI2cCmdHandle, 100 / portTICK_PERIOD_MS);	//"(# / portTICK_PERIOD_MS)"=maximum wait time. This task will be blocked until all the commands have been sent (not thread-safe - if you want to use one I2C port in different tasks you need to take care of multi-thread issues)

	i2c_cmd_link_delete(OurI2cCmdHandle);

Comments

  1. vignesh

    6 years ago

    Hi! I am New for esp32. can you brief of how to develop the i2c for reading any sensor data.

    1. Mark

      5 years ago

      Hello vignesh. The example given for the ESP32 reading I2C shows the technique for reading/writing on I2C. Each sensor will have documentation describing its own data details as far as what can or needs to be written or read and when. Once you have a specific sensor in mind, read the documentation and it will give that information.