Rev 2109 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
#include "twimaster.h"
#include "analog.h"
#include "output.h"
#include <inttypes.h>
#include <util/twi.h>
#include <avr/interrupt.h>
uint8_t twiState;
uint8_t twiTroubleSpot;
uint8_t twiGotStatus;
volatile int16_t ITG3200SensorInputs[4];
void twimaster_init(void) {
// Set pullups OFF
uint8_t sreg = SREG;
cli();
DDRC = 0;
PORTC &= ~((1<<4) | (1<<5));
TWBR = ((F_CPU / SCL_CLOCK) - 16) / 2;
twiState = TWI_STATE_INIT_0;
SREG = sreg;
}
void I2CStart(void) {
TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN) | (1 << TWIE);
}
void I2CStop(void) {
TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN);
}
void I2CWriteByte(int8_t byte) {
TWDR = byte;
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE);
}
void I2CReceiveByte(void) {
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE) | (1 << TWEA);
}
void I2CReceiveLastByte(void) {
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE);
}
void I2CReset(void) {
debugOut.analog[29]++;
I2CStop();
TWCR = (1 << TWINT); // reset to original state incl. interrupt flag reset
TWAMR = 0;
TWAR = 0;
TWDR = 0;
TWSR = 0;
TWBR = 0;
// Naaaah we dont need this: init_I2C();
I2CStart();
twiState = TWI_STATE_INIT_0;
}
void twimaster_setNeutral(void) {
twiState = TWI_STATE_INIT_0;
I2CStart();
}
void twimaster_startCycle(void) {
if (sensorDataReady & TWI_DATA_READY) { // if OK last time
twiState = TWI_STATE_LOOP_0;
I2CStart();
} else { // go get em.
I2CReset();
}
}
const uint8_t EXPECTED_STATUS[] = { START, MT_SLA_ACK, MT_DATA_ACK,
MT_DATA_ACK, MT_DATA_ACK, REPEATED_START, MT_SLA_ACK, MT_DATA_ACK,
REPEATED_START, MR_SLA_ACK, MR_DATA_ACK, MR_DATA_ACK, MR_DATA_ACK,
MR_DATA_ACK, MR_DATA_ACK, MR_DATA_ACK, MR_DATA_ACK, MR_DATA_NACK };
const uint8_t GYRO_CONFIGURATION[] = { 15, 3 << 3 };
ISR( TWI_vect) {
if (twiState == sizeof(EXPECTED_STATUS)) {
// We have come too far, panic!
I2CReset();
}
uint8_t cur_twi_state = twiState;
twiState++;
uint8_t status = TWSR_FILTER;
if (status != EXPECTED_STATUS[cur_twi_state]) {
// A little confusion between repeated and nonrepeated start is OK.
if (!((status == START && EXPECTED_STATUS[cur_twi_state]
== REPEATED_START) || (status == REPEATED_START
&& EXPECTED_STATUS[cur_twi_state] == START))) {
// Panic, reset
twiTroubleSpot = cur_twi_state;
twiGotStatus = status;
I2CReset();
}
}
uint8_t dataIndex = cur_twi_state - TWI_STATE_LOOP_0 - 5;
// Fix endiannness!
if (dataIndex & 1)
dataIndex &= ~1;
else
dataIndex |= 1;
switch (cur_twi_state) {
case TWI_STATE_INIT_0:
I2CWriteByte((SLA << 1) | 0);
break;
case TWI_STATE_INIT_0 + 1:
I2CWriteByte(GYRO_CONFIGURATION_START);
break;
case TWI_STATE_INIT_0 + 2:
I2CWriteByte(GYRO_CONFIGURATION[0]);
break;
case TWI_STATE_INIT_0 + 3:
I2CWriteByte(GYRO_CONFIGURATION[1]);
break;
case TWI_STATE_INIT_0 + 4:
I2CStop();
// Need to check ACK ans return to 0 if not (skipping start below).
I2CStart();
break;
case TWI_STATE_LOOP_0:
I2CWriteByte((SLA << 1) | 0);
break;
case TWI_STATE_LOOP_0 + 1:
I2CWriteByte(GYRO_DATA_START);
break;
case TWI_STATE_LOOP_0 + 2:
I2CStop();
I2CStart();
break;
case TWI_STATE_LOOP_0 + 3:
I2CWriteByte((SLA << 1) | 1);
break;
case TWI_STATE_LOOP_0 + 4:
I2CReceiveByte();
break;
default: // data bytes
((uint8_t*) ITG3200SensorInputs)[dataIndex] = TWDR;
if (twiState < TWI_STATE_LOOP_0 + 5 + sizeof(ITG3200SensorInputs) - 1)
I2CReceiveByte();
else
I2CReceiveLastByte();
break;
case TWI_STATE_LOOP_0 + 5 + sizeof(ITG3200SensorInputs) - 1: // last data byte
((uint8_t*) ITG3200SensorInputs)[dataIndex] = TWDR;
// Dont re-init the gyro but just restart the loop.
I2CStop();
sensorDataReady |= TWI_DATA_READY;
debugOut.analog[28]++;
break;
}
}