Skip to content

Commit

Permalink
Fix too small timeout in i2c_start()
Browse files Browse the repository at this point in the history
In qmk#11930 the I2C master driver for AVR was changed to perform multiple
retries (20 by default, configurable via `I2C_START_RETRY_COUNT`) in
`i2c_start()`, apparently as a workaround for failures when the slave
half had interrupts disabled for some time.  Unfortunately, the
implementation of those retries limited the minimum timeout for a single
start attempt to 1 ms, but the timeout handling in the I2C master driver
handles the partial millisecond before the next timer tick as if it was
a full millisecond, therefore the timeout for a single attempt could be
really short in some cases.  These short timeouts resulted in some
problems when various I2C APIs were invoked with timeouts not greater
than 40 ms - e.g., qmk#14935.

As a minimal fix for this problem, limit the minimum timeout for a
single start attempt to 2 ms instead of 1 (the actual timeout will be
1...2 ms, instead of 0...1 ms before the change).
  • Loading branch information
sigprof committed Oct 24, 2021
1 parent 6ee29d9 commit b1cf7b7
Showing 1 changed file with 1 addition and 1 deletion.
2 changes: 1 addition & 1 deletion platforms/avr/drivers/i2c_master.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ static i2c_status_t i2c_start_impl(uint8_t address, uint16_t timeout) {
i2c_status_t i2c_start(uint8_t address, uint16_t timeout) {
// Retry i2c_start_impl a bunch times in case the remote side has interrupts disabled.
uint16_t timeout_timer = timer_read();
uint16_t time_slice = MAX(1, (timeout == (I2C_TIMEOUT_INFINITE)) ? 5 : (timeout / (I2C_START_RETRY_COUNT))); // if it's infinite, wait 1ms between attempts, otherwise split up the entire timeout into the number of retries
uint16_t time_slice = MAX(2, (timeout == (I2C_TIMEOUT_INFINITE)) ? 5 : (timeout / (I2C_START_RETRY_COUNT))); // if it's infinite, wait 5ms between attempts, otherwise split up the entire timeout into the number of retries
i2c_status_t status;
do {
status = i2c_start_impl(address, time_slice);
Expand Down

0 comments on commit b1cf7b7

Please sign in to comment.