Project

General

Profile

Statistics
| Branch: | Revision:

scoutos / scout_avr / bom / tiny-twi.c @ 0167b233

History | View | Annotate | Download (2.25 KB)

1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4

    
5
#define RECV_BUF_SIZE 2
6

    
7
uint8_t address;
8

    
9
enum {
10
  IDLE,
11
  ADDRESS,
12
  SEND_READ_ACK,
13
  SEND_WRITE_ACK,
14
  SEND_DATA,
15
  RECV_DATA,
16
  RECV_ACK
17
} state;
18

    
19
uint8_t recv_idx;
20
uint8_t recv_data[RECV_BUF_SIZE];
21
slave_rx_t onDataRecieved;
22

    
23
static void twi_set_ctr(char n) {
24
  USISR &= ~0x0F;
25
  USISR |= n;
26
}
27

    
28
static void twi_ready() {
29

    
30
  // enable start condition interrupt
31
  USICR |= _BV(USISIE);
32

    
33
  // disable counter overflow interrupt
34
  USICR &= ~_BV(USIOIE);
35

    
36
  // TODO somehow release SCL following the ovf interrupt
37

    
38
  state = IDLE;
39
}
40

    
41
static void twi_start() {
42

    
43
  // zero counter
44
  twi_set_ctr(0);
45

    
46
  // enable counter overflow interrupt (fires after 8 bits)
47
  USICR |= _BV(USIOIE);
48

    
49
  state = ADDRESS;
50
  recv_idx = 0;
51
}
52

    
53
static void twi_send_ack(char is_read) {
54

    
55
  // set counter to 14
56
  twi_set_ctr(14);
57

    
58
  // set SDA low
59
  USIDR = 0;
60

    
61
  // set state
62
  state = is_read? SEND_READ_ACK : SEND_WRITE_ACK;
63
}
64

    
65
ISR(USI_START_vect) {
66
  twi_start();
67
}
68

    
69
ISR(USI_OVF_vect) {
70
  uint8_t input = USIBR;
71
  switch (state) {
72

    
73
    case IDLE:
74
      // shouldn't reach here
75
      twi_ready();
76
      break;
77

    
78
    case ADDRESS:
79
      if (input >> 1 == address) {
80
        // send ack
81
        twi_send_ack(input & 1);
82
      } else {
83
        // go back to listening for start condition
84
        twi_ready();
85
      }
86
      break;
87

    
88
    case SEND_WRITE_ACK:
89
      state = RECV_DATA;
90
      break;
91

    
92
    case RECV_DATA:
93
      twi_send_ack(0);
94
      recv_data[recv_idx] = USIBR;
95
      recv_idx++;
96
      if (recv_idx == RECV_BUF_SIZE) {
97
        twi_ready();
98
        onDataRecieved(recv_data, RECV_BUF_SIZE);
99
      }
100
      break;
101

    
102
    case SEND_READ_ACK:
103
      // TODO write to USIDR
104
      state = SEND_DATA;
105
      break;
106

    
107
    case SEND_DATA:
108
      break;
109

    
110
    case RECV_ACK:
111
      break;
112
  }
113
}
114

    
115
void smb_init(slave_rx_t callback) {
116
  state = START;
117

    
118
  // TODO do we want USICS0 (3)?
119
  USICR = _BV(USIWM1) | _BV(USIWM0) | _BV(USICS1);
120
  twi_ready();
121
  onDataRecieved = callback;
122
}
123

    
124
void smb_set_address(uint8_t addr) {
125
  address = addr;
126
}
127

    
128
void testCB(uint8_t* data, int length) {
129
  PORTB |= _BV(PB4);
130
  if (data[0])
131
    _delay_ms(1000);
132
  else
133
    _delay_ms(500);
134
  PORTB &= ~_BV(PB4);
135
}
136

    
137

    
138
int main() {
139
  smb_set_address(5);
140
  DDRB |= _BV(DDB4);
141
  smb_init(testCB);
142
}