Advertisement
grist

usiTwiSlave.c

Feb 12th, 2012
472
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 16.47 KB | None | 0 0
  1. /********************************************************************************
  2.  
  3. USI TWI Slave driver.
  4.  
  5. Created by Donald R. Blake
  6. donblake at worldnet.att.net
  7.  
  8. ---------------------------------------------------------------------------------
  9.  
  10. Created from Atmel source files for Application Note AVR312: Using the USI Module
  11. as an I2C slave.
  12.  
  13. This program is free software; you can redistribute it and/or modify it under the
  14. terms of the GNU General Public License as published by the Free Software
  15. Foundation; either version 2 of the License, or (at your option) any later
  16. version.
  17.  
  18. This program is distributed in the hope that it will be useful, but WITHOUT ANY
  19. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
  20. PARTICULAR PURPOSE.  See the GNU General Public License for more details.
  21.  
  22. ---------------------------------------------------------------------------------
  23.  
  24. Change Activity:
  25.  
  26.     Date       Description
  27.    ------      -------------
  28.   16 Mar 2007  Created.
  29.   27 Mar 2007  Added support for ATtiny261, 461 and 861.
  30.   26 Apr 2007  Fixed ACK of slave address on a read.
  31.  
  32. ********************************************************************************/
  33.  
  34.  
  35.  
  36. /********************************************************************************
  37.  
  38.                                     includes
  39.  
  40. ********************************************************************************/
  41.  
  42. #include <avr/io.h>
  43. #include <avr/interrupt.h>
  44. #include "usiTwiSlave.h"
  45.  
  46.  
  47.  
  48. /********************************************************************************
  49.  
  50.                             device dependent defines
  51.  
  52. ********************************************************************************/
  53.  
  54. #if defined( __AVR_ATtiny2313__ )
  55. #  define DDR_USI             DDRB
  56. #  define PORT_USI            PORTB
  57. #  define PIN_USI             PINB
  58. #  define PORT_USI_SDA        PB5
  59. #  define PORT_USI_SCL        PB7
  60. #  define PIN_USI_SDA         PINB5
  61. #  define PIN_USI_SCL         PINB7
  62. #  define USI_START_COND_INT  USISIF
  63. #  define USI_START_VECTOR    USI_START_vect
  64. #  define USI_OVERFLOW_VECTOR USI_OVERFLOW_vect
  65. #endif
  66.  
  67. #if defined( __AVR_ATtiny25__ ) | \
  68.      defined( __AVR_ATtiny45__ ) | \
  69.      defined( __AVR_ATtiny85__ )
  70. #  define DDR_USI             DDRB
  71. #  define PORT_USI            PORTB
  72. #  define PIN_USI             PINB
  73. #  define PORT_USI_SDA        PB0
  74. #  define PORT_USI_SCL        PB2
  75. #  define PIN_USI_SDA         PINB0
  76. #  define PIN_USI_SCL         PINB2
  77. #  define USI_START_COND_INT  USICIF
  78. #  define USI_START_VECTOR    USI_START_vect
  79. #  define USI_OVERFLOW_VECTOR USI_OVF_vect
  80. #endif
  81.  
  82. #if defined( __AVR_ATtiny26__ )
  83. #  define DDR_USI             DDRB
  84. #  define PORT_USI            PORTB
  85. #  define PIN_USI             PINB
  86. #  define PORT_USI_SDA        PB0
  87. #  define PORT_USI_SCL        PB2
  88. #  define PIN_USI_SDA         PINB0
  89. #  define PIN_USI_SCL         PINB2
  90. #  define USI_START_COND_INT  USISIF
  91. #  define USI_START_VECTOR    USI_STRT_vect
  92. #  define USI_OVERFLOW_VECTOR USI_OVF_vect
  93. #endif
  94.  
  95. #if defined( __AVR_ATtiny261__ ) | \
  96.      defined( __AVR_ATtiny461__ ) | \
  97.      defined( __AVR_ATtiny861__ )
  98. #  define DDR_USI             DDRB
  99. #  define PORT_USI            PORTB
  100. #  define PIN_USI             PINB
  101. #  define PORT_USI_SDA        PB0
  102. #  define PORT_USI_SCL        PB2
  103. #  define PIN_USI_SDA         PINB0
  104. #  define PIN_USI_SCL         PINB2
  105. #  define USI_START_COND_INT  USISIF
  106. #  define USI_START_VECTOR    USI_START_vect
  107. #  define USI_OVERFLOW_VECTOR USI_OVF_vect
  108. #endif
  109.  
  110. #if defined( __AVR_ATmega165__ ) | \
  111.      defined( __AVR_ATmega325__ ) | \
  112.      defined( __AVR_ATmega3250__ ) | \
  113.      defined( __AVR_ATmega645__ ) | \
  114.      defined( __AVR_ATmega6450__ ) | \
  115.      defined( __AVR_ATmega329__ ) | \
  116.      defined( __AVR_ATmega3290__ )
  117. #  define DDR_USI             DDRE
  118. #  define PORT_USI            PORTE
  119. #  define PIN_USI             PINE
  120. #  define PORT_USI_SDA        PE5
  121. #  define PORT_USI_SCL        PE4
  122. #  define PIN_USI_SDA         PINE5
  123. #  define PIN_USI_SCL         PINE4
  124. #  define USI_START_COND_INT  USISIF
  125. #  define USI_START_VECTOR    USI_START_vect
  126. #  define USI_OVERFLOW_VECTOR USI_OVERFLOW_vect
  127. #endif
  128.  
  129. #if defined( __AVR_ATmega169__ )
  130. #  define DDR_USI             DDRE
  131. #  define PORT_USI            PORTE
  132. #  define PIN_USI             PINE
  133. #  define PORT_USI_SDA        PE5
  134. #  define PORT_USI_SCL        PE4
  135. #  define PIN_USI_SDA         PINE5
  136. #  define PIN_USI_SCL         PINE4
  137. #  define USI_START_COND_INT  USISIF
  138. #  define USI_START_VECTOR    USI_START_vect
  139. #  define USI_OVERFLOW_VECTOR USI_OVERFLOW_vect
  140. #endif
  141.  
  142.  
  143.  
  144. /********************************************************************************
  145.  
  146.                         functions implemented as macros
  147.  
  148. ********************************************************************************/
  149.  
  150. #define SET_USI_TO_SEND_ACK( ) \
  151. { \
  152.   /* prepare ACK */ \
  153.   USIDR = 0; \
  154.   /* set SDA as output */ \
  155.   DDR_USI |= ( 1 << PORT_USI_SDA ); \
  156.   /* clear all interrupt flags, except Start Cond */ \
  157.   USISR = \
  158.        ( 0 << USI_START_COND_INT ) | \
  159.        ( 1 << USIOIF ) | ( 1 << USIPF ) | \
  160.        ( 1 << USIDC )| \
  161.        /* set USI counter to shift 1 bit */ \
  162.        ( 0x0E << USICNT0 ); \
  163. }
  164.  
  165. #define SET_USI_TO_READ_ACK( ) \
  166. { \
  167.   /* set SDA as input */ \
  168.   DDR_USI &= ~( 1 << PORT_USI_SDA ); \
  169.   /* prepare ACK */ \
  170.   USIDR = 0; \
  171.   /* clear all interrupt flags, except Start Cond */ \
  172.   USISR = \
  173.        ( 0 << USI_START_COND_INT ) | \
  174.        ( 1 << USIOIF ) | \
  175.        ( 1 << USIPF ) | \
  176.        ( 1 << USIDC ) | \
  177.        /* set USI counter to shift 1 bit */ \
  178.        ( 0x0E << USICNT0 ); \
  179. }
  180.  
  181. #define SET_USI_TO_TWI_START_CONDITION_MODE( ) \
  182. { \
  183.   USICR = \
  184.        /* enable Start Condition Interrupt, disable Overflow Interrupt */ \
  185.        ( 1 << USISIE ) | ( 0 << USIOIE ) | \
  186.        /* set USI in Two-wire mode, no USI Counter overflow hold */ \
  187.        ( 1 << USIWM1 ) | ( 0 << USIWM0 ) | \
  188.        /* Shift Register Clock Source = External, positive edge */ \
  189.        /* 4-Bit Counter Source = external, both edges */ \
  190.        ( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) | \
  191.        /* no toggle clock-port pin */ \
  192.        ( 0 << USITC ); \
  193.   USISR = \
  194.         /* clear all interrupt flags, except Start Cond */ \
  195.         ( 0 << USI_START_COND_INT ) | ( 1 << USIOIF ) | ( 1 << USIPF ) | \
  196.         ( 1 << USIDC ) | ( 0x0 << USICNT0 ); \
  197. }
  198.  
  199. #define SET_USI_TO_SEND_DATA( ) \
  200. { \
  201.   /* set SDA as output */ \
  202.   DDR_USI |=  ( 1 << PORT_USI_SDA ); \
  203.   /* clear all interrupt flags, except Start Cond */ \
  204.   USISR    =  \
  205.        ( 0 << USI_START_COND_INT ) | ( 1 << USIOIF ) | ( 1 << USIPF ) | \
  206.        ( 1 << USIDC) | \
  207.        /* set USI to shift out 8 bits */ \
  208.        ( 0x0 << USICNT0 ); \
  209. }
  210.  
  211. #define SET_USI_TO_READ_DATA( ) \
  212. { \
  213.   /* set SDA as input */ \
  214.   DDR_USI &= ~( 1 << PORT_USI_SDA ); \
  215.   /* clear all interrupt flags, except Start Cond */ \
  216.   USISR    = \
  217.        ( 0 << USI_START_COND_INT ) | ( 1 << USIOIF ) | \
  218.        ( 1 << USIPF ) | ( 1 << USIDC ) | \
  219.        /* set USI to shift out 8 bits */ \
  220.        ( 0x0 << USICNT0 ); \
  221. }
  222.  
  223.  
  224.  
  225. /********************************************************************************
  226.  
  227.                                    typedef's
  228.  
  229. ********************************************************************************/
  230.  
  231. typedef enum
  232. {
  233.   USI_SLAVE_CHECK_ADDRESS                = 0x00,
  234.   USI_SLAVE_SEND_DATA                    = 0x01,
  235.   USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA = 0x02,
  236.   USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA   = 0x03,
  237.   USI_SLAVE_REQUEST_DATA                 = 0x04,
  238.   USI_SLAVE_GET_DATA_AND_SEND_ACK        = 0x05
  239. } overflowState_t;
  240.  
  241.  
  242.  
  243. /********************************************************************************
  244.  
  245.                                 local variables
  246.  
  247. ********************************************************************************/
  248.  
  249. static uint8_t                  slaveAddress;
  250. static volatile overflowState_t overflowState;
  251.  
  252.  
  253. static uint8_t          rxBuf[ TWI_RX_BUFFER_SIZE ];
  254. static volatile uint8_t rxHead;
  255. static volatile uint8_t rxTail;
  256.  
  257. static uint8_t          txBuf[ TWI_TX_BUFFER_SIZE ];
  258. static volatile uint8_t txHead;
  259. static volatile uint8_t txTail;
  260.  
  261.  
  262.  
  263. /********************************************************************************
  264.  
  265.                                 local functions
  266.  
  267. ********************************************************************************/
  268.  
  269.  
  270.  
  271. // flushes the TWI buffers
  272.  
  273. static
  274. void
  275. flushTwiBuffers(
  276.   void
  277. )
  278. {
  279.   rxTail = 0;
  280.   rxHead = 0;
  281.   txTail = 0;
  282.   txHead = 0;
  283. } // end flushTwiBuffers
  284.  
  285.  
  286.  
  287. /********************************************************************************
  288.  
  289.                                 public functions
  290.  
  291. ********************************************************************************/
  292.  
  293.  
  294.  
  295. // initialise USI for TWI slave mode
  296.  
  297. void
  298. usiTwiSlaveInit(
  299.   uint8_t ownAddress
  300. )
  301. {
  302.  
  303.   flushTwiBuffers( );
  304.  
  305.   slaveAddress = ownAddress;
  306.  
  307.   // In Two Wire mode (USIWM1, USIWM0 = 1X), the slave USI will pull SCL
  308.   // low when a start condition is detected or a counter overflow (only
  309.   // for USIWM1, USIWM0 = 11).  This inserts a wait state.  SCL is released
  310.   // by the ISRs (USI_START_vect and USI_OVERFLOW_vect).
  311.  
  312.   // Set SCL and SDA as output
  313.   DDR_USI |= ( 1 << PORT_USI_SCL ) | ( 1 << PORT_USI_SDA );
  314.  
  315.   // set SCL high
  316.   PORT_USI |= ( 1 << PORT_USI_SCL );
  317.  
  318.   // set SDA high
  319.   PORT_USI |= ( 1 << PORT_USI_SDA );
  320.  
  321.   // Set SDA as input
  322.   DDR_USI &= ~( 1 << PORT_USI_SDA );
  323.  
  324.   USICR =
  325.        // enable Start Condition Interrupt
  326.        ( 1 << USISIE ) |
  327.        // disable Overflow Interrupt
  328.        ( 0 << USIOIE ) |
  329.        // set USI in Two-wire mode, no USI Counter overflow hold
  330.        ( 1 << USIWM1 ) | ( 0 << USIWM0 ) |
  331.        // Shift Register Clock Source = external, positive edge
  332.        // 4-Bit Counter Source = external, both edges
  333.        ( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) |
  334.        // no toggle clock-port pin
  335.        ( 0 << USITC );
  336.  
  337.   // clear all interrupt flags and reset overflow counter
  338.  
  339.   USISR = ( 1 << USI_START_COND_INT ) | ( 1 << USIOIF ) | ( 1 << USIPF ) | ( 1 << USIDC );
  340.  
  341. } // end usiTwiSlaveInit
  342.  
  343.  
  344.  
  345. // put data in the transmission buffer, wait if buffer is full
  346.  
  347. void
  348. usiTwiTransmitByte(
  349.   uint8_t data
  350. )
  351. {
  352.  
  353.   uint8_t tmphead;
  354.  
  355.   // calculate buffer index
  356.   tmphead = ( txHead + 1 ) & TWI_TX_BUFFER_MASK;
  357.  
  358.   // wait for free space in buffer
  359.   while ( tmphead == txTail );
  360.  
  361.   // store data in buffer
  362.   txBuf[ tmphead ] = data;
  363.  
  364.   // store new index
  365.   txHead = tmphead;
  366.  
  367. } // end usiTwiTransmitByte
  368.  
  369.  
  370.  
  371. // return a byte from the receive buffer, wait if buffer is empty
  372.  
  373. uint8_t
  374. usiTwiReceiveByte(
  375.   void
  376. )
  377. {
  378.  
  379.   // wait for Rx data
  380.   while ( rxHead == rxTail );
  381.  
  382.   // calculate buffer index
  383.   rxTail = ( rxTail + 1 ) & TWI_RX_BUFFER_MASK;
  384.  
  385.   // return data from the buffer.
  386.   return rxBuf[ rxTail ];
  387.  
  388. } // end usiTwiReceiveByte
  389.  
  390.  
  391.  
  392. // check if there is data in the receive buffer
  393.  
  394. bool
  395. usiTwiDataInReceiveBuffer(
  396.   void
  397. )
  398. {
  399.  
  400.   // return 0 (false) if the receive buffer is empty
  401.   return rxHead != rxTail;
  402.  
  403. } // end usiTwiDataInReceiveBuffer
  404.  
  405.  
  406.  
  407. /********************************************************************************
  408.  
  409.                             USI Start Condition ISR
  410.  
  411. ********************************************************************************/
  412.  
  413. ISR( USI_START_VECTOR )
  414. {
  415.  
  416.   // set default starting conditions for new TWI package
  417.   overflowState = USI_SLAVE_CHECK_ADDRESS;
  418.  
  419.   // set SDA as input
  420.   DDR_USI &= ~( 1 << PORT_USI_SDA );
  421.  
  422.   // wait for SCL to go low to ensure the Start Condition has completed (the
  423.   // start detector will hold SCL low ) - if a Stop Condition arises then leave
  424.   // the interrupt to prevent waiting forever - don't use USISR to test for Stop
  425.   // Condition as in Application Note AVR312 because the Stop Condition Flag is
  426.   // going to be set from the last TWI sequence
  427.   while (
  428.        // SCL his high
  429.        ( PIN_USI & ( 1 << PIN_USI_SCL ) ) &&
  430.        // and SDA is low
  431.        !( ( PIN_USI & ( 1 << PIN_USI_SDA ) ) )
  432.   );
  433.  
  434.  
  435.   if ( !( PIN_USI & ( 1 << PIN_USI_SDA ) ) )
  436.   {
  437.  
  438.     // a Stop Condition did not occur
  439.  
  440.     USICR =
  441.          // keep Start Condition Interrupt enabled to detect RESTART
  442.          ( 1 << USISIE ) |
  443.          // enable Overflow Interrupt
  444.          ( 1 << USIOIE ) |
  445.          // set USI in Two-wire mode, hold SCL low on USI Counter overflow
  446.          ( 1 << USIWM1 ) | ( 1 << USIWM0 ) |
  447.          // Shift Register Clock Source = External, positive edge
  448.          // 4-Bit Counter Source = external, both edges
  449.          ( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) |
  450.          // no toggle clock-port pin
  451.          ( 0 << USITC );
  452.  
  453.   }
  454.   else
  455.   {
  456.  
  457.     // a Stop Condition did occur
  458.     USICR =
  459.          // enable Start Condition Interrupt
  460.          ( 1 << USISIE ) |
  461.          // disable Overflow Interrupt
  462.          ( 0 << USIOIE ) |
  463.          // set USI in Two-wire mode, no USI Counter overflow hold
  464.          ( 1 << USIWM1 ) | ( 0 << USIWM0 ) |
  465.          // Shift Register Clock Source = external, positive edge
  466.          // 4-Bit Counter Source = external, both edges
  467.          ( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) |
  468.          // no toggle clock-port pin
  469.          ( 0 << USITC );
  470.  
  471.   } // end if
  472.  
  473.   USISR =
  474.        // clear interrupt flags - resetting the Start Condition Flag will
  475.        // release SCL
  476.        ( 1 << USI_START_COND_INT ) | ( 1 << USIOIF ) |
  477.        ( 1 << USIPF ) |( 1 << USIDC ) |
  478.        // set USI to sample 8 bits (count 16 external SCL pin toggles)
  479.        ( 0x0 << USICNT0);
  480.  
  481. } // end ISR( USI_START_VECTOR )
  482.  
  483.  
  484.  
  485. /********************************************************************************
  486.  
  487.                                 USI Overflow ISR
  488.  
  489. Handles all the communication.
  490.  
  491. Only disabled when waiting for a new Start Condition.
  492.  
  493. ********************************************************************************/
  494.  
  495. ISR( USI_OVERFLOW_VECTOR )
  496. {
  497.  
  498.   switch ( overflowState )
  499.   {
  500.  
  501.     // Address mode: check address and send ACK (and next USI_SLAVE_SEND_DATA) if OK,
  502.     // else reset USI
  503.     case USI_SLAVE_CHECK_ADDRESS:
  504.       if ( ( USIDR == 0 ) || ( ( USIDR >> 1 ) == slaveAddress) )
  505.       {
  506.           if ( USIDR & 0x01 )
  507.         {
  508.           overflowState = USI_SLAVE_SEND_DATA;
  509.         }
  510.         else
  511.         {
  512.           overflowState = USI_SLAVE_REQUEST_DATA;
  513.         } // end if
  514.         SET_USI_TO_SEND_ACK( );
  515.       }
  516.       else
  517.       {
  518.         SET_USI_TO_TWI_START_CONDITION_MODE( );
  519.       }
  520.       break;
  521.  
  522.     // Master write data mode: check reply and goto USI_SLAVE_SEND_DATA if OK,
  523.     // else reset USI
  524.     case USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA:
  525.       if ( USIDR )
  526.       {
  527.         // if NACK, the master does not want more data
  528.         SET_USI_TO_TWI_START_CONDITION_MODE( );
  529.         return;
  530.       }
  531.       // from here we just drop straight into USI_SLAVE_SEND_DATA if the
  532.       // master sent an ACK
  533.  
  534.     // copy data from buffer to USIDR and set USI to shift byte
  535.     // next USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA
  536.     case USI_SLAVE_SEND_DATA:
  537.       // Get data from Buffer
  538.       if ( txHead != txTail )
  539.       {
  540.         txTail = ( txTail + 1 ) & TWI_TX_BUFFER_MASK;
  541.         USIDR = txBuf[ txTail ];
  542.       }
  543.       else
  544.       {
  545.         // the buffer is empty
  546.         SET_USI_TO_TWI_START_CONDITION_MODE( );
  547.         return;
  548.       } // end if
  549.       overflowState = USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA;
  550.       SET_USI_TO_SEND_DATA( );
  551.       break;
  552.  
  553.     // set USI to sample reply from master
  554.     // next USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA
  555.     case USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA:
  556.       overflowState = USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA;
  557.       SET_USI_TO_READ_ACK( );
  558.       break;
  559.  
  560.     // Master read data mode: set USI to sample data from master, next
  561.     // USI_SLAVE_GET_DATA_AND_SEND_ACK
  562.     case USI_SLAVE_REQUEST_DATA:
  563.       overflowState = USI_SLAVE_GET_DATA_AND_SEND_ACK;
  564.       SET_USI_TO_READ_DATA( );
  565.       break;
  566.  
  567.     // copy data from USIDR and send ACK
  568.     // next USI_SLAVE_REQUEST_DATA
  569.     case USI_SLAVE_GET_DATA_AND_SEND_ACK:
  570.       // put data into buffer
  571.       // Not necessary, but prevents warnings
  572.       rxHead = ( rxHead + 1 ) & TWI_RX_BUFFER_MASK;
  573.       rxBuf[ rxHead ] = USIDR;
  574.       // next USI_SLAVE_REQUEST_DATA
  575.       overflowState = USI_SLAVE_REQUEST_DATA;
  576.       SET_USI_TO_SEND_ACK( );
  577.       break;
  578.  
  579.   } // end switch
  580.  
  581. } // end ISR( USI_OVERFLOW_VECTOR )
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement