Skip to content

Implements I2C Wire Refactoring on top of IDF #5664

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

Closed
wants to merge 5 commits into from
Closed

Implements I2C Wire Refactoring on top of IDF #5664

wants to merge 5 commits into from

Conversation

SuGlider
Copy link
Collaborator

@SuGlider SuGlider commented Sep 14, 2021

Summary

This PR is a complete refactoring of Wire Library and I2C HAL in order to use IDF instead of current Register manipulation approach.

It implements Arduino Wire and TWI functionality.

Fix #5478
Fix #5635
Fix #5636
Fix #4729
Fix #5470

Impact

It solves many reported issues related to I2C.

@marcboon
Copy link

marcboon commented Sep 14, 2021

Thank you so much for this fix. I just discovered the problem with the repeated start condition not being honoured (#4729), when testing code on my ESP32-S2 design where I'm using a Vishay VEML3328 I2C RGB sensor, which requires the repeated start condition to read data from the device.

After applying your fix (4 affected files), it works as expected if the sensor is the only device on the I2C bus (I can see the repeated start condition on my logic analyzer, and data is read correctly), however, when I add another device (SSD1306 oled display) on the same bus, I get a crash with the message:

assertion "pxMutex" failed: file "IDF/components/freertos/queue.c", line 618, function: xQueueGiveMutexRecursive

The stack trace report is:
0x4008b292: panic_abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp_system/panic.c line 402 0x400298b5: esp_system_abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp_system/esp_system.c line 129 0x4002e68d: abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/newlib/abort.c line 46 0x4002a145: xQueueGiveMutexRecursive at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/queue.c line 618 0x40082c5a: i2cRelease at C:\Users\marc\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.0\cores\esp32\esp32-hal-i2c.c line 154 0x40082cd7: i2cMasterInit at C:\Users\marc\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.0\cores\esp32\esp32-hal-i2c.c line 140 0x40081570: TwoWire::begin(int, int, unsigned int) at C:\Users\marc\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.0\libraries\Wire\src\Wire.cpp line 123 0x40081ca5: Adafruit_SSD1306::begin(unsigned char, unsigned char, bool, bool) at D:\Documents\Arduino\libraries\Adafruit_SSD1306\Adafruit_SSD1306.cpp line 490 0x40081234: setup() at D:\Documents\Arduino\DR-00-tester-rgb-sensor/DR-00-tester-rgb-sensor.ino line 28 0x40083eca: loopTask(void*) at C:\Users\marc\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.0\cores\esp32\main.cpp line 38

Update: Also when I ONLY have the SSD1306 display on the I2C bus I get the above result (using the Adafruit_SSD1306 library v2.4.6).

Update 2: I discovered that the above crash happens when Wire.begin() is executed twice. Once explicitly at the beginning of setup(), and secondly within Adafruit_SSD1306::begin(), with the default argument for periphBegin = true. However, when I remove the explicit Wire.begin() OR supply Adafruit_SSD1306::begin() with periphBegin = false (so Wire.begin() is only called once) the above crash doesn't happen, but instead I get the following message:
E (307) i2c: i2c command link allocation error: the buffer provided is too small.
repeatedly for about 6 seconds, after which it stops.

So in either case it still doesn't work.

@SuGlider
Copy link
Collaborator Author

SuGlider commented Sep 14, 2021

however, when I add another device (SSD1306 oled display) on the same bus, I get a crash with the message:

Hi @marcboon, thank you for testing and reporting the results back here.
I see the issue, it's very clear. I'll fix it today and commit it to this PR.
Thanks!

@SuGlider
Copy link
Collaborator Author

SuGlider commented Sep 14, 2021

@marcboon , I fixed the issue with begin() you reported.
I'm looking into the issue with "command link allocation error".

@SuGlider
Copy link
Collaborator Author

SuGlider commented Sep 14, 2021

@marcboon , The issue with
assertion "pxMutex" failed: file "IDF/components/freertos/queue.c", line 618, function: xQueueGiveMutexRecursive
and
E (307) i2c: i2c command link allocation error: the buffer provided is too small.
shall be solved by now.

Please try again and let me know.
Thanks!

@marcboon
Copy link

@marcboon , The issue with
assertion "pxMutex" failed: file "IDF/components/freertos/queue.c", line 618, function: xQueueGiveMutexRecursive
and
E (307) i2c: i2c command link allocation error: the buffer provided is too small.
shall be solved by now.

Please try again and let me know.
Thanks!

Yes, thank you very much!
I have the SSD1306 oled display and VEML3328 RGB sensor (using repeated start) now running correctly on the same bus.

Thanks again for the quick update. I hope there won't be any more issues with this patch :)

@@ -120,136 +133,28 @@ bool TwoWire::begin(int sdaPin, int sclPin, uint32_t frequency)
void TwoWire::setTimeOut(uint16_t timeOutMillis)
{
_timeOutMillis = timeOutMillis;
i2cSetTimeOut(i2c, timeOutMillis);
Copy link
Contributor

Choose a reason for hiding this comment

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

According to the IDF documentation, the timeout is not in units of a msec, but its unit is: APB 80Mhz clock cycle.

Also it is a bit strange to have it here offered as millis, while the somewhat related stretch limit in the ESP8266 implementation is in usec.
I guess it will break some implementations out there that use the timeout, but at least the parameter suggestion is not what it does.
Having it in msec is fine I guess, but then you need to convert it in units of 1/80th MHz. (thus effectively multiply it by 80000)

Copy link
Collaborator Author

@SuGlider SuGlider Sep 17, 2021

Choose a reason for hiding this comment

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

@TD-er

Thanks for the comment.
TwoWire::setTimeOut is an API from Arduino Stream Class.
https://www.arduino.cc/reference/en/language/functions/communication/stream/streamsettimeout/
It takes its argument in milliseconds. Thus, the implementation follows Arduino standard.

If users follow Arduino Standards, nothing will break.

The link you sent is regarding something else, not the whole transaction timeout, but actually the time in cycles that i2c bus can be keept idle in order to the ESP i2c hardware machine state considers that there was no response for ACK/NACK.

The implentation of Arduino HAL i2cSetTimeOut() calculates FreeRTOS ticks and keep this value to use it in the IDF I2C APIs regarading a full i2c transaction, but not the bus idle time in cycles.

You won't find a call to IDF i2c_set_timeout() in the code of this PR.
You can read this PR code in order to see how it's used.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

In this case, I understand there is nothing to change reagarding the matter you presented.
Please let me know if you see diferently or there is something I am missing.
Thank you.

Jason2866 added a commit to arendst/Tasmota that referenced this pull request Sep 17, 2021
@me-no-dev
Copy link
Member

Hi All! I am closing this in favor of #5683 Please confirm that all is working as expected :)

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