Browse files

Initial commit

  • Loading branch information...
0 parents commit 27ca4782eebec1c518372b7c44996982df96c977 @NSBum NSBum committed Apr 4, 2012
25 ATTINY_2313_I2C_SLAVE_TEST.avrsln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# AvrStudio Solution File, Format Version 11.00
+Project("{D1100916-62DA-4D80-A9B4-55A1E7CCEEB3}") = "ATTINY_2313_I2C_SLAVE_TEST", "ATTINY_2313_I2C_SLAVE_TEST\ATTINY_2313_I2C_SLAVE_TEST.avrgccproj", "{420B8F0D-2CC3-4724-A9D5-73DA44B22C38}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{CC35C171-55BE-491E-9089-A5A20A740AFB}"
+ ProjectSection(SolutionItems) = preProject
+ ..\..\lib\i2s-slave\usiTwiSlave.c = ..\..\lib\i2s-slave\usiTwiSlave.c
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|AVR = Debug|AVR
+ Release|AVR = Release|AVR
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {420B8F0D-2CC3-4724-A9D5-73DA44B22C38}.Debug|AVR.ActiveCfg = Debug|AVR
+ {420B8F0D-2CC3-4724-A9D5-73DA44B22C38}.Debug|AVR.Build.0 = Debug|AVR
+ {420B8F0D-2CC3-4724-A9D5-73DA44B22C38}.Release|AVR.ActiveCfg = Release|AVR
+ {420B8F0D-2CC3-4724-A9D5-73DA44B22C38}.Release|AVR.Build.0 = Release|AVR
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
BIN ATTINY_2313_I2C_SLAVE_TEST.avrsuo
Binary file not shown.
76 ATTINY_2313_I2C_SLAVE_TEST/ATTINY_2313_I2C_SLAVE_TEST.avrgccproj
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectVersion>5.0</ProjectVersion>
+ <ProjectGuid>{420b8f0d-2cc3-4724-a9d5-73da44b22c38}</ProjectGuid>
+ <avrdevice>ATtiny2313</avrdevice>
+ <avrdeviceseries>none</avrdeviceseries>
+ <OutputType>Executable</OutputType>
+ <Language>C</Language>
+ <OutputFile>$(MSBuildProjectName).elf</OutputFile>
+ <OutputDirectory>$(MSBuildProjectDirectory)\$(Configuration)</OutputDirectory>
+ <UseGlobalToolchain>True</UseGlobalToolchain>
+ <ToolchainDirPath>
+ </ToolchainDirPath>
+ <MakeDirPath>
+ </MakeDirPath>
+ <GlobalToolchainPath>C:\Program Files\Atmel\AVR Studio 5.0\AVR ToolChain\bin</GlobalToolchainPath>
+ <AvrGccProjectExtensions>
+ </AvrGccProjectExtensions>
+ <AssemblyName>ATTINY_2313_I2C_SLAVE_TEST</AssemblyName>
+ <Name>ATTINY_2313_I2C_SLAVE_TEST</Name>
+ <RootNamespace>ATTINY_2313_I2C_SLAVE_TEST</RootNamespace>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
+ <ToolchainSettings>
+ <AvrGcc>
+ <avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>
+ <avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>
+ <avrgcc.compiler.optimization.level>Optimize for size (-Os)</avrgcc.compiler.optimization.level>
+ <avrgcc.compiler.optimization.PackStructureMembers>True</avrgcc.compiler.optimization.PackStructureMembers>
+ <avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>
+ <avrgcc.compiler.optimization.DebugLevel>None</avrgcc.compiler.optimization.DebugLevel>
+ <avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>
+ </AvrGcc>
+ </ToolchainSettings>
+ <MemorySettings>
+ </MemorySettings>
+ <GenerateHexFile>True</GenerateHexFile>
+ <GenerateMapFile>True</GenerateMapFile>
+ <GenerateListFile>True</GenerateListFile>
+ <GenerateEepFile>True</GenerateEepFile>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
+ <ToolchainSettings>
+ <AvrGcc>
+ <avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>
+ <avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>
+ <avrgcc.compiler.optimization.level>Optimize most (-O3)</avrgcc.compiler.optimization.level>
+ <avrgcc.compiler.optimization.PackStructureMembers>True</avrgcc.compiler.optimization.PackStructureMembers>
+ <avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>
+ <avrgcc.compiler.optimization.DebugLevel>Default (-g2)</avrgcc.compiler.optimization.DebugLevel>
+ <avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>
+ <avrgcc.assembler.debugging.DebugLevel>Default (-g2)</avrgcc.assembler.debugging.DebugLevel>
+</AvrGcc>
+ </ToolchainSettings>
+ <MemorySettings>
+ </MemorySettings>
+ <GenerateHexFile>True</GenerateHexFile>
+ <GenerateMapFile>True</GenerateMapFile>
+ <GenerateListFile>True</GenerateListFile>
+ <GenerateEepFile>True</GenerateEepFile>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="ATTINY_2313_I2C_SLAVE_TEST.c">
+ <SubType>compile</SubType>
+ </Compile>
+ <Compile Include="usiTwiSlave.c">
+ <SubType>compile</SubType>
+ </Compile>
+ <Compile Include="usiTwiSlave.h">
+ <SubType>compile</SubType>
+ </Compile>
+ </ItemGroup>
+ <Import Project="$(AVRSTUDIO_EXE_PATH)\\Vs\\AvrGCC.targets" />
+</Project>
251 ATTINY_2313_I2C_SLAVE_TEST/ATTINY_2313_I2C_SLAVE_TEST.c
@@ -0,0 +1,251 @@
+/*
+ * ATTINY_2313_I2C_SLAVE_TEST.c
+ *
+ * Created: 11/28/2011 9:07:52 AM
+ * Author: Owner
+ */
+
+/***********************************************************************+/
+/| ATTiny2313 setup diagram |/
+ | |
+ | --------- -- |
+ | Vcc ----|1 20|----Vcc |
+ | HADDR0--|2 19|----SCL |
+ | HADDR1--|3 18|----NC |
+ | NC------|4 17|----SDA |
+ | NC------|5 16|----NC |
+ | HADDR2--|6 15|----NC |
+ | 1s sig--|7 14|----NC |
+ | NC------|8 13|----NC |
+ | NC------|9 12|----BURN |
+ | GND-----|10 11|----NC |
+ | ------------ |
+ | |
+ | Where HADDR0-2 is the hardware address that is read by the code at |
+ | startup. |
+ | BURN is the burn trigger. This pin is set to logic level 1 to begin |
+ | the burn process, typically triggering a relay to complete the burn |
+ | circuit.
+ | 1s sig is a 1 second pulse meant only for debugging. It will be |
+ | disabled in production code. |
+/************************************************************************/
+
+// Default clock speed
+/*
+ * The internal oscillator of the ATTiny2313 runs at 8 MHz. If the CKDIV8
+ * fuse is set, the system clock is prescaled by 8; therefore, we are setting
+ * the F_CPU at 1 MHz
+ */
+#define F_CPU 1000000UL
+#define DEBUG 0
+
+#include <util/delay.h>
+#include <avr/io.h>
+#include <avr/sfr_defs.h>
+#include <compat/twi.h>
+#include <avr/interrupt.h>
+#include "usiTwiSlave.h"
+
+#define NOP asm("nop"); // skip one clock cycle
+
+#ifndef SDA
+#define SDA (1<<PB5) // I2C SDA
+#endif
+
+#ifndef SCL
+#define SCL (1<<PB7) // I2C SCL
+#endif
+
+#ifndef BURN_TRIGGER
+#define BURN_TRIGGER (1<<PB0) // When this pin is high, the burn is turned on
+#endif
+
+#define DEFAULT_BURN_DURATION 2
+
+//
+// OPCODES FOR OUR VIRTUAL DEVICE
+//
+
+#define I2C_INITIATE_BURN 0x10 // stage 1 of the sequence
+#define I2C_CONFIRM_BURN 0x20 // stage 2 of the sequence; followed by secret code
+#define I2C_CANCEL_BURN 0x30 // cancel the process
+#define I2C_SET_BURN_DURATION 0x40 // followed by duration in seconds
+#define I2C_CONFIRM_BURN_SECRET_CODE 0xCC // this is the code that must be passed after I2C_CONFIRM_BURN
+#define I2C_ACKNOWLEDGE 0x7F // acknowledgment sent back to host after successfully confirming burn
+
+//
+// FUNCTION PROTOTYPES
+//
+void initTimer();
+uint8_t hardwareAddress();
+void beginBurn();
+
+enum {
+ MODE_DEFAULT,
+ MODE_INITIATED,
+ MODE_BURN
+};
+typedef uint8_t AKDBurnMode;
+
+//
+// GLOBALS
+//
+uint16_t second_count;
+AKDBurnMode _burn_mode;
+uint8_t _burn_duration;
+
+int main(void)
+{
+ _burn_mode = MODE_DEFAULT;
+ _burn_duration = DEFAULT_BURN_DURATION;
+ second_count = 0;
+
+ // setup Timer/Counter1 (16bit) which we will use for intervals
+ initTimer();
+
+ // setup PORTD data direction (PIND0-2 are the hardware address)
+ DDRD = 0b11111000;
+ // PB0 is the burn trigger; so set the data direction register
+ DDRB |= BURN_TRIGGER;
+ // we must not trigger a burn right now (don't want to drop the payload before takeoff!)
+ PORTB &= ~BURN_TRIGGER;
+ // obtain I2C address at PIND0-2
+ uint8_t slave_address = hardwareAddress();
+ // initialize as slave with our hardware address
+ usiTwiSlaveInit( slave_address );
+
+ // enable interrupts (must be there, i2c needs them!)
+ sei();
+ // handle commands via I2C bus
+ while (1)
+ {
+ // check if data is in the i2c receive buffer
+ if( usiTwiDataInReceiveBuffer() )
+ {
+ // the first byte in the stream is our opcode
+ uint8_t b = usiTwiReceiveByte();
+ _delay_ms(25);
+ if( b == I2C_INITIATE_BURN )
+ {
+ // if request is to initiate burn, only initiate if we are in default mode
+ // otherwise, for safety, we drop back to default mode
+ _burn_mode = (_burn_mode == MODE_DEFAULT)?MODE_INITIATED:MODE_DEFAULT;
+ }
+ else if( b == I2C_CANCEL_BURN )
+ {
+ // if the request is to cancel, always drop back to default mode
+ _burn_mode = MODE_DEFAULT;
+ PORTD &= ~BURN_TRIGGER;
+ }
+ else if( b == I2C_CONFIRM_BURN )
+ {
+ // if the request is to confirm, look for a second byte that has the
+ // confirmation code.
+ uint8_t confirm_byte = usiTwiReceiveByte();
+ if( confirm_byte == I2C_CONFIRM_BURN_SECRET_CODE )
+ {
+ usiTwiTransmitByte(I2C_ACKNOWLEDGE);
+ _delay_ms(10);
+ _burn_mode = MODE_BURN;
+ beginBurn();
+ }
+ }
+ else if( b == I2C_SET_BURN_DURATION )
+ {
+ // if the request if to set the burn duration, then look for the duration
+ // in seconds in the next byte
+ uint8_t duration_byte = usiTwiReceiveByte();
+ _burn_duration = duration_byte;
+ }
+ }
+ // waste a cycle
+ NOP
+ }
+ return 0;
+}
+
+//
+// Initiate the timer/counter
+//
+// We are using TIMER/COUNTER 1 in CTC mode
+// Target Timer Count = (Input Frequency / Prescale) / Target Frequency - 1
+// or, (10^6/64/1)-1 = 15624
+//
+void initTimer()
+{
+ // Configure timer 1 for CTC mode
+ TCCR1B |= (1 << WGM12);
+ // Enable CTC interrupt
+ TIMSK |= (1 << OCIE1A);
+
+ // Enable global interrupts
+ sei();
+
+ // Set CTC compare value to 1Hz at 1MHz AVR clock, with a prescaler of 64
+ OCR1A = 15624;
+ // Start timer at Fcpu/64
+ TCCR1B |= ((1 << CS10) | (1 << CS11));
+}
+//
+// Reads the hardware address of the device
+//
+// The hardware address is set at PD0-2
+//
+uint8_t hardwareAddress() {
+ return PIND & ~0b11111000;
+}
+
+void beginBurn()
+{
+ PORTB |= BURN_TRIGGER;
+}
+
+ISR(TIMER1_COMPA_vect)
+{
+ // pulse the PD3 pin every second for testing purposes
+ if( DEBUG ) {
+ PORTD ^= (1<<PD3);
+ }
+ // don't increment second count if we're not burning
+ if( _burn_mode == MODE_BURN )
+ {
+ second_count++;
+ // if we reach the end of the burn cycle, then turn off the relay
+ if( second_count >= _burn_duration )
+ {
+ second_count = 0;
+ _burn_mode = MODE_DEFAULT;
+ PORTB &= ~BURN_TRIGGER;
+ }
+ }
+}
+
+
+/*
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+
+int main (void)
+{
+ DDRB |= (1 << 0); // Set LED as output
+
+ TIMSK |= (1 << TOIE1); // Enable overflow interrupt
+ sei(); // Enable global interrupts
+
+ TCNT1 = 49911; // Preload timer with precalculated value
+
+ TCCR1B |= ((1 << CS10) | (1 << CS11)); // Set up timer at Fcpu/64
+
+ for (;;)
+ {
+
+ }
+}
+
+ISR(TIMER1_OVF_vect)
+{
+ PORTB ^= (1 << 0); // Toggle the LED
+ TCNT1 = 49911; // Reload timer with precalculated value
+}
+*/
598 ATTINY_2313_I2C_SLAVE_TEST/usiTwiSlave.c
@@ -0,0 +1,598 @@
+/********************************************************************************
+
+USI TWI Slave driver.
+
+Created by Donald R. Blake. donblake at worldnet.att.net
+Adapted by Jochen Toppe, jochen.toppe at jtoee.com
+
+---------------------------------------------------------------------------------
+
+Created from Atmel source files for Application Note AVR312: Using the USI Module
+as an I2C slave.
+
+This program is free software; you can redistribute it and/or modify it under the
+terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program 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 General Public License for more details.
+
+---------------------------------------------------------------------------------
+
+Change Activity:
+
+ Date Description
+ ------ -------------
+ 16 Mar 2007 Created.
+ 27 Mar 2007 Added support for ATtiny261, 461 and 861.
+ 26 Apr 2007 Fixed ACK of slave address on a read.
+ 04 Jul 2007 Fixed USISIF in ATtiny45 def
+ 12 Dev 2009 Added callback functions for data requests
+
+********************************************************************************/
+
+#ifndef TEST
+
+/********************************************************************************
+ includes
+********************************************************************************/
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+
+#include "usiTwiSlave.h"
+//#include "../common/util.h"
+
+
+/********************************************************************************
+ device dependent defines
+********************************************************************************/
+
+#if defined( __AVR_ATtiny2313__ )
+# define DDR_USI DDRB
+# define PORT_USI PORTB
+# define PIN_USI PINB
+# define PORT_USI_SDA PB5
+# define PORT_USI_SCL PB7
+# define PIN_USI_SDA PINB5
+# define PIN_USI_SCL PINB7
+# define USI_START_COND_INT USISIF
+# define USI_START_VECTOR USI_START_vect
+# define USI_OVERFLOW_VECTOR USI_OVERFLOW_vect
+#endif
+
+#if defined( __AVR_ATtiny25__ ) | \
+ defined( __AVR_ATtiny45__ ) | \
+ defined( __AVR_ATtiny85__ )
+# 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_COND_INT USISIF
+# 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 PB0
+# define PORT_USI_SCL PB2
+# define PIN_USI_SDA PINB0
+# define PIN_USI_SCL PINB2
+# define USI_START_COND_INT USISIF
+# define USI_START_VECTOR USI_STRT_vect
+# define USI_OVERFLOW_VECTOR USI_OVF_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_COND_INT USISIF
+# define USI_START_VECTOR USI_START_vect
+# define USI_OVERFLOW_VECTOR USI_OVF_vect
+#endif
+
+#if defined( __AVR_ATmega165__ ) | \
+ defined( __AVR_ATmega325__ ) | \
+ defined( __AVR_ATmega3250__ ) | \
+ defined( __AVR_ATmega645__ ) | \
+ defined( __AVR_ATmega6450__ ) | \
+ defined( __AVR_ATmega329__ ) | \
+ defined( __AVR_ATmega3290__ )
+# define DDR_USI DDRE
+# define PORT_USI PORTE
+# define PIN_USI PINE
+# define PORT_USI_SDA PE5
+# define PORT_USI_SCL PE4
+# define PIN_USI_SDA PINE5
+# define PIN_USI_SCL PINE4
+# define USI_START_COND_INT USISIF
+# define USI_START_VECTOR USI_START_vect
+# define USI_OVERFLOW_VECTOR USI_OVERFLOW_vect
+#endif
+
+#if defined( __AVR_ATmega169__ )
+# define DDR_USI DDRE
+# define PORT_USI PORTE
+# define PIN_USI PINE
+# define PORT_USI_SDA PE5
+# define PORT_USI_SCL PE4
+# define PIN_USI_SDA PINE5
+# define PIN_USI_SCL PINE4
+# define USI_START_COND_INT USISIF
+# define USI_START_VECTOR USI_START_vect
+# define USI_OVERFLOW_VECTOR USI_OVERFLOW_vect
+#endif
+
+
+
+/********************************************************************************
+
+ functions implemented as macros
+
+********************************************************************************/
+
+#define SET_USI_TO_SEND_ACK( ) \
+{ \
+ /* prepare ACK */ \
+ USIDR = 0; \
+ /* set SDA as output */ \
+ DDR_USI |= ( 1 << PORT_USI_SDA ); \
+ /* clear all interrupt flags, except Start Cond */ \
+ USISR = \
+ ( 0 << USI_START_COND_INT ) | \
+ ( 1 << USIOIF ) | ( 1 << USIPF ) | \
+ ( 1 << USIDC )| \
+ /* set USI counter to shift 1 bit */ \
+ ( 0x0E << USICNT0 ); \
+}
+
+#define SET_USI_TO_READ_ACK( ) \
+{ \
+ /* set SDA as input */ \
+ DDR_USI &= ~( 1 << PORT_USI_SDA ); \
+ /* prepare ACK */ \
+ USIDR = 0; \
+ /* clear all interrupt flags, except Start Cond */ \
+ USISR = \
+ ( 0 << USI_START_COND_INT ) | \
+ ( 1 << USIOIF ) | \
+ ( 1 << USIPF ) | \
+ ( 1 << USIDC ) | \
+ /* set USI counter to shift 1 bit */ \
+ ( 0x0E << USICNT0 ); \
+}
+
+#define SET_USI_TO_TWI_START_CONDITION_MODE( ) \
+{ \
+ USICR = \
+ /* enable Start Condition Interrupt, disable Overflow Interrupt */ \
+ ( 1 << USISIE ) | ( 0 << USIOIE ) | \
+ /* set USI in Two-wire mode, no USI Counter overflow hold */ \
+ ( 1 << USIWM1 ) | ( 0 << USIWM0 ) | \
+ /* Shift Register Clock Source = External, positive edge */ \
+ /* 4-Bit Counter Source = external, both edges */ \
+ ( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) | \
+ /* no toggle clock-port pin */ \
+ ( 0 << USITC ); \
+ USISR = \
+ /* clear all interrupt flags, except Start Cond */ \
+ ( 0 << USI_START_COND_INT ) | ( 1 << USIOIF ) | ( 1 << USIPF ) | \
+ ( 1 << USIDC ) | ( 0x0 << USICNT0 ); \
+}
+
+#define SET_USI_TO_SEND_DATA( ) \
+{ \
+ /* set SDA as output */ \
+ DDR_USI |= ( 1 << PORT_USI_SDA ); \
+ /* clear all interrupt flags, except Start Cond */ \
+ USISR = \
+ ( 0 << USI_START_COND_INT ) | ( 1 << USIOIF ) | ( 1 << USIPF ) | \
+ ( 1 << USIDC) | \
+ /* set USI to shift out 8 bits */ \
+ ( 0x0 << USICNT0 ); \
+}
+
+#define SET_USI_TO_READ_DATA( ) \
+{ \
+ /* set SDA as input */ \
+ DDR_USI &= ~( 1 << PORT_USI_SDA ); \
+ /* clear all interrupt flags, except Start Cond */ \
+ USISR = \
+ ( 0 << USI_START_COND_INT ) | ( 1 << USIOIF ) | \
+ ( 1 << USIPF ) | ( 1 << USIDC ) | \
+ /* set USI to shift out 8 bits */ \
+ ( 0x0 << USICNT0 ); \
+}
+
+
+
+/********************************************************************************
+
+ typedef's
+
+********************************************************************************/
+
+typedef enum
+{
+ USI_SLAVE_CHECK_ADDRESS = 0x00,
+ USI_SLAVE_SEND_DATA = 0x01,
+ USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA = 0x02,
+ USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA = 0x03,
+ USI_SLAVE_REQUEST_DATA = 0x04,
+ USI_SLAVE_GET_DATA_AND_SEND_ACK = 0x05
+} overflowState_t;
+
+
+
+/********************************************************************************
+
+ local variables
+
+********************************************************************************/
+
+static uint8_t slaveAddress;
+static volatile overflowState_t overflowState;
+
+
+static uint8_t rxBuf[ TWI_RX_BUFFER_SIZE ];
+static volatile uint8_t rxHead;
+static volatile uint8_t rxTail;
+
+static uint8_t txBuf[ TWI_TX_BUFFER_SIZE ];
+static volatile uint8_t txHead;
+static volatile uint8_t txTail;
+
+// data requested callback
+void (*_onTwiDataRequest)(void);
+
+
+
+/********************************************************************************
+
+ local functions
+
+********************************************************************************/
+
+
+
+// flushes the TWI buffers
+
+static
+void
+flushTwiBuffers(
+ void
+)
+{
+ rxTail = 0;
+ rxHead = 0;
+ txTail = 0;
+ txHead = 0;
+} // end flushTwiBuffers
+
+
+
+/********************************************************************************
+
+ public functions
+
+********************************************************************************/
+
+
+
+// initialise USI for TWI slave mode
+
+void
+usiTwiSlaveInit(
+ uint8_t ownAddress
+)
+{
+
+ flushTwiBuffers( );
+
+ slaveAddress = ownAddress;
+
+ // In Two Wire mode (USIWM1, USIWM0 = 1X), the slave USI will pull SCL
+ // low when a start condition is detected or a counter overflow (only
+ // for USIWM1, USIWM0 = 11). This inserts a wait state. SCL is released
+ // by the ISRs (USI_START_vect and USI_OVERFLOW_vect).
+
+ // Set SCL and SDA as output
+ DDR_USI |= ( 1 << PORT_USI_SCL ) | ( 1 << PORT_USI_SDA );
+
+ // set SCL high
+ PORT_USI |= ( 1 << PORT_USI_SCL );
+
+ // set SDA high
+ PORT_USI |= ( 1 << PORT_USI_SDA );
+
+ // Set SDA as input
+ DDR_USI &= ~( 1 << PORT_USI_SDA );
+
+ USICR =
+ // enable Start Condition Interrupt
+ ( 1 << USISIE ) |
+ // disable Overflow Interrupt
+ ( 0 << USIOIE ) |
+ // set USI in Two-wire mode, no USI Counter overflow hold
+ ( 1 << USIWM1 ) | ( 0 << USIWM0 ) |
+ // Shift Register Clock Source = external, positive edge
+ // 4-Bit Counter Source = external, both edges
+ ( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) |
+ // no toggle clock-port pin
+ ( 0 << USITC );
+
+ // clear all interrupt flags and reset overflow counter
+
+ USISR = ( 1 << USI_START_COND_INT ) | ( 1 << USIOIF ) | ( 1 << USIPF ) | ( 1 << USIDC );
+
+} // end usiTwiSlaveInit
+
+
+bool usiTwiDataInTransmitBuffer(void)
+{
+
+ // return 0 (false) if the receive buffer is empty
+ return txHead != txTail;
+
+} // end usiTwiDataInTransmitBuffer
+
+
+// put data in the transmission buffer, wait if buffer is full
+
+void
+usiTwiTransmitByte(
+ uint8_t data
+)
+{
+
+ uint8_t tmphead;
+
+ // calculate buffer index
+ tmphead = ( txHead + 1 ) & TWI_TX_BUFFER_MASK;
+
+ // wait for free space in buffer
+ while ( tmphead == txTail );
+
+ // store data in buffer
+ txBuf[ tmphead ] = data;
+
+ // store new index
+ txHead = tmphead;
+
+} // end usiTwiTransmitByte
+
+
+
+
+
+// return a byte from the receive buffer, wait if buffer is empty
+
+uint8_t
+usiTwiReceiveByte(
+ void
+)
+{
+
+ // wait for Rx data
+ while ( rxHead == rxTail );
+
+ // calculate buffer index
+ rxTail = ( rxTail + 1 ) & TWI_RX_BUFFER_MASK;
+
+ // return data from the buffer.
+ return rxBuf[ rxTail ];
+
+} // end usiTwiReceiveByte
+
+
+
+// check if there is data in the receive buffer
+
+bool
+usiTwiDataInReceiveBuffer(
+ void
+)
+{
+
+ // return 0 (false) if the receive buffer is empty
+ return rxHead != rxTail;
+
+} // end usiTwiDataInReceiveBuffer
+
+
+
+/********************************************************************************
+
+ USI Start Condition ISR
+
+********************************************************************************/
+
+ISR( USI_START_VECTOR )
+{
+
+ // set default starting conditions for new TWI package
+ overflowState = USI_SLAVE_CHECK_ADDRESS;
+
+ // set SDA as input
+ DDR_USI &= ~( 1 << PORT_USI_SDA );
+
+ // wait for SCL to go low to ensure the Start Condition has completed (the
+ // start detector will hold SCL low ) - if a Stop Condition arises then leave
+ // the interrupt to prevent waiting forever - don't use USISR to test for Stop
+ // Condition as in Application Note AVR312 because the Stop Condition Flag is
+ // going to be set from the last TWI sequence
+ while (
+ // SCL his high
+ ( PIN_USI & ( 1 << PIN_USI_SCL ) ) &&
+ // and SDA is low
+ !( ( PIN_USI & ( 1 << PIN_USI_SDA ) ) )
+ );
+
+
+ if ( !( PIN_USI & ( 1 << PIN_USI_SDA ) ) )
+ {
+
+ // a Stop Condition did not occur
+
+ USICR =
+ // keep Start Condition Interrupt enabled to detect RESTART
+ ( 1 << USISIE ) |
+ // enable Overflow Interrupt
+ ( 1 << USIOIE ) |
+ // set USI in Two-wire mode, hold SCL low on USI Counter overflow
+ ( 1 << USIWM1 ) | ( 1 << USIWM0 ) |
+ // Shift Register Clock Source = External, positive edge
+ // 4-Bit Counter Source = external, both edges
+ ( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) |
+ // no toggle clock-port pin
+ ( 0 << USITC );
+
+ }
+ else
+ {
+
+ // a Stop Condition did occur
+ USICR =
+ // enable Start Condition Interrupt
+ ( 1 << USISIE ) |
+ // disable Overflow Interrupt
+ ( 0 << USIOIE ) |
+ // set USI in Two-wire mode, no USI Counter overflow hold
+ ( 1 << USIWM1 ) | ( 0 << USIWM0 ) |
+ // Shift Register Clock Source = external, positive edge
+ // 4-Bit Counter Source = external, both edges
+ ( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) |
+ // no toggle clock-port pin
+ ( 0 << USITC );
+
+ } // end if
+
+ USISR =
+ // clear interrupt flags - resetting the Start Condition Flag will
+ // release SCL
+ ( 1 << USI_START_COND_INT ) | ( 1 << USIOIF ) |
+ ( 1 << USIPF ) |( 1 << USIDC ) |
+ // set USI to sample 8 bits (count 16 external SCL pin toggles)
+ ( 0x0 << USICNT0);
+
+} // end ISR( USI_START_VECTOR )
+
+
+
+/********************************************************************************
+
+ USI Overflow ISR
+
+Handles all the communication.
+
+Only disabled when waiting for a new Start Condition.
+
+********************************************************************************/
+
+ISR( USI_OVERFLOW_VECTOR )
+{
+
+ switch ( overflowState )
+ {
+
+ // 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 ) == slaveAddress) )
+ {
+ // callback
+ if(_onTwiDataRequest) _onTwiDataRequest();
+ if ( USIDR & 0x01 )
+ {
+ overflowState = USI_SLAVE_SEND_DATA;
+ }
+ else
+ {
+ overflowState = USI_SLAVE_REQUEST_DATA;
+ } // end if
+ 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
+ if ( txHead != txTail )
+ {
+ txTail = ( txTail + 1 ) & TWI_TX_BUFFER_MASK;
+ USIDR = txBuf[ txTail ];
+ }
+ else
+ {
+ // the buffer is empty
+ SET_USI_TO_TWI_START_CONDITION_MODE( );
+ return;
+ } // end if
+ overflowState = 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:
+ overflowState = 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:
+ overflowState = USI_SLAVE_GET_DATA_AND_SEND_ACK;
+ SET_USI_TO_READ_DATA( );
+ 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
+ // Not necessary, but prevents warnings
+ rxHead = ( rxHead + 1 ) & TWI_RX_BUFFER_MASK;
+ rxBuf[ rxHead ] = USIDR;
+ // next USI_SLAVE_REQUEST_DATA
+ overflowState = USI_SLAVE_REQUEST_DATA;
+ SET_USI_TO_SEND_ACK( );
+ break;
+
+ } // end switch
+
+} // end ISR( USI_OVERFLOW_VECTOR )
+
+#endif /* TEST */
+
90 ATTINY_2313_I2C_SLAVE_TEST/usiTwiSlave.h
@@ -0,0 +1,90 @@
+/********************************************************************************
+
+Header file for the USI TWI Slave driver.
+
+Created by Donald R. Blake
+donblake at worldnet.att.net
+
+---------------------------------------------------------------------------------
+
+Created from Atmel source files for Application Note AVR312: Using the USI Module
+as an I2C slave.
+
+This program is free software; you can redistribute it and/or modify it under the
+terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program 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 General Public License for more details.
+
+---------------------------------------------------------------------------------
+
+Change Activity:
+
+ Date Description
+ ------ -------------
+ 15 Mar 2007 Created.
+
+********************************************************************************/
+
+
+
+#ifndef _USI_TWI_SLAVE_H_
+#define _USI_TWI_SLAVE_H_
+
+
+
+/********************************************************************************
+
+ includes
+
+********************************************************************************/
+
+#include <stdbool.h>
+
+
+
+/********************************************************************************
+
+ prototypes
+
+********************************************************************************/
+
+void usiTwiSlaveInit( uint8_t );
+void usiTwiTransmitByte( uint8_t );
+uint8_t usiTwiReceiveByte( void );
+bool usiTwiDataInReceiveBuffer( void );
+void (*_onTwiDataRequest)(void);
+bool usiTwiDataInTransmitBuffer(void);
+
+
+/********************************************************************************
+
+ driver buffer definitions
+
+********************************************************************************/
+
+// permitted RX buffer sizes: 1, 2, 4, 8, 16, 32, 64, 128 or 256
+
+#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
+
+// permitted TX buffer sizes: 1, 2, 4, 8, 16, 32, 64, 128 or 256
+
+#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
+
+
+
+#endif // ifndef _USI_TWI_SLAVE_H_
+

0 comments on commit 27ca478

Please sign in to comment.