Skip to content

Commit

Permalink
Fix timeout handling for u8g_i2c_stop()
Browse files Browse the repository at this point in the history
To trigger a stop condition, the code sets the TWSTO bit, which is
automaticaly cleared when the stop is copmleted. However, the code would
call u8g_i2c_wait() to wait until the bit was *set*, not *cleared*. In
most cases, the stop condition seems slow enough so the bit is not
cleared and u8g_i2c_wait() is satisfied (though without waiting for the
stop to be completed). However, in some cases the bit is already
cleared, so u8g_i2c_wait stalls for the entire timeout and then sets a
timeout error.

In practice, these errors aren't usually checked, so this mostly causes
some unneeded delays and not waiting for stop complete is probably not
problematic either, but it is good to fix it anyway.

This commit changes u8g_i2c_wait to allow waiting for a bit to be
cleared in addition to it being set.
  • Loading branch information
matthijskooijman committed Apr 7, 2017
1 parent 00609fe commit 99afbd1
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 9 deletions.
2 changes: 1 addition & 1 deletion csrc/u8g.h
Original file line number Diff line number Diff line change
Expand Up @@ -1511,7 +1511,7 @@ void u8g_i2c_clear_error(void) U8G_NOINLINE;
uint8_t u8g_i2c_get_error(void) U8G_NOINLINE;
uint8_t u8g_i2c_get_err_pos(void) U8G_NOINLINE;
void u8g_i2c_init(uint8_t options) U8G_NOINLINE; /* use U8G_I2C_OPT_NONE as options */
uint8_t u8g_i2c_wait(uint8_t mask, uint8_t pos) U8G_NOINLINE;
uint8_t u8g_i2c_wait(uint8_t mask, uint8_t value, uint8_t pos) U8G_NOINLINE;
uint8_t u8g_i2c_start(uint8_t sla) U8G_NOINLINE;
uint8_t u8g_i2c_send_byte(uint8_t data) U8G_NOINLINE;
uint8_t u8g_i2c_send_mode(uint8_t mode) U8G_NOINLINE;
Expand Down
16 changes: 8 additions & 8 deletions csrc/u8g_com_i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,10 @@ void u8g_i2c_init(uint8_t options)
u8g_i2c_clear_error();
}

uint8_t u8g_i2c_wait(uint8_t mask, uint8_t pos)
uint8_t u8g_i2c_wait(uint8_t mask, uint8_t value, uint8_t pos)
{
volatile uint16_t cnt = 2000; /* timout value should be > 280 for 50KHz Bus and 16 Mhz CPU, however the start condition might need longer */
while( !(TWCR & mask) )
while( (TWCR & mask) != value )
{
if ( cnt == 0 )
{
Expand Down Expand Up @@ -175,7 +175,7 @@ uint8_t u8g_i2c_start(uint8_t sla)
TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN);

/* wait */
if ( u8g_i2c_wait(_BV(TWINT), 1) == 0 )
if ( u8g_i2c_wait(_BV(TWINT), _BV(TWINT), 1) == 0 )
return 0;

status = TW_STATUS;
Expand All @@ -194,7 +194,7 @@ uint8_t u8g_i2c_start(uint8_t sla)
TWCR = _BV(TWINT) | _BV(TWEN);

/* wait */
if ( u8g_i2c_wait(_BV(TWINT), 2) == 0 )
if ( u8g_i2c_wait(_BV(TWINT), _BV(TWINT), 2) == 0 )
return 0;

if ( u8g_i2c_opt & U8G_I2C_OPT_NO_ACK )
Expand All @@ -220,7 +220,7 @@ uint8_t u8g_i2c_send_byte(uint8_t data)
register uint8_t status;
TWDR = data;
TWCR = _BV(TWINT) | _BV(TWEN);
if ( u8g_i2c_wait(_BV(TWINT), 3) == 0 )
if ( u8g_i2c_wait(_BV(TWINT), _BV(TWINT), 3) == 0 )
return 0;

if ( u8g_i2c_opt & U8G_I2C_OPT_NO_ACK )
Expand All @@ -246,7 +246,7 @@ void u8g_i2c_stop(void)
TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWSTO);

/* no error is checked for the stop condition */
u8g_i2c_wait(_BV(TWSTO), 4);
u8g_i2c_wait(_BV(TWSTO), 0, 4);

}

Expand Down Expand Up @@ -612,7 +612,7 @@ uint8_t u8g_i2c_send_byte(uint8_t data) {
return 1;
}

uint8_t u8g_i2c_wait(uint8_t mask, uint8_t pos)
uint8_t u8g_i2c_wait(uint8_t mask, uint8_t value, uint8_t pos)
{
return 1;
}
Expand All @@ -626,7 +626,7 @@ void u8g_i2c_init(uint8_t options)
u8g_i2c_clear_error();
}

uint8_t u8g_i2c_wait(uint8_t mask, uint8_t pos)
uint8_t u8g_i2c_wait(uint8_t mask, uint8_t value, uint8_t pos)
{
return 1;
}
Expand Down

0 comments on commit 99afbd1

Please sign in to comment.