ESP32 Arduino Wire Library


I’ve been building a project using PlatformIO and the ESP32 on a custom board.
I’m interfacing an LED matrix using a matrix driver that communicates over I2C. The issue that I am facing is that for some reason there is a big delay between consecutive I2C transfers (write only) that is causing very poor refresh rate. This using the Wire library.

This is how I’m sending the data:

I am filling 2 buffers with data

uint8_t i2cAddrbuffer[1054];
uint8_t i2cCMDbuffer[1054];
int tail = 0;   
for(int y = 0; y<9; y++){

	for(int x = 0; x<39; x++){
		i2cAddrbuffer[tail] = 0xFE;
		i2cCMDbuffer[tail++] = 0xC5;

		i2cAddrbuffer[tail] = 0xFD;
		i2cCMDbuffer[tail++] = IS31FL3741addrmap[y][x][1];

		i2cAddrbuffer[tail] = IS31FL3741addrmap[y][x][0];
		i2cCMDbuffer[tail++] = 0x3;

And then sending the data over to the I2C bus using the wire library:

for(int i = 0; i<tail; i++)
	I2CWriteByte(addr, i2cAddrbuffer[i], i2cCMDbuffer[i]);

I’ve hooked up my scope and captured some screenshots to made it easier to show what’s happening:

Is this an inherent problem with the Wire library? Should I use the original ESP I2C library?
I thought that this could be an issue that could be caused by task switching from FreeRTOS (I’m running this code on the Setup function) but lowering the freertos scheduler frequency didnt help.

Thanks in advance!

So how did you implement this function? This doesn’t seem like a Wire call to me at all.

Do you have to make 351 individual one-byte I2C transfers or can you string it together in a large buffer if the chip has something like an auto-address-increase feature?

Hmm it seems that I have forgot to include the call, but here it is:

void I2CWriteByte(int Dev_Add,int Reg_Add,int Reg_Dat)
 Wire.beginTransmission(Dev_Add); // transmit to device IS31FL373x
 Wire.write((byte)Reg_Add); // sends regaddress
 Wire.write((byte)Reg_Dat); // sends regaddress
 Wire.endTransmission(); // stop transmitting

auto-address-increase feature?

I have found that recently but I’m still trying. This driver IC has some weird register locking rules.

I will continue to investigate, thanks for the help!

The Wire library seems to have some significant overhead in its drivers, looking at places like here and more importantly the I2C write functions and sub-calls like this, so 62 microseconds overhead between I2C transmissions doesn’t seem that absurd…

Even Wire.setClock(1000000); (docs) won’t help much if the inter-write times are so big. BTW your chip supports 1000 kHz fast-mode plus at p.6 – default Wire frequency is 100kHZ.

Also page 8 of the datasheet shows the "Writing to IS31FL3741 (Automatic address increment) " which should be what you want and the way to go to overcome the driver-overhead. Give the I2C driver the biggest possible continuous buffer it can handle and if it writes it efficiently (only big setup functions at the beginning of a multi-byte tranmissions) it should increase performance significantly.

If the driver is still limiting you might want to try the ESP-IDF implementation of the I2C driver – start at platform-espressif32/examples/espidf-blink at develop · platformio/platform-espressif32 · GitHub and use code from the I2C example to get up and running. You can also combine ESP-IDF and Arduino if you still want to use Arduino APIs (except for Wire in your case).

1 Like

Even Wire.setClock(1000000); (docs) won’t help much if the inter-write times are so big. BTW your chip supports 1000 kHz fast-mode plus at p.6 – default Wire frequency is 100kHZ.

Yes! I noticed that, I am running the Wire library with that same configuration. And like you said, it doesen’t help.

It was only when i tested the usual transfer without the unlocking command that I started to get better results. That led me believe that i could do the transfer of all of the registers of one page in one go (if the buffer allows it). I’m am still exploring this option but I think I will replace the Wire library with the IDF, that seems more robust.

Anyway, I appreciate the help and support, have a great day!