Project

General

Profile

Statistics
| Branch: | Revision:

scoutos / scout_avr / bom / tiny-twi.c @ 5f7a1707

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