/* * Function twi_readFrom * Desc attempts to become twi bus master and read a * series of bytes from a device on the bus * Input address: 7bit i2c device address * data: pointer to byte array * length: number of bytes to read into array * Output number of bytes read */ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length) { uint8_t i; // ensure data will fit into buffer if(TWI_BUFFER_LENGTH < length){ return 0; } // wait until twi is ready, become master receiver twi_tout(1);//Ini TimeOut while(TWI_READY != twi_state){ if (twi_tout(0)) break; continue; } twi_state = TWI_MRX; // reset error state (0xFF.. no error occured) twi_error = 0xFF; // initialize buffer iteration vars 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. // 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. // build sla+w, slave device address + w bit twi_slarw = TW_READ; twi_slarw |= address << 1; // send start condition TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA); // wait for read operation to complete twi_tout(1); while(TWI_MRX == twi_state){ if (twi_tout(0)) break; continue; } if (twi_masterBufferIndex < length) length = twi_masterBufferIndex; // copy twi buffer to data 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 * Input address: 7bit i2c device address * data: pointer to byte array * length: number of bytes in array * wait: boolean indicating to wait for write or not * Output 0 .. success * 1 .. length to long for buffer * 2 .. address send, NACK received * 3 .. data send, NACK received * 4 .. other twi error (lost bus arbitration, bus error, ..) */ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait) { uint8_t i; // ensure data will fit into buffer if(TWI_BUFFER_LENGTH < length){ return 1; } // wait until twi is ready, become master transmitter twi_tout(1); while(TWI_READY != twi_state){ if (twi_tout(0)) return 5; continue; } twi_state = TWI_MTX; // reset error state (0xFF.. no error occured) twi_error = 0xFF; // 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; // send start condition TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA); // wait for write operation to complete twi_tout(1); while(wait && (TWI_MTX == twi_state)){ if (twi_tout(0)) return 5; continue; } if (twi_error == 0xFF) return 0; // success else if (twi_error == TW_MT_SLA_NACK) return 2; // error: address send, nack received else if (twi_error == TW_MT_DATA_NACK) return 3; // error: data send, nack received else return 4; // other twi error }
/* * Function twi_stop * Desc relinquishes bus master status * Input none * Output none */ void twi_stop(void) { // send stop condition TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO); // wait for stop condition to be exectued on bus // TWINT is not set after a stop condition! twi_tout(1); while(TWCR & _BV(TWSTO)){ if (twi_tout(0)) break; continue; } // update twi state twi_state = TWI_READY; }
/* * Function twi_writeTo * Desc attempts to become twi bus master and write a * series of bytes to a device on the bus * Input address: 7bit i2c device address * data: pointer to byte array * length: number of bytes in array * wait: boolean indicating to wait for write or not * sendStop: boolean indicating whether or not to send a stop at the end * Output 0 .. success * 1 .. length to long for buffer * 2 .. address send, NACK received * 3 .. data send, NACK received * 4 .. other twi error (lost bus arbitration, bus error, ..) * 5 .. timed out while trying to become Bus Master * 6 .. timed out while waiting for data to be sent */ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait, uint8_t sendStop) { uint8_t i; // ensure data will fit into buffer if(TWI_BUFFER_LENGTH < length){ return 1; } // wait until twi is ready, become master transmitter twi_tout(1); while(TWI_READY != twi_state){ if (twi_tout(0)) return 5; //timed out while trying to become Bus Master continue; } twi_state = TWI_MTX; twi_sendStop = sendStop; // reset error state (0xFF.. no error occured) twi_error = 0xFF; // 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. // if (true == twi_inRepStart) { // if we're in the repeated start state, then we've already sent the start, // (@@@ 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 // 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; TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE); // enable INTs, but not START } else // send start condition TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTA); // enable INTs // wait for write operation to complete twi_tout(1); while(wait && (TWI_MTX == twi_state)){ if (twi_tout(0)) return 6; //timed out while waiting for data to be sent continue; } if (twi_error == 0xFF) return 0; // success else if (twi_error == TW_MT_SLA_NACK) return 2; // error: address send, nack received else if (twi_error == TW_MT_DATA_NACK) return 3; // error: data send, nack received else return 4; // other twi error }
/* * Function twi_readFrom * Desc attempts to become twi bus master and read a * series of bytes from a device on the bus * Input address: 7bit i2c device address * data: pointer to byte array * length: number of bytes to read into array * sendStop: Boolean indicating whether to send a stop at the end * Output number of bytes read */ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop) { uint8_t i; // ensure data will fit into buffer if(TWI_BUFFER_LENGTH < length){ return 0; } // wait until twi is ready, become master receiver twi_tout(1); while(TWI_READY != twi_state){ if (twi_tout(0)) break; //timed out waiting for twi to become ready continue; } twi_state = TWI_MRX; twi_sendStop = sendStop; // reset error state (0xFF.. no error occured) twi_error = 0xFF; // initialize buffer iteration vars 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. // 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. // build sla+w, slave device address + w bit twi_slarw = TW_READ; twi_slarw |= address << 1; if (true == twi_inRepStart) { // if we're in the repeated start state, then we've already sent the start, // (@@@ 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 // 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; TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE); // enable INTs, but not START } else // send start condition TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA); // wait for read operation to complete twi_tout(1); while(TWI_MRX == twi_state){ if (twi_tout(0)) break; //Timeout during read operation continue; } if (twi_masterBufferIndex < length) length = twi_masterBufferIndex; // copy twi buffer to data for(i = 0; i < length; ++i){ data[i] = twi_masterBuffer[i]; } return length; }