2
0
Jack Humbert 8 лет назад
Родитель
Сommit
f0a425c537
2 измененных файлов с 232 добавлено и 0 удалено
  1. 228 0
      drivers/avr/twi.c
  2. 4 0
      drivers/avr/twi.h

+ 228 - 0
drivers/avr/twi.c

@@ -0,0 +1,228 @@
+#include <avr/io.h>
+#include <util/twi.h>
+#include <avr/interrupt.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include "twi.h"
+
+#ifndef F_SCL
+    #define F_SCL 100000UL // SCL frequency
+#endif
+#ifndef PRESCALER
+    #define PRESCALER 1
+#endif
+
+// Limits the amount of we wait for any one i2c transaction.
+// Since were running SCL line 100kHz (=> 10μs/bit), and each transactions is
+// 9 bits, a single transaction will take around 90μs to complete.
+//
+// (F_CPU/SCL_CLOCK)  =>  # of μC cycles to transfer a bit
+// poll loop takes at least 8 clock cycles to execute
+
+#ifdef TWI_TIMEOUT
+    #ifndef TWI_TX_SIZE
+        #define TWI_TX_SIZE 9
+    #endif
+#endif
+
+// Wait for an twi operation to finish
+inline static
+void twi_wait(uint8_t status) {
+    #ifdef TWI_TIMEOUT
+        uint16_t lim = 0;
+        while ( !(TWCR & (_BV(status))) && lim < (TWI_TX_SIZE+1)*(F_CPU/F_SCL)/8)
+            lim++;
+    #else 
+        while ( !(TWCR & (_BV(status))) );
+    #endif
+}
+
+void twi_master_init(void) {
+    TWBR = (uint8_t) ((((F_CPU / F_SCL) / PRESCALER) - 16 ) / 2);
+}
+
+void twi_slave_init(uint8_t address) {
+    TWAR = address << 0; // slave i2c address
+    TWCR = _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWEN);
+}
+
+uint8_t twi_master_start(uint8_t address) {
+    // reset TWI control register and transmit start
+    TWCR = 0;
+    TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWSTA);
+
+    twi_wait(TWINT);
+    
+    // check if the start condition was successfully transmitted
+    if (TW_STATUS != TW_START)
+        return 1;
+    
+    // set slave address and transmit
+    TWDR = address;
+    TWCR = _BV(TWINT) | _BV(TWEN);
+
+    twi_wait(TWINT);
+
+    // check if the device has acknowledged the READ / WRITE mode
+    if ( (TW_STATUS != TW_MT_SLA_ACK) && (TW_STATUS != TW_MR_SLA_ACK) ) 
+        return 1;
+    
+    return 0;
+}
+
+void twi_master_stop(void) {
+    // transmit STOP condition
+    TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWSTO);
+
+    twi_wait(TWSTO);
+}
+
+uint8_t twi_write(uint8_t data) {
+    // load data into data register and start transmission of data
+    TWDR = data;
+    TWCR = _BV(TWINT) | _BV(TWEN);
+
+    twi_wait(TWINT);
+    
+    if ( TW_STATUS != TW_MT_DATA_ACK )
+        return 1;
+    
+    return 0;
+}
+
+uint8_t twi_read(bool ack) {
+    // start TWI module and acknowledge data after reception
+    if (ack)
+        TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWEA); 
+    else
+        TWCR = _BV(TWINT) | _BV(TWEN);
+    
+    twi_wait(TWINT);
+
+    return TWDR;
+}
+
+uint8_t twi_transmit(uint8_t address, uint8_t* data, uint16_t length) {
+    if (twi_start(address | TW_WRITE)) 
+        return 1;
+    
+    for (uint16_t i = 0; i < length; i++) {
+        if (twi_write(data[i])) 
+            return 1;
+    }
+    
+    twi_stop();
+    
+    return 0;
+}
+
+uint8_t twi_receive(uint8_t address, uint8_t* data, uint16_t length) {
+    if (twi_start(address | TW_READ)) 
+        return 1;
+    
+    for (uint16_t i = 0; i < (length-1); i++) {
+        data[i] = twi_read(true);
+    }
+    data[(length-1)] = twi_read(false);
+    
+    twi_stop();
+    
+    return 0;
+}
+
+uint8_t twi_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length) {
+    if (twi_start(devaddr | TW_WRITE)) 
+        return 1;
+
+    twi_write(regaddr);
+
+    for (uint16_t i = 0; i < length; i++) {
+        if (twi_write(data[i])) 
+            return 1;
+    }
+
+    twi_stop();
+
+    return 0;
+}
+
+uint8_t twi_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length)
+{
+    if (twi_start(devaddr)) 
+        return 1;
+
+    twi_write(regaddr);
+
+    if (twi_start(devaddr | TW_READ)) 
+        return 1;
+
+    for (uint16_t i = 0; i < (length-1); i++) {
+        data[i] = twi_read(true);
+    }
+    data[(length-1)] = twi_read(false);
+
+    twi_stop();
+
+    return 0;
+}
+
+uint8_t buffer_address = 0;
+
+ISR(TWI_vect) {
+    uint8_t data;
+    switch (TW_STATUS) {
+        case TW_SR_SLA_ACK:
+            buffer_address = 0xff;
+            TWCR |= _BV(TWIE) | _BV(TWINT) | _BV(TWEA) | _BV(TWEN);
+            break;
+        case TW_SR_DATA_ACK:
+            data = TWDR;
+            if (buffer_address == 0xff) {
+                // store address to read from later
+                buffer_address = data;
+                TWCR |= _BV(TWIE) | _BV(TWINT) | _BV(TWEA) | _BV(TWEN);
+            } else {
+                // store data from address and increment
+                rxbuffer[buffer_address] = data;
+                buffer_address++;
+
+                if (buffer_address < 0xFF) {
+                    // ack
+                    TWCR |= _BV(TWIE) | _BV(TWINT) | _BV(TWEA) | _BV(TWEN);
+                } else {
+                    // nack
+                    TWCR &= ~_BV(TWEA);
+                    TWCR |= _BV(TWIE) | _BV(TWINT) | _BV(TWEN);
+                }
+
+            }
+            break;
+        case TW_ST_SLA_ACK:
+        case TW_ST_DATA_ACK:
+            data = TWDR;
+
+            if (buffer_address == 0xFF) {
+                buffer_address = data;
+            }
+
+            TWDR = txbuffer[buffer_address];
+            buffer_address++;
+
+
+            if (buffer_address < 0xFF) {
+                // ack
+                TWCR |= _BV(TWIE) | _BV(TWINT) | _BV(TWEA) | _BV(TWEN);
+            } else {
+                // nack
+                TWCR &= ~_BV(TWEA);
+                TWCR |= _BV(TWIE) | _BV(TWINT) | _BV(TWEN);
+            }
+            break;
+        case TW_BUS_ERROR:
+            TWCR = 0;
+            break;
+        default:
+            TWCR |= _BV(TWIE) | _BV(TWEA) | _BV(TWEN);
+            break;
+    }
+}

+ 4 - 0
drivers/avr/twi.h

@@ -0,0 +1,4 @@
+#ifndef TWI_H
+#define TWI_H
+
+#endif