Project

General

Profile

Statistics
| Revision:

root / trunk / code / projects / autonomous_recharging / archs / USI_TWI_Slave.c @ 80

History | View | Annotate | Download (8.53 KB)

1
// This file has been prepared for Doxygen automatic documentation generation.
2
/*! \file ********************************************************************
3
*
4
* Atmel Corporation
5
*
6
* File              : USI_TWI_Slave.c
7
* Compiler          : IAR EWAAVR 4.11A
8
* Revision          : $Revision: 1.14 $
9
* Date              : $Date: Friday, December 09, 2005 17:25:38 UTC $
10
* Updated by        : $Author: jtyssoe $
11
*
12
* Support mail      : avr@atmel.com
13
*
14
* Supported devices : All device with USI module can be used.
15
*
16
* AppNote           : AVR312 - Using the USI module as a I2C slave
17
*
18
* Description       : Functions for USI_TWI_receiver and USI_TWI_transmitter.
19
*
20
*
21
****************************************************************************/
22

    
23
#ifndef _USI_TWI_SLAVE_H
24
#define _USI_TWI_SLAVE_H
25

    
26
#include <avr/io.h>
27
#include <avr/interrupt.h>
28
#include "USI_TWI_Slave.h"
29

    
30
/*! Static Variables */
31

    
32
static unsigned char TWI_slaveAddress;
33
static volatile unsigned char USI_TWI_Overflow_State;
34

    
35
/*! Local variables */
36
static uint8_t TWI_RxBuf[TWI_RX_BUFFER_SIZE];
37
static volatile uint8_t TWI_RxHead;
38
static volatile uint8_t TWI_RxTail;
39

    
40
static uint8_t TWI_TxBuf[TWI_TX_BUFFER_SIZE];
41
static volatile uint8_t TWI_TxHead;
42
static volatile uint8_t TWI_TxTail;
43

    
44
/*! \brief Flushes the TWI buffers
45
 */
46
void Flush_TWI_Buffers(void)
47
{
48
    TWI_RxTail = 0;
49
    TWI_RxHead = 0;
50
    TWI_TxTail = 0;
51
    TWI_TxHead = 0;
52
}
53

    
54
//********** USI_TWI functions **********//
55

    
56
/*! \brief
57
 * Initialise USI for TWI Slave mode.
58
 */
59
void USI_TWI_Slave_Initialise( unsigned char TWI_ownAddress )
60
{
61
  Flush_TWI_Buffers();
62

    
63
  TWI_slaveAddress = TWI_ownAddress;
64

    
65
  PORT_USI |=  (1<<PORT_USI_SCL);                                 // Set SCL high
66
  PORT_USI |=  (1<<PORT_USI_SDA);                                 // Set SDA high
67
  DDR_USI  |=  (1<<PORT_USI_SCL);                                 // Set SCL as output
68
  DDR_USI  &= ~(1<<PORT_USI_SDA);                                 // Set SDA as input
69
  USICR    =  (1<<USISIE)|(0<<USIOIE)|                            // Enable Start Condition Interrupt. Disable Overflow Interrupt.
70
              (1<<USIWM1)|(0<<USIWM0)|                            // Set USI in Two-wire mode. No USI Counter overflow prior
71
                                                                  // to first Start Condition (potentail failure)
72
              (1<<USICS1)|(0<<USICS0)|(0<<USICLK)|                // Shift Register Clock Source = External, positive edge
73
              (0<<USITC);
74
  USISR    = 0xF0;                                                // Clear all flags and reset overflow counter
75
}
76

    
77

    
78
/*! \brief Puts data in the transmission buffer, Waits if buffer is full.
79
*/
80
void USI_TWI_Transmit_Byte( unsigned char data )
81
{
82
    unsigned char tmphead;
83

    
84
    tmphead = ( TWI_TxHead + 1 ) & TWI_TX_BUFFER_MASK;         // Calculate buffer index.
85
    while ( tmphead == TWI_TxTail );                           // Wait for free space in buffer.
86
    TWI_TxBuf[tmphead] = data;                                 // Store data in buffer.
87
    TWI_TxHead = tmphead;                                      // Store new index.
88
}
89

    
90
/*! \brief Returns a byte from the receive buffer. Waits if buffer is empty.
91
 */
92
unsigned char USI_TWI_Receive_Byte( void )
93
{
94
    unsigned char tmptail;
95
    unsigned char tmpRxTail;                                  // Temporary variable to store volatile
96
    tmpRxTail = TWI_RxTail;                                   // Not necessary, but prevents warnings
97
    while ( TWI_RxHead == tmpRxTail );
98
    tmptail = ( TWI_RxTail + 1 ) & TWI_RX_BUFFER_MASK;        // Calculate buffer index
99
    TWI_RxTail = tmptail;                                     // Store new index
100
    return TWI_RxBuf[tmptail];                                // Return data from the buffer.
101
}
102

    
103
/*! \brief Check if there is data in the receive buffer.
104
 */
105
unsigned char USI_TWI_Data_In_Receive_Buffer( void )
106
{
107
    unsigned char tmpRxTail;                            // Temporary variable to store volatile
108
    tmpRxTail = TWI_RxTail;                             // Not necessary, but prevents warnings
109
    return ( TWI_RxHead != tmpRxTail );                 // Return 0 (FALSE) if the receive buffer is empty.
110
}
111

    
112
/*! \brief Usi start condition ISR
113
 * Detects the USI_TWI Start Condition and intialises the USI
114
 * for reception of the "TWI Address" packet.
115
 */
116
ISR(USI_START_vect) {
117

    
118
    unsigned char tmpUSISR;                                         // Temporary variable to store volatile
119
    tmpUSISR = USISR;                                               // Not necessary, but prevents warnings
120
// Set default starting conditions for new TWI package
121
    USI_TWI_Overflow_State = USI_SLAVE_CHECK_ADDRESS;
122
    DDR_USI  &= ~(1<<PORT_USI_SDA);                                 // Set SDA as input
123
    while ( (PIN_USI & (1<<PORT_USI_SCL)) & !(tmpUSISR & (1<<USIPF)) );   // Wait for SCL to go low to ensure the "Start Condition" has completed.
124
                                                                       // If a Stop condition arises then leave the interrupt to prevent waiting forever.
125
    USICR   =   (1<<USISIE)|(1<<USIOIE)|                            // Enable Overflow and Start Condition Interrupt. (Keep StartCondInt to detect RESTART)
126
                (1<<USIWM1)|(1<<USIWM0)|                            // Set USI in Two-wire mode.
127
                (1<<USICS1)|(0<<USICS0)|(0<<USICLK)|                // Shift Register Clock Source = External, positive edge
128
                (0<<USITC);
129
    USISR  =    (1<<USI_START_COND_INT)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|      // Clear flags
130
                (0x0<<USICNT0);                                     // Set USI to sample 8 bits i.e. count 16 external pin toggles.
131
}
132

    
133

    
134
/*! \brief USI counter overflow ISR
135
 * Handels all the comunication. Is disabled only when waiting
136
 * for new Start Condition.
137
 */
138
ISR(USI_OVF_vect) {
139

    
140
  unsigned char tmpTxTail;     // Temporary variables to store volatiles
141
  unsigned char tmpUSIDR;
142

    
143

    
144
  switch (USI_TWI_Overflow_State)
145
  {
146
    // ---------- Address mode ----------
147
    // Check address and send ACK (and next USI_SLAVE_SEND_DATA) if OK, else reset USI.
148
    case USI_SLAVE_CHECK_ADDRESS:
149
      if ((USIDR == 0) || (( USIDR>>1 ) == TWI_slaveAddress))
150
      {
151
        if ( USIDR & 0x01 )
152
          USI_TWI_Overflow_State = USI_SLAVE_SEND_DATA;
153
        else
154
          USI_TWI_Overflow_State = USI_SLAVE_REQUEST_DATA;
155
          SET_USI_TO_SEND_ACK();
156
      }
157
      else
158
      {
159
        SET_USI_TO_TWI_START_CONDITION_MODE();
160
      }
161
      break;
162

    
163
    // ----- Master write data mode ------
164
    // Check reply and goto USI_SLAVE_SEND_DATA if OK, else reset USI.
165
    case USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA:
166
      if ( USIDR ) // If NACK, the master does not want more data.
167
      {
168
        SET_USI_TO_TWI_START_CONDITION_MODE();
169
        return;
170
      }
171
      // From here we just drop straight into USI_SLAVE_SEND_DATA if the master sent an ACK
172

    
173
    // Copy data from buffer to USIDR and set USI to shift byte. Next USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA
174
    case USI_SLAVE_SEND_DATA:
175

    
176
      // Get data from Buffer
177
      tmpTxTail = TWI_TxTail;           // Not necessary, but prevents warnings
178
      if ( TWI_TxHead != tmpTxTail )
179
      {
180
        TWI_TxTail = ( TWI_TxTail + 1 ) & TWI_TX_BUFFER_MASK;
181
        USIDR = TWI_TxBuf[TWI_TxTail];
182
      }
183
      else // If the buffer is empty then:
184
      {
185
          SET_USI_TO_TWI_START_CONDITION_MODE();
186
          return;
187
      }
188
      USI_TWI_Overflow_State = USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA;
189
      SET_USI_TO_SEND_DATA();
190
      break;
191

    
192
    // Set USI to sample reply from master. Next USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA
193
    case USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA:
194
      USI_TWI_Overflow_State = USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA;
195
      SET_USI_TO_READ_ACK();
196
      break;
197

    
198
    // ----- Master read data mode ------
199
    // Set USI to sample data from master. Next USI_SLAVE_GET_DATA_AND_SEND_ACK.
200
    case USI_SLAVE_REQUEST_DATA:
201
      USI_TWI_Overflow_State = USI_SLAVE_GET_DATA_AND_SEND_ACK;
202
      SET_USI_TO_READ_DATA();
203
      break;
204

    
205
    // Copy data from USIDR and send ACK. Next USI_SLAVE_REQUEST_DATA
206
    case USI_SLAVE_GET_DATA_AND_SEND_ACK:
207
      // Put data into Buffer
208
      tmpUSIDR = USIDR;             // Not necessary, but prevents warnings
209
      TWI_RxHead = ( TWI_RxHead + 1 ) & TWI_RX_BUFFER_MASK;
210
      TWI_RxBuf[TWI_RxHead] = tmpUSIDR;
211

    
212
      USI_TWI_Overflow_State = USI_SLAVE_REQUEST_DATA;
213
      SET_USI_TO_SEND_ACK();
214
      break;
215
  }
216
}
217

    
218
#endif