Project

General

Profile

Statistics
| Revision:

root / branches / analog / code / projects / colonet / robot / dragonfly_wireless_relay / i2c.c @ 1390

History | View | Annotate | Download (2.71 KB)

1 13 emarinel
/* 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
}