]> sigrok.org Git - sigrok-firmware-fx2lafw.git/blob - fx2lib/lib/i2c.c
Import fx2lib into fx2lafw directly.
[sigrok-firmware-fx2lafw.git] / fx2lib / lib / i2c.c
1 /**
2  * Copyright (C) 2009 Ubixum, Inc. 
3  *
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.
8  *
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.
13  *
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  **/
18
19 #include <stdio.h> // NOTE this needs deleted
20
21 #include <fx2regs.h>
22 #include <fx2macros.h>
23 #include <i2c.h>
24 #include <delay.h>
25
26
27 //#define DEBUG_I2C 1
28
29 #ifdef DEBUG_I2C
30 #define i2c_printf(...) printf(__VA_ARGS__)
31 #else
32 #define i2c_printf(...)
33 #endif
34
35
36 volatile __xdata BOOL cancel_i2c_trans;
37 #define CHECK_I2C_CANCEL() if (cancel_i2c_trans) return FALSE
38
39 /**
40  *
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 ) {
52     
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
58
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;
68             }
69    
70     
71     // 2. Write the 7-bit peripheral address and the direction bit (0 for a write) to I2DAT.
72         I2DAT = addr << 1;
73         
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;
80         }
81     
82         
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;
92         }
93         delay(10);
94         goto step1;
95     }
96     
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;
108         }
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; 
115         }
116     }
117
118     
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();
124
125     return TRUE;
126
127 }
128
129 /*
130  trm 13.4.4
131  
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
151 */
152
153 /*
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
158   
159   how many cycles at XTAL cycles/second = 9 cycles at 400k (or 100k) cycles/second
160   
161   timeout = n i2c cycles / I2C cycles/sec = timeout seconds
162           timeout seconds * XTAL cycles/sec = XTAL cycles
163           9 / 400 (or 100) * (XTAL)
164   
165 */
166 BOOL i2c_read( BYTE addr, WORD len, BYTE* buf) {
167     
168     
169     BYTE tmp;
170     WORD cur_byte;
171     cancel_i2c_trans=FALSE;
172     //WORD timeout_cycles = (WORD)(9.0 * XTAL / I2CFREQ );
173     
174     // 1. Set START=1. If BERR = 1, start timer*.
175     start:
176         CHECK_I2C_CANCEL();
177         cur_byte=0;        
178
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;
184         }
185         
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
188     
189     // 3. Wait for DONE=1 or for timer to expire*. If BERR=1, go to step 1.
190                 
191         while ( !(I2CS & bmDONE) && !cancel_i2c_trans ); CHECK_I2C_CANCEL();
192         if ( I2CS & bmBERR )
193             goto start;
194             
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; 
200         }
201         
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; 
205         
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
209     
210     while (len>cur_byte+1) { // reserve last byte read for after the loop
211         
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;
216
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;
220         
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;
225                         
226         // 8. Repeat steps 6 and 7 for each byte until ready to read the second-to-last byte.
227     }
228     
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
238
239     while ( (I2CS&bmSTOP) && !cancel_i2c_trans); CHECK_I2C_CANCEL();
240
241     return TRUE;
242 }
243
244
245
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;
251
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" );
257     }
258 #endif
259     
260     while ( cur_byte<length ) {
261         addr_len=0;
262         if (EEPROM_TWO_BYTE) {
263             data_buffer[addr_len++] = MSB(addr);
264         }
265         data_buffer[addr_len++] = LSB(addr);
266         data_buffer[addr_len++] = buf[cur_byte++];
267
268         i2c_printf ( "%02x " , data_buffer[addr_len-1] );
269         
270         if ( ! i2c_write ( prom_addr, addr_len, data_buffer, 0, NULL ) ) return FALSE;
271         ++addr; // next byte goes to next address
272     }
273
274     return TRUE;
275     
276 }
277
278
279 BOOL eeprom_read (BYTE prom_addr, WORD addr, WORD length, BYTE *buf)
280 {
281
282     BYTE eeprom_addr[2];
283     BYTE addr_len=0;
284     if (EEPROM_TWO_BYTE) 
285         eeprom_addr[addr_len++] = MSB(addr);
286     
287     eeprom_addr[addr_len++] = LSB(addr);
288
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;
294
295     return TRUE;
296     
297 }
298