Project

General

Profile

Statistics
| Branch: | Revision:

root / scout_avr / bom / tiny-twi-sync.c @ b8bdb8a1

History | View | Annotate | Download (3.19 KB)

1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
#include "tiny-twi-sync.h"
5

    
6
#define SDA PB0
7
#define SCL PB2
8

    
9
#define RECV_BUF_SIZE 3
10
#define SEND_BUF_SIZE 100
11

    
12
uint8_t address;
13

    
14
typedef enum {
15
  IDLE,
16
  ADDRESS,
17
  SEND_READ_ACK,
18
  SEND_WRITE_ACK,
19
  SEND_DATA,
20
  RECV_DATA,
21
  RECV_ACK
22
} state_t;
23

    
24
state_t state;
25
uint8_t recv_idx;
26
uint8_t recv_data[RECV_BUF_SIZE];
27
slave_rx_t onDataRecieved;
28
typedef struct {
29
  uint8_t start;
30
  uint8_t end;
31
  uint8_t data[SEND_BUF_SIZE];
32
  bool    full;
33
} queue;
34

    
35
queue send_queue;
36

    
37
static void twi_set_ctr(char n) {
38
  USISR = n;
39
}
40

    
41
static void twi_ready() {
42
  USISR = _BV(USISIF) | _BV(USIOIF) | _BV(USIPF) | _BV(USIDC);
43
  DDRB |= _BV(SCL);  //SCL output
44
  DDRB &= ~_BV(SDA); //SDA input
45

    
46
  state = IDLE;
47
}
48

    
49
static void twi_start() {
50
  // zero counter
51
  twi_set_ctr(0);
52

    
53
  state = ADDRESS;
54
  recv_idx = 0;
55
}
56

    
57
static void twi_send_ack(char is_read) {
58

    
59
  // set counter to 14
60
  twi_set_ctr(14);
61

    
62
  // set SDA low
63
  USIDR = 0;
64
  DDRB |= _BV(SDA);
65

    
66
  // set state
67
  state = is_read? SEND_READ_ACK : SEND_WRITE_ACK;
68
}
69

    
70
static void twi_send_data() {
71
  twi_set_ctr(0);
72
  if (send_queue.start == send_queue.end && !send_queue.full) {
73
    USIDR = 0xFF;
74
  } else {
75
    USIDR = send_queue.data[send_queue.start++];
76
    if (send_queue.start == SEND_BUF_SIZE)
77
      send_queue.start = 0;
78
    send_queue.full = 0;
79
  }
80
  DDRB |= _BV(SDA);
81
  state = SEND_DATA;
82
}
83

    
84
static void twi_recv_ack() {
85
  twi_set_ctr(14);
86
  DDRB &= ~_BV(SDA);
87
  state = RECV_ACK;
88
}
89

    
90
static void twi_on_overflow(void) {
91
  uint8_t input = USIDR; // TODO make sure this is correct
92
  switch (state) {
93

    
94
    case IDLE:
95
      // shouldn't reach here
96
      break;
97

    
98
    case ADDRESS:
99
      if (input >> 1 == address) {
100
        // send ack
101
        twi_send_ack(input & 1);
102
      } else {
103
        // go back to listening for start condition
104
        twi_ready();
105
      }
106
      break;
107

    
108
    case SEND_WRITE_ACK:
109
      if (recv_idx == RECV_BUF_SIZE) {
110
        onDataRecieved(recv_data, RECV_BUF_SIZE);
111
        twi_ready();
112
      } else {
113
        DDRB &= ~_BV(SDA);
114
        state = RECV_DATA;
115
      }
116
      break;
117

    
118
    case RECV_DATA:
119
      twi_send_ack(0);
120
      recv_data[recv_idx] = input;
121
      recv_idx++;
122
      break;
123

    
124
    case SEND_READ_ACK:
125
      twi_send_data();
126
      break;
127

    
128
    case SEND_DATA:
129
      twi_recv_ack();
130
      break;
131

    
132
    case RECV_ACK:
133
      if (input & 1) {
134
        // received nak
135
        twi_ready();
136
      } else {
137
        // received ack
138
        twi_send_data();
139
      }
140
      break;
141
  }
142
}
143

    
144
void smb_init(slave_rx_t callback) {
145
  // TODO do we want USICS0 (3)?
146
  USICR = _BV(USIWM1) | _BV(USIWM0) | _BV(USICS1);
147
  PORTB |= _BV(SDA) | _BV(SCL);
148
  twi_ready();
149
  onDataRecieved = callback;
150
}
151

    
152
void smb_set_address(uint8_t addr) {
153
  address = addr;
154
}
155

    
156
void smb_send_data(uint8_t* data, uint8_t length) {
157
  uint8_t i;
158
  for (i=0; i<length && !send_queue.full; i++) {
159
    send_queue.data[send_queue.end++] = data[i];
160
    if (send_queue.end == SEND_BUF_SIZE)
161
      send_queue.end = 0;
162
    if (send_queue.end == send_queue.start)
163
      send_queue.full = 1;
164
  }
165
}
166

    
167
void twi_run(void) {
168
  if (USISR & _BV(USISIF)) {
169
    twi_start();
170
    USISR |= _BV(USISIF);
171
  }
172
  if (USISR & _BV(USIOIF)) {
173
    twi_on_overflow();
174
    USISR |= _BV(USIOIF);
175
  }
176
}