]> git.donarmstrong.com Git - qmk_firmware.git/blob - drivers/avr/i2c_slave.c
Add GPL3 header to avr i2c files (#6332)
[qmk_firmware.git] / drivers / avr / i2c_slave.c
1 /*  Copyright (C) 2019 Elia Ritterbusch
2  +
3  *  This program is free software: you can redistribute it and/or modify
4  *  it under the terms of the GNU General Public License as published by
5  *  the Free Software Foundation, either version 3 of the License, or
6  *  (at your option) any later version.
7  *
8  *  This program is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *  GNU General Public License for more details.
12  *
13  *  You should have received a copy of the GNU General Public License
14  *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
15  */
16 /* Library made by: g4lvanix
17  * Github repository: https://github.com/g4lvanix/I2C-slave-lib
18  */
19
20 #include <avr/io.h>
21 #include <util/twi.h>
22 #include <avr/interrupt.h>
23 #include <stdbool.h>
24
25 #include "i2c_slave.h"
26
27 volatile uint8_t i2c_slave_reg[I2C_SLAVE_REG_COUNT];
28
29 static volatile uint8_t buffer_address;
30 static volatile bool slave_has_register_set = false;
31
32 void i2c_slave_init(uint8_t address){
33     // load address into TWI address register
34     TWAR = address;
35     // set the TWCR to enable address matching and enable TWI, clear TWINT, enable TWI interrupt
36     TWCR = (1 << TWIE) | (1 << TWEA) | (1 << TWINT) | (1 << TWEN);
37 }
38
39 void i2c_slave_stop(void){
40     // clear acknowledge and enable bits
41     TWCR &= ~((1 << TWEA) | (1 << TWEN));
42 }
43
44 ISR(TWI_vect){
45     uint8_t ack = 1;
46
47     switch(TW_STATUS){
48         case TW_SR_SLA_ACK:
49             // The device is now a slave receiver
50             slave_has_register_set = false;
51             break;
52
53         case TW_SR_DATA_ACK:
54             // This device is a slave receiver and has received data
55             // First byte is the location then the bytes will be writen in buffer with auto-incriment
56             if(!slave_has_register_set){
57                 buffer_address = TWDR;
58
59                 if (buffer_address >= I2C_SLAVE_REG_COUNT) {  // address out of bounds dont ack
60                   ack            = 0;
61                   buffer_address = 0;
62                 }
63                 slave_has_register_set = true; // address has been receaved now fill in buffer
64             } else {
65                 i2c_slave_reg[buffer_address] = TWDR;
66                 buffer_address++;
67             }
68             break;
69
70         case TW_ST_SLA_ACK:
71         case TW_ST_DATA_ACK:
72             // This device is a slave transmitter and master has requested data
73             TWDR = i2c_slave_reg[buffer_address];
74             buffer_address++;
75             break;
76
77         case TW_BUS_ERROR:
78             // We got an error, reset i2c
79             TWCR = 0;
80         default:
81             break;
82     }
83
84     // Reset i2c state machine to be ready for next interrupt
85     TWCR |= (1 << TWIE) | (1 << TWINT) | (ack << TWEA) | (1 << TWEN);
86 }