forked from kenzanin/I2C-slave-lib
-
Notifications
You must be signed in to change notification settings - Fork 0
/
I2C_slave.c
137 lines (107 loc) · 4.22 KB
/
I2C_slave.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
#include <avr/io.h>
#include <avr/cpufunc.h>
#include <util/twi.h>
#include <avr/interrupt.h>
#include "I2C_slave.h"
void I2C_init_slave (uint8_t address) {
// Load slave address into TWI address register
TWAR = (address << 1);
// Set the TWCR to enable address matching and
// enable TWI, clear TWINT, enable TWI interrupt
TWCR = (1<<TWIE) | (1<<TWEA) | (1<<TWINT) | (1<<TWEN);
}
void I2C_stop (void) {
// Clear acknowledge and enable bits
TWCR &= ~( (1<<TWEA) | (1<<TWEN) );
}
ISR (TWI_vect) {
// Temporarily stores the received data
uint8_t data;
uint8_t status = (TWSR & 0xF8);
// -- Called in Slave Receiver Mode -------------------------------------
// This MCU's own address has been called by a master on the bus,
// on the next interrupt cycle data will presumably be received
if (status == TW_SR_SLA_ACK) {
buffer_address = 0xFF;
// Clear TWI interrupt flag,
// prepare to receive next byte and acknowledge
TWCR |= (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
// Execute whatever external function is assigned to this callback
i2c_address_matched(I2C_SLAVE_RECEIVER_MODE);
}
// -- Received data in Slave Receiver Mode ------------------------------
// The MCU is in slave receiver mode and a data byte
// has been received from a master on the bus
else if (status == TW_SR_DATA_ACK) {
data = TWDR;
// Check if a register has been set/selected.
// If not, assume this received byte is the register address.
if (buffer_address == 0xFF) {
buffer_address = data;
// Clear TWI interrupt flag,
// prepare to receive next byte and acknowledge
TWCR |= (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
// Execute whatever external function is assigned to this callback
i2c_register_address_received(data);
}
// A register was previously set, so assume this data byte
// is a value to store into the previously selected register
else {
// store the data at the current address
i2c_rx_buffer[buffer_address] = data;
buffer_address++;
// If there is still enough space inside the buffer
if (buffer_address < 0xFF) {
// Clear TWI interrupt flag, prepare to receive
// next byte and acknowledge
TWCR |= (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
}
// Don't acknowledge; the buffer is full
else {
TWCR &= ~(1<<TWEA);
// Clear TWI interrupt flag, prepare to receive last byte.
TWCR |= (1<<TWIE) | (1<<TWINT) | (1<<TWEN);
}
// Execute whatever external function is assigned to this callback
i2c_data_value_received(data);
}
}
// -- Called in Slave Transmitter Mode ----------------------------------
// This MCU's own address has been called by a master on the bus,
// on the next interrupt cycle data will presumably be transmitted
else if (status == TW_ST_SLA_ACK) {
TWDR = i2c_tx_buffer[buffer_address];
// Clear the TWI interrupt flag,
// prepare to receive next byte and acknowledge
TWCR |= (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
// Execute whatever external function is assigned to this callback
i2c_address_matched(I2C_SLAVE_TRANSMITTER_MODE);
}
// -- Transmitter data in Slave Transmitter Mode ------------------------
// The MCU is in slave transmitter mode and a data byte
// has been transmitted back to a master on the bus
else if (status == TW_ST_DATA_ACK ) {
// Copy the specified buffer address into the
// TWDR register for transmission
TWDR = i2c_tx_buffer[buffer_address];
buffer_address++;
// If there is another buffer address that can be sent
if (buffer_address < 0xFF) {
// Clear TWI interrupt flag, prepare to
// send next byte and receive acknowledge
TWCR |= (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
}
// Don't acknowledge; end of buffer was reached,
// No more data can be sent
else {
TWCR &= ~(1<<TWEA);
// clear TWI interrupt flag, prepare to receive last byte.
TWCR |= (1<<TWIE) | (1<<TWINT) | (1<<TWEN);
}
}
// If none of the above apply prepare the TWI to
// listen on the bus and respond to future requests
else {
TWCR |= (1<<TWIE) | (1<<TWEA) | (1<<TWEN);
}
}