miketeachman / micropython-esp32-i2s-examples

Usage and examples for I2S support on the ESP32 microcontroller
MIT License
156 stars 29 forks source link

ESP32 I2S breaks I2C, need I2S.start/stop #28

Open jetpax opened 2 years ago

jetpax commented 2 years ago

There's a long standing unresolved issue with I2C failing when running at the same time as I2S on the ESP32.

eg https://esp32.com/viewtopic.php?t=5563 and several others over the years

Admittedly this is an esp-idf issue, but I've found it can be worked around by turning off the I2S clocks while accessing I2C, which may not sound like a great general workaround, but works in my application.

These functions are available in esp-idf, but not exposed in the MP I2S driver.

Doing so is just a matter of adding a couple of stanzas, and modifying the machine_i2s_locals_dict_table eg

STATIC mp_obj_t machine_i2s_start(mp_obj_t self_in) {
    machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
    i2s_start(self->port);
    return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_i2s_start_obj, machine_i2s_start);

STATIC mp_obj_t machine_i2s_stop(mp_obj_t self_in) {
    machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
    i2s_stop(self->port);
    return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_i2s_stop_obj, machine_i2s_stop);

Would be great if this could be added to main library (would add this to MP issues, but Damien always seems so busy...)

miketeachman commented 2 years ago

Thanks for bringing this to my attention. This is new to me. I checked the ESP-IDF issues list on github -- this problem is not reported. It might be a problem in the silicon and not in the ESP-IDF (although the ESP32 errata does not indicate this problem).

Before considering any changes to the MicroPython I2S API it is necessary to reproduce the problem. Do you have time to find the minimum amount of MicroPython code that can reliably reproduce the problem?

thanks !

jetpax commented 2 years ago

Hi Mike,

Yes, thats exactly the issue, it only really happens when driving the system hard with necessarily complex code.

I'm running an IMU at full tilt on I2C (1MHz bus , 2kHz 48bits data) as well as using your code to get data from an ICS43434 MEMS mic @ 20kHz32 bit, and I'm not sure I can distill this to a nugget.

All I can say is on a logic analyser , the difference between having the stop /start methods and not having them are dramatic.

Anyhow, I'm cool adding these changes in, so no worries

miketeachman commented 2 years ago

I think that gives me enough background to try and reproduce the failure. I'm in the middle of adding I2S support to the MIMXRT port (e.g. Teensy boards), so I won't be able to work on this for a while yet.

For a short-term workaround I wonder if using the deinit() method followed the init() method could substitute for start/stop? Whatever samples that are remaining in the internal buffer would be wiped out with the deinit/init calls, but perhaps that is not important?

jetpax commented 2 years ago

Hi Mike,

Yes init/deinit was the first thing I tried, but this didnt work in my app, which is actually why I added the start/stop methods into your code.