Conversation
FreqToClockDiv could produce a CLKDIV_PRE value wider than the register field when the requested frequency was far below the base clock, spilling into adjacent fields. Clamp both divider components with the target register definitions so each SoC retains its supported range without corrupting neighboring bits.
Decode each supported ESP32 target's live GPSPI clock source and pre-divider instead of assuming an 80 MHz APB clock. Acquire the bus before reading that state because the driver may change it, allowing the existing cache to recalculate whenever another owner selects a different source. Unknown selectors use a safe upper bound so divider calculation does not accidentally overspeed the request.
On ESP32-C5, C61, C6, and P4 Arduino builds, temporarily select an 80 MHz GPSPI base only when it produces a strictly closer write clock without overspeeding either requested rate. Equal write results keep the current source; read throughput may decrease when write throughput improves. Save and restore only the owned clock fields inside the RCC atomic section, and clean up active ownership when a bus is released or destroyed. ESP-IDF transactions retain driver ownership, and the Arduino mutex does not serialize mixed API users.
Derive the SPI divider base from the active GPSPI clock source
The software I2C moved SDA in the same breath as pulling SCL low. A data line that changes while the clock still reads high is a start or a stop to every device on the bus, so the transfer ended instead of carrying a bit and no device ever acknowledged its address. Wait for each line to reach the level it was just given, rather than budgeting a fixed time for it: the clock is driven low, so waiting for it costs the fall time of the bus and nothing more, and the released data line is given the time its own rise actually takes. A fixed hold would have to come out of the setup time, which is what the slow rise of a released line needs at the higher clock rates. The same wait now precedes the start, the repeated start and the stop, where the rise of the released data line decides whether the condition appears on the bus at all. A line that never reaches its level is reported the way a clock that will not rise already was, so the transfer ends instead of carrying on with a bus that is not there. The recovery path is the one exception: a clock that will not settle is the condition it exists to clear. An acknowledge needs one more distinction. This master drives the data line low for the bit before it, so a low reading is either a device holding the line or a rise that has not finished. A device holds it for the whole pulse while a rise is over within the time the bus is allowed to take for one, so the level is read again to separate them.
Software I2C: hold the data line until the clock is actually down
A backup restored the mux, the routing and the output enable, but not the level the pin was driving. A pin that had been held low came back driving high, because whoever borrowed it left the latch there - releasing an open drain line means letting the latch go high, and every probe ends that way. Restoring in place was not enough on its own: putting the pad configuration back can turn an open drain output into a push-pull one while the enable is still set and the latch is still high, and the pin drives that high before the latch is ever reached. So the output is taken down first, then the latch goes back, then the configuration, and the pin is only enabled again at the end if that is how it was found. The enable is set and cleared through its own registers rather than read back and written, so a pin being restored elsewhere is not caught in between.
The note told a sketch to use port -2 because no library takes it. Board identification in M5Unified takes it, so the advice would have handed a sketch the slot a probe is about to reopen on other pins - and a transfer does not check that the slot is still the one it was given, so the wrong pins would move with no error to show for it. Describe what actually happens instead: both slots are borrowed while a board is being brought up, and a sketch that wants one should open it afterwards.
Restore the output latch with the pin, and correct the note on the negative ports
Tab5X upgrades the ESP32-P4 silicon revision used by Tab5.
Add M5Tab5X display support
1. Detect CoreP4X on the internal I2C bus using GPIO11 (SDA) and GPIO9 (SCL), with M5IOE1 at 0x4F and M5PM1 at 0x6E. 2. Add ST7102 MIPI DSI display and Touch_CST3530 touch support.
readBytes splits transfers at the hardware RX FIFO boundary. Record the same data-transfer wait stage used by writeBytes after starting each read command, so the next chunk or endTransaction waits for and clears that command completion instead of racing a stale END interrupt.
The software wait limits gave a stalled transfer 1-2ms before declaring connection_lost: the FIFO poll in readBytes allowed us_limit+1024us and the END wait in i2c_wait allowed 512<<stage. A slave holding SCL longer than that - legal under the I2C spec, and up to 25ms under SMBus - had its transfer killed. Raise both limits to a shared 25ms constant and make the waits and the watchdog agree on what it means: - i2c_wait also wakes on TIME_OUT, and treats TIME_OUT or a lost arbitration as fatal even when END is set alongside, matching the SDK event priority: the bus state is unknown past either of them. - The STOP wait requires TRANS_COMPLETE: a watchdog bite, a lost arbitration, or the limit expiring with no interrupt at all used to return success from endTransaction. - The exponent-encoded SCL-low watchdog is set to 2^20 source clocks (about 26ms at 40MHz), just past the software limit so the software limit is the sole authority on tolerated stretching; the previous value 31 meant almost a minute. The ESP32 register is at its ceiling, about 13ms, so that target tolerates less stretching. - The soft I2C SCL-high wait adopts the same 25ms allowance. NACK handling does not lean on these limits, so probing an absent device stays fast: measured on the ESP32, an address NACK raises no error interrupt at all - the command sequence still reaches END and the error only surfaces in the ack_err evaluation after STOP - and that path is unchanged (absent-address probe: 99-113us before and after). Measured with hosts reading 31-128 bytes from a slave that stretches at the 32-byte chunk boundary: previously failures began at 1ms of stretch; now the ESP32 passes everything through 10ms and reports 15/30ms as connection_lost (its watchdog ceiling), the ESP32-S3 passes through 15ms and reports 30ms (the 25ms software limit), and both recover cleanly on the next transaction.
Add M5Stack CoreP4X display support
Survive I2C slaves that stretch the clock
Bump version to 0.2.28
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
New device / panel support
Fixes
/ C61 / H2 the SCLK could come out far below the requested value, and on ESP32-S3 up to twice as fast;
Arduino builds now also select the faster source. Dividers are clamped to their register widths.
milliseconds SMBus allows, and wait for each chunk of a split read to complete before issuing the next
command.
acknowledge as they should.
low does not come back driving high after a probe; clarify which negative port numbers the library reserves.