gpif single write function.
[fx2lib.git] / lib / i2c.c
blob5b4c5196177c22c71731d4f2934390ed4aa1a593
1 /**
2 * Copyright (C) 2008 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 /**
29 1. Set START=1. If BERR=1, start timer*.
30 2. Write the 7-bit peripheral address and the direction bit (0 for a write) to I2DAT.
31 3. Wait for DONE=1 or for timer to expire*. If BERR=1, go to step 1.
32 4. If ACK=0, go to step 9.
33 5. Load I2DAT with a data byte.
34 6. Wait for DONE=1*. If BERR=1, go to step 1.
35 7. If ACK=0, go to step 9.
36 8. Repeat steps 5-7 for each byte until all bytes have been transferred.
37 9. Set STOP=1. Wait for STOP = 0 before initiating another transfer.
38 **/
39 void i2c_write ( BYTE addr, WORD len, BYTE *dat ) {
41 WORD cur_byte;
42 //BOOL wait=FALSE; // use timer if needed
44 // 9. Set STOP=1. Wait for STOP = 0 before initiating another transfer.
45 // not setting STOP here though
46 step9:
47 while ( I2CS & bmSTOP ); // WAIT for STOP = 0 before another transfer
49 // 1. Set START=1. If BERR=1, start timer*.
50 step1:
51 cur_byte=0;
52 I2CS |= bmSTART;
53 if ( I2CS & bmBERR ) {
54 printf ( "Woops.. need to do the timer\n" );
55 delay(10); // way too long
56 goto step1;
59 // 2. Write the 7-bit peripheral address and the direction bit (0 for a write) to I2DAT.
60 I2DAT = addr << 1;
62 // 3. Wait for DONE=1 or for timer to expire*. If BERR=1, go to step 1.
63 while ( !(I2CS & bmDONE) );
64 if (I2CS&bmBERR) {
65 goto step1;
68 // 4. If ACK=0, go to step 9.
69 if ( !(I2CS & bmACK) ) {
70 I2CS |= bmSTOP;
71 //printf ( "no ack!\n");
72 goto step9;
75 // 8. Repeat steps 5-7 for each byte until all bytes have been transferred.
76 while ( cur_byte < len ) {
77 // 5. Load I2DAT with a data byte.
78 I2DAT = dat[cur_byte++];
79 // 6. Wait for DONE=1*. If BERR=1, go to step 1.
80 while (!(I2CS&bmDONE)); if ( I2CS&bmBERR ) goto step1;
81 // 7. If ACK=0, go to step 9.
82 if ( !(I2CS & bmACK) ) {
83 I2CS |= bmSTOP;
84 goto step9;
88 //real step 9
89 I2CS |= bmSTOP;
94 trm 13.4.4
96 1. Set START=1. If BERR = 1, start timer*.
97 2. Write the 7-bit peripheral address and the direction bit (1 for a read) to I2DAT.
98 3. Wait for DONE=1 or for timer to expire*. If BERR=1, go to step 1.
99 4. If ACK=0, set STOP=1 and go to step 15.
100 5. Read I2DAT to initiate the first burst of nine SCL pulses to clock in the first byte from the slave.
101 Discard the value that was read from I2DAT.
102 6. Wait for DONE=1. If BERR=1, go to step 1.
103 7. Read the just-received byte of data from I2DAT. This read also initiates the next read transfer.
104 8. Repeat steps 6 and 7 for each byte until ready to read the second-to-last byte.
105 9. Wait for DONE=1. If BERR=1, go to step 1.
106 10. Before reading the second-to-last I2DAT byte, set LASTRD=1.
107 11. Read the second-to-last byte from I2DAT. With LASTRD=1, this initiates the final byte read on
108 the bus.
109 12. Wait for DONE=1. If BERR=1, go to step 1.
110 13. Set STOP=1.
111 14. Read the final byte from I2DAT immediately (the next instruction) after setting the STOP bit. By
112 reading I2DAT while the "stop" condition is being generated, the just-received data byte will be
113 retrieved without initiating an extra read transaction (nine more SCL pulses) on the I²Cbus.
114 15. Wait for STOP = 0 before initiating another transfer
118 * timer should be at least as long as longest start-stop interval on the bus
119 serial clock for i2c bus runs at 100khz by default and can run at 400khz for devices that support it
120 start-stop interval is about 9 serial clock cycles
121 400KHZ bit 0=100khz, 1=400khz
123 how many cycles at XTAL cycles/second = 9 cycles at 400k (or 100k) cycles/second
125 timeout = n i2c cycles / I2C cycles/sec = timeout seconds
126 timeout seconds * XTAL cycles/sec = XTAL cycles
127 9 / 400 (or 100) * (XTAL)
130 void i2c_read( BYTE addr, WORD len, BYTE* buf) {
133 BYTE tmp;
134 WORD cur_byte;
135 //WORD timeout_cycles = (WORD)(9.0 * XTAL / I2CFREQ );
137 /*printf ( "I2C: %04x%04x\nXTAL: %04x%04x\ntimeout cycles: %d\n",
138 (WORD)(I2CFREQ>>16), (WORD)(I2CFREQ&0xffff),
139 (WORD)(XTAL>>16),
140 (WORD)(XTAL&0xffff),
141 timeout_cycles ); */
144 // step 15 1st.
145 step15:
146 while ( I2CS & bmSTOP);
149 // 1. Set START=1. If BERR = 1, start timer*.
150 start:
151 cur_byte=0;
152 I2CS |= bmSTART;
153 if ( I2CS & bmBERR ) {
154 printf ( "Woops, step1 BERR, need to do timeout\n");
155 delay(10); // NOTE way too long
156 goto start;
159 // 2. Write the 7-bit peripheral address and the direction bit (1 for a read) to I2DAT.
160 I2DAT = (addr << 1) | 1; // last 1 for read
162 // 3. Wait for DONE=1 or for timer to expire*. If BERR=1, go to step 1.
164 while ( !(I2CS & bmDONE) );
165 if ( I2CS & bmBERR )
166 goto start;
168 // 4. If ACK=0, set STOP=1 and go to step 15.
169 if (!(I2CS&bmACK) ) {
170 I2CS |= bmSTOP;
171 goto step15;
174 // with only one byte to read, this needs set here.
175 // (In this case, the tmp read is the 2nd to last read)
176 if ( len==1 ) I2CS |= bmLASTRD;
178 // 5. Read I2DAT to initiate the first burst of nine SCL pulses to clock in the first byte from the slave.
179 // Discard the value that was read from I2DAT.
180 tmp = I2DAT; // discard read
182 while (len>cur_byte+1) { // reserve last byte read for after the loop
184 // 6. Wait for DONE=1. If BERR=1, go to step 1.
185 // 9. Wait for DONE=1. If BERR=1, go to step 1.
186 while (!(I2CS&bmDONE)); if ( I2CS&bmBERR ) goto start;
188 // 10. Before reading the second-to-last I2DAT byte, set LASTRD=1.
189 if (len==cur_byte+2) // 2nd to last byte
190 I2CS |= bmLASTRD;
192 // 7. Read the just-received byte of data from I2DAT. This read also initiates the next read transfer.
193 // 11. Read the second-to-last byte from I2DAT. With LASTRD=1, this initiates the final byte read on
194 // the bus.
195 buf[cur_byte++] = I2DAT;
197 // 8. Repeat steps 6 and 7 for each byte until ready to read the second-to-last byte.
200 //12. Wait for DONE=1. If BERR=1, go to step 1.
201 while (!(I2CS&bmDONE)); if ( I2CS&bmBERR ) goto start;
202 // 13. Set STOP=1.
203 I2CS |= bmSTOP;
204 // 14. Read the final byte from I2DAT immediately (the next instruction) after setting the STOP bit. By
205 // reading I2DAT while the "stop" condition is being generated, the just-received data byte will be
206 // retrieved without initiating an extra read transaction (nine more SCL pulses) on the I²Cbus.
207 buf[cur_byte] = I2DAT; // use instead of buffer addressing so next instruction reads I2DAT
212 void eeprom_write(BYTE prom_addr, WORD addr, WORD length, BYTE* buf) {
213 BYTE addr_len=0;
214 // 1st bytes of buffer are address and next byte is value
215 BYTE data_buffer[3];
216 WORD cur_byte=0;
218 while ( cur_byte<length ) {
219 addr_len=0;
220 if (EEPROM_TWO_BYTE)
221 data_buffer[addr_len++] = MSB(addr);
222 data_buffer[addr_len++] = LSB(addr);
223 data_buffer[addr_len++] = buf[cur_byte++];
225 i2c_write ( prom_addr, addr_len, data_buffer );
226 ++addr; // next byte goes to next address
232 void eeprom_read (BYTE prom_addr, WORD addr, WORD length, BYTE *buf)
235 BYTE eeprom_addr[2];
236 BYTE addr_len=0;
237 if (EEPROM_TWO_BYTE)
238 eeprom_addr[addr_len++] = MSB(addr);
240 eeprom_addr[addr_len++] = LSB(addr);
242 // write the address we want to read to the prom
243 //printf ("Starting Addr Write with addr len %d\n", addr_len);
244 i2c_write( prom_addr, addr_len, eeprom_addr );
245 //printf ( "Starting read\n" );
246 i2c_read ( prom_addr, length, buf );