summaryrefslogtreecommitdiff
path: root/src/i2c.cc
blob: 37af10406048a0e3d833e792309645ef37f26e93 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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);
}