forked from TakkTile/takktile-boards
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.c
264 lines (209 loc) · 6.78 KB
/
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
// (C) 2012 Biorobotics Lab and Nonolith Labs
// written by Ian Daniher, based off usiTwiSlave.c by Donald R. Blake
// licensed under the terms of the GNU GPLv3+
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define RST0 1 << PA0
#define RST1 1 << PA1
#define RST2 1 << PA2
#define RST3 1 << PA3
#define RST4 1 << PA5
#define ADDR3 1 << PA7
#define ADDR0 1 << PB0
#define ADDR1 1 << PB1
#define ADDR2 1 << PB2
//#define DEVICE_TAKKSTRIP // un-comment this line if the target is TakkStrip
typedef enum
{
USI_SLAVE_CHECK_ADDRESS = 0x00,
USI_SLAVE_END_TRX= 0x01,
} overflowState_t;
static volatile overflowState_t overflowState;
uint8_t slaveAddress;
void usiTwiSlaveInit( void ) {
// set SCL and SDA as output
SDA_DDR |= ( 1 << SDA_BIT );
SCL_DDR |= ( 1 << SCL_BIT );
// set SCL high
SCL_PORT |= ( 1 << SCL_BIT );
// set SDA high
SDA_PORT |= ( 1 << SDA_BIT );
// set SDA as input
SDA_DDR &= ~( 1 << SDA_BIT );
// enable Start Condition Interrupt
// disable Overflow Interrupt
// set USI in Two-wire mode, no USI Counter overflow hold
// shift Register Clock Source = external, positive edge
// 4-Bit Counter Source = external, both edges
// no toggle clock-port pin
USICR = ( 1 << USISIE ) |
( 0 << USIOIE ) |
( 1 << USIWM1 ) | ( 0 << USIWM0 ) |
( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) |
( 0 << USITC );
// clear all interrupt flags and reset overflow counter
USISR = ( 1 << USISIF ) | ( 1 << USIOIF ) | ( 1 << USIPF ) | ( 1 << USIDC );
}
ISR( USI_STR_vect ) {
// set default starting conditions for new TWI packageDDRA
overflowState = USI_SLAVE_CHECK_ADDRESS;
// set SDA as input
SDA_DDR &= ~( 1 << SDA_BIT );
// wait for SCL to be high and SDA to be low
while ( ( SCL_PIN & ( 1 << SCL_BIT ) ) && !( ( SDA_PIN & ( 1 << SDA_BIT ) ) ) );
// a stop condition did not occur
if ( !( SDA_PIN & ( 1 << SDA_BIT ) ) ) {
// keep Start Condition Interrupt enabled to detect RESTART
// enable Overflow Interrupt
// set USI in Two-wire mode, hold SCL low on USI Counter overflow
// shift Register Clock Source = External, positive edge
// 4-Bit Counter Source = external, both edges
// no toggle clock-port pin
USICR = ( 1 << USISIE ) |
( 1 << USIOIE ) |
( 1 << USIWM1 ) | ( 1 << USIWM0 ) |
( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) |
( 0 << USITC );
}
// a stop condition did occur
else {
// enable Start Condition Interrupt
// disable Overflow Interrupt
// set USI in Two-wire mode, no USI Counter overflow hold
// shift Register Clock Source = external, positive edge
// 4-Bit Counter Source = external, both edges
// no toggle clock-port pin
USICR = ( 1 << USISIE ) |
( 0 << USIOIE ) |
( 1 << USIWM1 ) | ( 0 << USIWM0 ) |
( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) |
( 0 << USITC );
}
// clear interrupt flags - resetting the Start Condition Flag will release SCL
// set USI to sample 8 bits (count 16 external SCL pin toggles)
USISR = ( 1 << USISIF ) | ( 1 << USIOIF ) |
( 1 << USIPF ) |( 1 << USIDC ) |
( 0x0 << USICNT0);
}
ISR( USI_OVF_vect ) {
switch ( overflowState ) {
case USI_SLAVE_CHECK_ADDRESS: {
uint8_t ADDR = USIDR;
if ( ( ADDR == 0x0C ) || (ADDR == 0x0D) || (( (ADDR&0xF0) == (slaveAddress&0xF0) ))){
// pin bit position determined by LSB1..3 inclusive
uint8_t pin_bp = (ADDR & 0x0F) >> 1;
// pin bitmask defaults to 1 << pin_bp
uint8_t pin_bm = 1 << pin_bp;
// if you're theoretically writing the state of the "sixth" sensor, set the bitmask to match all of them
if ( pin_bp == 6 ) pin_bm = 0x2F;
// RST4 is actually located at PA5
if ( pin_bp == 4 ) pin_bm = 0x20;
// inverted logic - if transaction is a "read", disable the corresponding sensor
if ( ADDR & 0x01 ) PORTA &= ~pin_bm;
// otherwise, enable it
else PORTA |= pin_bm;
// prep ACK
USIDR = 0;
// set SDA as an output
SDA_DDR |= ( 1 << SDA_BIT );
// reset all interrupt flags but start condition and set USI to shift out one bit
USISR = ( 0 << USISIF ) | ( 1 << USIOIF ) | ( 1 << USIPF ) | ( 1 << USIDC ) | ( 0x0E << USICNT0 );
// after the oveflow interrupt is triggered after one bit is shifted, go to USI_SLAVE_END_TRX condition
overflowState = USI_SLAVE_END_TRX;
}
else {
overflowState = USI_SLAVE_END_TRX;
return;
}
}
break;
case USI_SLAVE_END_TRX: {
// next time overflow interrupt trips, check the address
overflowState = USI_SLAVE_CHECK_ADDRESS;
// SDA as input
SDA_DDR &= ~( 1 << SDA_BIT );
// enable Start Condition Interrupt, disable Overflow Interrupt
// set USI in Two-wire mode, no USI Counter overflow hold
// shift Register Clock Source = External, positive edge
// 4-Bit Counter Source = external, both edges
// no toggle clock-port pin
USICR = ( 1 << USISIE ) | ( 0 << USIOIE ) |
( 1 << USIWM1 ) | ( 0 << USIWM0 ) |
( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) |
( 0 << USITC );
// reset all interrupt flags but start condition
// set USI to shift out one bit
USISR = ( 0 << USISIF ) | ( 1 << USIOIF ) | ( 1 << USIPF ) | ( 1 << USIDC ) | ( 0x0 << USICNT0 );
}
break;
}
}
uint8_t getAddress(void) {
uint8_t slaveAddress;
uint8_t tmpAddress;
slaveAddress = ((PINA & (ADDR3)) >> 4) | ( PINB & ((ADDR0) | (ADDR1) | (ADDR2)) );
// ---- TakkArray -----
// calculate slaveAddress from state of ADDR pins
slaveAddress -= 1;
// --------------------
// ---- TakkStrip -----
#ifdef DEVICE_TAKKSTRIP
slaveAddress += 1;
// calculate slaveAddress from state of ADDR pins
tmpAddress = 0;
slaveAddress ^= 0b0111; // exclusive or ... to invert the bits value.
if (slaveAddress & 0b001) {
tmpAddress = 0b100;
}
if (slaveAddress & 0b010) {
tmpAddress |= 0b010;
}
if (slaveAddress & 0b100) {
tmpAddress |= 0b001;
}
slaveAddress = tmpAddress;
#endif
// --------------------
slaveAddress <<= 4;
return slaveAddress;
}
int main(void) {
uint16_t bigAddress;
bigAddress=0;
// disable all MPL115A2 sensors
DDRA |= RST0 | RST1 | RST2 | RST3 | RST4;
PORTA &= ~(RST0 | RST1 | RST2 | RST3 | RST4);
// set all ADDR pins as inputs with pullups
DDRA &= ~(ADDR3);
DDRB &= ~(ADDR0 | ADDR1 | ADDR2);
PORTA |= ADDR3;
PORTB |= ADDR0 | ADDR1 | ADDR2;
for (uint8_t i = 0; i < 8; i++) {
// first wait, and then read the address
_delay_us(100);
bigAddress += getAddress();
}
slaveAddress = bigAddress >> 3;
// ---- for Debugging ----------------------
// if (bigAddress % 8) {
// if (1) {
// PORTA |= RST0;
// _delay_us(5);
// PORTA &= ~ RST0;
// tmp=slaveAddress;
// tmp>>=4;
//
// for (uint8_t i = 0; i < (tmp); i++) {
// PORTA |= RST0;
// _delay_us(9);
// PORTA &= ~ RST0;
// }
// }
// --------------------------
// enable interupts
sei();
// instantiate usiTwiSlave code
usiTwiSlaveInit();
for(;;) {}
}