diff --git a/hardware/arduino/avr/libraries/Wire/utility/twi.c b/hardware/arduino/avr/libraries/Wire/utility/twi.c index 201d7d1bbbf..b0130b9aa01 100644 --- a/hardware/arduino/avr/libraries/Wire/utility/twi.c +++ b/hardware/arduino/avr/libraries/Wire/utility/twi.c @@ -59,7 +59,9 @@ static volatile uint8_t twi_rxBufferIndex; static volatile uint8_t twi_error; -/* +volatile uint32_t twi_iter_count; + +/* * Function twi_init * Desc readys twi pins and sets twi bitrate * Input none @@ -71,7 +73,7 @@ void twi_init(void) twi_state = TWI_READY; twi_sendStop = true; // default value twi_inRepStart = false; - + // activate internal pullups for twi. digitalWrite(SDA, 1); digitalWrite(SCL, 1); @@ -90,7 +92,7 @@ void twi_init(void) TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA); } -/* +/* * Function twi_slaveInit * Desc sets slave address and enables interrupt * Input none @@ -102,7 +104,7 @@ void twi_setAddress(uint8_t address) TWAR = address << 1; } -/* +/* * Function twi_readFrom * Desc attempts to become twi bus master and read a * series of bytes from a device on the bus @@ -122,7 +124,8 @@ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sen } // wait until twi is ready, become master receiver - while(TWI_READY != twi_state){ + twi_timeout_guard(1); + while((TWI_READY != twi_state) && !twi_timeout_guard(0)){ continue; } twi_state = TWI_MRX; @@ -134,7 +137,7 @@ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sen twi_masterBufferIndex = 0; twi_masterBufferLength = length-1; // This is not intuitive, read on... // On receive, the previously configured ACK/NACK setting is transmitted in - // response to the received byte before the interrupt is signalled. + // response to the received byte before the interrupt is signalled. // Therefor we must actually set NACK when the _next_ to last byte is // received, causing that NACK to be sent in response to receiving the last // expected byte of data. @@ -148,7 +151,7 @@ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sen // (@@@ we hope), and the TWI statemachine is just waiting for the address byte. // We need to remove ourselves from the repeated start state before we enable interrupts, // since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning - // up. Also, don't enable the START interrupt. There may be one pending from the + // up. Also, don't enable the START interrupt. There may be one pending from the // repeated start that we sent outselves, and that would really confuse things. twi_inRepStart = false; // remember, we're dealing with an ASYNC ISR TWDR = twi_slarw; @@ -159,7 +162,8 @@ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sen TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA); // wait for read operation to complete - while(TWI_MRX == twi_state){ + twi_timeout_guard(1); + while((TWI_MRX == twi_state) && !twi_timeout_guard(0)){ continue; } @@ -170,11 +174,11 @@ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sen for(i = 0; i < length; ++i){ data[i] = twi_masterBuffer[i]; } - + return length; } -/* +/* * Function twi_writeTo * Desc attempts to become twi bus master and write a * series of bytes to a device on the bus @@ -199,7 +203,8 @@ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait } // wait until twi is ready, become master transmitter - while(TWI_READY != twi_state){ + twi_timeout_guard(1); + while((TWI_READY != twi_state) && !twi_timeout_guard(0)){ continue; } twi_state = TWI_MTX; @@ -210,16 +215,16 @@ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait // initialize buffer iteration vars twi_masterBufferIndex = 0; twi_masterBufferLength = length; - + // copy data to twi buffer for(i = 0; i < length; ++i){ twi_masterBuffer[i] = data[i]; } - + // build sla+w, slave device address + w bit twi_slarw = TW_WRITE; twi_slarw |= address << 1; - + // if we're in a repeated start, then we've already sent the START // in the ISR. Don't do it again. // @@ -228,10 +233,10 @@ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait // (@@@ we hope), and the TWI statemachine is just waiting for the address byte. // We need to remove ourselves from the repeated start state before we enable interrupts, // since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning - // up. Also, don't enable the START interrupt. There may be one pending from the + // up. Also, don't enable the START interrupt. There may be one pending from the // repeated start that we sent outselves, and that would really confuse things. twi_inRepStart = false; // remember, we're dealing with an ASYNC ISR - TWDR = twi_slarw; + TWDR = twi_slarw; TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE); // enable INTs, but not START } else @@ -239,10 +244,11 @@ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTA); // enable INTs // wait for write operation to complete - while(wait && (TWI_MTX == twi_state)){ + twi_timeout_guard(1); + while((wait && (TWI_MTX == twi_state)) && !twi_timeout_guard(0)){ continue; } - + if (twi_error == 0xFF) return 0; // success else if (twi_error == TW_MT_SLA_NACK) @@ -253,7 +259,7 @@ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait return 4; // other twi error } -/* +/* * Function twi_transmit * Desc fills slave tx buffer with data * must be called in slave tx event callback @@ -271,22 +277,22 @@ uint8_t twi_transmit(const uint8_t* data, uint8_t length) if(TWI_BUFFER_LENGTH < length){ return 1; } - + // ensure we are currently a slave transmitter if(TWI_STX != twi_state){ return 2; } - + // set length and copy data into tx buffer twi_txBufferLength = length; for(i = 0; i < length; ++i){ twi_txBuffer[i] = data[i]; } - + return 0; } -/* +/* * Function twi_attachSlaveRxEvent * Desc sets function called before a slave read operation * Input function: callback function to use @@ -297,7 +303,7 @@ void twi_attachSlaveRxEvent( void (*function)(uint8_t*, int) ) twi_onSlaveReceive = function; } -/* +/* * Function twi_attachSlaveTxEvent * Desc sets function called before a slave write operation * Input function: callback function to use @@ -308,7 +314,7 @@ void twi_attachSlaveTxEvent( void (*function)(void) ) twi_onSlaveTransmit = function; } -/* +/* * Function twi_reply * Desc sends byte or readys receive line * Input ack: byte indicating to ack or to nack @@ -324,7 +330,7 @@ void twi_reply(uint8_t ack) } } -/* +/* * Function twi_stop * Desc relinquishes bus master status * Input none @@ -337,7 +343,8 @@ void twi_stop(void) // wait for stop condition to be exectued on bus // TWINT is not set after a stop condition! - while(TWCR & _BV(TWSTO)){ + twi_timeout_guard(1); + while((TWCR & _BV(TWSTO)) && !twi_timeout_guard(0)){ continue; } @@ -345,7 +352,7 @@ void twi_stop(void) twi_state = TWI_READY; } -/* +/* * Function twi_releaseBus * Desc releases bus control * Input none @@ -374,7 +381,7 @@ ISR(TWI_vect) // Master Transmitter case TW_MT_SLA_ACK: // slave receiver acked address case TW_MT_DATA_ACK: // slave receiver acked data - // if there is data to send, send it, otherwise stop + // if there is data to send, send it, otherwise stop if(twi_masterBufferIndex < twi_masterBufferLength){ // copy data to output register and ack TWDR = twi_masterBuffer[twi_masterBufferIndex++]; @@ -384,7 +391,7 @@ ISR(TWI_vect) twi_stop(); else { twi_inRepStart = true; // we're gonna send the START - // don't enable the interrupt. We'll generate the start, but we + // don't enable the interrupt. We'll generate the start, but we // avoid handling the interrupt until we're in the next transaction, // at the point where we would normally issue the start. TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ; @@ -424,12 +431,12 @@ ISR(TWI_vect) twi_stop(); else { twi_inRepStart = true; // we're gonna send the START - // don't enable the interrupt. We'll generate the start, but we + // don't enable the interrupt. We'll generate the start, but we // avoid handling the interrupt until we're in the next transaction, // at the point where we would normally issue the start. TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ; twi_state = TWI_READY; - } + } break; case TW_MR_SLA_NACK: // address sent, nack received twi_stop(); @@ -478,7 +485,7 @@ ISR(TWI_vect) // nack back at master twi_reply(0); break; - + // Slave Transmitter case TW_ST_SLA_ACK: // addressed, returned ack case TW_ST_ARB_LOST_SLA_ACK: // arbitration lost, returned ack @@ -507,7 +514,7 @@ ISR(TWI_vect) twi_reply(0); } break; - case TW_ST_DATA_NACK: // received nack, we are done + case TW_ST_DATA_NACK: // received nack, we are done case TW_ST_LAST_DATA: // received ack, but we are done already! // ack future responses twi_reply(1); @@ -525,3 +532,20 @@ ISR(TWI_vect) } } +uint8_t twi_timeout_guard(uint8_t init) +{ + if(init) + twi_iter_count = 0; + else + { + twi_iter_count++; + if(twi_iter_count > TWI_MAX_ITERS) + { + twi_init(); + TWCR = 0; + return 1; + } + } + return 0; +} + diff --git a/hardware/arduino/avr/libraries/Wire/utility/twi.h b/hardware/arduino/avr/libraries/Wire/utility/twi.h index 6526593394e..6830c88886a 100644 --- a/hardware/arduino/avr/libraries/Wire/utility/twi.h +++ b/hardware/arduino/avr/libraries/Wire/utility/twi.h @@ -37,7 +37,9 @@ #define TWI_MTX 2 #define TWI_SRX 3 #define TWI_STX 4 - + + #define TWI_MAX_ITERS 100000UL + void twi_init(void); void twi_setAddress(uint8_t); uint8_t twi_readFrom(uint8_t, uint8_t*, uint8_t, uint8_t); @@ -48,6 +50,7 @@ void twi_reply(uint8_t); void twi_stop(void); void twi_releaseBus(void); + uint8_t twi_timeout_guard(uint8_t); #endif