changeset 0:6953c3fb919a draft

Initial commit
author Radomir Dopieralski <sheep-devel@sheep.art.pl>
date Sat, 19 May 2018 13:42:11 +0200
parents
children f297755eda97
files firmware/Makefile firmware/USI_TWI_Slave/USI_TWI_Slave.c firmware/USI_TWI_Slave/USI_TWI_Slave.d firmware/USI_TWI_Slave/USI_TWI_Slave.h firmware/USI_TWI_Slave/avr312_using_usi_module_as_i2c_slave.rst firmware/USI_TWI_Slave/main.c.txt firmware/USI_TWI_Slave/usi_io.h firmware/main.c tote-leg.fzz
diffstat 9 files changed, 797 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/firmware/Makefile	Sat May 19 13:42:11 2018 +0200
@@ -0,0 +1,64 @@
+DEVICE     = attiny44
+CLOCK      = 8000000
+PROGRAMMER = -c usbtiny
+OBJECTS    = main.o USI_TWI_Slave/USI_TWI_Slave.o
+
+# for ATTiny44
+# see http://www.engbedded.com/fusecalc/
+FUSES      = -U lfuse:w:0x62:m -U hfuse:w:0xdf:m -U efuse:w:0xff:m
+
+# Tune the lines below only if you know what you are doing:
+AVRDUDE = avrdude $(PROGRAMMER) -p $(DEVICE)
+COMPILE = avr-gcc -std=gnu99 -Wall -Os -DF_CPU=$(CLOCK) -mmcu=$(DEVICE)
+
+# symbolic targets:
+all:	main.hex
+
+.c.o:
+	$(COMPILE) -c $< -o $@
+	$(COMPILE) -MM -MF $*.d $<
+
+.S.o:
+	$(COMPILE) -x assembler-with-cpp -c $< -o $@
+
+.c.s:
+	$(COMPILE) -S $< -o $@
+
+flash:	all
+	$(AVRDUDE) -U flash:w:main.hex:i
+
+fuse:
+	$(AVRDUDE) $(FUSES)
+
+# Xcode uses the Makefile targets "", "clean" and "install"
+install: flash fuse
+
+# if you use a bootloader, change the command below appropriately:
+load: all
+	bootloadHID main.hex
+
+clean:
+	rm -f main.hex main.elf $(OBJECTS) *.d
+
+# file targets:
+main.elf: $(OBJECTS)
+	$(COMPILE) -o main.elf $(OBJECTS)
+
+main.hex: main.elf
+	rm -f main.hex
+	avr-objcopy -j .text -j .data -O ihex main.elf main.hex
+	avr-size --format=avr --mcu=$(DEVICE) main.elf
+# If you have an EEPROM section, you must also create a hex file for the
+# EEPROM and add it to the "flash" target.
+
+# Targets for code debugging and analysis:
+disasm:	main.elf
+	avr-objdump -d main.elf
+
+cpp:
+	$(COMPILE) -E main.c`gg
+
+deps:
+	$(COMPILE) -M *.c > deps.mk
+
+-include *.d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/firmware/USI_TWI_Slave/USI_TWI_Slave.c	Sat May 19 13:42:11 2018 +0200
@@ -0,0 +1,307 @@
+// This file has been prepared for Doxygen automatic documentation generation.
+/*! \file ********************************************************************
+*
+* Atmel Corporation
+*
+* File              : USI_TWI_Slave.c
+* Compiler          : IAR EWAAVR 4.11A
+* Revision          : $Revision: 614 $
+* Date              : $Date: 2006-07-07 16:27:05 +0800 (Fri, 07 Jul 2006) $
+* Updated by        : $Author: jllassen $
+*
+* Support mail      : avr@atmel.com
+*
+* Supported devices : All device with USI module can be used.
+*                     The example is written for the ATmega169, ATtiny26, ATmega325 & ATtiny2313
+*
+* AppNote           : AVR312 - Using the USI module as a I2C slave
+*
+* Description       : Functions for USI_TWI_receiver and USI_TWI_transmitter.
+*
+*
+****************************************************************************/
+#ifdef __GNUC__
+#include "avr/io.h"
+#include "avr/interrupt.h"
+#elif __ICCAVR__
+#include "ioavr.h"
+#include "inavr.h"
+#endif
+#include "USI_TWI_Slave.h"
+
+//********** Buffer **********//
+uint8_t TWI_Buffer[TWI_BUFFER_SIZE];
+
+//********** Static Variables **********//
+
+static unsigned char          TWI_slaveAddress;
+static volatile unsigned char USI_TWI_Overflow_State;
+
+/*=========================> Locals <=======================================*/
+static uint8_t *        TWI_RxBuf = TWI_Buffer;
+static volatile uint8_t TWI_RxHead;
+static volatile uint8_t TWI_RxTail;
+
+static uint8_t *        TWI_TxBuf = TWI_Buffer + TWI_RX_BUFFER_SIZE;
+static volatile uint8_t TWI_TxHead;
+static volatile uint8_t TWI_TxTail;
+
+void Flush_TWI_Buffers(void)
+{
+	TWI_RxTail = 0;
+	TWI_RxHead = 0;
+	TWI_TxTail = 0;
+	TWI_TxHead = 0;
+}
+
+//********** USI_TWI functions **********//
+
+/*----------------------------------------------------------
+  Initialise USI for TWI Slave mode.
+----------------------------------------------------------*/
+void USI_TWI_Slave_Initialise(unsigned char TWI_ownAddress)
+{
+	Flush_TWI_Buffers();
+
+	TWI_slaveAddress = TWI_ownAddress;
+
+	USI_TWI_On_Slave_Transmit = 0;
+	USI_TWI_On_Slave_Receive = 0;
+
+	PORT_USI_CL |= (1 << PORT_USI_SCL);     // Set SCL high
+	PORT_USI |= (1 << PORT_USI_SDA);        // Set SDA high
+	DDR_USI_CL |= (1 << PORT_USI_SCL);      // Set SCL as output
+	DDR_USI &= ~(1 << PORT_USI_SDA);        // Set SDA as input
+	USICR = (1 << USISIE) | (0 << USIOIE) | // Enable Start Condition Interrupt. Disable Overflow Interrupt.
+	        (1 << USIWM1) | (0 << USIWM0) | // Set USI in Two-wire mode. No USI Counter overflow prior
+	                                        // to first Start Condition (potentail failure)
+	        (1 << USICS1) | (0 << USICS0) | (0 << USICLK) | // Shift Register Clock Source = External, positive edge
+	        (0 << USITC);
+	USISR = 0xF0; // Clear all flags and reset overflow counter
+}
+
+// Disable USI for TWI Slave mode.
+void USI_TWI_Slave_Disable()
+{
+	DDR_USI_CL &= ~(1 << PORT_USI_SCL);  // Set SCL as input
+	DDR_USI &= ~(1 << PORT_USI_SDA);  // Set SDA as input
+	USICR = 0x00; // Disable USI
+	USISR = 0xF0; // Clear all flags and reset overflow counter
+}
+
+// Puts data in the transmission buffer, Waits if buffer is full.
+void USI_TWI_Transmit_Byte(unsigned char data)
+{
+	unsigned char tmphead;
+
+	tmphead = (TWI_TxHead + 1) & TWI_TX_BUFFER_MASK; // Calculate buffer index.
+	while (tmphead == TWI_TxTail)
+		;                         // Wait for free space in buffer.
+	TWI_TxBuf[tmphead] = data;    // Store data in buffer.
+	TWI_TxHead         = tmphead; // Store new index.
+}
+
+// Returns a byte from the receive buffer. Waits if buffer is empty.
+unsigned char USI_TWI_Receive_Byte(void)
+{
+	unsigned char tmptail;
+	unsigned char tmpRxTail; // Temporary variable to store volatile
+	tmpRxTail = TWI_RxTail;  // Not necessary, but prevents warnings
+	while (TWI_RxHead == tmpRxTail)
+		;
+	tmptail    = (TWI_RxTail + 1) & TWI_RX_BUFFER_MASK; // Calculate buffer index
+	TWI_RxTail = tmptail;                               // Store new index
+	return TWI_RxBuf[tmptail];                          // Return data from the buffer.
+}
+
+// Returns a byte from the receive buffer without incrementing TWI_RxTail. Waits if buffer is empty.
+unsigned char USI_TWI_Peek_Receive_Byte(void)
+{
+	unsigned char tmptail;
+	unsigned char tmpRxTail; // Temporary variable to store volatile
+	tmpRxTail = TWI_RxTail;  // Not necessary, but prevents warnings
+	while (TWI_RxHead == tmpRxTail)
+		;
+	tmptail    = (TWI_RxTail + 1) & TWI_RX_BUFFER_MASK; // Calculate buffer index
+	return TWI_RxBuf[tmptail];                          // Return data from the buffer.
+}
+
+// Check if there is data in the receive buffer.
+unsigned char USI_TWI_Data_In_Receive_Buffer(void)
+{
+	unsigned char tmpRxTail;          // Temporary variable to store volatile
+	tmpRxTail = TWI_RxTail;           // Not necessary, but prevents warnings
+	return (TWI_RxHead - tmpRxTail) & TWI_RX_BUFFER_MASK; // Return 0 (FALSE) if the receive buffer is empty.
+}
+
+// Check if there is space in the transmission buffer.
+unsigned char USI_TWI_Space_In_Transmission_Buffer(void)
+{
+	unsigned char tmpTxHead;
+	tmpTxHead = (TWI_TxHead + 1) & TWI_TX_BUFFER_MASK; // Calculate next buffer index.
+	return (TWI_TxTail - tmpTxHead) & TWI_TX_BUFFER_MASK; // Return 0 (FALSE) if the transmission buffer is full.
+}
+
+// Check if there is an active data session.
+unsigned char USI_TWI_Slave_Is_Active()
+{
+	// Active if Overflow Interrupt is enabled and no Stop Condition occurred
+	return (USICR & (1 << USIOIE)) && ((USISR & (1 << USIPF)) == 0);
+}
+
+/*----------------------------------------------------------
+ Detects the USI_TWI Start Condition and intialises the USI
+ for reception of the "TWI Address" packet.
+----------------------------------------------------------*/
+#ifdef __GNUC__
+ISR(USI_START_VECTOR)
+#elif __ICCAVR__
+#pragma vector = USI_START_VECTOR
+__interrupt void USI_Start_Condition_ISR(void)
+#endif
+{
+	unsigned char tmpPin; // Temporary variable for pin state
+	unsigned char tmpRxHead; // Temporary variable to store volatile
+	// call slave receive callback on repeated start
+	if (USI_TWI_On_Slave_Receive) {
+		tmpRxHead = TWI_RxHead;
+		if (TWI_RxTail != tmpRxHead) { // data in receive buffer
+			USI_TWI_On_Slave_Receive(USI_TWI_Data_In_Receive_Buffer());
+			// reset rx buffer
+			TWI_RxTail = tmpRxHead;
+		}
+	}
+
+	USI_TWI_Overflow_State = USI_SLAVE_CHECK_ADDRESS;
+	DDR_USI &= ~(1 << PORT_USI_SDA); // Set SDA as input
+	while ((tmpPin = (PIN_USI_CL & (1 << PORT_USI_SCL))) && ((PIN_USI & (1 << PIN_USI_SDA)) == 0))
+		; // Wait for SCL to go low to ensure the "Start Condition" has completed.
+	      // If a Stop condition arises then leave the interrupt to prevent waiting forever.
+	if (tmpPin) {
+		// Stop Condition (waiting for next Start Condition)
+		USICR = (1 << USISIE) | (0 << USIOIE) | // Enable Start Condition Interrupt. Disable Overflow Interrupt.
+		        (1 << USIWM1) | (0 << USIWM0) | // Set USI in Two-wire mode. No USI Counter overflow prior
+		                                        // to first Start Condition (potentail failure)
+		        (1 << USICS1) | (0 << USICS0) | (0 << USICLK) | // Shift Register Clock Source = External, positive edge
+		        (0 << USITC);
+	} else {
+		// really Start Condition (Enable Overflow Interrupt)
+		USICR = (1 << USISIE) | (1 << USIOIE)
+		        | // Enable Overflow and Start Condition Interrupt. (Keep StartCondInt to detect RESTART)
+		        (1 << USIWM1) | (1 << USIWM0) |                 // Set USI in Two-wire mode.
+		        (1 << USICS1) | (0 << USICS0) | (0 << USICLK) | // Shift Register Clock Source = External, positive edge
+		        (0 << USITC);
+	}
+	USISR = (1 << USI_START_COND_INT) | (1 << USIOIF) | (1 << USIPF) | (1 << USIDC) | // Clear flags
+	        (0x0 << USICNT0); // Set USI to sample 8 bits i.e. count 16 external pin toggles.
+}
+
+/*----------------------------------------------------------
+ Handels all the comunication. Is disabled only when waiting
+ for new Start Condition.
+----------------------------------------------------------*/
+#ifdef __GNUC__
+ISR(USI_OVERFLOW_VECTOR)
+#elif __ICCAVR__
+#pragma vector = USI_OVERFLOW_VECTOR
+__interrupt void USI_Counter_Overflow_ISR(void)
+#endif
+{
+	unsigned char tmpRxHead;
+	unsigned char tmpTxTail; // Temporary variables to store volatiles
+	unsigned char tmpUSIDR;
+
+	switch (USI_TWI_Overflow_State) {
+	// ---------- Address mode ----------
+	// Check address and send ACK (and next USI_SLAVE_SEND_DATA) if OK, else reset USI.
+	case USI_SLAVE_CHECK_ADDRESS:
+		if ((USIDR == 0) || ((USIDR >> 1) == TWI_slaveAddress)) {
+			if (USIDR & 0x01) {
+				if (USI_TWI_On_Slave_Transmit) {
+					// reset tx buffer and call callback
+					tmpTxTail = TWI_TxHead;
+					TWI_TxTail = tmpTxTail;
+					USI_TWI_On_Slave_Transmit();
+				}
+				USI_TWI_Overflow_State = USI_SLAVE_SEND_DATA;
+			} else {
+				USI_TWI_Overflow_State = USI_SLAVE_REQUEST_DATA;
+			}
+			SET_USI_TO_SEND_ACK();
+		} else {
+			SET_USI_TO_TWI_START_CONDITION_MODE();
+		}
+		break;
+
+	// ----- Master write data mode ------
+	// Check reply and goto USI_SLAVE_SEND_DATA if OK, else reset USI.
+	case USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA:
+		if (USIDR) // If NACK, the master does not want more data.
+		{
+			SET_USI_TO_TWI_START_CONDITION_MODE();
+			return;
+		}
+	// From here we just drop straight into USI_SLAVE_SEND_DATA if the master sent an ACK
+
+	// Copy data from buffer to USIDR and set USI to shift byte. Next USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA
+	case USI_SLAVE_SEND_DATA:
+
+		// Get data from Buffer
+		tmpTxTail = TWI_TxTail; // Not necessary, but prevents warnings
+		if (TWI_TxHead != tmpTxTail) {
+			TWI_TxTail = (TWI_TxTail + 1) & TWI_TX_BUFFER_MASK;
+			USIDR      = TWI_TxBuf[TWI_TxTail];
+		} else // If the buffer is empty then:
+		{
+			SET_USI_TO_TWI_START_CONDITION_MODE();
+			return;
+		}
+		USI_TWI_Overflow_State = USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA;
+		SET_USI_TO_SEND_DATA();
+		break;
+
+	// Set USI to sample reply from master. Next USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA
+	case USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA:
+		USI_TWI_Overflow_State = USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA;
+		SET_USI_TO_READ_ACK();
+		break;
+
+	// ----- Master read data mode ------
+	// Set USI to sample data from master. Next USI_SLAVE_GET_DATA_AND_SEND_ACK.
+	case USI_SLAVE_REQUEST_DATA:
+		USI_TWI_Overflow_State = USI_SLAVE_GET_DATA_AND_SEND_ACK;
+		SET_USI_TO_READ_DATA();
+		// call slave receive callback on stop condition
+		if (USI_TWI_On_Slave_Receive) {
+			tmpRxHead = TWI_RxHead;
+			if (TWI_RxTail != tmpRxHead) { // data in receive buffer
+				// check for stop Condition
+				while ((USISR & ((1 << USI_START_COND_INT) | (1 << USIPF) | (0xE << USICNT0))) == 0)
+					;// wait for either Start or Stop Condition
+					// cancel after one SCL cycle
+				if (USISR & (1 << USIPF)) { // Stop Condition
+					USI_TWI_On_Slave_Receive(USI_TWI_Data_In_Receive_Buffer());
+					// reset rx buffer
+					TWI_RxTail = tmpRxHead;
+				}
+			}
+		}
+		break;
+
+	// Copy data from USIDR and send ACK. Next USI_SLAVE_REQUEST_DATA
+	case USI_SLAVE_GET_DATA_AND_SEND_ACK:
+		// Put data into Buffer
+		USI_TWI_Overflow_State = USI_SLAVE_REQUEST_DATA;
+		tmpUSIDR              = USIDR; // Not necessary, but prevents warnings
+		tmpRxHead = (TWI_RxHead + 1) & TWI_RX_BUFFER_MASK;
+		if (TWI_RxTail != tmpRxHead) {
+			TWI_RxHead            = tmpRxHead;
+			TWI_RxBuf[TWI_RxHead] = tmpUSIDR;
+			SET_USI_TO_SEND_ACK();
+		} else // If the buffer is full then:
+		{
+			SET_USI_TO_SEND_NACK();
+		}
+		break;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/firmware/USI_TWI_Slave/USI_TWI_Slave.d	Sat May 19 13:42:11 2018 +0200
@@ -0,0 +1,2 @@
+USI_TWI_Slave.o: USI_TWI_Slave/USI_TWI_Slave.c \
+ USI_TWI_Slave/USI_TWI_Slave.h USI_TWI_Slave/usi_io.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/firmware/USI_TWI_Slave/USI_TWI_Slave.h	Sat May 19 13:42:11 2018 +0200
@@ -0,0 +1,133 @@
+// This file has been prepared for Doxygen automatic documentation generation.
+/*! \file ********************************************************************
+ *
+ * Atmel Corporation
+ *
+ * File              : USI_TWI_Slave.h
+ * Compiler          : IAR EWAAVR 4.11A
+ * Revision          : $Revision: 6351 $
+ * Date              : $Date: 2010-01-29 20:15:43 +0800 (Fri, 29 Jan 2010) $
+ * Updated by        : $Author: hskinnemoen $
+ *
+ * Support mail      : avr@atmel.com
+ *
+ * Supported devices : All device with USI module can be used.
+ *                     The example is written for the ATmega169, ATtiny26 & ATtiny2313
+ *
+ * AppNote           : AVR312 - Using the USI module as a TWI slave
+ *
+ * Description       : Header file for USI_TWI driver
+ *
+ *
+ *
+ ****************************************************************************/
+//********** Prototypes **********//
+
+void          USI_TWI_Slave_Initialise(unsigned char);
+void          USI_TWI_Slave_Disable();
+void          USI_TWI_Transmit_Byte(unsigned char);
+unsigned char USI_TWI_Receive_Byte(void);
+unsigned char USI_TWI_Peek_Receive_Byte(void);
+unsigned char USI_TWI_Data_In_Receive_Buffer(void);
+unsigned char USI_TWI_Space_In_Transmission_Buffer(void);
+unsigned char USI_TWI_Slave_Is_Active();
+
+void (*USI_TWI_On_Slave_Transmit)(void);
+void (*USI_TWI_On_Slave_Receive)(int);
+
+void Timer_Init(void);
+
+#define TRUE 1
+#define FALSE 0
+
+typedef unsigned char uint8_t;
+
+//////////////////////////////////////////////////////////////////
+///////////////// Driver Buffer Definitions //////////////////////
+//////////////////////////////////////////////////////////////////
+// 1,2,4,8,16,32,64,128 or 256 bytes are allowed buffer sizes
+extern uint8_t TWI_Buffer[];
+
+#define TWI_RX_BUFFER_SIZE (16)
+#define TWI_RX_BUFFER_MASK (TWI_RX_BUFFER_SIZE - 1)
+
+#if (TWI_RX_BUFFER_SIZE & TWI_RX_BUFFER_MASK)
+#error TWI RX buffer size is not a power of 2
+#endif
+
+// 1,2,4,8,16,32,64,128 or 256 bytes are allowed buffer sizes
+
+#define TWI_TX_BUFFER_SIZE (16)
+#define TWI_TX_BUFFER_MASK (TWI_TX_BUFFER_SIZE - 1)
+
+#if (TWI_TX_BUFFER_SIZE & TWI_TX_BUFFER_MASK)
+#error TWI TX buffer size is not a power of 2
+#endif
+
+#define TWI_BUFFER_SIZE (TWI_RX_BUFFER_SIZE + TWI_TX_BUFFER_SIZE)
+//////////////////////////////////////////////////////////////////
+
+#define USI_SLAVE_CHECK_ADDRESS (0x00)
+#define USI_SLAVE_SEND_DATA (0x01)
+#define USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA (0x02)
+#define USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA (0x03)
+#define USI_SLAVE_REQUEST_DATA (0x04)
+#define USI_SLAVE_GET_DATA_AND_SEND_ACK (0x05)
+
+// Device dependant defines
+#include "usi_io.h"
+
+#define SET_USI_TO_SEND_ACK()                                                                                          \
+	{                                                                                                                  \
+		USIDR = 0;                      /* Prepare ACK                         */                                      \
+		DDR_USI |= (1 << PORT_USI_SDA); /* Set SDA as output                   */                                      \
+		USISR = (0 << USI_START_COND_INT) | (1 << USIOIF) | (1 << USIPF) | (1 << USIDC)                                \
+		        |                  /* Clear all flags, except Start Cond  */                                           \
+		        (0x0E << USICNT0); /* set USI counter to shift 1 bit. */                                               \
+	}
+
+#define SET_USI_TO_SEND_NACK()                                                                                          \
+	{                                                                                                                  \
+		DDR_USI &= ~(1 << PORT_USI_SDA); /* Set SDA as intput, NACK is SDA high */                                     \
+		USISR = (0 << USI_START_COND_INT) | (1 << USIOIF) | (1 << USIPF) | (1 << USIDC)                                \
+		        |                  /* Clear all flags, except Start Cond  */                                           \
+		        (0x0E << USICNT0); /* set USI counter to shift 1 bit. */                                               \
+	}
+
+#define SET_USI_TO_READ_ACK()                                                                                          \
+	{                                                                                                                  \
+		DDR_USI &= ~(1 << PORT_USI_SDA); /* Set SDA as intput */                                                       \
+		USIDR = 0;                       /* Prepare ACK        */                                                      \
+		USISR = (0 << USI_START_COND_INT) | (1 << USIOIF) | (1 << USIPF) | (1 << USIDC)                                \
+		        |                  /* Clear all flags, except Start Cond  */                                           \
+		        (0x0E << USICNT0); /* set USI counter to shift 1 bit. */                                               \
+	}
+
+#define SET_USI_TO_TWI_START_CONDITION_MODE()                                                                          \
+	{                                                                                                                  \
+		DDR_USI &= ~(1 << PORT_USI_SDA); /* Set SDA as intput */                                                       \
+		USICR = (1 << USISIE) | (0 << USIOIE) | /* Enable Start Condition Interrupt. Disable Overflow Interrupt.*/     \
+		        (1 << USIWM1) | (0 << USIWM0) | /* Set USI in Two-wire mode. No USI Counter overflow hold.      */     \
+		        (1 << USICS1) | (0 << USICS0) | (0 << USICLK)                                                          \
+		        | /* Shift Register Clock Source = External, positive edge        */                                   \
+		        (0 << USITC);                                                                                          \
+		USISR = (0 << USI_START_COND_INT) | (1 << USIOIF) | (1 << USIPF) | (1 << USIDC)                                \
+		        | /* Clear all flags, except Start Cond                            */                                  \
+		        (0x0 << USICNT0);                                                                                      \
+	}
+
+#define SET_USI_TO_SEND_DATA()                                                                                         \
+	{                                                                                                                  \
+		DDR_USI |= (1 << PORT_USI_SDA); /* Set SDA as output                  */                                       \
+		USISR = (0 << USI_START_COND_INT) | (1 << USIOIF) | (1 << USIPF) | (1 << USIDC)                                \
+		        |                 /* Clear all flags, except Start Cond */                                             \
+		        (0x0 << USICNT0); /* set USI to shift out 8 bits        */                                             \
+	}
+
+#define SET_USI_TO_READ_DATA()                                                                                         \
+	{                                                                                                                  \
+		DDR_USI &= ~(1 << PORT_USI_SDA); /* Set SDA as input                   */                                      \
+		USISR = (0 << USI_START_COND_INT) | (1 << USIOIF) | (1 << USIPF) | (1 << USIDC)                                \
+		        |                 /* Clear all flags, except Start Cond */                                             \
+		        (0x0 << USICNT0); /* set USI to shift out 8 bits        */                                             \
+	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/firmware/USI_TWI_Slave/avr312_using_usi_module_as_i2c_slave.rst	Sat May 19 13:42:11 2018 +0200
@@ -0,0 +1,16 @@
+==========================================================================
+AVR312: Using the USI module as a I2C slave on tinyAVR and megaAVR devices
+==========================================================================
+
+This application note provides code examples to use the USI module on AVR devices as a I2C slave. Most of the tinyAVR and megaAVR devices have USI module which can perform both I2C slave and
+I2C master.
+
+For a more detailed description, please see the applicaiton note available from: http://www.atmel.com/images/atmel-2560-using-the-usi-module-as-a-i2c-slave_applicationnote_avr312.pdf
+
+================
+RUNNING THE DEMO
+================
+1. download the example .atzip file from Atmel|START
+2. With Atmel Studio 7 (or later), import .atzip file into Atmel Studio 7, File->Import->Atmel Start Project
+3. build and flash into supported evaluation board
+4. run (debug) the code
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/firmware/USI_TWI_Slave/main.c.txt	Sat May 19 13:42:11 2018 +0200
@@ -0,0 +1,106 @@
+/**
+ * \file
+ *
+ * \brief Using USI module as I2C slave example
+ *
+ * Copyright (C) 2016 Atmel Corporation. All rights reserved.
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ *    Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#ifdef __GNUC__
+#include "avr/io.h"
+#include "avr/interrupt.h"
+#include "avr/cpufunc.h"
+#elif __ICCAVR__
+#include "ioavr.h"
+#include "inavr.h"
+#endif
+
+#include "atmel_start.h"
+#include "USI_TWI_Slave.h"
+
+// Sample TWI transmission commands
+#define TWI_CMD_MASTER_WRITE 0x10
+#define TWI_CMD_MASTER_READ 0x20
+#define TWI_CMD_MASTER_WRITE_ALOT 0x30
+
+int main(void)
+{
+	unsigned char TWI_slaveAddress, temp;
+
+	atmel_start_init();
+	// LED feedback port - connect port B to the STK500 LEDS
+	// Below equals to PORTB = 0x55, low level is valid
+	PORTB_set_port_level(0xff, true);
+	PORTB_set_port_level((0xff - 0x55), false);
+
+	PORTA_set_port_dir(0xFF, PORT_DIR_OUT);
+	// Own TWI slave address
+	TWI_slaveAddress = 0x10;
+	USI_TWI_Slave_Initialise(TWI_slaveAddress);
+
+#ifdef __GNUC__
+	sei();
+#elif __ICCAVR__
+	__enable_interrupt();
+#endif
+	// This example is made to work together with the AVR310 USI TWI Master application note. In adition to connecting
+	// the TWI
+	// pins, also connect PORTB to the LEDS. The code reads a message as a TWI slave and acts according to if it is a
+	// general call, or an address call. If it is an address call, then the first byte is considered a command byte and
+	// it then responds differently according to the commands.
+
+	// This loop runs forever. If the TWI Transceiver is busy the execution will just continue doing other operations.
+	for (;;) {
+
+		if (USI_TWI_Data_In_Receive_Buffer()) {
+			temp = USI_TWI_Receive_Byte();
+			// Below equals to PORTB = temp, low level is valid
+			PORTB_set_port_level(0xff, true);
+			PORTB_set_port_level((0xff - temp), false);
+
+			USI_TWI_Transmit_Byte(temp);
+		}
+
+// Do something else while waiting for the TWI transceiver to complete.
+#ifdef __GNUC__
+		_NOP();
+#elif __ICCAVR__
+		__no_operation(); // Put own code here.
+#endif
+	}
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/firmware/USI_TWI_Slave/usi_io.h	Sat May 19 13:42:11 2018 +0200
@@ -0,0 +1,141 @@
+/*
+  usi_io.h - definitions for TWI/I2C via USI
+  Copyright (c) 2017 Puuu.  All right reserved.
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 3.0 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#ifndef USI_IO_h
+#define USI_IO_h
+
+#include <avr/io.h>
+
+#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) \
+    || defined(__AVR_ATtiny84__)
+#  define DDR_USI DDRA
+#  define PORT_USI PORTA
+#  define PIN_USI PINA
+#  define PORT_USI_SDA PORTA6
+#  define PORT_USI_SCL PORTA4
+#  define PIN_USI_SDA PINA6
+#  define PIN_USI_SCL PINA4
+#  define USI_START_VECTOR USI_START_vect
+#  define USI_OVERFLOW_VECTOR USI_OVF_vect
+#endif
+#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) \
+    || defined(__AVR_ATtiny85__) \
+    || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
+#  define DDR_USI DDRB
+#  define PORT_USI PORTB
+#  define PIN_USI PINB
+#  define PORT_USI_SDA PORTB0
+#  define PORT_USI_SCL PORTB2
+#  define PIN_USI_SDA PINB0
+#  define PIN_USI_SCL PINB2
+#  define USI_START_VECTOR USI_START_vect
+#  define USI_OVERFLOW_VECTOR USI_OVF_vect
+#endif
+#if defined(__AVR_ATtiny26__)
+#  define DDR_USI DDRB
+#  define PORT_USI PORTB
+#  define PIN_USI PINB
+#  define PORT_USI_SDA PORTB0
+#  define PORT_USI_SCL PORTB2
+#  define PIN_USI_SDA PINB0
+#  define PIN_USI_SCL PINB2
+#  define USI_START_VECTOR USI_STRT_vect
+#  define USI_OVERFLOW_VECTOR USI_OVF_vect
+#endif
+#if defined(__AVR_ATtiny2313__) || defined(__AVR_ATtiny4313__)
+#  define DDR_USI DDRB
+#  define PORT_USI PORTB
+#  define PIN_USI PINB
+#  define PORT_USI_SDA PORTB5
+#  define PORT_USI_SCL PORTB7
+#  define PIN_USI_SDA PINB5
+#  define PIN_USI_SCL PINB7
+#  define USI_START_VECTOR USI_START_vect
+#  define USI_OVERFLOW_VECTOR USI_OVERFLOW_vect
+#endif
+#if defined( __AVR_ATtiny261__ ) || defined( __AVR_ATtiny461__ ) \
+    || defined( __AVR_ATtiny861__ )
+#  define DDR_USI DDRB
+#  define PORT_USI PORTB
+#  define PIN_USI PINB
+#  define PORT_USI_SDA PB0
+#  define PORT_USI_SCL PB2
+#  define PIN_USI_SDA PINB0
+#  define PIN_USI_SCL PINB2
+#  define USI_START_VECTOR USI_START_vect
+#  define USI_OVERFLOW_VECTOR USI_OVF_vect
+#endif
+#if defined(__AVR_ATtiny43U__)
+#  define DDR_USI DDRB
+#  define PORT_USI PORTB
+#  define PIN_USI PINB
+#  define PORT_USI_SDA PORTB4
+#  define PORT_USI_SCL PORTB6
+#  define PIN_USI_SDA PINB4
+#  define PIN_USI_SCL PINB6
+#  define USI_START_VECTOR USI_START_vect
+#  define USI_OVERFLOW_VECTOR USI_OVF_vect
+#endif
+#if defined(__AVR_ATtiny1634__)
+#  define DDR_USI DDRB
+#  define PORT_USI PORTB
+#  define PIN_USI PINB
+#  define DDR_USI_CL DDRC
+#  define PORT_USI_CL PORTC
+#  define PIN_USI_CL PINC
+#  define PORT_USI_SDA PORTB1
+#  define PORT_USI_SCL PORTC1
+#  define PIN_USI_SDA PINB1
+#  define PIN_USI_SCL PINC1
+#  define USI_START_VECTOR USI_START_vect
+#  define USI_OVERFLOW_VECTOR USI_OVF_vect
+#endif
+#if defined(__AVR_ATmega165__) || defined(__AVR_ATmega165P__) \
+    || defined(__AVR_ATmega165PA__) \
+    || defined(__AVR_ATmega169__) || defined(__AVR_ATmega169P__) \
+    || defined(__AVR_ATmega169PA__) \
+    || defined(__AVR_ATmega645__) || defined(__AVR_ATmega6450__) \
+    || defined(__AVR_ATmega649__) || defined(__AVR_ATmega6490__) \
+    || defined(__AVR_ATmega649P__) \
+    || defined(__AVR_ATmega325__) || defined(__AVR_ATmega325PA__) \
+    || defined(__AVR_ATmega3250__) || defined(__AVR_ATmega3250PA__) \
+    || defined(__AVR_ATmega329__) || defined(__AVR_ATmega329P__) \
+    || defined(__AVR_ATmega3290PA__) || defined(__AVR_ATmega3290__)
+#  define DDR_USI DDRE
+#  define PORT_USI PORTE
+#  define PIN_USI PINE
+#  define PORT_USI_SDA PORTE5
+#  define PORT_USI_SCL PORTE4
+#  define PIN_USI_SDA PINE5
+#  define PIN_USI_SCL PINE4
+#  define USI_START_VECTOR USI_START_vect
+#  define USI_OVERFLOW_VECTOR USI_OVERFLOW_vect
+#endif
+
+#ifndef USI_START_COND_INT
+#  define USI_START_COND_INT USISIF
+#endif
+
+#ifndef DDR_USI_CL
+#  define DDR_USI_CL DDR_USI
+#  define PORT_USI_CL PORT_USI
+#  define PIN_USI_CL PIN_USI
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/firmware/main.c	Sat May 19 13:42:11 2018 +0200
@@ -0,0 +1,28 @@
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "USI_TWI_Slave/USI_TWI_Slave.h"
+
+
+#define I2C_ADDRESS 0x20
+volatile uint8_t command = 0;
+
+
+void on_i2c_transmit() {
+    switch (command) {
+        default:
+            USI_TWI_Transmit_Byte(command);
+    }
+}
+
+void on_i2c_receive(int count) {
+    if (count) {
+        command = USI_TWI_Receive_Byte();
+    }
+}
+
+void main() {
+    USI_TWI_Slave_Initialise(I2C_ADDRESS);
+    USI_TWI_On_Slave_Transmit = on_i2c_transmit;
+    USI_TWI_On_Slave_Receive = on_i2c_receive;
+}
Binary file tote-leg.fzz has changed