]> sigrok.org Git - sigrok-firmware-fx2lafw.git/blob - fx2lib/lib/i2c.c
Add Hantek PSO2020 firmware support
[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, see <http://www.gnu.org/licenses/>.
16  **/
17
18 #include <stdio.h> // NOTE this needs deleted
19
20 #include <fx2regs.h>
21 #include <fx2macros.h>
22 #include <i2c.h>
23 #include <delay.h>
24
25
26 //#define DEBUG_I2C 1
27
28 #ifdef DEBUG_I2C
29 #define i2c_printf(...) printf(__VA_ARGS__)
30 #else
31 #define i2c_printf(...)
32 #endif
33
34
35 volatile __xdata BOOL cancel_i2c_trans;
36 #define CHECK_I2C_CANCEL() if (cancel_i2c_trans) return FALSE
37
38 /**
39  *
40     1. Set START=1. If BERR=1, start timer*.
41     2. Write the 7-bit peripheral address and the direction bit (0 for a write) to I2DAT.
42     3. Wait for DONE=1 or for timer to expire*. If BERR=1, go to step 1.
43     4. If ACK=0, go to step 9.
44     5. Load I2DAT with a data byte.
45     6. Wait for DONE=1*. If BERR=1, go to step 1.
46     7. If ACK=0, go to step 9.
47     8. Repeat steps 5-7 for each byte until all bytes have been transferred.
48     9. Set STOP=1. Wait for STOP = 0 before initiating another transfer.
49  **/
50 BOOL i2c_write ( BYTE addr, WORD len, BYTE *addr_buf, WORD len2, BYTE* data_buf ) {
51     
52     WORD cur_byte;
53     WORD total_bytes = len+len2; // NOTE overflow error?
54     BYTE retry_count=2; // two tries to write address/read ack
55     cancel_i2c_trans=FALSE;
56     //BOOL wait=FALSE; // use timer if needed
57
58     // 1. Set START=1. If BERR=1, start timer*.
59     step1:
60         CHECK_I2C_CANCEL();
61         cur_byte=0;
62         I2CS |= bmSTART;
63         if ( I2CS & bmBERR ) {
64             i2c_printf ( "Woops.. need to do the timer\n" );
65             delay(10); // way too long probably
66             goto step1;
67             }
68    
69     
70     // 2. Write the 7-bit peripheral address and the direction bit (0 for a write) to I2DAT.
71         I2DAT = addr << 1;
72         
73     // 3. Wait for DONE=1 or for timer to expire*. If BERR=1, go to step 1.
74         while ( !(I2CS & bmDONE) && !cancel_i2c_trans);
75         CHECK_I2C_CANCEL();
76         if (I2CS&bmBERR) {
77             i2c_printf ( "bmBERR, going to step 1\n" );
78             goto step1;
79         }
80     
81         
82     // 4. If ACK=0, go to step 9.
83     if ( !(I2CS & bmACK) ) {
84         I2CS |= bmSTOP;
85         while ( (I2CS & bmSTOP) && !cancel_i2c_trans);
86         CHECK_I2C_CANCEL();
87         --retry_count;
88         if (!retry_count){
89             i2c_printf ( "No ack after writing address.! Fail\n");
90             return FALSE;
91         }
92         delay(10);
93         goto step1;
94     }
95     
96     // 8. Repeat steps 5-7 for each byte until all bytes have been transferred.
97     while ( cur_byte < total_bytes ) {
98         // 5. Load I2DAT with a data byte.
99         I2DAT = cur_byte < len ? addr_buf[cur_byte] : data_buf[cur_byte-len];
100         ++cur_byte;
101         // 6. Wait for DONE=1*. If BERR=1, go to step 1.
102         while (!(I2CS&bmDONE) && !cancel_i2c_trans); CHECK_I2C_CANCEL();
103         if ( I2CS&bmBERR ) {
104          i2c_printf ( "bmBERR on byte %d. Going to step 1\n" , cur_byte-1 );
105          goto step1;
106          //return FALSE;
107         }
108         // 7. If ACK=0, go to step 9.
109         if ( !(I2CS & bmACK) ) {
110             I2CS |= bmSTOP;
111             while ( (I2CS&bmSTOP) && !cancel_i2c_trans);
112             i2c_printf ( "No Ack after byte %d. Fail\n", cur_byte-1 );
113             return FALSE; 
114         }
115     }
116
117     
118     // 9. Set STOP=1. Wait for STOP = 0 before initiating another transfer.
119     //real step 9
120     I2CS |= bmSTOP;
121     while ( (I2CS & bmSTOP) && !cancel_i2c_trans);
122     CHECK_I2C_CANCEL();
123
124     return TRUE;
125
126 }
127
128 /*
129  trm 13.4.4
130  
131     1. Set START=1. If BERR = 1, start timer*.
132     2. Write the 7-bit peripheral address and the direction bit (1 for a read) to I2DAT.
133     3. Wait for DONE=1 or for timer to expire*. If BERR=1, go to step 1.
134     4. If ACK=0, set STOP=1 and go to step 15.
135     5. Read I2DAT to initiate the first burst of nine SCL pulses to clock in the first byte from the slave.
136     Discard the value that was read from I2DAT.
137     6. Wait for DONE=1. If BERR=1, go to step 1.
138     7. Read the just-received byte of data from I2DAT. This read also initiates the next read transfer.
139     8. Repeat steps 6 and 7 for each byte until ready to read the second-to-last byte.
140     9. Wait for DONE=1. If BERR=1, go to step 1.
141     10. Before reading the second-to-last I2DAT byte, set LASTRD=1.
142     11. Read the second-to-last byte from I2DAT. With LASTRD=1, this initiates the final byte read on
143     the bus.
144     12. Wait for DONE=1. If BERR=1, go to step 1.
145     13. Set STOP=1.
146     14. Read the final byte from I2DAT immediately (the next instruction) after setting the STOP bit. By
147     reading I2DAT while the "stop" condition is being generated, the just-received data byte will be
148     retrieved without initiating an extra read transaction (nine more SCL pulses) on the I²Cbus.
149     15. Wait for STOP = 0 before initiating another transfer
150 */
151
152 /*
153   * timer should be at least as long as longest start-stop interval on the bus
154   serial clock for i2c bus runs at 100khz by default and can run at 400khz for devices that support it
155   start-stop interval is about 9 serial clock cycles
156   400KHZ bit 0=100khz, 1=400khz
157   
158   how many cycles at XTAL cycles/second = 9 cycles at 400k (or 100k) cycles/second
159   
160   timeout = n i2c cycles / I2C cycles/sec = timeout seconds
161           timeout seconds * XTAL cycles/sec = XTAL cycles
162           9 / 400 (or 100) * (XTAL)
163   
164 */
165 BOOL i2c_read( BYTE addr, WORD len, BYTE* buf) {
166     
167     
168     BYTE tmp;
169     WORD cur_byte;
170     cancel_i2c_trans=FALSE;
171     //WORD timeout_cycles = (WORD)(9.0 * XTAL / I2CFREQ );
172     
173     // 1. Set START=1. If BERR = 1, start timer*.
174     start:
175         CHECK_I2C_CANCEL();
176         cur_byte=0;        
177
178         I2CS |= bmSTART;
179         if ( I2CS & bmBERR ) {            
180             i2c_printf ( "Woops, step1 BERR, need to do timeout\n");
181             delay(10); // NOTE way too long
182             goto start;
183         }
184         
185     // 2. Write the 7-bit peripheral address and the direction bit (1 for a read) to I2DAT.
186         I2DAT = (addr << 1) | 1; // last 1 for read
187     
188     // 3. Wait for DONE=1 or for timer to expire*. If BERR=1, go to step 1.
189                 
190         while ( !(I2CS & bmDONE) && !cancel_i2c_trans ); CHECK_I2C_CANCEL();
191         if ( I2CS & bmBERR )
192             goto start;
193             
194     // 4. If ACK=0, set STOP=1 and go to step 15.
195         if (!(I2CS&bmACK) ) {
196             I2CS |= bmSTOP;
197             while ( (I2CS&bmSTOP) && !cancel_i2c_trans );
198             return FALSE; 
199         }
200         
201     // with only one byte to read, this needs set here.
202     // (In this case, the tmp read is the 2nd to last read)
203     if ( len==1 ) I2CS |= bmLASTRD; 
204         
205     // 5. Read I2DAT to initiate the first burst of nine SCL pulses to clock in the first byte from the slave.
206     //    Discard the value that was read from I2DAT.
207         tmp = I2DAT; // discard read
208     
209     while (len>cur_byte+1) { // reserve last byte read for after the loop
210         
211         // 6. Wait for DONE=1. If BERR=1, go to step 1.
212         // 9. Wait for DONE=1. If BERR=1, go to step 1.
213         while (!(I2CS&bmDONE) && !cancel_i2c_trans); CHECK_I2C_CANCEL(); 
214         if ( I2CS&bmBERR ) goto start;
215
216         // 10. Before reading the second-to-last I2DAT byte, set LASTRD=1.
217         if (len==cur_byte+2) // 2nd to last byte
218             I2CS |= bmLASTRD;
219         
220         // 7. Read the just-received byte of data from I2DAT. This read also initiates the next read transfer.
221         // 11. Read the second-to-last byte from I2DAT. With LASTRD=1, this initiates the final byte read on
222         //     the bus.
223             buf[cur_byte++] = I2DAT;
224                         
225         // 8. Repeat steps 6 and 7 for each byte until ready to read the second-to-last byte.
226     }
227     
228     //12. Wait for DONE=1. If BERR=1, go to step 1.
229         while (!(I2CS&bmDONE) && !cancel_i2c_trans); CHECK_I2C_CANCEL();
230         if ( I2CS&bmBERR ) goto start;
231     // 13. Set STOP=1.
232         I2CS |= bmSTOP;
233     // 14. Read the final byte from I2DAT immediately (the next instruction) after setting the STOP bit. By
234     // reading I2DAT while the "stop" condition is being generated, the just-received data byte will be
235     // retrieved without initiating an extra read transaction (nine more SCL pulses) on the I²Cbus.
236         buf[cur_byte] = I2DAT; // use instead of buffer addressing so next instruction reads I2DAT
237
238     while ( (I2CS&bmSTOP) && !cancel_i2c_trans); CHECK_I2C_CANCEL();
239
240     return TRUE;
241 }
242
243
244
245 BOOL eeprom_write(BYTE prom_addr, WORD addr, WORD length, BYTE* buf) {
246     BYTE addr_len=0;
247     // 1st bytes of buffer are address and next byte is value
248     BYTE data_buffer[3];
249     WORD cur_byte=0;
250
251 #ifdef DEBUG_I2C
252     if ( EEPROM_TWO_BYTE ) {
253         i2c_printf ( "Two Byte EEProm Address detected.\n" );
254     } else {
255         i2c_printf ( "Single Byte EEProm address detected.\n" );
256     }
257 #endif
258     
259     while ( cur_byte<length ) {
260         addr_len=0;
261         if (EEPROM_TWO_BYTE) {
262             data_buffer[addr_len++] = MSB(addr);
263         }
264         data_buffer[addr_len++] = LSB(addr);
265         data_buffer[addr_len++] = buf[cur_byte++];
266
267         i2c_printf ( "%02x " , data_buffer[addr_len-1] );
268         
269         if ( ! i2c_write ( prom_addr, addr_len, data_buffer, 0, NULL ) ) return FALSE;
270         ++addr; // next byte goes to next address
271     }
272
273     return TRUE;
274     
275 }
276
277
278 BOOL eeprom_read (BYTE prom_addr, WORD addr, WORD length, BYTE *buf)
279 {
280
281     BYTE eeprom_addr[2];
282     BYTE addr_len=0;
283     if (EEPROM_TWO_BYTE) 
284         eeprom_addr[addr_len++] = MSB(addr);
285     
286     eeprom_addr[addr_len++] = LSB(addr);
287
288     // write the address we want to read to the prom
289     //printf ("Starting Addr Write with addr len %d\n", addr_len);
290     if ( !i2c_write( prom_addr, addr_len, eeprom_addr, 0, NULL ) ) return FALSE;
291     //printf ( "Starting read\n" );
292     if ( !i2c_read ( prom_addr, length, buf ) ) return FALSE;
293
294     return TRUE;
295     
296 }
297