I2C_Slave.c


1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
#define USI_DATA         USIDR
5
#define USI_STATUS      USISR
6
#define USI_CONTROL     USICR
7
#define USI_ADDRESS      0x08
8
9
#define NONE          0
10
#define ACK_PR_RX      1
11
#define BYTE_RX        2
12
#define ACK_PR_TX      3
13
#define PR_ACK_TX      4
14
#define BYTE_TX        5
15
16
#define DDR_USI             DDRA
17
#define PORT_USI            PORTA
18
#define PIN_USI             PINA
19
#define PORT_USI_SDA        PORTA6
20
#define PORT_USI_SCL        PORTA4
21
22
#define RC_OFFSET      100
23
24
volatile uint8_t COMM_STATUS = NONE;
25
volatile uint8_t ACT_CHANNEL = NONE;
26
volatile uint8_t tWidth_1=0, tWidth_2=0, tWidth_3=0, tWidth_4=0;
27
28
uint8_t tStart_1=0, tStart_2=0, tStart_3=0, tStart_4=0;
29
30
31
void USIinit(void) {
32
  // 2-wire mode; Hold SCL on start and overflow; ext. clock
33
  USI_CONTROL |= (1<<USIWM1) | (1<<USICS1);
34
  USI_STATUS = 0xf0;  // write 1 to clear flags, clear counter
35
  DDR_USI  &= ~(1<<PORT_USI_SDA);
36
  PORT_USI &= ~(1<<PORT_USI_SDA);
37
  DDR_USI  |=  (1<<PORT_USI_SCL);
38
  PORT_USI |=  (1<<PORT_USI_SCL);
39
  // startcondition interrupt enable
40
  USI_CONTROL |= (1<<USISIE);
41
}
42
43
void RCinit(void) {    
44
  TCCR0B |= (1<<CS00) | (1<<CS01); //Prescaler
45
  PCMSK0 |= (1<<PCINT0) | (1<<PCINT1) | (1<<PCINT2) | (1<<PCINT3); //PC Maske
46
  GIMSK |= (1<<PCIE0);//Interrupt anschalten
47
48
  DDRB &= ~ (1<<DDB0) | (1<<DDB1) | (1<<DDB2) | (1<<DDB3); //Port A auf Eingang
49
    PORTB &= ~ (1<<PORTB0) | (1<<PORTB1) | (1<<PORTB2) | (1<<PORTB3); //PullUp ausschalten
50
}
51
52
53
int main(void) {
54
    RCinit();
55
  USIinit();
56
  
57
  sei();
58
59
  for(;;)  {
60
  }
61
62
}
63
64
65
ISR (USI_STR_vect) {
66
    uint8_t tmpUSI_STATUS;
67
  tmpUSI_STATUS = USI_STATUS;
68
  COMM_STATUS = NONE;
69
  // Wait for SCL to go low to ensure the "Start Condition" has completed.
70
  // otherwise the counter will count the transition
71
  while ( (PIN_USI & (1<<PORT_USI_SCL)) );
72
  USI_STATUS = 0xf0; // write 1 to clear flags; clear counter
73
  // enable USI interrupt on overflow; SCL goes low on overflow
74
  USI_CONTROL |= (1<<USIOIE) | (1<<USIWM0);
75
}
76
77
78
79
80
ISR (USI_OVF_vect) {
81
  uint8_t BUF_USI_DATA = USI_DATA;
82
  switch(COMM_STATUS) {
83
  case NONE:
84
    if (((BUF_USI_DATA & 0xfe) >> 1) != USI_ADDRESS) {  // if not receiving my address
85
      // disable USI interrupt on overflow; disable SCL low on overflow
86
      USI_CONTROL &= ~((1<<USIOIE) | (1<<USIWM0));
87
    }
88
    else { // else address is mine
89
      DDR_USI  |=  (1<<PORT_USI_SDA);
90
      USI_STATUS = 0x0e;  // reload counter for ACK, (SCL) high and back low
91
            if (BUF_USI_DATA & 0x01) {
92
                COMM_STATUS = ACK_PR_TX; 
93
            } else {
94
                COMM_STATUS = ACK_PR_RX;
95
            }
96
    }
97
    break;
98
  case ACK_PR_RX:
99
    DDR_USI  &= ~(1<<PORT_USI_SDA);
100
    COMM_STATUS = BYTE_RX;
101
    break;
102
  case BYTE_RX:
103
    ACT_CHANNEL = USI_DATA; //Empfangenes Byte als aktuellen Channel speichern
104
    DDR_USI  |=  (1<<PORT_USI_SDA);
105
    USI_STATUS = 0x0e;  // reload counter for ACK, (SCL) high and back low
106
    COMM_STATUS = ACK_PR_RX;
107
    break;
108
  case ACK_PR_TX:
109
        //Aktuellen kanal senden
110
        switch (ACT_CHANNEL) {
111
        case 1:
112
        USI_DATA = tWidth_1;
113
            break;
114
        case 2:
115
            USI_DATA = tWidth_2;
116
            break;
117
        case 3:
118
            USI_DATA = tWidth_3;
119
            break;
120
        case 4:
121
            USI_DATA = tWidth_4;
122
            break;
123
        }
124
    PORT_USI |=  (1<<PORT_USI_SDA); // transparent for shifting data out
125
    COMM_STATUS = BYTE_TX;
126
    break;
127
  case PR_ACK_TX:
128
    if(BUF_USI_DATA & 0x01) {
129
      COMM_STATUS = NONE; // no ACK from master --> no more bytes to send
130
    }
131
    else {
132
      /* Put next byte to transmit in buffer here! USI_DATA = ... */
133
      PORT_USI |=  (1<<PORT_USI_SDA); // transparent for shifting data out
134
      DDR_USI  |=  (1<<PORT_USI_SDA);
135
      COMM_STATUS = BYTE_TX;
136
    }
137
    break;
138
  case BYTE_TX:
139
    DDR_USI  &= ~(1<<PORT_USI_SDA);
140
    PORT_USI &= ~(1<<PORT_USI_SDA);
141
    USI_STATUS = 0x0e;  // reload counter for ACK, (SCL) high and back low
142
    COMM_STATUS = PR_ACK_TX;
143
    break;
144
  }
145
  USI_STATUS |= (1<<USIOIF); // clear overflowinterruptflag, this also releases SCL
146
}
147
148
149
ISR(PCINT0_vect) {
150
  //Channel 1
151
  if (PINB & ( 1 << PINB0 ))
152
  {
153
    tStart_1 = TCNT0;
154
  }
155
  if (!(PINB & ( 1 << PINB0 )) && (tStart_1!=0))
156
  {
157
    tWidth_1 = TCNT0 - tStart_1 - RC_OFFSET;
158
    tStart_1 = 0;
159
  }
160
  
161
  //Channel 2
162
  if (PINB & ( 1 << PINB1 ))
163
  {
164
    tStart_2 = TCNT0;
165
  }
166
  if (!(PINB & ( 1 << PINB1 )) && (tStart_2!=0))
167
  {
168
    tWidth_2 = TCNT0 - tStart_2 - RC_OFFSET;
169
    tStart_2 = 0;
170
  }   
171
  
172
  //Channel 3
173
  if (PINB & ( 1 << PINB2 ))
174
  {
175
    tStart_3 = TCNT0;
176
  }
177
  if (!(PINB & ( 1 << PINB2 )) && (tStart_3!=0))
178
  {
179
    tWidth_3 = TCNT0 - tStart_3 - RC_OFFSET;
180
    tStart_3 = 0;
181
  }    
182
  
183
  //Channel 4
184
  if (PINB & ( 1 << PINB3 ))
185
  {
186
    tStart_4 = TCNT0;
187
  }
188
  if (!(PINB & ( 1 << PINB3 )) && (tStart_4!=0))
189
  {
190
    tWidth_4 = TCNT0 - tStart_4 - RC_OFFSET;
191
    tStart_4 = 0;
192
  }    
193
}