From 60797c8439f472c68f374acc11337e362a8836eb Mon Sep 17 00:00:00 2001
From: yiancar <yiangosyiangou@cytanet.com.cy>
Date: Thu, 12 Jul 2018 11:50:55 +0300
Subject: [PATCH] Add I2C slave library

- Add I2C slave library for general use.
---
 drivers/avr/i2c_slave.c | 100 ++++++++++++++++++++++++++++++++++++++++
 drivers/avr/i2c_slave.h |  19 ++++++++
 2 files changed, 119 insertions(+)
 create mode 100755 drivers/avr/i2c_slave.c
 create mode 100755 drivers/avr/i2c_slave.h

diff --git a/drivers/avr/i2c_slave.c b/drivers/avr/i2c_slave.c
new file mode 100755
index 0000000000..3edf85b12b
--- /dev/null
+++ b/drivers/avr/i2c_slave.c
@@ -0,0 +1,100 @@
+/* Library made by: g4lvanix
+ * Github repository: https://github.com/g4lvanix/I2C-slave-lib
+ */
+
+#include <avr/io.h>
+#include <util/twi.h>
+#include <avr/interrupt.h>
+
+#include "i2c_slave.h"
+
+void i2c_init(uint8_t address){
+	// load 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){
+	
+	// temporary stores the received data
+	uint8_t data;
+	
+	// own address has been acknowledged
+	if( (TWSR & 0xF8) == 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); 
+	}
+	else if( (TWSR & 0xF8) == TW_SR_DATA_ACK ){ // data has been received in slave receiver mode
+		
+		// save the received byte inside data 
+		data = TWDR;
+		
+		// check wether an address has already been transmitted or not
+		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); 
+		}
+		else{ // if a databyte has already been received
+			
+			// store the data at the current address
+			rxbuffer[buffer_address] = data;
+			
+			// increment the buffer address
+			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); 
+			}
+			else{
+				// Don't acknowledge
+				TWCR &= ~(1<<TWEA); 
+				// clear TWI interrupt flag, prepare to receive last byte.
+				TWCR |= (1<<TWIE) | (1<<TWINT) | (1<<TWEN); 
+			}
+		}
+	}
+	else if( (TWSR & 0xF8) == TW_ST_DATA_ACK ){ // device has been addressed to be a transmitter
+		
+		// copy data from TWDR to the temporary memory
+		data = TWDR;
+		
+		// if no buffer read address has been sent yet
+		if( buffer_address == 0xFF ){
+			buffer_address = data;
+		}
+		
+		// copy the specified buffer address into the TWDR register for transmission
+		TWDR = txbuffer[buffer_address];
+		// increment buffer read 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); 
+		}
+		else{
+			// Don't acknowledge
+			TWCR &= ~(1<<TWEA); 
+			// clear TWI interrupt flag, prepare to receive last byte.
+			TWCR |= (1<<TWIE) | (1<<TWINT) | (1<<TWEN); 
+		}
+		
+	}
+	else{
+		// if none of the above apply prepare TWI to be addressed again
+		TWCR |= (1<<TWIE) | (1<<TWEA) | (1<<TWEN);
+	} 
+}
diff --git a/drivers/avr/i2c_slave.h b/drivers/avr/i2c_slave.h
new file mode 100755
index 0000000000..3fda7f8c09
--- /dev/null
+++ b/drivers/avr/i2c_slave.h
@@ -0,0 +1,19 @@
+/* Library made by: g4lvanix
+ * Github repository: https://github.com/g4lvanix/I2C-slave-lib
+
+ Info: Inititate the library by giving the required address.
+       Read or write to the necessary buffer according to the opperation.
+ */
+
+#ifndef I2C_SLAVE_H
+#define I2C_SLAVE_H
+
+volatile uint8_t buffer_address;
+volatile uint8_t txbuffer[0xFF];
+volatile uint8_t rxbuffer[0xFF];
+
+void i2c_init(uint8_t address);
+void i2c_stop(void);
+ISR(TWI_vect);
+
+#endif // I2C_SLAVE_H