Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Esp32-S2 I2C fixes #4387

Merged
merged 7 commits into from
Mar 12, 2021
Merged

Esp32-S2 I2C fixes #4387

merged 7 commits into from
Mar 12, 2021

Conversation

dhalbert
Copy link
Collaborator

@dhalbert dhalbert commented Mar 11, 2021

Fixes #3846.
Fixes #4046.

Tagging @askpatrickw, @microdev1, @skieast for testing.

This is a draft because it depends on adafruit/esp-idf#1, which is not yet done. This build temporarily uses https://github.com/dhalbert/esp-idf/tree/circuitpython-i2c-cmd_mux-fix.

Tests that now work:

import board,busio

i2c = busio.I2C(board.SCL, board.SDA)
i2c.deinit()

import wifi
import time
import board
from busio import I2C

def scan(deinit=True):
    i2c = I2C(board.SCL, board.SDA)
    i2c.try_lock()
    results = i2c.scan()
    if deinit:
        i2c.deinit()
    return results

print(scan())
print(scan())
print(scan())
import board,busio,adafruit_sht31d

import wifi

i2c = busio.I2C(board.SCL, board.SDA)
i2c.deinit()

i2c = busio.I2C(board.SCL, board.SDA)
s = adafruit_sht31d.SHT31D(i2c)
print(s.temperature)

i2c.deinit()

@dhalbert dhalbert mentioned this pull request Mar 11, 2021
@tannewt tannewt requested a review from microdev1 March 11, 2021 18:46
@askpatrickw
Copy link

@dhalbert I have some time and will test this now

Copy link

@askpatrickw askpatrickw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested this using the CI artifacts on a MetroS2 an a Feather S2 PreRelease.
I ran dan's second code sample, and my own script using the BME_680. Both worked as expected.

I then copied over a script that connects to wifi and then prints the BME values.
It failed to safemode, when I disconnected USB and connected again the script worked.
I tried to reproduce that auto-load failure 10 times and could not.

Unless other people see that behavior, I would call this good.

@skieast
Copy link

skieast commented Mar 12, 2021

tested on UM FeatherS2.
Script uses wifi, AdaFruit_requests, then setup two i2c devices on different busses. AHt20 and SGP30
Loop pinging google and reading both devices. Works. Interrupt with CTL-C, restart wih CTRL-D, works
From the repl create two i2c busses, i2c and i2c2. try_lock and unlock work on both.
Looks great.

@dhalbert dhalbert marked this pull request as ready for review March 12, 2021 01:06
@dhalbert
Copy link
Collaborator Author

Thank you very much for the testing! I've now moved this up to esp-idf merge commit (code is identical), and turned off draft status.

@dhalbert
Copy link
Collaborator Author

When #4378 is changed and merged, it will change from using bitbangio for 0, 1, or 2-byte writes to just 0-byte writes. I will try to test the equivalent of that change with some of the failing peripherals above.

Copy link
Collaborator

@microdev1 microdev1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! @dhalbert.
I tested all three provided examples on my microS2 and they work flawlessly. Just one question...

ports/esp32s2/common-hal/busio/I2C.c Outdated Show resolved Hide resolved
@microdev1
Copy link
Collaborator

@dhalbert I think we can get the idf patch in v4.3 since its a pre-release at the moment.

@dhalbert
Copy link
Collaborator Author

@dhalbert I think we can get the idf patch in v4.3 since its a pre-release at the moment.

I agree, it would be good to PR upstream, but I am still somewhat bothered by the whole thing because I don't see why the IDF fix works. I did some more experiments yesterday and re-read a bunch of our code and their code. I came to no new conclusion. I haven't gotten feedback from igrr about it. Also I inquired with FreeRTOS: https://forums.freertos.org/t/vsemaphoredelete-immediately-after-xsemaphoretake/11956.

Ideally I would like to reproduce this in a simple ESP-IDF program, because they might ask for a test case, but I don't have any experience writing one. I could submit a PR and see what happens, but the fix seems a bit superstitious. There are other examples of Take followed by Delete in the ESP-IDF, mostly in test code. There are also a couple of examples of Take-Give-Delete. Do you have an intuition about this?

Copy link
Collaborator

@microdev1 microdev1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! for making the changes.

@microdev1
Copy link
Collaborator

Do you have an intuition about this?

No clue at the moment, I'll try to replicate this behavior in an IDF program.

@dhalbert
Copy link
Collaborator Author

Failed build was a network problem. Merging.

@dhalbert dhalbert merged commit bbb1a8b into adafruit:main Mar 12, 2021
@dhalbert dhalbert deleted the esp32s2-i2c-bug branch March 12, 2021 15:27
@dhalbert
Copy link
Collaborator Author

No clue at the moment, I'll try to replicate this behavior in an IDF program.

When I look at the multiple threads running in a "crashed" program vs one running this fix, they look the same. In other words, it is not a hard crash, but some kind of loop or other problem. The clue with my simple tests above is that the REPL stops working, and eventually disconnects. So perhaps some program that does some USB serial activitiy would hang up. Perhaps also some wifi or I2C activity would fail - that might be easier to test.

@dhalbert
Copy link
Collaborator Author

This is the simplest example that reliably fails without the fix. It prints >>> after the import wifi but then the REPL hangs.

import board,busio

i2c = busio.I2C(board.SCL, board.SDA)
i2c.deinit()

import wifi

@microdev1
Copy link
Collaborator

It prints >>> after the import wifi but then the REPL hangs.

Yes, I get the same behavior... it hangs and no backtrace. From the debug print I see that wifi starts initializing but stops abruptly.
This also happens on V4.3. I am going to replicate the sequence of code that is executed with these commands.

@dhalbert
Copy link
Collaborator Author

dhalbert commented Mar 12, 2021

So the essence of the above is (you can double check this):

// From busio.I2C().
i2c_driver_delete(NULL);   // does nothing
i2c_param_config();
i2c_driver_install();
// i2c.deinit().
i2c_driver_delete();

// Below from common_hal_wifi_init() and common_hal_wifi_radio_set_enabled().
esp_netif_init();               
esp_event_loop_create_default();
 xEventGroupCreateStatic();
esp_event_handler_instance_register();
esp_event_handler_instance_register();
esp_wifi_init();
esp_wifi_set_mode();
esp_wifi_start();

I tried moving the esp_event_loop_create_default() to earlier, doing it during port_init(), but that was worse.

@microdev1
Copy link
Collaborator

So the essence of the above is

Yup! that's it... you want to go ahead with the IDF program? If not I can run this sequence tomorrow.

@dhalbert
Copy link
Collaborator Author

I'll try to get the time; I'll let you know. I guess I can gut one of their examples and put that in.

@skieast
Copy link

skieast commented Mar 12, 2021

Glad someone is also wondering why it works. I just got in and all my questions have been posed.

@dhalbert
Copy link
Collaborator Author

Moving this discussion to a new issue, #4401.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants