diff options
Diffstat (limited to 'i2c.cpp')
-rw-r--r-- | i2c.cpp | 148 |
1 files changed, 148 insertions, 0 deletions
@@ -0,0 +1,148 @@ +#include "i2c.h" + +#include <util/twi.h> + + +static bool I2CStartSend(uint8_t addr); +static bool I2CStartRecv(uint8_t addr); +static void I2CStop(); + + +static bool I2CStartSend(uint8_t addr) { + TWCR = (1<<TWEN)|(1<<TWINT)|(1<<TWSTA); + + while(!(TWCR & (1<<TWINT))); + + if (TW_STATUS != TW_START) return false; + + TWDR = (addr&0xFE); + TWCR = (1<<TWEN)|(1<<TWINT); + + while(!(TWCR & (1<<TWINT))); + + if(TW_STATUS == TW_MT_SLA_ACK) + return true; + + I2CStop(); + return false; +} + +static bool I2CStartRecv(uint8_t addr) { + TWCR = (1<<TWEN)|(1<<TWINT)|(1<<TWSTA); + + while(!(TWCR & (1<<TWINT))); + + if (TW_STATUS != TW_START) return false; + + TWDR = (addr|1); + TWCR = (1<<TWEN)|(1<<TWINT); + + while(!(TWCR & (1<<TWINT))); + + if(TW_STATUS == TW_MR_SLA_ACK) + return true; + + I2CStop(); + return false; +} + +static void I2CStop() { + TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); +} + + +void initI2C() { + TWBR = 10; + TWCR = (1<<TWEN); + TWSR = 0; +} + +bool I2CSendByte(uint8_t addr, uint8_t data) { + if(!I2CStartSend(addr)) return false; + + TWDR=data; + + TWCR = (1<<TWEN)|(1<<TWINT); + while(!(TWCR & (1<<TWINT))); + + if(TW_STATUS != TW_MT_DATA_ACK) { + I2CStop(); + return false; + } + + I2CStop(); + return true; +} + +bool I2CSend(uint8_t addr, uint8_t *data, int length) { + if(!I2CStartSend(addr)) return false; + + for(int i = 0; i < length; i++) { + TWDR=data[i]; + + TWCR = (1<<TWEN)|(1<<TWINT); + while(!(TWCR & (1<<TWINT))); + + if(TW_STATUS != TW_MT_DATA_ACK) { + I2CStop(); + return false; + } + } + + I2CStop(); + return true; +} + +bool I2CRecvByte(uint8_t addr, uint8_t *data) { + if(!I2CStartRecv(addr)) return false; + + while(!(TWCR & (1<<TWINT))); + + if(TW_STATUS != TW_MR_DATA_ACK && TW_STATUS != TW_MR_DATA_NACK) { + I2CStop(); + return false; + } + + *data = TWDR; + TWCR = (1<<TWEN)|(1<<TWINT); + + I2CStop(); + return true; +} + +int I2CRecv(uint8_t addr, uint8_t *data, int length) { + if(!I2CStartRecv(addr)) return -1; + + for(int i = 0; i < length-1; i++) { + while(!(TWCR & (1<<TWINT))); + + switch(TW_STATUS) { + case TW_MR_DATA_ACK: + data[i] = TWDR; + TWCR = (1<<TWEN)|(1<<TWINT)|(1<<TWEA); + break; + case TW_MR_DATA_NACK: + data[i] = TWDR; + TWCR = (1<<TWEN)|(1<<TWINT); + I2CStop(); + return i+1; + default: + I2CStop(); + return -1; + } + } + + while(!(TWCR & (1<<TWINT))); + + switch(TW_STATUS) { + case TW_MR_DATA_ACK: + case TW_MR_DATA_NACK: + data[length-1] = TWDR; + TWCR = (1<<TWEN)|(1<<TWINT); + I2CStop(); + return length; + } + + I2CStop(); + return -1; +} |