From d803883cdb9ff6098f6cef41654904dc69543fe1 Mon Sep 17 00:00:00 2001 From: Markus Hitter Date: Tue, 26 Apr 2016 23:21:35 +0200 Subject: [PATCH] i2c.c: review error handling yet again. - Flag I2C_MODE_FREE was misleading, because one couldn't test for it the same way as for I2C_MODE_BUSY. At an error condition, 'i2c_mode & I2C_MODE_FREE' would still evaluate to true. - On error, drop not only the buffer, but the entire transmission. All of a sudden, the display works reliably, even at the previously shaky speed of 100'000 bits/s! TBH, probably I didn't understand some parts of Ruslan's code earlier but tweaked it anyways. Shame on me! --- i2c.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/i2c.c b/i2c.c index 2e35cae..78b50bb 100644 --- a/i2c.c +++ b/i2c.c @@ -57,13 +57,9 @@ #define I2C_MODE_ENHA 0b00001000 // Transponder is busy. #define I2C_MODE_BUSY 0b01000000 -// Transponder is free. -#define I2C_MODE_FREE 0b10111111 // Transmission interrupted. #define I2C_INTERRUPTED 0b10000000 -// Transmission not interrupted. -#define I2C_NOINTERRUPTED 0b01111111 #define I2C_ERROR 0b00000001 #define I2C_ERROR_LOW_PRIO 0b00100000 @@ -73,7 +69,7 @@ uint8_t i2c_address; // State of TWI component of MCU. -volatile uint8_t i2c_state = I2C_MODE_FREE; +volatile uint8_t i2c_state = 0; /** Wether transmission should be terminated on buffer drain. This also means @@ -207,19 +203,20 @@ uint8_t i2c_busy(void) { */ void i2c_write(uint8_t data, uint8_t last_byte) { + // Drop characters until transmission end. Transmissions to the display + // start with a command byte, so sending truncated transmissions is harmful. + if (i2c_state & I2C_ERROR) { + if (last_byte) { + i2c_state &= ~I2C_ERROR; + } + return; + } + while (i2c_should_end || ! buf_canwrite(send)) { delay_us(10); } - // Recover from error conditions by draining the buffer. - if (i2c_state & I2C_ERROR) { - while (buf_canread(send)) { - buf_pop(send, TWDR); - } - i2c_state = I2C_MODE_FREE; - } - - if (i2c_state & I2C_MODE_FREE) { + if ( ! (i2c_state & I2C_MODE_BUSY)) { // No transmission ongoing, start one. i2c_state = I2C_MODE_SAWP; TWCR = (1<