Project

General

Profile

Statistics
| Branch: | Revision:

root / scout_avr / bom / tiny-twi.c @ 64b6024c

History | View | Annotate | Download (2.86 KB)

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

    
6
#define SDA PB0
7
#define SCL PB2
8

    
9
#define RECV_BUF_SIZE 2
10

    
11
uint8_t address;
12

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

    
23
state_t state;
24
uint8_t recv_idx;
25
uint8_t recv_data[RECV_BUF_SIZE];
26
slave_rx_t onDataRecieved;
27

    
28
static void twi_set_ctr(char n) {
29
  USISR = n;
30
}
31

    
32
static void twi_ready() {
33
  USISR = _BV(USISIF) | _BV(USIOIF) | _BV(USIPF) | _BV(USIDC);
34
  DDRB |= _BV(SCL);  //SCL output
35
  DDRB &= ~_BV(SDA); //SDA input
36

    
37
  // enable start condition interrupt
38
  USICR |= _BV(USISIE);
39

    
40
  // disable counter overflow interrupt
41
  USICR &= ~_BV(USIOIE);
42

    
43
  state = IDLE;
44
}
45

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

    
50
  USISR = _BV(USISIF);
51

    
52
  // zero counter
53
  twi_set_ctr(0);
54

    
55
  state = ADDRESS;
56
  recv_idx = 0;
57
}
58

    
59
static void twi_send_ack(char is_read) {
60

    
61
  // set counter to 14
62
  twi_set_ctr(14);
63

    
64
  // set SDA low
65
  USIDR = 0;
66
  DDRB |= _BV(SDA);
67

    
68
  // set state
69
  state = is_read? SEND_READ_ACK : SEND_WRITE_ACK;
70
}
71

    
72
ISR(USI_START_vect) {
73
  twi_start();
74
}
75

    
76
ISR(USI_OVF_vect) {
77
  uint8_t input = USIDR; // WTF ASK TOM
78
  switch (state) {
79

    
80
    case IDLE:
81
      // shouldn't reach here
82
      twi_ready();
83
      break;
84

    
85
    case ADDRESS:
86
      if (input >> 1 == address) {
87
        // send ack
88
        twi_send_ack(input & 1);
89
        PORTB |= _BV(PB4); // DEBUG LED ON
90
      } else {
91
        // go back to listening for start condition
92
        twi_ready();
93
      }
94
      break;
95

    
96
    case SEND_WRITE_ACK:
97
      DDRB &= ~_BV(SDA);
98
      state = RECV_DATA;
99
      break;
100

    
101
    case RECV_DATA:
102
      twi_send_ack(0);
103
      recv_data[recv_idx] = USIBR;
104
      recv_idx++;
105
      if (recv_idx == RECV_BUF_SIZE) {
106
        twi_ready();
107
        onDataRecieved(recv_data, RECV_BUF_SIZE);
108
      }
109
      break;
110

    
111
    case SEND_READ_ACK:
112
      DDRB &= ~_BV(SDA);
113
      // TODO write to USIDR
114
      state = SEND_DATA;
115
      break;
116

    
117
    case SEND_DATA:
118
      break;
119

    
120
    case RECV_ACK:
121
      break;
122
  }
123
  USISR = _BV(USIOIF) | (USISR & 0xF);
124
}
125

    
126
void smb_init(slave_rx_t callback) {
127
  // TODO do we want USICS0 (3)?
128
  USICR = _BV(USIWM1) | _BV(USIWM0) | _BV(USICS1);
129
  PORTB |= _BV(SDA) | _BV(SCL);
130
  twi_ready();
131
  onDataRecieved = callback;
132
}
133

    
134
void smb_set_address(uint8_t addr) {
135
  address = addr;
136
}
137

    
138
void testCB(uint8_t* data, int length) {
139
  PORTB |= _BV(PB4);
140
  if (data[0])
141
    _delay_ms(1000);
142
  else
143
    _delay_ms(500);
144
  PORTB &= ~_BV(PB4);
145
}
146

    
147

    
148
int main() {
149
  sei();
150
  smb_set_address(5);
151
  DDRB |= _BV(DDB4);
152
  smb_init(testCB);
153
  while(1);
154
}
155

    
156

    
157

    
158

    
159

    
160
/* debug code
161
USICR &= ~_BV(USISIE);
162
USICR &= ~_BV(USIOIE);
163

164
int i;
165
for (i=0; i<8; i++) {
166
  _delay_ms(1000);
167
          PORTB |= _BV(PB4); // DEBUG LED ON
168
  if ((input >> i) & 1) _delay_ms(1000);
169
  else _delay_ms(500);
170
      PORTB &= ~_BV(PB4); // DEBUG LED OFF
171
}
172
*/