Project

General

Profile

Statistics
| Branch: | Revision:

root / scout_avr / bom / tiny-twi.c @ 08af0896

History | View | Annotate | Download (2.47 KB)

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

    
6
#define RECV_BUF_SIZE 2
7

    
8
uint8_t address;
9

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

    
20
state_t state;
21
uint8_t recv_idx;
22
uint8_t recv_data[RECV_BUF_SIZE];
23
slave_rx_t onDataRecieved;
24

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

    
30
static void twi_release_scl() {
31
  DDRB &= ~_BV(DDB2);
32
}
33

    
34
static void twi_sink_sda() {
35
  DDRB |= _BV(DDB0);
36
}
37

    
38
static void twi_release_sda() {
39
  DDRB &= ~_BV(DDB0);
40
}
41

    
42
static void twi_ready() {
43

    
44
  // enable start condition interrupt
45
  USICR |= _BV(USISIE);
46

    
47
  // disable counter overflow interrupt
48
  USICR &= ~_BV(USIOIE);
49

    
50
  state = IDLE;
51
}
52

    
53
static void twi_start() {
54

    
55
  // zero counter
56
  twi_set_ctr(0);
57

    
58
  // enable counter overflow interrupt (fires after 8 bits)
59
  USICR |= _BV(USIOIE);
60

    
61
  state = ADDRESS;
62
  recv_idx = 0;
63
}
64

    
65
static void twi_send_ack(char is_read) {
66

    
67
  // set counter to 14
68
  twi_set_ctr(14);
69

    
70
  // set SDA low
71
  USIDR = 0;
72
  twi_sink_sda();
73

    
74
  // set state
75
  state = is_read? SEND_READ_ACK : SEND_WRITE_ACK;
76
}
77

    
78
ISR(USI_START_vect) {
79
  twi_start();
80
}
81

    
82
ISR(USI_OVF_vect) {
83
  uint8_t input = USIBR;
84
  switch (state) {
85

    
86
    case IDLE:
87
      // shouldn't reach here
88
      twi_ready();
89
      break;
90

    
91
    case ADDRESS:
92
      if (input >> 1 == address) {
93
        // send ack
94
        twi_send_ack(input & 1);
95
      } else {
96
        // go back to listening for start condition
97
        twi_ready();
98
      }
99
      break;
100

    
101
    case SEND_WRITE_ACK:
102
      twi_release_sda();
103
      state = RECV_DATA;
104
      break;
105

    
106
    case RECV_DATA:
107
      twi_send_ack(0);
108
      recv_data[recv_idx] = USIBR;
109
      recv_idx++;
110
      if (recv_idx == RECV_BUF_SIZE) {
111
        twi_ready();
112
        onDataRecieved(recv_data, RECV_BUF_SIZE);
113
      }
114
      break;
115

    
116
    case SEND_READ_ACK:
117
      twi_release_sda();
118
      // TODO write to USIDR
119
      state = SEND_DATA;
120
      break;
121

    
122
    case SEND_DATA:
123
      break;
124

    
125
    case RECV_ACK:
126
      break;
127
  }
128
  twi_release_scl();
129
}
130

    
131
void smb_init(slave_rx_t callback) {
132
  // TODO do we want USICS0 (3)?
133
  USICR = _BV(USIWM1) | _BV(USIWM0) | _BV(USICS1);
134
  twi_ready();
135
  onDataRecieved = callback;
136
}
137

    
138
void smb_set_address(uint8_t addr) {
139
  address = addr;
140
}
141

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

    
151

    
152
int main() {
153
  smb_set_address(5);
154
  DDRB |= _BV(DDB4);
155
  smb_init(testCB);
156
}