root / trunk / code / projects / autonomous_recharging / archs / USI_TWI_Slave.c @ 80
History | View | Annotate | Download (8.53 KB)
1 | 80 | bneuman | // 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 |