Mercurial > tote-leg
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; +}
