root / branches / autonomous_recharging / code / projects / autonomous_recharging / archs / homing stop / USI_TWI_Master.c @ 660
History | View | Annotate | Download (10.3 KB)
1 | 660 | bneuman | /*****************************************************************************
|
---|---|---|---|
2 | *
|
||
3 | * Atmel Corporation
|
||
4 | *
|
||
5 | * File : USI_TWI_Master.c
|
||
6 | * Compiler : IAR EWAAVR 2.28a/3.10a
|
||
7 | * Revision : $Revision: 1.11 $
|
||
8 | * Date : $Date: Tuesday, September 13, 2005 09:09:36 UTC $
|
||
9 | * Updated by : $Author: jtyssoe $
|
||
10 | *
|
||
11 | * Support mail : avr@atmel.com
|
||
12 | *
|
||
13 | * Supported devices : All device with USI module can be used.
|
||
14 | * The example is written for the ATmega169, ATtiny26 and ATtiny2313
|
||
15 | *
|
||
16 | * AppNote : AVR310 - Using the USI module as a TWI Master
|
||
17 | *
|
||
18 | * Description : This is an implementation of an TWI master using
|
||
19 | * the USI module as basis. The implementation assumes the AVR to
|
||
20 | * be the only TWI master in the system and can therefore not be
|
||
21 | * used in a multi-master system.
|
||
22 | * Usage : Initialize the USI module by calling the USI_TWI_Master_Initialise()
|
||
23 | * function. Hence messages/data are transceived on the bus using
|
||
24 | * the USI_TWI_Transceive() function. The transceive function
|
||
25 | * returns a status byte, which can be used to evaluate the
|
||
26 | * success of the transmission.
|
||
27 | *
|
||
28 | ****************************************************************************/
|
||
29 | #ifndef _USI_TWI_MASTER_H
|
||
30 | #define _USI_TWI_MASTER_H
|
||
31 | |||
32 | #include <util/delay.h> |
||
33 | #include <avr/io.h> |
||
34 | #include <avr/interrupt.h> |
||
35 | #include "USI_TWI_Master.h" |
||
36 | |||
37 | unsigned char USI_TWI_Master_Transfer( unsigned char ); |
||
38 | unsigned char USI_TWI_Master_Stop( void ); |
||
39 | |||
40 | union USI_TWI_state
|
||
41 | { |
||
42 | unsigned char errorState; // Can reuse the TWI_state for error states due to that it will not be need if there exists an error. |
||
43 | struct
|
||
44 | { |
||
45 | unsigned char addressMode : 1; |
||
46 | unsigned char masterWriteDataMode : 1; |
||
47 | unsigned char unused : 6; |
||
48 | }; |
||
49 | } USI_TWI_state; |
||
50 | |||
51 | /*---------------------------------------------------------------
|
||
52 | USI TWI single master initialization function
|
||
53 | ---------------------------------------------------------------*/
|
||
54 | void USI_TWI_Master_Initialise( void ) |
||
55 | { |
||
56 | PORT_USI |= (1<<PIN_USI_SDA); // Enable pullup on SDA, to set high as released state. |
||
57 | PORT_USI |= (1<<PIN_USI_SCL); // Enable pullup on SCL, to set high as released state. |
||
58 | |||
59 | DDR_USI |= (1<<PIN_USI_SCL); // Enable SCL as output. |
||
60 | DDR_USI |= (1<<PIN_USI_SDA); // Enable SDA as output. |
||
61 | |||
62 | USIDR = 0xFF; // Preload dataregister with "released level" data. |
||
63 | USICR = (0<<USISIE)|(0<<USIOIE)| // Disable Interrupts. |
||
64 | (1<<USIWM1)|(0<<USIWM0)| // Set USI in Two-wire mode. |
||
65 | (1<<USICS1)|(0<<USICS0)|(1<<USICLK)| // Software stobe as counter clock source |
||
66 | (0<<USITC);
|
||
67 | USISR = (1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)| // Clear flags, |
||
68 | (0x0<<USICNT0); // and reset counter. |
||
69 | } |
||
70 | |||
71 | /*---------------------------------------------------------------
|
||
72 | Use this function to get hold of the error message from the last transmission
|
||
73 | ---------------------------------------------------------------*/
|
||
74 | unsigned char USI_TWI_Get_State_Info( void ) |
||
75 | { |
||
76 | return ( USI_TWI_state.errorState ); // Return error state. |
||
77 | } |
||
78 | |||
79 | /*---------------------------------------------------------------
|
||
80 | USI Transmit and receive function. LSB of first byte in data
|
||
81 | indicates if a read or write cycles is performed. If set a read
|
||
82 | operation is performed.
|
||
83 | |||
84 | Function generates (Repeated) Start Condition, sends address and
|
||
85 | R/W, Reads/Writes Data, and verifies/sends ACK.
|
||
86 | |||
87 | Success or error code is returned. Error codes are defined in
|
||
88 | USI_TWI_Master.h
|
||
89 | ---------------------------------------------------------------*/
|
||
90 | unsigned char USI_TWI_Start_Transceiver_With_Data( unsigned char *msg, unsigned char msgSize) |
||
91 | { |
||
92 | unsigned char tempUSISR_8bit = (1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)| // Prepare register value to: Clear flags, and |
||
93 | (0x0<<USICNT0); // set USI to shift 8 bits i.e. count 16 clock edges. |
||
94 | unsigned char tempUSISR_1bit = (1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)| // Prepare register value to: Clear flags, and |
||
95 | (0xE<<USICNT0); // set USI to shift 1 bit i.e. count 2 clock edges. |
||
96 | |||
97 | USI_TWI_state.errorState = 0;
|
||
98 | USI_TWI_state.addressMode = TRUE; |
||
99 | |||
100 | |||
101 | |||
102 | if ( !(*msg & (1<<TWI_READ_BIT)) ) // The LSB in the address byte determines if is a masterRead or masterWrite operation. |
||
103 | { |
||
104 | USI_TWI_state.masterWriteDataMode = TRUE; |
||
105 | } |
||
106 | |||
107 | /* Release SCL to ensure that (repeated) Start can be performed */
|
||
108 | PORT_USI |= (1<<PIN_USI_SCL); // Release SCL. |
||
109 | while( !(PORT_USI & (1<<PIN_USI_SCL)) ); // Verify that SCL becomes high. |
||
110 | |||
111 | _delay_loop_1(T2_TWI); |
||
112 | //_delay_us(T4_TWI);
|
||
113 | //__delay_cycles( T2_TWI ); // Delay for T2TWI if TWI_STANDARD_MODE
|
||
114 | |||
115 | |||
116 | /* Generate Start Condition */
|
||
117 | PORT_USI &= ~(1<<PIN_USI_SDA); // Force SDA LOW. |
||
118 | _delay_loop_1(T4_TWI); |
||
119 | //_delay_us(T4_TWI);
|
||
120 | //__delay_cycles( T4_TWI );
|
||
121 | PORT_USI &= ~(1<<PIN_USI_SCL); // Pull SCL LOW. |
||
122 | PORT_USI |= (1<<PIN_USI_SDA); // Release SDA. |
||
123 | |||
124 | //Start
|
||
125 | PORTA |= _BV(PA3); |
||
126 | |||
127 | |||
128 | /*Write address and Read/Write data */
|
||
129 | do
|
||
130 | { |
||
131 | /* If masterWrite cycle (or inital address tranmission)*/
|
||
132 | if (USI_TWI_state.addressMode || USI_TWI_state.masterWriteDataMode)
|
||
133 | { |
||
134 | PORTA |= _BV(PA4); |
||
135 | /* Write a byte */
|
||
136 | PORT_USI &= ~(1<<PIN_USI_SCL); // Pull SCL LOW. |
||
137 | USIDR = *(msg++); // Setup data.
|
||
138 | USI_TWI_Master_Transfer( tempUSISR_8bit ); // Send 8 bits on bus.
|
||
139 | |||
140 | /* Clock and verify (N)ACK from slave */
|
||
141 | DDR_USI &= ~(1<<PIN_USI_SDA); // Enable SDA as input. |
||
142 | |||
143 | PORTA |= _BV(PA5); |
||
144 | |||
145 | if( USI_TWI_Master_Transfer( tempUSISR_1bit ) & (1<<TWI_NACK_BIT) ) |
||
146 | { |
||
147 | //Shit
|
||
148 | PORTA |= _BV(PA3) | _BV(PA4) | _BV(PA5) | _BV(PA6) | _BV(PA7); |
||
149 | |||
150 | if ( USI_TWI_state.addressMode )
|
||
151 | USI_TWI_state.errorState = USI_TWI_NO_ACK_ON_ADDRESS; |
||
152 | else
|
||
153 | USI_TWI_state.errorState = USI_TWI_NO_ACK_ON_DATA; |
||
154 | return (FALSE);
|
||
155 | } |
||
156 | USI_TWI_state.addressMode = FALSE; // Only perform address transmission once.
|
||
157 | |||
158 | |||
159 | PORTA &= (~_BV(PA4) | ~_BV(PA5)); |
||
160 | } |
||
161 | /* Else masterRead cycle*/
|
||
162 | else
|
||
163 | { |
||
164 | /* Read a data byte */
|
||
165 | DDR_USI &= ~(1<<PIN_USI_SDA); // Enable SDA as input. |
||
166 | *(msg++) = USI_TWI_Master_Transfer( tempUSISR_8bit ); |
||
167 | |||
168 | /* Prepare to generate ACK (or NACK in case of End Of Transmission) */
|
||
169 | if( msgSize == 1) // If transmission of last byte was performed. |
||
170 | { |
||
171 | USIDR = 0xFF; // Load NACK to confirm End Of Transmission. |
||
172 | } |
||
173 | else
|
||
174 | { |
||
175 | USIDR = 0x00; // Load ACK. Set data register bit 7 (output for SDA) low. |
||
176 | } |
||
177 | USI_TWI_Master_Transfer( tempUSISR_1bit ); // Generate ACK/NACK.
|
||
178 | } |
||
179 | }while( --msgSize) ; // Until all data sent/received. |
||
180 | |||
181 | |||
182 | PORTA |= _BV(PA6); |
||
183 | |||
184 | USI_TWI_Master_Stop(); // Send a STOP condition on the TWI bus.
|
||
185 | |||
186 | /* Transmission successfully completed*/
|
||
187 | return (TRUE);
|
||
188 | } |
||
189 | |||
190 | /*---------------------------------------------------------------
|
||
191 | Core function for shifting data in and out from the USI.
|
||
192 | Data to be sent has to be placed into the USIDR prior to calling
|
||
193 | this function. Data read, will be return'ed from the function.
|
||
194 | ---------------------------------------------------------------*/
|
||
195 | unsigned char USI_TWI_Master_Transfer( unsigned char temp ) |
||
196 | { |
||
197 | USISR = temp; // Set USISR according to temp.
|
||
198 | // Prepare clocking.
|
||
199 | temp = (0<<USISIE)|(0<<USIOIE)| // Interrupts disabled |
||
200 | (1<<USIWM1)|(0<<USIWM0)| // Set USI in Two-wire mode. |
||
201 | (1<<USICS1)|(0<<USICS0)|(1<<USICLK)| // Software clock strobe as source. |
||
202 | (1<<USITC); // Toggle Clock Port. |
||
203 | do
|
||
204 | { |
||
205 | //__delay_cycles( T2_TWI );
|
||
206 | _delay_loop_1(T2_TWI); |
||
207 | //_delay_us(T2_TWI);
|
||
208 | USICR = temp; // Generate positve SCL edge.
|
||
209 | while( !(PIN_USI & (1<<PIN_USI_SCL)) );// Wait for SCL to go high. |
||
210 | _delay_loop_1(T4_TWI); |
||
211 | //__delay_cycles( T4_TWI );
|
||
212 | // _delay_us(T4_TWI);
|
||
213 | USICR = temp; // Generate negative SCL edge.
|
||
214 | }while( !(USISR & (1<<USIOIF)) ); // Check for transfer complete. |
||
215 | _delay_loop_1(T2_TWI); |
||
216 | //_delay_us(T2_TWI);
|
||
217 | //__delay_cycles( T2_TWI );
|
||
218 | temp = USIDR; // Read out data.
|
||
219 | USIDR = 0xFF; // Release SDA. |
||
220 | DDR_USI |= (1<<PIN_USI_SDA); // Enable SDA as output. |
||
221 | |||
222 | return temp; // Return the data from the USIDR |
||
223 | } |
||
224 | |||
225 | /*---------------------------------------------------------------
|
||
226 | Function for generating a TWI Stop Condition. Used to release
|
||
227 | the TWI bus.
|
||
228 | ---------------------------------------------------------------*/
|
||
229 | unsigned char USI_TWI_Master_Stop( void ) |
||
230 | { |
||
231 | PORT_USI &= ~(1<<PIN_USI_SDA); // Pull SDA low. |
||
232 | PORT_USI |= (1<<PIN_USI_SCL); // Release SCL. |
||
233 | while( !(PIN_USI & (1<<PIN_USI_SCL)) ); // Wait for SCL to go high. |
||
234 | _delay_loop_1(T4_TWI); |
||
235 | //_delay_us(T4_TWI);
|
||
236 | //__delay_cycles( T4_TWI );
|
||
237 | PORT_USI |= (1<<PIN_USI_SDA); // Release SDA. |
||
238 | _delay_loop_1(T2_TWI); |
||
239 | //_delay_us(T2_TWI);
|
||
240 | //__delay_cycles( T2_TWI );
|
||
241 | |||
242 | #ifdef SIGNAL_VERIFY
|
||
243 | if( !(USISR & (1<<USIPF)) ) |
||
244 | { |
||
245 | USI_TWI_state.errorState = USI_TWI_MISSING_STOP_CON; |
||
246 | return (FALSE);
|
||
247 | } |
||
248 | #endif
|
||
249 | |||
250 | return (TRUE);
|
||
251 | } |
||
252 | |||
253 | #endif |