Cast to WORD (not sure it's necessary) and put braces around the arguments.
[fx2lib.git] / lib / i2c.c
blobc18bceec2db306a2d3a3f8ef44dbb85e02b485c2
1 /**
2 * Copyright (C) 2009 Ubixum, Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 **/
19 #include <stdio.h> // NOTE this needs deleted
21 #include <fx2regs.h>
22 #include <fx2macros.h>
23 #include <i2c.h>
24 #include <delay.h>
27 //#define DEBUG_I2C 1
29 #ifdef DEBUG_I2C
30 #define i2c_printf(...) printf(__VA_ARGS__)
31 #else
32 #define i2c_printf(...)
33 #endif
36 volatile __xdata BOOL cancel_i2c_trans;
37 #define CHECK_I2C_CANCEL() if (cancel_i2c_trans) return FALSE
39 /**
41 1. Set START=1. If BERR=1, start timer*.
42 2. Write the 7-bit peripheral address and the direction bit (0 for a write) to I2DAT.
43 3. Wait for DONE=1 or for timer to expire*. If BERR=1, go to step 1.
44 4. If ACK=0, go to step 9.
45 5. Load I2DAT with a data byte.
46 6. Wait for DONE=1*. If BERR=1, go to step 1.
47 7. If ACK=0, go to step 9.
48 8. Repeat steps 5-7 for each byte until all bytes have been transferred.
49 9. Set STOP=1. Wait for STOP = 0 before initiating another transfer.
50 **/
51 BOOL i2c_write ( BYTE addr, WORD len, BYTE *addr_buf, WORD len2, BYTE* data_buf ) {
53 WORD cur_byte;
54 WORD total_bytes = len+len2; // NOTE overflow error?
55 BYTE retry_count=2; // two tries to write address/read ack
56 cancel_i2c_trans=FALSE;
57 //BOOL wait=FALSE; // use timer if needed
59 // 1. Set START=1. If BERR=1, start timer*.
60 step1:
61 CHECK_I2C_CANCEL();
62 cur_byte=0;
63 I2CS |= bmSTART;
64 if ( I2CS & bmBERR ) {
65 i2c_printf ( "Woops.. need to do the timer\n" );
66 delay(10); // way too long probably
67 goto step1;
71 // 2. Write the 7-bit peripheral address and the direction bit (0 for a write) to I2DAT.
72 I2DAT = addr << 1;
74 // 3. Wait for DONE=1 or for timer to expire*. If BERR=1, go to step 1.
75 while ( !(I2CS & bmDONE) && !cancel_i2c_trans);
76 CHECK_I2C_CANCEL();
77 if (I2CS&bmBERR) {
78 i2c_printf ( "bmBERR, going to step 1\n" );
79 goto step1;
83 // 4. If ACK=0, go to step 9.
84 if ( !(I2CS & bmACK) ) {
85 I2CS |= bmSTOP;
86 while ( (I2CS & bmSTOP) && !cancel_i2c_trans);
87 CHECK_I2C_CANCEL();
88 --retry_count;
89 if (!retry_count){
90 i2c_printf ( "No ack after writing address.! Fail\n");
91 return FALSE;
93 delay(10);
94 goto step1;
97 // 8. Repeat steps 5-7 for each byte until all bytes have been transferred.
98 while ( cur_byte < total_bytes ) {
99 // 5. Load I2DAT with a data byte.
100 I2DAT = cur_byte < len ? addr_buf[cur_byte] : data_buf[cur_byte-len];
101 ++cur_byte;
102 // 6. Wait for DONE=1*. If BERR=1, go to step 1.
103 while (!(I2CS&bmDONE) && !cancel_i2c_trans); CHECK_I2C_CANCEL();
104 if ( I2CS&bmBERR ) {
105 i2c_printf ( "bmBERR on byte %d. Going to step 1\n" , cur_byte-1 );
106 goto step1;
107 //return FALSE;
109 // 7. If ACK=0, go to step 9.
110 if ( !(I2CS & bmACK) ) {
111 I2CS |= bmSTOP;
112 while ( (I2CS&bmSTOP) && !cancel_i2c_trans);
113 i2c_printf ( "No Ack after byte %d. Fail\n", cur_byte-1 );
114 return FALSE;
119 // 9. Set STOP=1. Wait for STOP = 0 before initiating another transfer.
120 //real step 9
121 I2CS |= bmSTOP;
122 while ( (I2CS & bmSTOP) && !cancel_i2c_trans);
123 CHECK_I2C_CANCEL();
125 return TRUE;
130 trm 13.4.4
132 1. Set START=1. If BERR = 1, start timer*.
133 2. Write the 7-bit peripheral address and the direction bit (1 for a read) to I2DAT.
134 3. Wait for DONE=1 or for timer to expire*. If BERR=1, go to step 1.
135 4. If ACK=0, set STOP=1 and go to step 15.
136 5. Read I2DAT to initiate the first burst of nine SCL pulses to clock in the first byte from the slave.
137 Discard the value that was read from I2DAT.
138 6. Wait for DONE=1. If BERR=1, go to step 1.
139 7. Read the just-received byte of data from I2DAT. This read also initiates the next read transfer.
140 8. Repeat steps 6 and 7 for each byte until ready to read the second-to-last byte.
141 9. Wait for DONE=1. If BERR=1, go to step 1.
142 10. Before reading the second-to-last I2DAT byte, set LASTRD=1.
143 11. Read the second-to-last byte from I2DAT. With LASTRD=1, this initiates the final byte read on
144 the bus.
145 12. Wait for DONE=1. If BERR=1, go to step 1.
146 13. Set STOP=1.
147 14. Read the final byte from I2DAT immediately (the next instruction) after setting the STOP bit. By
148 reading I2DAT while the "stop" condition is being generated, the just-received data byte will be
149 retrieved without initiating an extra read transaction (nine more SCL pulses) on the I²Cbus.
150 15. Wait for STOP = 0 before initiating another transfer
154 * timer should be at least as long as longest start-stop interval on the bus
155 serial clock for i2c bus runs at 100khz by default and can run at 400khz for devices that support it
156 start-stop interval is about 9 serial clock cycles
157 400KHZ bit 0=100khz, 1=400khz
159 how many cycles at XTAL cycles/second = 9 cycles at 400k (or 100k) cycles/second
161 timeout = n i2c cycles / I2C cycles/sec = timeout seconds
162 timeout seconds * XTAL cycles/sec = XTAL cycles
163 9 / 400 (or 100) * (XTAL)
166 BOOL i2c_read( BYTE addr, WORD len, BYTE* buf) {
169 BYTE tmp;
170 WORD cur_byte;
171 cancel_i2c_trans=FALSE;
172 //WORD timeout_cycles = (WORD)(9.0 * XTAL / I2CFREQ );
174 // 1. Set START=1. If BERR = 1, start timer*.
175 start:
176 CHECK_I2C_CANCEL();
177 cur_byte=0;
179 I2CS |= bmSTART;
180 if ( I2CS & bmBERR ) {
181 i2c_printf ( "Woops, step1 BERR, need to do timeout\n");
182 delay(10); // NOTE way too long
183 goto start;
186 // 2. Write the 7-bit peripheral address and the direction bit (1 for a read) to I2DAT.
187 I2DAT = (addr << 1) | 1; // last 1 for read
189 // 3. Wait for DONE=1 or for timer to expire*. If BERR=1, go to step 1.
191 while ( !(I2CS & bmDONE) && !cancel_i2c_trans ); CHECK_I2C_CANCEL();
192 if ( I2CS & bmBERR )
193 goto start;
195 // 4. If ACK=0, set STOP=1 and go to step 15.
196 if (!(I2CS&bmACK) ) {
197 I2CS |= bmSTOP;
198 while ( (I2CS&bmSTOP) && !cancel_i2c_trans );
199 return FALSE;
202 // with only one byte to read, this needs set here.
203 // (In this case, the tmp read is the 2nd to last read)
204 if ( len==1 ) I2CS |= bmLASTRD;
206 // 5. Read I2DAT to initiate the first burst of nine SCL pulses to clock in the first byte from the slave.
207 // Discard the value that was read from I2DAT.
208 tmp = I2DAT; // discard read
210 while (len>cur_byte+1) { // reserve last byte read for after the loop
212 // 6. Wait for DONE=1. If BERR=1, go to step 1.
213 // 9. Wait for DONE=1. If BERR=1, go to step 1.
214 while (!(I2CS&bmDONE) && !cancel_i2c_trans); CHECK_I2C_CANCEL();
215 if ( I2CS&bmBERR ) goto start;
217 // 10. Before reading the second-to-last I2DAT byte, set LASTRD=1.
218 if (len==cur_byte+2) // 2nd to last byte
219 I2CS |= bmLASTRD;
221 // 7. Read the just-received byte of data from I2DAT. This read also initiates the next read transfer.
222 // 11. Read the second-to-last byte from I2DAT. With LASTRD=1, this initiates the final byte read on
223 // the bus.
224 buf[cur_byte++] = I2DAT;
226 // 8. Repeat steps 6 and 7 for each byte until ready to read the second-to-last byte.
229 //12. Wait for DONE=1. If BERR=1, go to step 1.
230 while (!(I2CS&bmDONE) && !cancel_i2c_trans); CHECK_I2C_CANCEL();
231 if ( I2CS&bmBERR ) goto start;
232 // 13. Set STOP=1.
233 I2CS |= bmSTOP;
234 // 14. Read the final byte from I2DAT immediately (the next instruction) after setting the STOP bit. By
235 // reading I2DAT while the "stop" condition is being generated, the just-received data byte will be
236 // retrieved without initiating an extra read transaction (nine more SCL pulses) on the I²Cbus.
237 buf[cur_byte] = I2DAT; // use instead of buffer addressing so next instruction reads I2DAT
239 while ( (I2CS&bmSTOP) && !cancel_i2c_trans); CHECK_I2C_CANCEL();
241 return TRUE;
246 BOOL eeprom_write(BYTE prom_addr, WORD addr, WORD length, BYTE* buf) {
247 BYTE addr_len=0;
248 // 1st bytes of buffer are address and next byte is value
249 BYTE data_buffer[3];
250 WORD cur_byte=0;
252 #ifdef DEBUG_I2C
253 if ( EEPROM_TWO_BYTE ) {
254 i2c_printf ( "Two Byte EEProm Address detected.\n" );
255 } else {
256 i2c_printf ( "Single Byte EEProm address detected.\n" );
258 #endif
260 while ( cur_byte<length ) {
261 addr_len=0;
262 if (EEPROM_TWO_BYTE) {
263 data_buffer[addr_len++] = MSB(addr);
265 data_buffer[addr_len++] = LSB(addr);
266 data_buffer[addr_len++] = buf[cur_byte++];
268 i2c_printf ( "%02x " , data_buffer[addr_len-1] );
270 if ( ! i2c_write ( prom_addr, addr_len, data_buffer, 0, NULL ) ) return FALSE;
271 ++addr; // next byte goes to next address
274 return TRUE;
279 BOOL eeprom_read (BYTE prom_addr, WORD addr, WORD length, BYTE *buf)
282 BYTE eeprom_addr[2];
283 BYTE addr_len=0;
284 if (EEPROM_TWO_BYTE)
285 eeprom_addr[addr_len++] = MSB(addr);
287 eeprom_addr[addr_len++] = LSB(addr);
289 // write the address we want to read to the prom
290 //printf ("Starting Addr Write with addr len %d\n", addr_len);
291 if ( !i2c_write( prom_addr, addr_len, eeprom_addr, 0, NULL ) ) return FALSE;
292 //printf ( "Starting read\n" );
293 if ( !i2c_read ( prom_addr, length, buf ) ) return FALSE;
295 return TRUE;