• Main Page
  • Data Structures
  • Files
  • File List
  • Globals

usiTwiSlave.c

Go to the documentation of this file.
00001 /********************************************************************************
00002 
00003 USI TWI Slave driver.
00004 
00005 Created by Donald R. Blake
00006 donblake at worldnet.att.net
00007 
00008 ---------------------------------------------------------------------------------
00009 
00010 Created from Atmel source files for Application Note AVR312: Using the USI Module
00011 as an I2C slave.
00012 
00013 This program is free software; you can redistribute it and/or modify it under the
00014 terms of the GNU General Public License as published by the Free Software
00015 Foundation; either version 2 of the License, or (at your option) any later
00016 version.
00017 
00018 This program is distributed in the hope that it will be useful, but WITHOUT ANY
00019 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
00020 PARTICULAR PURPOSE.  See the GNU General Public License for more details.
00021 
00022 ---------------------------------------------------------------------------------
00023 
00024 Change Activity:
00025 
00026     Date       Description
00027    ------      -------------
00028   16 Mar 2007  Created.
00029   27 Mar 2007  Added support for ATtiny261, 461 and 861.
00030   26 Apr 2007  Fixed ACK of slave address on a read.
00031 
00032 ********************************************************************************/
00033 
00034 
00035 
00036 /********************************************************************************
00037 
00038                                     includes
00039 
00040 ********************************************************************************/
00041 
00042 #include <avr/io.h>
00043 #include <avr/interrupt.h>
00044 #include "usiTwiSlave.h"
00045 
00046 
00047 
00048 /********************************************************************************
00049 
00050                             device dependent defines
00051 
00052 ********************************************************************************/
00053 
00054 #if defined( __AVR_ATtiny2313__ )
00055 #  define DDR_USI             DDRB
00056 #  define PORT_USI            PORTB
00057 #  define PIN_USI             PINB
00058 #  define PORT_USI_SDA        PB5
00059 #  define PORT_USI_SCL        PB7
00060 #  define PIN_USI_SDA         PINB5
00061 #  define PIN_USI_SCL         PINB7
00062 #  define USI_START_COND_INT  USISIF
00063 #  define USI_START_VECTOR    USI_START_vect
00064 #  define USI_OVERFLOW_VECTOR USI_OVERFLOW_vect
00065 #endif
00066 
00067 #if defined( __AVR_ATtiny25__ ) | \
00068      defined( __AVR_ATtiny45__ ) | \
00069      defined( __AVR_ATtiny85__ )
00070 #  define DDR_USI             DDRB
00071 #  define PORT_USI            PORTB
00072 #  define PIN_USI             PINB
00073 #  define PORT_USI_SDA        PB0
00074 #  define PORT_USI_SCL        PB2
00075 #  define PIN_USI_SDA         PINB0
00076 #  define PIN_USI_SCL         PINB2
00077 #  define USI_START_COND_INT  USICIF
00078 #  define USI_START_VECTOR    USI_START_vect
00079 #  define USI_OVERFLOW_VECTOR USI_OVF_vect
00080 #endif
00081 
00082 #if defined( __AVR_ATtiny26__ )
00083 #  define DDR_USI             DDRB
00084 #  define PORT_USI            PORTB
00085 #  define PIN_USI             PINB
00086 #  define PORT_USI_SDA        PB0
00087 #  define PORT_USI_SCL        PB2
00088 #  define PIN_USI_SDA         PINB0
00089 #  define PIN_USI_SCL         PINB2
00090 #  define USI_START_COND_INT  USISIF
00091 #  define USI_START_VECTOR    USI_STRT_vect
00092 #  define USI_OVERFLOW_VECTOR USI_OVF_vect
00093 #endif
00094 
00095 #if defined( __AVR_ATtiny261__ ) | \
00096      defined( __AVR_ATtiny461__ ) | \
00097      defined( __AVR_ATtiny861__ )
00098 #  define DDR_USI             DDRB
00099 #  define PORT_USI            PORTB
00100 #  define PIN_USI             PINB
00101 #  define PORT_USI_SDA        PB0
00102 #  define PORT_USI_SCL        PB2
00103 #  define PIN_USI_SDA         PINB0
00104 #  define PIN_USI_SCL         PINB2
00105 #  define USI_START_COND_INT  USISIF
00106 #  define USI_START_VECTOR    USI_START_vect
00107 #  define USI_OVERFLOW_VECTOR USI_OVF_vect
00108 #endif
00109 
00110 #if defined( __AVR_ATmega165__ ) | \
00111      defined( __AVR_ATmega325__ ) | \
00112      defined( __AVR_ATmega3250__ ) | \
00113      defined( __AVR_ATmega645__ ) | \
00114      defined( __AVR_ATmega6450__ ) | \
00115      defined( __AVR_ATmega329__ ) | \
00116      defined( __AVR_ATmega3290__ )
00117 #  define DDR_USI             DDRE
00118 #  define PORT_USI            PORTE
00119 #  define PIN_USI             PINE
00120 #  define PORT_USI_SDA        PE5
00121 #  define PORT_USI_SCL        PE4
00122 #  define PIN_USI_SDA         PINE5
00123 #  define PIN_USI_SCL         PINE4
00124 #  define USI_START_COND_INT  USISIF
00125 #  define USI_START_VECTOR    USI_START_vect
00126 #  define USI_OVERFLOW_VECTOR USI_OVERFLOW_vect
00127 #endif
00128 
00129 #if defined( __AVR_ATmega169__ )
00130 #  define DDR_USI             DDRE
00131 #  define PORT_USI            PORTE
00132 #  define PIN_USI             PINE
00133 #  define PORT_USI_SDA        PE5
00134 #  define PORT_USI_SCL        PE4
00135 #  define PIN_USI_SDA         PINE5
00136 #  define PIN_USI_SCL         PINE4
00137 #  define USI_START_COND_INT  USISIF
00138 #  define USI_START_VECTOR    USI_START_vect
00139 #  define USI_OVERFLOW_VECTOR USI_OVERFLOW_vect
00140 #endif
00141 
00142 
00143 
00144 /********************************************************************************
00145 
00146                         functions implemented as macros
00147 
00148 ********************************************************************************/
00149 
00150 #define SET_USI_TO_SEND_ACK( ) \
00151 { \
00152   /* prepare ACK */ \
00153   USIDR = 0; \
00154   /* set SDA as output */ \
00155   DDR_USI |= ( 1 << PORT_USI_SDA ); \
00156   /* clear all interrupt flags, except Start Cond */ \
00157   USISR = \
00158        ( 0 << USI_START_COND_INT ) | \
00159        ( 1 << USIOIF ) | ( 1 << USIPF ) | \
00160        ( 1 << USIDC )| \
00161        /* set USI counter to shift 1 bit */ \
00162        ( 0x0E << USICNT0 ); \
00163 }
00164 
00165 #define SET_USI_TO_READ_ACK( ) \
00166 { \
00167   /* set SDA as input */ \
00168   DDR_USI &= ~( 1 << PORT_USI_SDA ); \
00169   /* prepare ACK */ \
00170   USIDR = 0; \
00171   /* clear all interrupt flags, except Start Cond */ \
00172   USISR = \
00173        ( 0 << USI_START_COND_INT ) | \
00174        ( 1 << USIOIF ) | \
00175        ( 1 << USIPF ) | \
00176        ( 1 << USIDC ) | \
00177        /* set USI counter to shift 1 bit */ \
00178        ( 0x0E << USICNT0 ); \
00179 }
00180 
00181 #define SET_USI_TO_TWI_START_CONDITION_MODE( ) \
00182 { \
00183   USICR = \
00184        /* enable Start Condition Interrupt, disable Overflow Interrupt */ \
00185        ( 1 << USISIE ) | ( 0 << USIOIE ) | \
00186        /* set USI in Two-wire mode, no USI Counter overflow hold */ \
00187        ( 1 << USIWM1 ) | ( 0 << USIWM0 ) | \
00188        /* Shift Register Clock Source = External, positive edge */ \
00189        /* 4-Bit Counter Source = external, both edges */ \
00190        ( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) | \
00191        /* no toggle clock-port pin */ \
00192        ( 0 << USITC ); \
00193   USISR = \
00194         /* clear all interrupt flags, except Start Cond */ \
00195         ( 0 << USI_START_COND_INT ) | ( 1 << USIOIF ) | ( 1 << USIPF ) | \
00196         ( 1 << USIDC ) | ( 0x0 << USICNT0 ); \
00197 }
00198 
00199 #define SET_USI_TO_SEND_DATA( ) \
00200 { \
00201   /* set SDA as output */ \
00202   DDR_USI |=  ( 1 << PORT_USI_SDA ); \
00203   /* clear all interrupt flags, except Start Cond */ \
00204   USISR    =  \
00205        ( 0 << USI_START_COND_INT ) | ( 1 << USIOIF ) | ( 1 << USIPF ) | \
00206        ( 1 << USIDC) | \
00207        /* set USI to shift out 8 bits */ \
00208        ( 0x0 << USICNT0 ); \
00209 }
00210 
00211 #define SET_USI_TO_READ_DATA( ) \
00212 { \
00213   /* set SDA as input */ \
00214   DDR_USI &= ~( 1 << PORT_USI_SDA ); \
00215   /* clear all interrupt flags, except Start Cond */ \
00216   USISR    = \
00217        ( 0 << USI_START_COND_INT ) | ( 1 << USIOIF ) | \
00218        ( 1 << USIPF ) | ( 1 << USIDC ) | \
00219        /* set USI to shift out 8 bits */ \
00220        ( 0x0 << USICNT0 ); \
00221 }
00222 
00223 
00224 
00225 /********************************************************************************
00226 
00227                                    typedef's
00228 
00229 ********************************************************************************/
00230 
00231 typedef enum
00232 {
00233   USI_SLAVE_CHECK_ADDRESS                = 0x00,
00234   USI_SLAVE_SEND_DATA                    = 0x01,
00235   USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA = 0x02,
00236   USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA   = 0x03,
00237   USI_SLAVE_REQUEST_DATA                 = 0x04,
00238   USI_SLAVE_GET_DATA_AND_SEND_ACK        = 0x05
00239 } overflowState_t;
00240 
00241 
00242 
00243 /********************************************************************************
00244 
00245                                 local variables
00246 
00247 ********************************************************************************/
00248 
00249 static uint8_t                  slaveAddress;
00250 static volatile overflowState_t overflowState;
00251 
00252 
00253 static uint8_t          rxBuf[ TWI_RX_BUFFER_SIZE ];
00254 static volatile uint8_t rxHead;
00255 static volatile uint8_t rxTail;
00256 
00257 static uint8_t          txBuf[ TWI_TX_BUFFER_SIZE ];
00258 static volatile uint8_t txHead;
00259 static volatile uint8_t txTail;
00260 
00261 
00262 
00263 /********************************************************************************
00264 
00265                                 local functions
00266 
00267 ********************************************************************************/
00268 
00269 
00270 
00271 // flushes the TWI buffers
00272 
00273 static
00274 void
00275 flushTwiBuffers(
00276   void
00277 )
00278 {
00279   rxTail = 0;
00280   rxHead = 0;
00281   txTail = 0;
00282   txHead = 0;
00283 } // end flushTwiBuffers
00284 
00285 
00286 
00287 /********************************************************************************
00288 
00289                                 public functions
00290 
00291 ********************************************************************************/
00292 
00293 
00294 
00295 // initialise USI for TWI slave mode
00296 
00297 void
00298 usiTwiSlaveInit(
00299   uint8_t ownAddress
00300 )
00301 {
00302 
00303   flushTwiBuffers( );
00304 
00305   slaveAddress = ownAddress;
00306 
00307   // In Two Wire mode (USIWM1, USIWM0 = 1X), the slave USI will pull SCL
00308   // low when a start condition is detected or a counter overflow (only
00309   // for USIWM1, USIWM0 = 11).  This inserts a wait state.  SCL is released
00310   // by the ISRs (USI_START_vect and USI_OVERFLOW_vect).
00311 
00312   // Set SCL and SDA as output
00313   DDR_USI |= ( 1 << PORT_USI_SCL ) | ( 1 << PORT_USI_SDA );
00314 
00315   // set SCL high
00316   PORT_USI |= ( 1 << PORT_USI_SCL );
00317 
00318   // set SDA high
00319   PORT_USI |= ( 1 << PORT_USI_SDA );
00320 
00321   // Set SDA as input
00322   DDR_USI &= ~( 1 << PORT_USI_SDA );
00323 
00324   USICR =
00325        // enable Start Condition Interrupt
00326        ( 1 << USISIE ) |
00327        // disable Overflow Interrupt
00328        ( 0 << USIOIE ) |
00329        // set USI in Two-wire mode, no USI Counter overflow hold
00330        ( 1 << USIWM1 ) | ( 0 << USIWM0 ) |
00331        // Shift Register Clock Source = external, positive edge
00332        // 4-Bit Counter Source = external, both edges
00333        ( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) |
00334        // no toggle clock-port pin
00335        ( 0 << USITC );
00336 
00337   // clear all interrupt flags and reset overflow counter
00338 
00339   USISR = ( 1 << USI_START_COND_INT ) | ( 1 << USIOIF ) | ( 1 << USIPF ) | ( 1 << USIDC );
00340 
00341 } // end usiTwiSlaveInit
00342 
00343 
00344 
00345 // put data in the transmission buffer, wait if buffer is full
00346 
00347 void
00348 usiTwiTransmitByte(
00349   uint8_t data
00350 )
00351 {
00352 
00353   uint8_t tmphead;
00354 
00355   // calculate buffer index
00356   tmphead = ( txHead + 1 ) & TWI_TX_BUFFER_MASK;
00357 
00358   // wait for free space in buffer
00359   while ( tmphead == txTail );
00360 
00361   // store data in buffer
00362   txBuf[ tmphead ] = data;
00363 
00364   // store new index
00365   txHead = tmphead;
00366 
00367 } // end usiTwiTransmitByte
00368 
00369 
00370 
00371 // return a byte from the receive buffer, wait if buffer is empty
00372 
00373 uint8_t
00374 usiTwiReceiveByte(
00375   void
00376 )
00377 {
00378 
00379   // wait for Rx data
00380   while ( rxHead == rxTail );
00381 
00382   // calculate buffer index
00383   rxTail = ( rxTail + 1 ) & TWI_RX_BUFFER_MASK;
00384 
00385   // return data from the buffer.
00386   return rxBuf[ rxTail ];
00387 
00388 } // end usiTwiReceiveByte
00389 
00390 
00391 
00392 // check if there is data in the receive buffer
00393 
00394 bool
00395 usiTwiDataInReceiveBuffer(
00396   void
00397 )
00398 {
00399 
00400   // return 0 (false) if the receive buffer is empty
00401   return rxHead != rxTail;
00402 
00403 } // end usiTwiDataInReceiveBuffer
00404 
00405 
00406 
00407 /********************************************************************************
00408 
00409                             USI Start Condition ISR
00410 
00411 ********************************************************************************/
00412 
00413 ISR( USI_START_VECTOR )
00414 {
00415 
00416   // set default starting conditions for new TWI package
00417   overflowState = USI_SLAVE_CHECK_ADDRESS;
00418 
00419   // set SDA as input
00420   DDR_USI &= ~( 1 << PORT_USI_SDA );
00421 
00422   // wait for SCL to go low to ensure the Start Condition has completed (the
00423   // start detector will hold SCL low ) - if a Stop Condition arises then leave
00424   // the interrupt to prevent waiting forever - don't use USISR to test for Stop
00425   // Condition as in Application Note AVR312 because the Stop Condition Flag is
00426   // going to be set from the last TWI sequence
00427   while (
00428        // SCL his high
00429        ( PIN_USI & ( 1 << PIN_USI_SCL ) ) &&
00430        // and SDA is low
00431        !( ( PIN_USI & ( 1 << PIN_USI_SDA ) ) )
00432   );
00433 
00434 
00435   if ( !( PIN_USI & ( 1 << PIN_USI_SDA ) ) )
00436   {
00437 
00438     // a Stop Condition did not occur
00439 
00440     USICR =
00441          // keep Start Condition Interrupt enabled to detect RESTART
00442          ( 1 << USISIE ) |
00443          // enable Overflow Interrupt
00444          ( 1 << USIOIE ) |
00445          // set USI in Two-wire mode, hold SCL low on USI Counter overflow
00446          ( 1 << USIWM1 ) | ( 1 << USIWM0 ) |
00447          // Shift Register Clock Source = External, positive edge
00448          // 4-Bit Counter Source = external, both edges
00449          ( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) |
00450          // no toggle clock-port pin
00451          ( 0 << USITC );
00452 
00453   }
00454   else
00455   {
00456 
00457     // a Stop Condition did occur
00458     USICR =
00459          // enable Start Condition Interrupt
00460          ( 1 << USISIE ) |
00461          // disable Overflow Interrupt
00462          ( 0 << USIOIE ) |
00463          // set USI in Two-wire mode, no USI Counter overflow hold
00464          ( 1 << USIWM1 ) | ( 0 << USIWM0 ) |
00465          // Shift Register Clock Source = external, positive edge
00466          // 4-Bit Counter Source = external, both edges
00467          ( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) |
00468          // no toggle clock-port pin
00469          ( 0 << USITC );
00470 
00471   } // end if
00472 
00473   USISR =
00474        // clear interrupt flags - resetting the Start Condition Flag will
00475        // release SCL
00476        ( 1 << USI_START_COND_INT ) | ( 1 << USIOIF ) |
00477        ( 1 << USIPF ) |( 1 << USIDC ) |
00478        // set USI to sample 8 bits (count 16 external SCL pin toggles)
00479        ( 0x0 << USICNT0);
00480 
00481 } // end ISR( USI_START_VECTOR )
00482 
00483 
00484 
00485 /********************************************************************************
00486 
00487                                 USI Overflow ISR
00488 
00489 Handles all the communication.
00490 
00491 Only disabled when waiting for a new Start Condition.
00492 
00493 ********************************************************************************/
00494 
00495 ISR( USI_OVERFLOW_VECTOR )
00496 {
00497 
00498   switch ( overflowState )
00499   {
00500 
00501     // Address mode: check address and send ACK (and next USI_SLAVE_SEND_DATA) if OK,
00502     // else reset USI
00503     case USI_SLAVE_CHECK_ADDRESS:
00504       if ( ( USIDR == 0 ) || ( ( USIDR >> 1 ) == slaveAddress) )
00505       {
00506           if ( USIDR & 0x01 )
00507         {
00508           overflowState = USI_SLAVE_SEND_DATA;
00509         }
00510         else
00511         {
00512           overflowState = USI_SLAVE_REQUEST_DATA;
00513         } // end if
00514         SET_USI_TO_SEND_ACK( );
00515       }
00516       else
00517       {
00518         SET_USI_TO_TWI_START_CONDITION_MODE( );
00519       }
00520       break;
00521 
00522     // Master write data mode: check reply and goto USI_SLAVE_SEND_DATA if OK,
00523     // else reset USI
00524     case USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA:
00525       if ( USIDR )
00526       {
00527         // if NACK, the master does not want more data
00528         SET_USI_TO_TWI_START_CONDITION_MODE( );
00529         return;
00530       }
00531       // from here we just drop straight into USI_SLAVE_SEND_DATA if the
00532       // master sent an ACK
00533 
00534     // copy data from buffer to USIDR and set USI to shift byte
00535     // next USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA
00536     case USI_SLAVE_SEND_DATA:
00537       // Get data from Buffer
00538       if ( txHead != txTail )
00539       {
00540         txTail = ( txTail + 1 ) & TWI_TX_BUFFER_MASK;
00541         USIDR = txBuf[ txTail ];
00542       }
00543       else
00544       {
00545         // the buffer is empty
00546         SET_USI_TO_TWI_START_CONDITION_MODE( );
00547         return;
00548       } // end if
00549       overflowState = USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA;
00550       SET_USI_TO_SEND_DATA( );
00551       break;
00552 
00553     // set USI to sample reply from master
00554     // next USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA
00555     case USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA:
00556       overflowState = USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA;
00557       SET_USI_TO_READ_ACK( );
00558       break;
00559 
00560     // Master read data mode: set USI to sample data from master, next
00561     // USI_SLAVE_GET_DATA_AND_SEND_ACK
00562     case USI_SLAVE_REQUEST_DATA:
00563       overflowState = USI_SLAVE_GET_DATA_AND_SEND_ACK;
00564       SET_USI_TO_READ_DATA( );
00565       break;
00566 
00567     // copy data from USIDR and send ACK
00568     // next USI_SLAVE_REQUEST_DATA
00569     case USI_SLAVE_GET_DATA_AND_SEND_ACK:
00570       // put data into buffer
00571       // Not necessary, but prevents warnings
00572       rxHead = ( rxHead + 1 ) & TWI_RX_BUFFER_MASK;
00573       rxBuf[ rxHead ] = USIDR;
00574       // next USI_SLAVE_REQUEST_DATA
00575       overflowState = USI_SLAVE_REQUEST_DATA;
00576       SET_USI_TO_SEND_ACK( );
00577       break;
00578 
00579   } // end switch
00580 
00581 } // end ISR( USI_OVERFLOW_VECTOR )

Generated on Sat Dec 10 2011 12:16:43 for I2C-Dimmer by  doxygen 1.7.2