I2C speed

All ESP32 boards running MicroPython.
Target audience: MicroPython users with an ESP32 board.
Post Reply
LupsterHD
Posts: 4
Joined: Wed Jan 05, 2022 9:06 pm

I2C speed

Post by LupsterHD » Wed Jan 05, 2022 9:36 pm

Hello there,
I'm having trouble with machine.freq().
I'm using the esp32 with devkit C V4 from AZ-delivery.
I'm reading(with the I2C Bus)/and then sending ~23 messages/s to my server with a cpu frequency of 160MHz,
But when im adjusting the frequency to 240MHz I'm only sending around ~20 messages/s.

I've meassured the time for how long it takes to read from my sensor (MPU6050)
-> With 240MHz it takes the esp around ~1ms longer to read 2Bytes.

Does anybody know what the potential problem may be?
Best regards.

marcidy
Posts: 133
Joined: Sat Dec 12, 2020 11:07 pm

Re: I2C speed

Post by marcidy » Fri Jan 07, 2022 8:17 pm

can you post a small example which reproduces the issue please? use the code tags to get nice formatting (the </> button will bring up code tags for you).

LupsterHD
Posts: 4
Joined: Wed Jan 05, 2022 9:06 pm

Re: I2C speed

Post by LupsterHD » Sun Jan 09, 2022 8:25 pm

Sorry for the late response.

These are basically my results.
With 16MHz
Image

With 24MHz
Image
(I2C Bus speed set to 400KHz on both tests)

I was unable to cut down my code because of an error I would then receive and I dont know how to fix it.
(Object with buffer protocol required)

Please have a look at my github instead:
https://github.com/JakobWeitzlab/Flugsi ... 32/main.py

Basically down at the bottom, when I call "main()", I manually set the speed of the CPU to either 24MHz or 16MHz.

Code: Select all

def main():
  machine.freq(160000000) #set frequency 
  print(machine.freq())
  wifi = Wifi()
  wifi.loop()
Code for the receiving end can be seen here.
https://github.com/JakobWeitzlab/Flugsi ... PServer.py
At the time the server only receives messages and then prints out "messages/sec".

marcidy
Posts: 133
Joined: Sat Dec 12, 2020 11:07 pm

Re: I2C speed

Post by marcidy » Mon Jan 10, 2022 12:15 am

Thank you for also posting the server. That error may indicate you need a bytes/bytearray instead of a normal string. (e.g. string.encode('ascii') or similar).

I don't see anything obvious as to what is causing that slowdown. I would expect the performance to be limited by the i2c bus. Do you have a scope to confirm the bus timing? Always good to check if you can.

Do you have average timings for _Acc()? Looks like you were timing it, would be helpful to know how much time is spend there.

I suggest sending constant test packets of the same length usually returned by _Acc() in a loop, eliminating the call to _Acc. See if the slowdown is reproduced. Perhaps also introduce a blocking delay of the same average time as a call to _Acc().

You can also use wireshark or similar to see if the packets are really stuck on the MCU or perhaps elsewhere. (I doubt this, but it's nice to know the problem is definitely on the MCU).

With the timings spent in _Acc and the above tests there should be a good indication of which part of the system is slowing down.

LupsterHD
Posts: 4
Joined: Wed Jan 05, 2022 9:06 pm

Re: I2C speed

Post by LupsterHD » Mon Jan 10, 2022 3:02 pm

Unfortunately I dont have a scope.

Time spend in _Acc() =>

160 MHz results:
min 26ms
max 58ms
average 40,375ms

240 MHz results:
min 23ms
max 59ms
average 43,65ms


Wireshark results:
Image

I already tried reading reading the sensor data with my raspberry and got results that where like 10x better.
Cable length 20cm between mpu and esp

Power delivery cant be a problem right?, because then the esp would crash.

I've tried the I2C slow mode (100kHz) and fast mode (400kHz) (both supported by the mpu)
100kHz -> 20 messages/s
400kHz -> 24 messages/s

I just saw a different forum post aswell discussing on how to get the most out of I2C.
They where talking about reading directly from FIFO.
The MPU supports FIFO "caching".
Is it worth a try?

marcidy
Posts: 133
Joined: Sat Dec 12, 2020 11:07 pm

Re: I2C speed

Post by marcidy » Mon Jan 10, 2022 6:14 pm

ah, is your complaint that both are slow? I thought you were just looking at the expectation that running at 240MHz should be faster than 160MHz. it certainly shouldn't be slower. I misunderstood your initial question as being the relative performance.

Considering the average timing in _Acc, 40.375 * 23 = 923.3 ms. so clearly the i2c communication is dominating. The wireshark timings show a variance that seems like it matches with the variance in the i2c.

Anything you can do to speed that up will help. If FIFO caching speeds that up, then yes, i suggest you try it. Sorry, I'm not familiar with the MP6050 (I hooked one up once and that was about it). i know its common so perhaps there are people on the forum who can help. It does seem to me the issue is in the i2c communication. Quickly reading of the MP6050 datasheet, i would expect data to be available at all times via an i2c read of the registers, so I'm not sure FIFO will help here.

Here's a good explanation of cables wrt to i2c: https://electronics.stackexchange.com/q ... -2m-cables
I rarely use i2c over cables beyond prototyping so I don't know limitations there.

I doubt it's power, you should confirm your supply is rated 2x the max expected draw.

If I have some time I can take a look at i2c bus timings, but it wouldn't be till later this week.

LupsterHD
Posts: 4
Joined: Wed Jan 05, 2022 9:06 pm

Re: I2C speed

Post by LupsterHD » Mon Jan 10, 2022 8:19 pm

I initially wanted to know why my esp project "works better" with a lower clock frequency and/or if the clock frequncy may interfere with the I2C bus.
Anyway, Thank you very much for your support :)

marcidy
Posts: 133
Joined: Sat Dec 12, 2020 11:07 pm

Re: I2C speed

Post by marcidy » Sat Jan 15, 2022 12:19 am

Unfortunately I don't have an answer for why the code is slightly slower at 240 MHz, but here's a follow up anyways.

Checking with a scope on a devkit-C v4, reading 8 bits, i see the following timings.

CPU: 160MHz, i2c clock: 100kHz -> 240 us
CPU: 160MHz, i2c clock: 400kHz -> 100 us
CPU: 240MHz, i2c clock: 100kHz -> 231 us
CPU: 240MHz, i2c clock: 400kHz -> 86 us

when i do something like this:

Code: Select all

def test():
    for _ in range(6):
        i2c.readfrom_mem(36, 0x01, 1)

>>> st = time.ticks_us();test();et=time.ticks_us();print(et-st)
3187
that's about 3ms for 6 register reads.

Code: Select all

>>> def test2():
...     ret = str(v1) + " " + str(v2) + " " + str(v3)
...     return ret
>>> print(test2())
255 187 96
>>> st = time.ticks_us();test2();et = time.ticks_us(); print(et - st)
'255 187 96'
5223
so 5 ms is spent building that string.

fyi this is faster:

Code: Select all

>>> st = time.ticks_us();out = "{} {} {}".format(v1, v2, v3);et = time.ticks_us(); print(et - st)
3673
But, it think the real story here is that the python statements are always going to be slower than the equivalent C code. The i2c reading is doing what it should be doing, and the i2c reads are mostly limited by the i2c bus speed. You might be able to speed things up by reading the i2c directly into the socket and having the server reconstruct the data as you need to see it. I personally aim for zero data manipulation on the device unless strictly necessary. I do all data manipulation on the server, as it's much easier to update the server and the server has far more resources. clearly that's not always possible, just an approach i prefer w/ sensor data being reported instead of consumed by the device.

Post Reply