i2c.c: simplify error handling.
If all error conditions are handled the same, there's not much
point to use distinct code for each of them.
Also, handle collisions like the other error conditions.
This saves a nice 52 bytes of program memory.
Program: 24404 bytes
Data: 1543 bytes
EEPROM: 32 bytes
This commit is contained in:
parent
a13312d9a9
commit
6e8067208e
98
i2c.c
98
i2c.c
|
|
@ -65,9 +65,7 @@
|
||||||
// Transmission not interrupted.
|
// Transmission not interrupted.
|
||||||
#define I2C_NOINTERRUPTED 0b01111111
|
#define I2C_NOINTERRUPTED 0b01111111
|
||||||
|
|
||||||
#define I2C_ERROR_BUS_FAIL 0b00000001
|
#define I2C_ERROR 0b00000001
|
||||||
#define I2C_ERROR_NACK 0b00000010
|
|
||||||
#define I2C_ERROR_NO_ANSWER 0b00010000
|
|
||||||
#define I2C_ERROR_LOW_PRIO 0b00100000
|
#define I2C_ERROR_LOW_PRIO 0b00100000
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -214,9 +212,7 @@ void i2c_write(uint8_t data, uint8_t last_byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recover from error conditions by draining the buffer.
|
// Recover from error conditions by draining the buffer.
|
||||||
if ((i2c_state & I2C_ERROR_BUS_FAIL) ||
|
if (i2c_state & I2C_ERROR) {
|
||||||
(i2c_state & I2C_ERROR_NO_ANSWER) ||
|
|
||||||
(i2c_state & I2C_ERROR_NACK)) {
|
|
||||||
while (buf_canread(send)) {
|
while (buf_canread(send)) {
|
||||||
buf_pop(send, TWDR);
|
buf_pop(send, TWDR);
|
||||||
}
|
}
|
||||||
|
|
@ -278,21 +274,10 @@ ISR(TWI_vect) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case TW_BUS_ERROR:
|
|
||||||
// A hardware error was detected.
|
|
||||||
#ifdef TWI_INTERRUPT_DEBUG
|
|
||||||
serial_writechar('1');
|
|
||||||
#endif
|
|
||||||
i2c_state |= I2C_ERROR_BUS_FAIL;
|
|
||||||
// Let i2c_write() continue.
|
|
||||||
i2c_should_end = 0;
|
|
||||||
// Send stop condition.
|
|
||||||
TWCR = (1<<TWINT)|(I2C_MODE<<TWEA)|(0<<TWSTA)|(1<<TWSTO)|(1<<TWEN)|(0<<TWIE);
|
|
||||||
break;
|
|
||||||
case TW_START:
|
case TW_START:
|
||||||
// Start happens, send a target address.
|
// Start happens, send a target address.
|
||||||
#ifdef TWI_INTERRUPT_DEBUG
|
#ifdef TWI_INTERRUPT_DEBUG
|
||||||
serial_writechar('2');
|
serial_writechar('1');
|
||||||
#endif
|
#endif
|
||||||
if ((i2c_state & I2C_MODE_MASK) == I2C_MODE_SARP) {
|
if ((i2c_state & I2C_MODE_MASK) == I2C_MODE_SARP) {
|
||||||
i2c_address |= 0x01;
|
i2c_address |= 0x01;
|
||||||
|
|
@ -305,7 +290,7 @@ ISR(TWI_vect) {
|
||||||
case TW_REP_START:
|
case TW_REP_START:
|
||||||
// Start happens, send a target address.
|
// Start happens, send a target address.
|
||||||
#ifdef TWI_INTERRUPT_DEBUG
|
#ifdef TWI_INTERRUPT_DEBUG
|
||||||
serial_writechar('3');
|
serial_writechar('2');
|
||||||
#endif
|
#endif
|
||||||
if ((i2c_state & I2C_MODE_MASK) == I2C_MODE_ENHA) {
|
if ((i2c_state & I2C_MODE_MASK) == I2C_MODE_ENHA) {
|
||||||
i2c_address |= 0x01;
|
i2c_address |= 0x01;
|
||||||
|
|
@ -318,7 +303,7 @@ ISR(TWI_vect) {
|
||||||
case TW_MT_SLA_ACK:
|
case TW_MT_SLA_ACK:
|
||||||
// SLA+W was sent, then ACK received.
|
// SLA+W was sent, then ACK received.
|
||||||
#ifdef TWI_INTERRUPT_DEBUG
|
#ifdef TWI_INTERRUPT_DEBUG
|
||||||
serial_writechar('4');
|
serial_writechar('3');
|
||||||
#endif
|
#endif
|
||||||
if ((i2c_state & I2C_MODE_MASK) == I2C_MODE_SAWP && buf_canread(send)) {
|
if ((i2c_state & I2C_MODE_MASK) == I2C_MODE_SAWP && buf_canread(send)) {
|
||||||
buf_pop(send, TWDR);
|
buf_pop(send, TWDR);
|
||||||
|
|
@ -331,21 +316,10 @@ ISR(TWI_vect) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case TW_MT_SLA_NACK:
|
|
||||||
// SLA+W was sent, got NACK, so slave is busy or out of bus.
|
|
||||||
#ifdef TWI_INTERRUPT_DEBUG
|
|
||||||
serial_writechar('5');
|
|
||||||
#endif
|
|
||||||
i2c_state |= I2C_ERROR_NO_ANSWER;
|
|
||||||
// Let i2c_write() continue.
|
|
||||||
i2c_should_end = 0;
|
|
||||||
// Send stop condition.
|
|
||||||
TWCR = (1<<TWINT)|(I2C_MODE<<TWEA)|(0<<TWSTA)|(1<<TWSTO)|(1<<TWEN)|(0<<TWIE);
|
|
||||||
break;
|
|
||||||
case TW_MT_DATA_ACK:
|
case TW_MT_DATA_ACK:
|
||||||
// A byte was sent, got ACK.
|
// A byte was sent, got ACK.
|
||||||
#ifdef TWI_INTERRUPT_DEBUG
|
#ifdef TWI_INTERRUPT_DEBUG
|
||||||
serial_writechar('6');
|
serial_writechar('4');
|
||||||
#endif
|
#endif
|
||||||
if ((i2c_state & I2C_MODE_MASK) == I2C_MODE_SAWP) {
|
if ((i2c_state & I2C_MODE_MASK) == I2C_MODE_SAWP) {
|
||||||
if (buf_canread(send)) {
|
if (buf_canread(send)) {
|
||||||
|
|
@ -374,33 +348,6 @@ ISR(TWI_vect) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case TW_MT_DATA_NACK:
|
|
||||||
// Byte was sent but got NACK, there are two possible reasons:
|
|
||||||
// - a slave stops transmission and it is ok, or
|
|
||||||
// - a slave became crazy.
|
|
||||||
#ifdef TWI_INTERRUPT_DEBUG
|
|
||||||
serial_writechar('7');
|
|
||||||
#endif
|
|
||||||
i2c_state |= I2C_ERROR_NACK;
|
|
||||||
// Let i2c_write() continue.
|
|
||||||
i2c_should_end = 0;
|
|
||||||
// Send stop condition.
|
|
||||||
TWCR = (1<<TWINT)|(I2C_MODE<<TWEA)|(0<<TWSTA)|(1<<TWSTO)|(1<<TWEN)|(0<<TWIE);
|
|
||||||
break;
|
|
||||||
case TW_MT_ARB_LOST: // Collision, identical to TW_MR_ARB_LOST.
|
|
||||||
// It looks like there is another master on the bus.
|
|
||||||
#ifdef TWI_INTERRUPT_DEBUG
|
|
||||||
serial_writechar('8');
|
|
||||||
#endif
|
|
||||||
i2c_state |= I2C_ERROR_LOW_PRIO;
|
|
||||||
// Setup all again.
|
|
||||||
sendtail = sendhead;
|
|
||||||
#ifdef I2C_EEPROM_SUPPORT
|
|
||||||
i2c_page_index = 0;
|
|
||||||
#endif
|
|
||||||
// Try to resend when the bus became free.
|
|
||||||
TWCR = (1<<TWINT)|(I2C_MODE<<TWEA)|(1<<TWSTA)|(0<<TWSTO)|(1<<TWEN)|(1<<TWIE);
|
|
||||||
break;
|
|
||||||
|
|
||||||
#ifdef I2C_READ_SUPPORT
|
#ifdef I2C_READ_SUPPORT
|
||||||
|
|
||||||
|
|
@ -534,6 +481,39 @@ ISR(TWI_vect) {
|
||||||
|
|
||||||
#endif /* I2C_SLAVE_MODE */
|
#endif /* I2C_SLAVE_MODE */
|
||||||
|
|
||||||
|
case TW_BUS_ERROR:
|
||||||
|
// A hardware error was detected.
|
||||||
|
#ifdef TWI_INTERRUPT_DEBUG
|
||||||
|
serial_writechar('5');
|
||||||
|
#endif
|
||||||
|
case TW_MT_SLA_NACK:
|
||||||
|
// SLA+W was sent, got NACK, so slave is busy or out of bus.
|
||||||
|
#ifdef TWI_INTERRUPT_DEBUG
|
||||||
|
serial_writechar('6');
|
||||||
|
#endif
|
||||||
|
case TW_MT_DATA_NACK:
|
||||||
|
// Byte was sent but got NACK, there are two possible reasons:
|
||||||
|
// - a slave stops transmission and it is ok, or
|
||||||
|
// - a slave became crazy.
|
||||||
|
#ifdef TWI_INTERRUPT_DEBUG
|
||||||
|
serial_writechar('7');
|
||||||
|
#endif
|
||||||
|
case TW_MT_ARB_LOST:
|
||||||
|
// Collision, identical to TW_MR_ARB_LOST.
|
||||||
|
// It looks like there is another master on the bus. Handle this like
|
||||||
|
// the other error conditions, because an eventual resend is handled in
|
||||||
|
// upper layers (display code).
|
||||||
|
#ifdef TWI_INTERRUPT_DEBUG
|
||||||
|
serial_writechar('8');
|
||||||
|
#endif
|
||||||
|
|
||||||
|
i2c_state |= I2C_ERROR;
|
||||||
|
// Let i2c_write() continue.
|
||||||
|
i2c_should_end = 0;
|
||||||
|
// Send stop condition.
|
||||||
|
TWCR = (1<<TWINT)|(I2C_MODE<<TWEA)|(0<<TWSTA)|(1<<TWSTO)|(1<<TWEN)|(0<<TWIE);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
#ifdef TWI_INTERRUPT_DEBUG
|
#ifdef TWI_INTERRUPT_DEBUG
|
||||||
sendf_P(serial_writechar, PSTR("(%sx)"), status);
|
sendf_P(serial_writechar, PSTR("(%sx)"), status);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue