-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathtwi.c
140 lines (110 loc) · 2.47 KB
/
twi.c
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/twi.h>
#include <string.h>
#include "twi.h"
static volatile uint8_t busy;
static struct {
uint8_t buffer[TWI_BUFFER_LENGTH];
uint8_t length;
uint8_t index;
void (*callback)(uint8_t, uint8_t *);
} transmission;
void twi_init() {
TWBR = ((F_CPU / TWI_FREQ) - 16) / 2;
TWSR = 0; // prescaler = 1
busy = 0;
sei();
TWCR = _BV(TWEN);
}
uint8_t *twi_wait() {
while (busy);
return &transmission.buffer[1];
}
void twi_start(void) {
TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTA);
}
void twi_stop(void) {
TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWSTO);
}
void twi_ack() {
TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
}
void twi_nack() {
TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE);
}
void twi_send(uint8_t data) {
TWDR = data;
}
void twi_recv() {
transmission.buffer[transmission.index++] = TWDR;
}
void twi_reply() {
if (transmission.index < (transmission.length - 1)) {
twi_ack();
} else {
twi_nack();
}
}
void twi_done() {
uint8_t address = transmission.buffer[0] >> 1;
uint8_t *data = &transmission.buffer[1];
busy = 0;
if (transmission.callback != NULL) {
transmission.callback(address, data);
}
}
void twi_write(uint8_t address, uint8_t* data, uint8_t length, void (*callback)(uint8_t, uint8_t *)) {
twi_wait();
busy = 1;
transmission.buffer[0] = (address << 1) | TW_WRITE;
transmission.length = length + 1;
transmission.index = 0;
transmission.callback = callback;
memcpy(&transmission.buffer[1], data, length);
twi_start();
}
void twi_read(uint8_t address, uint8_t length, void (*callback)(uint8_t, uint8_t *)) {
twi_wait();
busy = 1;
transmission.buffer[0] = (address << 1) | TW_READ;
transmission.length = length + 1;
transmission.index = 0;
transmission.callback = callback;
twi_start();
}
ISR(TWI_vect) {
switch (TW_STATUS) {
case TW_START:
case TW_REP_START:
case TW_MT_SLA_ACK:
case TW_MT_DATA_ACK:
if (transmission.index < transmission.length) {
twi_send(transmission.buffer[transmission.index++]);
twi_nack();
} else {
twi_stop();
twi_done();
}
break;
case TW_MR_DATA_ACK:
twi_recv();
twi_reply();
break;
case TW_MR_SLA_ACK:
twi_reply();
break;
case TW_MR_DATA_NACK:
twi_recv();
twi_stop();
twi_done();
break;
case TW_MT_SLA_NACK:
case TW_MR_SLA_NACK:
case TW_MT_DATA_NACK:
default:
twi_stop();
twi_done();
break;
}
}