diff --git a/i2c_test_attiny85/i2c_test_attiny85.componentinfo.xml b/i2c_test_attiny85/i2c_test_attiny85.componentinfo.xml index 80c79cc..f38ac81 100755 --- a/i2c_test_attiny85/i2c_test_attiny85.componentinfo.xml +++ b/i2c_test_attiny85/i2c_test_attiny85.componentinfo.xml @@ -9,57 +9,57 @@ Atmel - 1.2.0 - C:/Program Files (x86)\Atmel\Studio\7.0\Packs + 1.8.0 + D:/Programs\Atmelstudio\7.0\Packs - C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATtiny_DFP\1.2.118\include + D:/Programs\Atmelstudio\7.0\Packs\atmel\ATtiny_DFP\1.8.332\include\ include C - include + include/ - C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATtiny_DFP\1.2.118\include\avr\iotn85.h + D:/Programs\Atmelstudio\7.0\Packs\atmel\ATtiny_DFP\1.8.332\include\avr\iotn85.h header C - RcYmivGpgsCGGCzeWAIjcA== + T0lnJZ6iliUJCzU7ZHCMPQ== include/avr/iotn85.h - C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATtiny_DFP\1.2.118\templates\main.c + D:/Programs\Atmelstudio\7.0\Packs\atmel\ATtiny_DFP\1.8.332\templates\main.c template source C Exe - GD1k8YYhulqRs6FD1B2Hog== + KjvOcFWd++tbnsEMfVPd/w== templates/main.c Main file (.c) - C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATtiny_DFP\1.2.118\templates\main.cpp + D:/Programs\Atmelstudio\7.0\Packs\atmel\ATtiny_DFP\1.8.332\templates\main.cpp template source C Exe - YXFphlh0CtZJU+ebktABgQ== + mkKaE95TOoATsuBGv6jmxg== templates/main.cpp Main file (.cpp) - C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATtiny_DFP\1.2.118\gcc\dev\attiny85 + D:/Programs\Atmelstudio\7.0\Packs\atmel\ATtiny_DFP\1.8.332\gcc\dev\attiny85 libraryPrefix GCC @@ -71,8 +71,8 @@ ATtiny_DFP - C:/Program Files (x86)/Atmel/Studio/7.0/Packs/atmel/ATtiny_DFP/1.2.118/Atmel.ATtiny_DFP.pdsc - 1.2.118 + D:/Programs/Atmelstudio/7.0/Packs/atmel/ATtiny_DFP/1.8.332/Atmel.ATtiny_DFP.pdsc + 1.8.332 true ATtiny85 diff --git a/i2c_test_attiny85/i2c_test_attiny85.cproj b/i2c_test_attiny85/i2c_test_attiny85.cproj index 59a26aa..758d011 100755 --- a/i2c_test_attiny85/i2c_test_attiny85.cproj +++ b/i2c_test_attiny85/i2c_test_attiny85.cproj @@ -28,15 +28,15 @@ 0 - - - - - - - - - + + + + + + + + + com.atmel.avrdbg.tool.stk500 @@ -72,79 +72,79 @@ - -mmcu=attiny85 -B "%24(PackRepoDir)\atmel\ATtiny_DFP\1.2.118\gcc\dev\attiny85" - True - True - True - True - False - True - True - - - NDEBUG - - - - - %24(PackRepoDir)\atmel\ATtiny_DFP\1.2.118\include - - - Optimize for size (-Os) - True - True - True - - - libm - - - - - %24(PackRepoDir)\atmel\ATtiny_DFP\1.2.118\include - - - + -mmcu=attiny85 -B "%24(PackRepoDir)\atmel\ATtiny_DFP\1.2.118\gcc\dev\attiny85" + True + True + True + True + False + True + True + + + NDEBUG + + + + + %24(PackRepoDir)\atmel\ATtiny_DFP\1.2.118\include + + + Optimize for size (-Os) + True + True + True + + + libm + + + + + %24(PackRepoDir)\atmel\ATtiny_DFP\1.2.118\include + + + - -mmcu=attiny85 -B "%24(PackRepoDir)\atmel\ATtiny_DFP\1.2.118\gcc\dev\attiny85" - True - True - True - True - False - True - True - - - DEBUG - - - - - %24(PackRepoDir)\atmel\ATtiny_DFP\1.2.118\include - - - Optimize (-O1) - True - True - Default (-g2) - True - - - libm - - - - - %24(PackRepoDir)\atmel\ATtiny_DFP\1.2.118\include - - - Default (-Wa,-g) - + -mmcu=attiny85 -B "%24(PackRepoDir)\atmel\ATtiny_DFP\1.2.118\gcc\dev\attiny85" + True + True + True + True + False + True + True + + + DEBUG + + + + + %24(PackRepoDir)\atmel\ATtiny_DFP\1.2.118\include + + + Optimize (-O1) + True + True + Default (-g2) + True + + + libm + + + + + %24(PackRepoDir)\atmel\ATtiny_DFP\1.2.118\include + + + Default (-Wa,-g) + @@ -163,10 +163,10 @@ compile - + compile - + compile diff --git a/i2c_test_attiny85/led_gen.c b/i2c_test_attiny85/led_gen.c index 9e5e026..5c93e9e 100755 --- a/i2c_test_attiny85/led_gen.c +++ b/i2c_test_attiny85/led_gen.c @@ -11,16 +11,16 @@ void led1_init(void) { DDRB |= (1< #include @@ -21,7 +21,7 @@ #define NOTHING 0x54 #define ERROR 0xF0 #define VOLTMIN 1 -#define TIMING 100 +#define TIMING 5 void ADC_init(void); void ADC_start_conversion(void); diff --git a/i2c_test_attiny85/main.c b/i2c_test_attiny85/main.c index 90e2d40..1ff17b4 100755 --- a/i2c_test_attiny85/main.c +++ b/i2c_test_attiny85/main.c @@ -15,7 +15,7 @@ #include "led_gen.h" #include "led_receptor.h" -#include "USI_TWI_Slave.h" +#include "usiTwiSlave.h" //#define F_CPU 1000000 #define NOM_CONSTRUC 0x08 #define NOM_CAPTEUR 0x10 @@ -35,44 +35,52 @@ volatile unsigned char recVal; int main( void ) { - unsigned char slaveAdress, cmd,i=0; + float test1,test2; + unsigned char cmd,i=0; unsigned char nom_capteur[8]= {'T','u','r','k','i','s','h','Z'}; unsigned char sensor_type[8]= {'C','a','t','c','h','E','y','e'}; + uint8_t slaveAdress;//data = 0x45; slaveAdress = 0x01; MCUCR |= (1< + #include +#else + #include + #include +#endif +#include "USI_TWI_Slave.h" +#include "led_receptor.h" + +/*! Static Variables + */ + +static unsigned char TWI_slaveAddress; +static volatile unsigned char USI_TWI_Overflow_State; + + +/*! Local variables + */ +static uint8_t TWI_RxBuf[TWI_RX_BUFFER_SIZE]; +static volatile uint8_t TWI_RxHead; +static volatile uint8_t TWI_RxTail; + +static uint8_t TWI_TxBuf[TWI_TX_BUFFER_SIZE]; +static volatile uint8_t TWI_TxHead; +static volatile uint8_t TWI_TxTail; + +/*! \brief Flushes the TWI buffers + */ +void Flush_TWI_Buffers(void) +{ + TWI_RxTail = 0; + TWI_RxHead = 0; + TWI_TxTail = 0; + TWI_TxHead = 0; +} + +//********** USI_TWI functions **********// + +/*! \brief + * Initialise USI for TWI Slave mode. + */ +void USI_TWI_Slave_Initialise( unsigned char TWI_ownAddress ) +{ + Flush_TWI_Buffers(); + + TWI_slaveAddress = TWI_ownAddress; + + PORT_USI |= (1<>1 ) == TWI_slaveAddress)) + { + if ( USIDR & 0x01 ){ // R/W + USI_TWI_Overflow_State = USI_SLAVE_SEND_DATA; //Read => L'esclave doit envoyer une donn?e + }else{ + USI_TWI_Overflow_State = USI_SLAVE_REQUEST_DATA; //Write => L'esclave doit lire la demande + } + 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(); + 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 + tmpUSIDR = USIDR; // Not necessary, but prevents warnings + TWI_RxHead = ( TWI_RxHead + 1 ) & TWI_RX_BUFFER_MASK; + TWI_RxBuf[TWI_RxHead] = tmpUSIDR; + + USI_TWI_Overflow_State = USI_SLAVE_REQUEST_DATA; + SET_USI_TO_SEND_ACK(); + break; + } +} diff --git a/i2c_test_attiny85/old USI_TWI/USI_TWI_Slave.h b/i2c_test_attiny85/old USI_TWI/USI_TWI_Slave.h new file mode 100755 index 0000000..b7cd2a1 --- /dev/null +++ b/i2c_test_attiny85/old USI_TWI/USI_TWI_Slave.h @@ -0,0 +1,203 @@ +// 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 **********// +#include +#ifndef TWDR +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) + +#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) + +#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 dependent defines +#if defined(__AT90tiny26__) | defined(__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_COND_INT USISIF +#define USI_START_VECTOR USI_STRT_vect +#define USI_OVERFLOW_VECTOR USI_OVF_vect +#endif + +#if defined(__AT90Tiny2313__) | defined(__ATtiny2313__) +#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_COND_INT USISIF +#define USI_START_VECTOR USI_STRT_vect +#define USI_OVERFLOW_VECTOR USI_OVF_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(__AT90Mega165__) | defined(__ATmega165__) | \ +defined(__ATmega325__) | defined(__ATmega3250__) | \ +defined(__ATmega645__) | defined(__ATmega6450__) | \ +defined(__ATmega329__) | defined(__ATmega3290__) | \ +defined(__ATmega649__) | defined(__ATmega6490__) +#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_COND_INT USISIF +#define USI_START_VECTOR USI_START_vect +#define USI_OVERFLOW_VECTOR USI_OVERFLOW_vect +#endif + +//#if defined(__AT90Mega169__) | defined(__ATmega169__) +#if defined(__AT90Mega169__) | defined(__AVR_ATmega169PA__) +#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_COND_INT USISIF +#define USI_START_VECTOR USI_STRT_vect +#define USI_OVERFLOW_VECTOR USI_OVF_vect +#endif + +#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 input, 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 input */ \ + 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 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 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 */ \ + } +#endif \ No newline at end of file diff --git a/i2c_test_attiny85/usiTwiSlave.c b/i2c_test_attiny85/usiTwiSlave.c new file mode 100755 index 0000000..216ae78 --- /dev/null +++ b/i2c_test_attiny85/usiTwiSlave.c @@ -0,0 +1,748 @@ +/******************************************************************************** + +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 + 06 Feb 2016 Minor change to allow mutli-byte requestFrom() from master. + 10 Feb 2016 Simplied RX/TX buffer code and allowed use of full buffer. + 13 Feb 2016 Made USI_RECEIVE_CALLBACK() callback fully interrupt-driven + 12 Dec 2016 Added support for ATtiny167 + 23 Dec 2017 Fixed repeated restart (which broke when making receive callback + interrupt-driven) + +********************************************************************************/ + + +/******************************************************************************** + includes +********************************************************************************/ + +#include +#include + +#include "usiTwiSlave.h" +//#include "../common/util.h" + + +/******************************************************************************** + device dependent defines +********************************************************************************/ + +#if defined( __AVR_ATtiny167__ ) +# 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_OVERFLOW_vect +#endif + +#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_ATtiny84__) | \ + defined(__AVR_ATtiny44__) +# 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_COND_INT USISIF +# 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__ ) +# 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 + +// These macros make the stop condition detection code more readable. +#define USI_PINS_SCL_SDA ( ( 1 << PIN_USI_SDA ) | ( 1 << PIN_USI_SCL ) ) +#define USI_PINS_SDA ( 1 << PIN_USI_SDA ) +#define USI_PINS_SCL ( 1 << PIN_USI_SCL ) + +/******************************************************************************** + + functions implemented as macros + +********************************************************************************/ + +#define SET_USI_TO_SEND_ACK( ) \ +{ \ + /* prepare ACK, ack is a zero */ \ + 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() \ +{ \ + 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( ) \ +{ \ + /* 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 ); \ +} + +#define USI_RECEIVE_CALLBACK() \ +{ \ + if (usi_onReceiverPtr) \ + { \ + if (usiTwiAmountDataInReceiveBuffer()) \ + { \ + usi_onReceiverPtr(usiTwiAmountDataInReceiveBuffer()); \ + } \ + } \ +} + +#define USI_REQUEST_CALLBACK() \ +{ \ + if(usi_onRequestPtr) usi_onRequestPtr(); \ +} + +/******************************************************************************** + + 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 uint8_t sleep_enable_bit; +static uint8_t in_transaction; +static volatile overflowState_t overflowState; + + +static uint8_t rxBuf[ TWI_RX_BUFFER_SIZE ]; +static volatile uint8_t rxHead; +static volatile uint8_t rxTail; +static volatile uint8_t rxCount; + +static uint8_t txBuf[ TWI_TX_BUFFER_SIZE ]; +static volatile uint8_t txHead; +static volatile uint8_t txTail; +static volatile uint8_t txCount; + + + +/******************************************************************************** + + local functions + +********************************************************************************/ + +// flushes the TWI buffers + +static void flushTwiBuffers( void ) +{ + rxTail = 0; + rxHead = 0; + rxCount = 0; + txTail = 0; + txHead = 0; + txCount = 0; +} // end flushTwiBuffers + + + +/******************************************************************************** + + public functions + +********************************************************************************/ + +// initialise USI for TWI slave mode + +void usiTwiSlaveInit( uint8_t ownAddress ) +{ + // initialize the TX and RX buffers to empty + 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 ); + + // The 'in_transaction' variable remembers if the usiTwiSlave driver is in the middle of + // an i2c transaction. Initialize it to zero + in_transaction = 0; + +} // end usiTwiSlaveInit + + +bool usiTwiDataInTransmitBuffer(void) //Fonction modif : affiche 255 constamment +{ //Solution : creer une variable temporaire recuperant rxTail et la comparant avec rxHead + + unsigned char tmpRxTail; // Creation d'une variable temporaire pour stocker rxTail au moment present + tmpRxTail = rxTail; // on recupere rxTail dans la variable temporaire + return ( rxHead != tmpRxTail ); // Renvoi 0 si aucune donnee n'est envoyee + + // renvoi 0 mais perturbe la transmission + //return txCount; + +} // end usiTwiDataInTransmitBuffer + + +// put data in the transmission buffer, wait if buffer is full + +void usiTwiTransmitByte( uint8_t data ) +{ + + // wait for free space in buffer + while ( txCount == TWI_TX_BUFFER_SIZE) ; + + // store data in buffer + txBuf[ txHead ] = data; + txHead = ( txHead + 1 ) & TWI_TX_BUFFER_MASK; + txCount++; + +} // end usiTwiTransmitByte + + +// return a byte from the receive buffer, wait if buffer is empty + +uint8_t usiTwiReceiveByte( void ) +{ + uint8_t rtn_byte; + + // wait for Rx data + while ( !rxCount ); + + rtn_byte = rxBuf [ rxTail ]; + // calculate buffer index + rxTail = ( rxTail + 1 ) & TWI_RX_BUFFER_MASK; + rxCount--; + + // return data from the buffer. + return rtn_byte; + +} // end usiTwiReceiveByte + + +uint8_t usiTwiAmountDataInReceiveBuffer(void) +{ + return rxCount; +} + + +/******************************************************************************** + + USI Start Condition ISR + +********************************************************************************/ + +ISR( USI_START_VECTOR ) +{ + uint8_t usi_pins; + // http://www.atmel.com/webdoc/AVRLibcReferenceManual/group__avr__interrupts.html + + // Notes about ISR. The compiler in the Arduino IDE handles some of the + // basic ISR plumbing (unless the "ISR_NAKED" attribute is applied). + // * The AVR processor resets the SREG.I bit when jumping into an ISR + // * The compiler automatically adds code to save SREG + // * < user's ISR code goes here > + // * The compiler automatically adds code to restore SREG + // * The compiler automatically uses the RETI instruction to return from the ISR. + // The RETI instruction enables interrupts after the return from ISR. + // The compiler behavior can be altered with attributes into the ISR declaration; + // however, the description above is the default. + + // cli() call is not necessary. Processor disables interrupts when + // jumping to an ISR + + // no need to save the SREG. The compiler does this automatically when using the + // ISR construct without modifying attributes. + + if ( !in_transaction ) + { + // remeber the sleep enable bit when entering the ISR + sleep_enable_bit = MCUCR & ( 1 << SE ); + + // clear the sleep enable bit to prevent the CPU from entering sleep mode while executing this ISR. + MCUCR &= ~( 1 << SE ); + } + + // set default starting conditions for new TWI package + overflowState = USI_SLAVE_CHECK_ADDRESS; + + // set SDA as input + DDR_USI &= ~( 1 << PORT_USI_SDA ); + + // the start condition is that the master pulls SDA low. + + // 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 is high and SDA is low + while ( ( usi_pins = PIN_USI & USI_PINS_SCL_SDA ) == USI_PINS_SCL ); + + // if SDA line was low at SCL edge, then start condition occurred + if ( !( usi_pins & USI_PINS_SDA ) ) + { + // a Stop Condition did not occur + + // Execute callback if this is a repeated start + if (in_transaction) + { + USI_RECEIVE_CALLBACK(); + } + + 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 ); + + //remember that the USI is in a valid i2c transaction + in_transaction = 1; + + } + 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 ); + + //no longer in valid i2c transaction + in_transaction = 0; + // restore the sleep enable bit + MCUCR |= sleep_enable_bit; + + } // 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); + + // no need to restore the SREG. The compiler does this automatically when using the + // ISR construct without modifying attributes. + + // The compiler automatically uses an RETI instruction to return when using the + // ISR construct without modifying attributes. + +} // 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 ) +{ + uint8_t finished; + uint8_t usi_pins; + + // http://www.atmel.com/webdoc/AVRLibcReferenceManual/group__avr__interrupts.html + + // Notes about ISR. The compiler in the Arduino IDE handles some of the + // basic ISR plumbing. + // * The AVR processor resets the SREG.I bit when jumping into an ISR + // * The compiler automatically adds code to save the SREG + // * < user's ISR code goes here > + // * The compiler automatically adds code to restore the SREG + // * The compiler automatically uses the RETI instruction to return from the ISR. + // The RETI insturction enables interrupts after the return from ISR. + // The compiler behavior can be altered with attributes into the ISR declaration; + // however, the description above is the default. + + // cli() call is not necessary. Processor disables interrupts when + // jumping to an ISR + + // no need to save the SREG. The compiler does this automatically when using the + // ISR construct without modifying attributes. + + // The ISR is only ever entered because the ISR(USI_START_VECTOR) interrupt + // routine ran first. That routine saved the sleep mode and disabled sleep. + + // Most of the time this routine exits, it has setup the USI to shift in/out bits + // and is expected to re-entered because of the USI overflow interrupt. Track whether or + // not the transaction is completely finished. + finished = 0; + + + 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) ) + { + if ( USIDR & 0x01 ) + { + overflowState = USI_SLAVE_SEND_DATA; + } + else + { + overflowState = USI_SLAVE_REQUEST_DATA; + } // end if + + // ack the start frame + // sets up the USI to pull SDA low and clock one bit (two edges) + SET_USI_TO_SEND_ACK( ); + } + else + { + SET_USI_TO_TWI_START_CONDITION_MODE( ); + finished = 1; + } + break; + + // master-read / slave-send: check reply and goto USI_SLAVE_SEND_DATA if OK, + // else reset USI + case USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA: + // Execute request callback for each byte requested, as this is the intended + // behavior of this library + USI_REQUEST_CALLBACK(); + if ( USIDR ) + { + // if NACK, the master does not want more data + SET_USI_TO_TWI_START_CONDITION_MODE( ); + finished = 1; + break; + } + // 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 ( txCount ) + { + USIDR = txBuf[ txTail ]; + txTail = ( txTail + 1 ) & TWI_TX_BUFFER_MASK; + txCount--; + + overflowState = USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA; + SET_USI_TO_SEND_DATA( ); + } + else + { + // the buffer is empty + SET_USI_TO_READ_ACK( ); // This might be neccessary sometimes see http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=805227#805227 + SET_USI_TO_TWI_START_CONDITION_MODE( ); + } // end if + 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-send / slave-receive: 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( ); + + // with the SET_USI_TO_READ_DATA() macro call above, the USI has + // been setup to catch the next byte if the master sends one. + // while that's going on, look for a stop condition here which + // is when the SDA line goes high after the SCL line; + + // wait until SCL goes high + while ( ! ( ( usi_pins = PIN_USI & USI_PINS_SCL_SDA ) & USI_PINS_SCL ) ); + + // if SDA line was high at SCL edge, then not a stop condition + if ( usi_pins & USI_PINS_SDA ) + break; + + // wait until SCL goes low or SDA goes high + while ( ( usi_pins = PIN_USI & USI_PINS_SCL_SDA ) == USI_PINS_SCL ); + + // if both SCL and SDA are high, then stop condition occurred + if ( usi_pins == USI_PINS_SCL_SDA ) + { + USI_RECEIVE_CALLBACK(); + SET_USI_TO_TWI_START_CONDITION_MODE( ); + finished = 1; + } + + 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 + // check buffer size + if ( rxCount < TWI_RX_BUFFER_SIZE ) + { + rxBuf[ rxHead ] = USIDR; + rxHead = ( rxHead + 1 ) & TWI_RX_BUFFER_MASK; + rxCount++; + } else { + // overrun + // drop data + } + // next USI_SLAVE_REQUEST_DATA + overflowState = USI_SLAVE_REQUEST_DATA; + SET_USI_TO_SEND_ACK( ); + break; + + } // end switch + + if (finished) + { + //no longer in valid i2c transaction + in_transaction = 0; + // restore the sleep enable bit + // note that this allows sleep -- it does not cause sleep + MCUCR |= sleep_enable_bit; + } + + // no need to restore the SREG. The compiler does this automatically when using the + // ISR construct without modifying attributes. + + // The compiler automatically uses an RETI instruction to return when using the + // ISR construct without modifying attributes. + +} // end ISR( USI_OVERFLOW_VECTOR ) diff --git a/i2c_test_attiny85/usiTwiSlave.h b/i2c_test_attiny85/usiTwiSlave.h new file mode 100755 index 0000000..8a1cfaf --- /dev/null +++ b/i2c_test_attiny85/usiTwiSlave.h @@ -0,0 +1,96 @@ +/******************************************************************************** + +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 +#include + + + +/******************************************************************************** + + prototypes + +********************************************************************************/ + +void usiTwiSlaveInit( uint8_t ); +void usiTwiTransmitByte( uint8_t ); +uint8_t usiTwiReceiveByte( void ); +bool usiTwiDataInTransmitBuffer(void); +uint8_t usiTwiAmountDataInReceiveBuffer(void); +// on_XXX handler pointers +void (*usi_onRequestPtr)(void); +void (*usi_onReceiverPtr)(uint8_t); + + +/******************************************************************************** + + driver buffer definitions + +********************************************************************************/ + +// permitted RX buffer sizes: 1, 2, 4, 8, 16, 32, 64, 128 or 256 + +#ifndef TWI_RX_BUFFER_SIZE +#define TWI_RX_BUFFER_SIZE ( 16 ) +#endif +#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 + +#ifndef TWI_TX_BUFFER_SIZE +#define TWI_TX_BUFFER_SIZE ( 1 ) +#endif +#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_