diff options
author | Daniel Friesel <derf@finalrewind.org> | 2016-01-24 16:42:58 +0100 |
---|---|---|
committer | Daniel Friesel <derf@finalrewind.org> | 2016-01-24 16:42:58 +0100 |
commit | d6b2c7707b92f6daada2577dac51ba226f7b5046 (patch) | |
tree | 8cbf1c696da5363cf3c9451f27a6fa833202bb38 /src/i2c.cc | |
parent | b69f2a177a4613d1d9ccf93b5fe2f7dff68f468a (diff) |
I2C proof of concept: works!
Diffstat (limited to 'src/i2c.cc')
-rw-r--r-- | src/i2c.cc | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/src/i2c.cc b/src/i2c.cc new file mode 100644 index 0000000..37af104 --- /dev/null +++ b/src/i2c.cc @@ -0,0 +1,57 @@ +#include <avr/io.h> +#include <avr/interrupt.h> +#include <util/delay.h> +#include <stdlib.h> + +#include "i2c.h" + +I2C i2c; + +void I2C::enable() +{ + /* + * Set I2C clock frequency to 100kHz. + * freq = F_CPU / (16 + (2 * TWBR * TWPS) ) + * let TWPS = "00" = 1 + * -> TWBR = (F_CPU / 100000) - 16 / 2 + */ + TWSR = 0; // the lower two bits control TWPS + TWBR = ((F_CPU / 100000UL) - 16) / 2; +} + +// TODO Everything[tm] (error handling and generic code) +// Also TODO: Use interrupts instead of polling +void I2C::xmit(int num_tx, int num_rx, uint8_t *txbuf, uint8_t *rxbuf) +{ + int i; + + if (num_tx) { + TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); + while (!(TWCR & _BV(TWINT))); + TWDR = (I2C_EEPROM_ADDR << 1) | 0; + TWCR = _BV(TWINT) | _BV(TWEN); + while (!(TWCR & _BV(TWINT))); + for (i = 0; i < num_tx; i++) { + TWDR = txbuf[i]; + TWCR = _BV(TWINT) | _BV(TWEN); + while (!(TWCR & _BV(TWINT))); + } + } + if (num_rx) { + TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); + while (!(TWCR & _BV(TWINT))); + TWDR = (I2C_EEPROM_ADDR << 1) | 1; + TWCR = _BV(TWINT) | _BV(TWEN); + while (!(TWCR & _BV(TWINT))); + for (i = 0; i < num_rx; i++) { + if (i == num_rx-1) { + TWCR = _BV(TWINT) | _BV(TWEN); + } else { + TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWEA); + } + while (!(TWCR & _BV(TWINT))); + rxbuf[i] = TWDR; + } + } + TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); +} |