-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTwoWire841.cpp
143 lines (112 loc) · 3.34 KB
/
TwoWire841.cpp
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
/*
* TwoWire841.cpp
*
* Created: 7/16/2015 7:16:26 PM
* Author: ekt
*/
#if defined(__AVR_ATtiny841__) || defined(__AVR_ATtiny441__)
#include "TwoWire.h"
#include <avr/io.h>
#include <avr/interrupt.h>
static volatile uint8_t _deviceAddress = 0;
static const uint8_t broadcastAddress = 9;
#if !defined(__AVR_ATtiny841__)
#error "Only works with ATtiny841"
#endif
void TwoWireInit(bool useInterrupts) {
// Enable Data Interrupt, Address/Stop Interrupt, Two-Wire Interface, Stop Interrpt
TWSCRA = _BV(TWEN) | _BV(TWSIE);
if (useInterrupts) {
TWSCRA |= _BV(TWDIE) | _BV(TWASIE) ;
}
TWSCRB = _BV(TWHNM);
// Also listen for message on the broadcast address
TWSAM = (broadcastAddress << 1)| 1;
}
void TwoWireSetDeviceAddress(uint8_t address) {
_deviceAddress = address;
TWSA = (address << 1);
}
uint8_t TwoWireGetDeviceAddress() {
return _deviceAddress;
}
static void _Acknowledge(bool ack, bool complete=false) {
if (ack) {
TWSCRB &= ~_BV(TWAA);
} else {
TWSCRB |= _BV(TWAA);
}
TWSCRB |= _BV(TWCMD1) | (complete ? 0 : _BV(TWCMD0));
}
#define TWI_BUFFER_SIZE 32
static uint8_t twiBuffer[TWI_BUFFER_SIZE];
static uint8_t twiBufferLen = 0;
static uint8_t twiReadPos = 0;
static uint8_t twiAddress = 0;
enum TWIState {
TWIStateIdle,
TWIStateRead,
TWIStateWrite
};
static TWIState twiState = TWIStateIdle;
void TwoWireUpdate() {
uint8_t status = TWSSRA;
bool dataInterruptFlag = (status & _BV(TWDIF)); // Check whether the data interrupt flag is set
bool isAddressOrStop = (status & _BV(TWASIF)); // Get the TWI Address/Stop Interrupt Flag
bool isReadOperation = (status & _BV(TWDIR));
bool addressReceived = (status & _BV(TWAS)); // Check if we received an address and not a stop
// Clear the interrupt flags
// TWSSRA |= _BV(TWDIF) | _BV(TWASIF);
//volatile bool clockHold = (TWSSRA & _BV(TWCH));
//volatile bool receiveAck = (TWSSRA & _BV(TWRA));
//volatile bool collision = (TWSSRA & _BV(TWC));
//volatile bool busError = (TWSSRA & _BV(TWBE));
// Handle address received and stop conditions
if (isAddressOrStop) {
// Send an ack unless a read is starting and there are no bytes to read.
bool ack = (twiBufferLen > 0) or (!isReadOperation) or (!addressReceived);
_Acknowledge(ack, !addressReceived /*complete*/);
// If we were previously in a write, then execute the callback and setup for a read.
if ((twiState == TWIStateWrite) and twiBufferLen != 0) {
twiBufferLen = TwoWireCallback(twiAddress, twiBuffer, twiBufferLen, TWI_BUFFER_SIZE);
twiReadPos = 0;
}
if (!addressReceived) {
twiState = TWIStateIdle;
} else if (isReadOperation) {
twiState = TWIStateRead;
} else {
twiState = TWIStateWrite;
twiBufferLen = 0;
}
// The address is in the high 7 bits, the RD/WR bit is in the lsb
twiAddress = TWSD >> 1;
return;
}
// Data Read
if (dataInterruptFlag and isReadOperation) {
if (twiReadPos < twiBufferLen) {
TWSD = twiBuffer[twiReadPos++];
_Acknowledge(true /*ack*/, false /*complete*/);
} else {
TWSD = 0;
_Acknowledge(false /*ack*/, true /*complete*/);
}
return;
}
// Data Write
if (dataInterruptFlag and !isReadOperation) {
uint8_t data = TWSD;
_Acknowledge(true, false);
if (twiBufferLen < TWI_BUFFER_SIZE) {
twiBuffer[twiBufferLen++] = data;
}
return;
}
}
// The two wire interrupt service routine
ISR(TWI_SLAVE_vect)
{
TwoWireUpdate();
}
#endif