Project

General

Profile

Statistics
| Branch: | Revision:

root / scout_avr / bom / tiny-twi.c @ cbe25c0a

History | View | Annotate | Download (3.29 KB)

1 c4f160ba Tom Mullins
#include <avr/io.h>
2
#include <avr/interrupt.h>
3 0167b233 Aaron Perley
#include <util/delay.h>
4 08af0896 Tom Mullins
#include "tiny-twi.h"
5 c4f160ba Tom Mullins
6 797244ed Aaron Perley
#define SDA PB0
7
#define SCL PB2
8
9 cbe25c0a tmullins
#define RECV_BUF_SIZE 3
10 b3a1dae4 Tom Mullins
#define SEND_BUF_SIZE 100
11 c4f160ba Tom Mullins
12
uint8_t address;
13
14 08af0896 Tom Mullins
typedef enum {
15 c4f160ba Tom Mullins
  IDLE,
16
  ADDRESS,
17
  SEND_READ_ACK,
18
  SEND_WRITE_ACK,
19
  SEND_DATA,
20
  RECV_DATA,
21
  RECV_ACK
22 08af0896 Tom Mullins
} state_t;
23 c4f160ba Tom Mullins
24 08af0896 Tom Mullins
state_t state;
25 c4f160ba Tom Mullins
uint8_t recv_idx;
26
uint8_t recv_data[RECV_BUF_SIZE];
27 0167b233 Aaron Perley
slave_rx_t onDataRecieved;
28 b3a1dae4 Tom Mullins
struct {
29
  uint8_t start;
30
  uint8_t end;
31
  uint8_t data[SEND_BUF_SIZE];
32
  bool    full;
33
} send_queue;
34 c4f160ba Tom Mullins
35
static void twi_set_ctr(char n) {
36 797244ed Aaron Perley
  USISR = n;
37 16da2c8f Tom Mullins
}
38
39 c4f160ba Tom Mullins
static void twi_ready() {
40 797244ed Aaron Perley
  USISR = _BV(USISIF) | _BV(USIOIF) | _BV(USIPF) | _BV(USIDC);
41
  DDRB |= _BV(SCL);  //SCL output
42
  DDRB &= ~_BV(SDA); //SDA input
43 c4f160ba Tom Mullins
44
  // enable start condition interrupt
45
  USICR |= _BV(USISIE);
46
47
  // disable counter overflow interrupt
48
  USICR &= ~_BV(USIOIE);
49
50
  state = IDLE;
51
}
52
53
static void twi_start() {
54 797244ed Aaron Perley
  // enable counter overflow interrupt (fires after 8 bits)
55
  USICR |= _BV(USIOIE);
56
57
  USISR = _BV(USISIF);
58 c4f160ba Tom Mullins
59
  // zero counter
60
  twi_set_ctr(0);
61
62
  state = ADDRESS;
63
  recv_idx = 0;
64
}
65
66
static void twi_send_ack(char is_read) {
67
68
  // set counter to 14
69
  twi_set_ctr(14);
70
71
  // set SDA low
72
  USIDR = 0;
73 797244ed Aaron Perley
  DDRB |= _BV(SDA);
74 c4f160ba Tom Mullins
75
  // set state
76
  state = is_read? SEND_READ_ACK : SEND_WRITE_ACK;
77
}
78
79 240c122b Tom Mullins
static void twi_send_data() {
80
  twi_set_ctr(0);
81 b3a1dae4 Tom Mullins
  if (send_queue.start == send_queue.end && !send_queue.full) {
82
    USIDR = 0;
83
  } else {
84
    USIDR = send_queue.data[send_queue.start++];
85
    if (send_queue.start == SEND_BUF_SIZE)
86
      send_queue.start = 0;
87
    send_queue.full = 0;
88
  }
89 240c122b Tom Mullins
  DDRB |= _BV(SDA);
90
  state = SEND_DATA;
91
}
92
93
static void twi_recv_ack() {
94
  twi_set_ctr(14);
95
  DDRB &= ~_BV(SDA);
96
  state = RECV_ACK;
97
}
98
99 c4f160ba Tom Mullins
ISR(USI_START_vect) {
100
  twi_start();
101
}
102
103
ISR(USI_OVF_vect) {
104 6185434e Tom Mullins
  uint8_t input = USIDR; // TODO make sure this is correct
105 c4f160ba Tom Mullins
  switch (state) {
106
107
    case IDLE:
108
      // shouldn't reach here
109
      twi_ready();
110
      break;
111
112
    case ADDRESS:
113
      if (input >> 1 == address) {
114
        // send ack
115
        twi_send_ack(input & 1);
116
      } else {
117
        // go back to listening for start condition
118
        twi_ready();
119
      }
120
      break;
121
122
    case SEND_WRITE_ACK:
123 6185434e Tom Mullins
      if (recv_idx == RECV_BUF_SIZE) {
124
        twi_ready();
125
        onDataRecieved(recv_data, RECV_BUF_SIZE);
126
      } else {
127
        DDRB &= ~_BV(SDA);
128
        state = RECV_DATA;
129
      }
130 c4f160ba Tom Mullins
      break;
131
132
    case RECV_DATA:
133
      twi_send_ack(0);
134 6185434e Tom Mullins
      recv_data[recv_idx] = input;
135 c4f160ba Tom Mullins
      recv_idx++;
136
      break;
137
138
    case SEND_READ_ACK:
139 240c122b Tom Mullins
      twi_send_data();
140 c4f160ba Tom Mullins
      break;
141
142
    case SEND_DATA:
143 240c122b Tom Mullins
      twi_recv_ack();
144 c4f160ba Tom Mullins
      break;
145
146
    case RECV_ACK:
147 240c122b Tom Mullins
      if (input & 1) {
148
        // received nak
149
        twi_ready();
150
      } else {
151
        // received ack
152
        twi_send_data();
153
      }
154 c4f160ba Tom Mullins
      break;
155
  }
156 797244ed Aaron Perley
  USISR = _BV(USIOIF) | (USISR & 0xF);
157 c4f160ba Tom Mullins
}
158
159 0167b233 Aaron Perley
void smb_init(slave_rx_t callback) {
160 c4f160ba Tom Mullins
  // TODO do we want USICS0 (3)?
161
  USICR = _BV(USIWM1) | _BV(USIWM0) | _BV(USICS1);
162 797244ed Aaron Perley
  PORTB |= _BV(SDA) | _BV(SCL);
163 c4f160ba Tom Mullins
  twi_ready();
164 0167b233 Aaron Perley
  onDataRecieved = callback;
165 c4f160ba Tom Mullins
}
166
167
void smb_set_address(uint8_t addr) {
168
  address = addr;
169
}
170 0167b233 Aaron Perley
171 cbe25c0a tmullins
void smb_send_data(uint8_t* data, uint8_t length) {
172 b3a1dae4 Tom Mullins
  uint8_t i;
173
  for (i=0; i<length && !send_queue.full; i++) {
174
    send_queue.data[send_queue.end++] = data[i];
175
    if (send_queue.end == SEND_BUF_SIZE)
176
      send_queue.end = 0;
177
    if (send_queue.end == send_queue.start)
178
      send_queue.full = 1;
179
  }
180
}