root / branches / autonomous_recharging / code / projects / autonomous_recharging / archs / I2c test / USI_TWI_Slave.c @ 355
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
|