Project

General

Profile

Statistics
| Branch: | Revision:

root / scout_avr / bom / tiny-twi.c @ 240c122b

History | View | Annotate | Download (2.84 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
uint8_t temp;
28

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

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

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

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

    
44
  state = IDLE;
45
}
46

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

    
51
  USISR = _BV(USISIF);
52

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

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

    
60
static void twi_send_ack(char is_read) {
61

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

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

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

    
73
static void twi_send_data() {
74
  twi_set_ctr(0);
75
  // TODO set USIDR from buffer
76
  USIDR = ++temp;
77
  DDRB |= _BV(SDA);
78
  state = SEND_DATA;
79
}
80

    
81
static void twi_recv_ack() {
82
  twi_set_ctr(14);
83
  DDRB &= ~_BV(SDA);
84
  state = RECV_ACK;
85
}
86

    
87
ISR(USI_START_vect) {
88
  twi_start();
89
}
90

    
91
ISR(USI_OVF_vect) {
92
  uint8_t input = USIDR; // TODO make sure this is correct
93
  switch (state) {
94

    
95
    case IDLE:
96
      // shouldn't reach here
97
      twi_ready();
98
      break;
99

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

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

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

    
126
    case SEND_READ_ACK:
127
      twi_send_data();
128
      break;
129

    
130
    case SEND_DATA:
131
      twi_recv_ack();
132
      break;
133

    
134
    case RECV_ACK:
135
      if (input & 1) {
136
        // received nak
137
        twi_ready();
138
      } else {
139
        // received ack
140
        twi_send_data();
141
      }
142
      break;
143
  }
144
  USISR = _BV(USIOIF) | (USISR & 0xF);
145
}
146

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

    
155
void smb_set_address(uint8_t addr) {
156
  address = addr;
157
}
158

    
159
void testCB(uint8_t* data, int length) {
160
}
161

    
162

    
163
int main() {
164
  sei();
165
  smb_set_address(5);
166
  DDRB |= _BV(DDB4);
167
  smb_init(testCB);
168
  while(1);
169
}