diff --git a/att/usiTwiSlave.c b/att/usiTwiSlave.c new file mode 100755 index 0000000..61f312d --- /dev/null +++ b/att/usiTwiSlave.c @@ -0,0 +1,749 @@ +/******************************************************************************** + +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( ) \ +{ \ + /* 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 ); \ +} + +#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 and SCL as input + DDR_USI &= ~( 1 << PORT_USI_SDA ); + DDR_USI &= ~( 1 << PORT_USI_SCL ); + + 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) +{ + + // return 0 (false) if the receive buffer is empty + 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/att/usiTwiSlave.h b/att/usiTwiSlave.h new file mode 100755 index 0000000..88b9445 --- /dev/null +++ b/att/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 ( 16 ) +#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_ diff --git a/i2c_test_attiny85/USI_TWI_Slave.c b/i2c_test_attiny85/USI_TWI_Slave.c index dfaa86f..2be9b4f 100755 --- a/i2c_test_attiny85/USI_TWI_Slave.c +++ b/i2c_test_attiny85/USI_TWI_Slave.c @@ -20,9 +20,15 @@ * ****************************************************************************/ -#include -#include +#if __GNUC__ + #include + #include +#else + #include + #include +#endif #include "USI_TWI_Slave.h" +#include "led_receptor.h" /*! Static Variables */ @@ -64,7 +70,8 @@ void USI_TWI_Slave_Initialise( unsigned char TWI_ownAddress ) PORT_USI |= (1<>1 ) == TWI_slaveAddress)) { - if ( USIDR & 0x01 ) - USI_TWI_Overflow_State = USI_SLAVE_SEND_DATA; - else - USI_TWI_Overflow_State = USI_SLAVE_REQUEST_DATA; + 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(); + SET_USI_TO_TWI_START_CONDITION_MODE(); } break; diff --git a/i2c_test_attiny85/USI_TWI_Slave.h b/i2c_test_attiny85/USI_TWI_Slave.h index 219eb47..92cbcff 100755 --- a/i2c_test_attiny85/USI_TWI_Slave.h +++ b/i2c_test_attiny85/USI_TWI_Slave.h @@ -63,9 +63,26 @@ typedef unsigned char uint8_t; #define USI_SLAVE_REQUEST_DATA (0x04) #define USI_SLAVE_GET_DATA_AND_SEND_ACK (0x05) +// AJOUT ########################################################################" +#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 PA6 +#define PORT_USI_SCL PA4 +#define PIN_USI_SDA PINA6 +#define PIN_USI_SCL PINA4 +#define USI_START_COND_INT USISIF +#define USI_START_VECTOR USI_STR_vect +#define USI_OVERFLOW_VECTOR USI_OVF_vect +#endif +//############################################################################### + //! Device dependent defines -/*#if defined(__AT90tiny26__) | defined(__ATtiny26__) +#if defined(__AT90tiny26__) | defined(__ATtiny26__) #define DDR_USI DDRB #define PORT_USI PORTB #define PIN_USI PINB @@ -76,9 +93,9 @@ typedef unsigned char uint8_t; #define USI_START_COND_INT USISIF #define USI_START_VECTOR USI_STRT_vect #define USI_OVERFLOW_VECTOR USI_OVF_vect -#endif*/ +#endif -/*#if defined(__AT90Tiny2313__) | defined(__ATtiny2313__) +#if defined(__AT90Tiny2313__) | defined(__ATtiny2313__) #define DDR_USI DDRB #define PORT_USI PORTB #define PIN_USI PINB @@ -87,11 +104,13 @@ typedef unsigned char uint8_t; #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*/ + #define USI_START_VECTOR USI_STRT_vect + #define USI_OVERFLOW_VECTOR USI_OVF_vect +#endif -/*#if defined(__ATtiny25__) | defined(__ATtiny45__) | defined(__ATtiny85__)*/ +#if defined( __AVR_ATtiny25__ ) | \ +defined( __AVR_ATtiny45__ ) | \ +defined( __AVR_ATtiny85__ ) #define DDR_USI DDRB #define PORT_USI PORTB #define PIN_USI PINB @@ -99,12 +118,12 @@ typedef unsigned char uint8_t; #define PORT_USI_SCL PB2 #define PIN_USI_SDA PINB0 #define PIN_USI_SCL PINB2 - #define USI_START_COND_INT USISIF //soit USISIF ou USISIE + #define USI_START_COND_INT USISIF #define USI_START_VECTOR USI_START_vect #define USI_OVERFLOW_VECTOR USI_OVF_vect -/*#endif*/ +#endif -/*#if defined(__AT90Mega165__) | defined(__ATmega165__) | \ +#if defined(__AT90Mega165__) | defined(__ATmega165__) | \ defined(__ATmega325__) | defined(__ATmega3250__) | \ defined(__ATmega645__) | defined(__ATmega6450__) | \ defined(__ATmega329__) | defined(__ATmega3290__) | \ @@ -119,9 +138,10 @@ typedef unsigned char uint8_t; #define USI_START_COND_INT USISIF #define USI_START_VECTOR USI_START_vect #define USI_OVERFLOW_VECTOR USI_OVERFLOW_vect -#endif*/ +#endif -/*#if defined(__AT90Mega169__) | defined(__ATmega169__) +//#if defined(__AT90Mega169__) | defined(__ATmega169__) +#if defined(__AT90Mega169__) | defined(__AVR_ATmega169PA__) #define DDR_USI DDRE #define PORT_USI PORTE #define PIN_USI PINE @@ -132,7 +152,7 @@ typedef unsigned char uint8_t; #define USI_START_COND_INT USISIF #define USI_START_VECTOR USI_STRT_vect #define USI_OVERFLOW_VECTOR USI_OVF_vect -#endif*/ +#endif //! Functions implemented as macros #define SET_USI_TO_SEND_ACK() \ @@ -153,14 +173,16 @@ typedef unsigned char uint8_t; #define SET_USI_TO_TWI_START_CONDITION_MODE() \ { \ - USICR = (1< 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 - T6Fj/fIqJcOx0GrpJU4zHA== + 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 83e238d..e050ff9 100755 --- a/i2c_test_attiny85/i2c_test_attiny85.cproj +++ b/i2c_test_attiny85/i2c_test_attiny85.cproj @@ -27,24 +27,24 @@ 2 0 - + - + - com.atmel.avrdbg.tool.stk500 + com.atmel.avrdbg.tool.simulator 0x1E930B - 125000 + 0 ISP @@ -54,12 +54,25 @@ STK500 ISP - 125000 + 0 + 0 + + + + + + ISP + + com.atmel.avrdbg.tool.simulator + + + Simulator + - -mmcu=attiny85 -B "%24(PackRepoDir)\atmel\ATtiny_DFP\1.2.118\gcc\dev\attiny85" + -mmcu=attiny85 -B "%24(PackRepoDir)\atmel\ATtiny_DFP\1.8.332\gcc\dev\attiny85" True True True @@ -74,7 +87,7 @@ - %24(PackRepoDir)\atmel\ATtiny_DFP\1.2.118\include + %24(PackRepoDir)\atmel\ATtiny_DFP\1.8.332\include\ Optimize for size (-Os) @@ -88,7 +101,7 @@ - %24(PackRepoDir)\atmel\ATtiny_DFP\1.2.118\include + %24(PackRepoDir)\atmel\ATtiny_DFP\1.8.332\include\ @@ -97,7 +110,7 @@ - -mmcu=attiny85 -B "%24(PackRepoDir)\atmel\ATtiny_DFP\1.2.118\gcc\dev\attiny85" + -mmcu=attiny85 -B "%24(PackRepoDir)\atmel\ATtiny_DFP\1.8.332\gcc\dev\attiny85" True True True @@ -112,7 +125,7 @@ - %24(PackRepoDir)\atmel\ATtiny_DFP\1.2.118\include + %24(PackRepoDir)\atmel\ATtiny_DFP\1.8.332\include\ Optimize (-O1) @@ -127,7 +140,7 @@ - %24(PackRepoDir)\atmel\ATtiny_DFP\1.2.118\include + %24(PackRepoDir)\atmel\ATtiny_DFP\1.8.332\include\ Default (-Wa,-g) diff --git a/i2c_test_attiny85/led_gen.c b/i2c_test_attiny85/led_gen.c index b6e15ac..c3b4427 100755 --- a/i2c_test_attiny85/led_gen.c +++ b/i2c_test_attiny85/led_gen.c @@ -25,10 +25,12 @@ void led2_init(void) void led1_stop(void) { + DDRB &= ~(1< 0 ; precision --) { - valeur_finale = valeur_finale +(((ADC_read_value() * 0.01961) - valeur_finale) / 15); + valeur_finale = valeur_finale +(((val_ana * 0.01961) - valeur_finale) / 15); } return valeur_finale; }; @@ -35,30 +45,30 @@ float ADC_averaging(void) float measureLed1(void) { float adcLed; - led2_stop(); led1_init(); - _delay_ms(TIMING); - adcLed=ADC_averaging(); - _delay_ms(TIMING); + _delay_us(TIMING); + adcLed=ADC_averaging(ADCH); + _delay_us(TIMING); + led1_stop(); return adcLed; }; float measureLed2(void) { float adcLed; - led1_stop(); led2_init(); - _delay_ms(TIMING); - adcLed=ADC_averaging(); - _delay_ms(TIMING); + _delay_us(TIMING); + adcLed=ADC_averaging(ADCH); + _delay_us(TIMING); + led2_stop(); return adcLed; }; -char compareLed(void) +unsigned char compareLed(float led1,float led2) { - float adcLed1 = measureLed1(); - float adcLed2 = measureLed2(); - float adcCompare = adcLed1 - adcLed2; + float adcLed1 = led1; + float adcLed2 = led2; + float adcCompare = led1 - led2; if (adcCompare < -VOLTMIN) // adcLed2 > adcLed1 { return LEFT; diff --git a/i2c_test_attiny85/led_receptor.h b/i2c_test_attiny85/led_receptor.h index 12d6de4..b843340 100755 --- a/i2c_test_attiny85/led_receptor.h +++ b/i2c_test_attiny85/led_receptor.h @@ -10,8 +10,10 @@ #define LED_RECEPTOR_H_ #include "led_gen.h" -#define F_CPU 1000000 +#include "USI_TWI_Slave.h" +#define F_CPU 8000000UL #include +#include #define FRONT 0x51 #define RIGHT 0x52 @@ -19,13 +21,14 @@ #define NOTHING 0x54 #define ERROR 0xF0 #define VOLTMIN 1 -#define TIMING 250 +#define TIMING 500 void ADC_init(void); +void ADC_start_conversion(void); char ADC_read_value(void); -float ADC_averaging(void); +float ADC_averaging(unsigned char val_ana); float measureLed1(void); float measureLed2(void); -char compareLed(void); +unsigned char compareLed(float led1,float led2); #endif /* LED_RECEPTOR_H_ */ \ No newline at end of file diff --git a/i2c_test_attiny85/led_test.c b/i2c_test_attiny85/led_test.c index fc46c35..377084b 100755 --- a/i2c_test_attiny85/led_test.c +++ b/i2c_test_attiny85/led_test.c @@ -9,7 +9,7 @@ void testLed(void) { - char sendingData = compareLed(); + char sendingData = compareLed(5,5); switch(sendingData) { case NOTHING: diff --git a/i2c_test_attiny85/main.c b/i2c_test_attiny85/main.c index 6e6c792..82dcdd6 100755 --- a/i2c_test_attiny85/main.c +++ b/i2c_test_attiny85/main.c @@ -3,63 +3,78 @@ * * Created: 12/11/2021 15:26:38 * Author : 40008304 - */ + */ +#if __GNUC__ #include +#include +#else +#include +#include +#endif -#include "led_gen.h" +#include "led_gen.h" #include "led_receptor.h" -#include "led_test.h" #include "USI_TWI_Slave.h" -#define MSTR_TEST_WR 0x31 -#define MSTR_TEST_RE 0x32 - -#define SLAVE_ADRESS 0x01 #define NOM_CONSTRUC 0x08 #define NOM_CAPTEUR 0x10 #define VALEUR_DEMAN 0x49 #define BASIC_MODE 0x42 -int main(void) +volatile unsigned char rawVal; +volatile float adcled1; +volatile float adcled2; +volatile unsigned char recVal; + +ISR (ADC_vect){//On récupère les données à chaque fin de conversion Analogique/Numérique + adcled1=measureLed1(); + adcled2=measureLed2(); + recVal=compareLed(adcled1,adcled2); +} + +int main( void ) { - unsigned char cmd, i, val; - unsigned char nom_capteur[9]={'I','U','T','V','i','D','A','v'}; - unsigned char sensor_type[9]={'S','u','m','o','E','y','e','s'}; - USI_TWI_Slave_Initialise(SLAVE_ADRESS); - led2_init(); - led1_init(); + unsigned char slaveAdress, 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'}; + slaveAdress = 0x01; + + USI_TWI_Slave_Initialise(slaveAdress); + sei(); ADC_init(); - while (1) + ADC_start_conversion(); + + while(1) { - if( USI_TWI_Data_In_Receive_Buffer() ) - { - cmd = USI_TWI_Receive_Byte(); - - switch(cmd){ - case MSTR_TEST_WR : - val=USI_TWI_Receive_Byte(); - break; - - case MSTR_TEST_RE : - USI_TWI_Transmit_Byte(0x0F); - break; - - case NOM_CONSTRUC : - for (i=0;i<8;i++){USI_TWI_Transmit_Byte(nom_capteur[i]);} - break; - case NOM_CAPTEUR : - for (i=0;i<8;i++){USI_TWI_Transmit_Byte(sensor_type[i]);} - break; - - case VALEUR_DEMAN : - USI_TWI_Transmit_Byte(0x45); - break; - case BASIC_MODE : - USI_TWI_Transmit_Byte(0x46); - break; - }; - }; - }; - val++; -} \ No newline at end of file + if( USI_TWI_Data_In_Receive_Buffer() ) + { + cmd = USI_TWI_Receive_Byte(); + switch(cmd) + { + case NOM_CONSTRUC : + for (i=0; i<8; i++) + { + USI_TWI_Transmit_Byte(nom_capteur[i]); + } + break; + + case NOM_CAPTEUR : + for (i=0; i<8; i++) + { + USI_TWI_Transmit_Byte(sensor_type[i]); + } + break; + + case VALEUR_DEMAN : + USI_TWI_Transmit_Byte(recVal); + break; + + case BASIC_MODE : + USI_TWI_Transmit_Byte(0x46); + break; + } + } + } + return 0; +}