root / trunk / code / projects / colonet / utilities / robot_slave / i2c.c @ 13
History | View | Annotate | Download (2.71 KB)
1 |
/* I2C.c
|
---|---|
2 |
|
3 |
*/
|
4 |
|
5 |
#include <avr/interrupt.h> |
6 |
#include <util/twi.h> |
7 |
|
8 |
#include "i2c.h" |
9 |
#include "ring_buffer.h" |
10 |
|
11 |
|
12 |
static int start_flag; |
13 |
RING_BUFFER_NEW(i2c_buffer, 64, char, i2c_write_buff, i2c_addr_buff, i2c_read_buff); |
14 |
|
15 |
void i2c_init(char address) { |
16 |
// Enable I2C and turn on the interrupt
|
17 |
//TWCR = 0;
|
18 |
|
19 |
/* initialize the buffers */
|
20 |
RING_BUFFER_CLEAR(i2c_write_buff); |
21 |
RING_BUFFER_CLEAR(i2c_addr_buff); |
22 |
RING_BUFFER_CLEAR(i2c_read_buff); |
23 |
|
24 |
TWCR = (_BV(TWEA) | _BV(TWEN) | _BV(TWIE)); |
25 |
|
26 |
//Set bit rate 12 = 100kbit/s
|
27 |
TWBR = 0x0C;
|
28 |
|
29 |
TWAR = (address << 1); //0b0000001 address, 0 for global commands to be off |
30 |
|
31 |
//usb_putint(TWAR);
|
32 |
//i2cTXFlag = 0;
|
33 |
//i2cRXFlag = 0;
|
34 |
} |
35 |
|
36 |
char i2c_putc(char dest, char data) { |
37 |
if(RING_BUFFER_FULL(i2c_write_buff))
|
38 |
return -1; |
39 |
|
40 |
cli(); |
41 |
RING_BUFFER_ADD(i2c_write_buff, data); |
42 |
RING_BUFFER_ADD(i2c_addr_buff, dest << 1);
|
43 |
sei(); |
44 |
|
45 |
//Start bit
|
46 |
if(!start_flag) {
|
47 |
start_flag = 1;
|
48 |
TWCR |= _BV(TWSTA); |
49 |
TWCR |= _BV(TWINT); |
50 |
} |
51 |
|
52 |
return 0; |
53 |
} |
54 |
|
55 |
char i2c_getc(char * c) { |
56 |
if(RING_BUFFER_EMPTY(i2c_read_buff))
|
57 |
return -1; |
58 |
else
|
59 |
RING_BUFFER_REMOVE(i2c_read_buff, *c); |
60 |
|
61 |
return 0; |
62 |
} |
63 |
|
64 |
ISR(TWI_vect) { |
65 |
static char data_to_send; |
66 |
static char addr_to_send = -1; |
67 |
char addr, statusCode;
|
68 |
|
69 |
//Get status code (only upper 5 bits)
|
70 |
statusCode = (TWSR & 0xF8);
|
71 |
|
72 |
switch (statusCode) {
|
73 |
//Start sent successfully
|
74 |
case TW_START:
|
75 |
case TW_REP_START:
|
76 |
//Send address and write
|
77 |
//ring_buffer will not be empty
|
78 |
RING_BUFFER_REMOVE(i2c_addr_buff, addr_to_send); |
79 |
RING_BUFFER_REMOVE(i2c_write_buff, data_to_send); |
80 |
|
81 |
TWDR = addr_to_send; /* first send the address */
|
82 |
/* we will send the data next time around */
|
83 |
|
84 |
//Turn off start bits
|
85 |
TWCR &= ~_BV(TWSTA); |
86 |
break;
|
87 |
//Address sent successfully
|
88 |
case TW_MT_SLA_ACK:
|
89 |
//Send byte
|
90 |
TWDR = data_to_send; |
91 |
break;
|
92 |
//Packet complete, close line
|
93 |
case TW_MT_DATA_ACK:
|
94 |
if(!RING_BUFFER_EMPTY(i2c_write_buff)) {
|
95 |
RING_BUFFER_PEEK(i2c_addr_buff, addr); |
96 |
if(addr == addr_to_send) {
|
97 |
RING_BUFFER_REMOVE(i2c_addr_buff, addr); |
98 |
RING_BUFFER_REMOVE(i2c_write_buff, TWDR); |
99 |
break;
|
100 |
} |
101 |
else { /* no more bytes to this addr, bytes to send to new addr */ |
102 |
/* doing the start signal again */
|
103 |
TWCR |= _BV(TWSTA); |
104 |
break;
|
105 |
} |
106 |
} |
107 |
|
108 |
/* there are no bytes to send */
|
109 |
TWCR |= _BV(TWSTO); |
110 |
start_flag = 0;
|
111 |
|
112 |
break;
|
113 |
case TW_SR_SLA_ACK:
|
114 |
break;
|
115 |
case TW_SR_DATA_ACK:
|
116 |
if(!RING_BUFFER_FULL(i2c_read_buff))
|
117 |
RING_BUFFER_ADD(i2c_read_buff, TWDR); |
118 |
break;
|
119 |
case TW_SR_STOP:
|
120 |
break;
|
121 |
} |
122 |
|
123 |
TWCR |= _BV(TWINT); |
124 |
|
125 |
} |