root / branches / autonomous_recharging / code / projects / autonomous_recharging / archs / I2c test / USI_TWI_Master.c @ 410
History | View | Annotate | Download (10.3 KB)
1 |
/*****************************************************************************
|
---|---|
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
|