]> git.donarmstrong.com Git - qmk_firmware.git/blob - drivers/avr/i2c_slave.c
dbb9fb0df349375b0faea70f3a4a08903a61d26b
[qmk_firmware.git] / drivers / avr / i2c_slave.c
1 /* Library made by: g4lvanix
2  * Github repository: https://github.com/g4lvanix/I2C-slave-lib
3  */
4
5 #include <avr/io.h>
6 #include <util/twi.h>
7 #include <avr/interrupt.h>
8 #include <stdbool.h>
9
10 #include "i2c_slave.h"
11
12 volatile uint8_t i2c_slave_reg[I2C_SLAVE_REG_COUNT];
13
14 static volatile uint8_t buffer_address;
15 static volatile bool slave_has_register_set = false;
16
17 void i2c_slave_init(uint8_t address){
18     // load address into TWI address register
19     TWAR = address;
20     // set the TWCR to enable address matching and enable TWI, clear TWINT, enable TWI interrupt
21     TWCR = (1 << TWIE) | (1 << TWEA) | (1 << TWINT) | (1 << TWEN);
22 }
23
24 void i2c_slave_stop(void){
25     // clear acknowledge and enable bits
26     TWCR &= ~((1 << TWEA) | (1 << TWEN));
27 }
28
29 ISR(TWI_vect){
30     uint8_t ack = 1;
31
32     switch(TW_STATUS){
33         case TW_SR_SLA_ACK:
34             // The device is now a slave receiver
35             slave_has_register_set = false;
36             break;
37
38         case TW_SR_DATA_ACK:
39             // This device is a slave receiver and has received data
40             // First byte is the location then the bytes will be writen in buffer with auto-incriment
41             if(!slave_has_register_set){
42                 buffer_address = TWDR;
43
44                 if (buffer_address >= I2C_SLAVE_REG_COUNT) {  // address out of bounds dont ack
45                   ack            = 0;
46                   buffer_address = 0;
47                 }
48                 slave_has_register_set = true; // address has been receaved now fill in buffer
49             } else {
50                 i2c_slave_reg[buffer_address] = TWDR;
51                 buffer_address++;
52             }
53             break;
54
55         case TW_ST_SLA_ACK:
56         case TW_ST_DATA_ACK:
57             // This device is a slave transmitter and master has requested data
58             TWDR = i2c_slave_reg[buffer_address];
59             buffer_address++;
60             break;
61
62         case TW_BUS_ERROR:
63             // We got an error, reset i2c
64             TWCR = 0;
65         default:
66             break;
67     }
68
69     // Reset i2c state machine to be ready for next interrupt
70     TWCR |= (1 << TWIE) | (1 << TWINT) | (ack << TWEA) | (1 << TWEN);
71 }