This can be an important normal task, for instance when retrying an eeprom waiting for its last write burn cycle to complete before it will respond again.

We needed to do this on both the ESP32 S3 and the ESP32 S2 and found different issues on each (it seemed the Espressif I2C implementation is pretty flakey when you need to do something specific with it…)

Example code

void WaitForLastWriteToComplete ()
{
	uint16_t TriesCount = 5000;

	i2c_cmd_handle_t OurI2cCmdHandle = i2c_cmd_link_create();	//<<<<<<<<< ESP32 S3 NEEDED THIS HERE!

	while (1)
	{
		//i2c_cmd_handle_t OurI2cCmdHandle = i2c_cmd_link_create();	//<<<<<<<<< ESP32 S2 NEEDED THIS HERE INSTEAD!

		//----- DUMMY WRITE OPERATION -----
		i2c_master_start(OurI2cCmdHandle);
		i2c_master_write_byte(OurI2cCmdHandle, EXAMPLE_I2C_ADDR | EXAMPLE_I2C_WRITE_BIT, EXAMPLE_I2C_ACK_CHECK_EN);
		i2c_master_stop(OurI2cCmdHandle);
		//Send queued commands
		i2c_ret = i2c_master_cmd_begin(EXAMPLE_I2C_PORT_NUMBER, OurI2cCmdHandle, (1 / portTICK_PERIOD_MS));	//ticks_to_wait small value as we're not expecting the device to clock stretch 

		if (i2c_ret != ESP_FAIL)	//ESP_FAIL returned for Sending command error, slave hasn't ACK the transfer
			break;
		
		TriesCount--;
		if (TriesCount == 0)
			break;

		//i2c_cmd_link_delete(OurI2cCmdHandle);	//<<<<<<<<< ESP32 S2 NEEDED THIS HERE INSTEAD!

	} //while (1)

	i2c_cmd_link_delete(OurI2cCmdHandle);	//<<<<<<<<< ESP32 S3 NEEDED THIS HERE!
}

Things discovered when getting this to work on an ESP32 S3

For the ESP32 S3

Do not use i2c_cmd_link_delete() and i2c_cmd_link_create() between back-to-back retrying. In tests it causes a 1 second delay after the first NACK generating i2c_ret == 0x107 which is Operation timed out. Very odd as it should have just generated a new short attempt and i2c_ret == -1 ESP_FAIL like the first attempt. But it doesn’t, removing the use of i2c_cmd_link_delete() and i2c_cmd_link_create() between tries solved it.

i2c_master_write_byte() ack_en (Enable ACK signal) value must be 1, not 0. If you use 0 then the NACK is ignored and you get a ESP_OK back on the first try.

For the ESP32 S2

Tried the exact same approach as for the ESP32 S3 we’d done previously, but on the ESP32 S2 we found once the write was acknowledged the ESP32 S2 I2C peripheral then went into crazy mode throwing out repeated stop conditions for no reason. The solution was to either have it write a byte after the address, or move the i2c_cmd_link_create() and i2c_cmd_link_delete() so they are used for every try…. completely opposite to the problem we encountered with the ESP32 S3.

USEFUL?
We benefit hugely from resources on the web so we decided we should try and give back some of our knowledge and resources to the community by opening up many of our company’s internal notes and libraries through mini sites like this. We hope you find the site helpful.
Please feel free to comment if you can add help to this page or point out issues and solutions you have found, but please note that we do not provide support on this site. If you need help with a problem please use one of the many online forums.

Comments

Your email address will not be published. Required fields are marked *