summaryrefslogtreecommitdiffstats
path: root/i2c.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'i2c.cpp')
-rw-r--r--i2c.cpp148
1 files changed, 148 insertions, 0 deletions
diff --git a/i2c.cpp b/i2c.cpp
new file mode 100644
index 0000000..61450fa
--- /dev/null
+++ b/i2c.cpp
@@ -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;
+}