]> git.gag.com Git - fw/sdcc/blob - device/examples/ds390/i2c390/i2clole.c
Moved and unpacked examples to sdcc/device/examples/ds390
[fw/sdcc] / device / examples / ds390 / i2c390 / i2clole.c
1 /* This implemenation is based on an example I once grabbed from 
2    the Philips bbs.
3    Don't know who wrote it, but is has been hacked so heavely, he/she wouldn't
4    recogize it anyway */
5
6 #define DEBUG_I2C
7
8 #ifdef DEBUG_I2C
9 #include <stdio.h>
10 #endif
11
12 #include <ds80c390.h>
13 #include "i2clole.h"
14
15 #define I2CDELAY 1
16
17 // we are (ab)using the CAN CTX and CRX for serial data and serial clock
18 #define SCL_HIGH (P5 |= 1)
19 #define SCL_LOW (P5 &= ~1)
20 #define SDA_HIGH (P5 |= 2)
21 #define SDA_LOW (P5 &= ~2)
22
23 #define SDA_OUT(b) (b ? SDA_HIGH : SDA_LOW)
24 #define SDA_IN ((P5>>1)&1)
25 #define SCL_IN (P5&1)
26
27 char i2cTransmitBuffer[I2C_BUFSIZE];     /* Global transfer buffers */
28 char i2cReceiveBuffer[I2C_BUFSIZE];
29
30 char i2cError = 0;                 /* Last error */
31
32
33 /*
34  * Makes sure that the bus is in a known condition. Returns 1 on success,
35  * 0 if some other device is pulling on the bus.
36  */
37
38 char I2CReset(void)
39 {
40   //puts ("<I2CReset>");
41   SDA_LOW;
42   SCL_LOW;
43   SCL_HIGH;
44   SDA_HIGH;
45   i2cError = 0;
46   return (SCL_IN && SDA_IN);
47 }
48
49
50 /*
51  * Generates a start condition on the bus. Returns 0 on success, 1 if some
52  * other device is holding the bus.
53  */
54
55 char I2CStart(void)
56 {
57   //puts ("<I2CStart>");
58
59   SDA_HIGH;
60   SCL_HIGH;
61   I2CDelay(I2CDELAY);
62   SDA_LOW;        /* Pull SDA down... */
63   I2CDelay(I2CDELAY);
64   SCL_LOW;        /* ...and then SCL -> start condition. */
65   I2CDelay(I2CDELAY);
66   return 0;
67 }
68
69
70 /*
71  * Generates a stop condition on the bus. Returns 0 on success, 1 if some
72  * other device is holding the bus.
73  */
74
75 char I2CStop(void)
76 {
77   //puts ("<I2CStop>");
78
79   SDA_LOW;
80   SCL_HIGH;        /* Let SCL go up */
81   I2CDelay(I2CDELAY);
82   SDA_HIGH;        /* ...and then SDA up -> stop condition. */
83   I2CDelay(I2CDELAY);
84   
85   return (SCL_IN && SDA_IN);  /* Both will be up, if everything is fine */
86 }
87
88
89 /*
90  * Clock out one bit.
91  * Returns 0 on success, 1 if we lose arbitration.
92  */
93
94 char BitOutI2C(char bout)
95 {
96   //puts("<BitOutI2C>");
97
98   SDA_OUT(bout);              /* Put data out on SDA */
99   I2CDelay(I2CDELAY);
100   SCL_HIGH;                    /* Let SCL go up */
101   while(!SCL_IN)            /* Wait until all other devices are ready */
102     {
103       // should do a timeout here
104     }
105   
106   if (SDA_IN != bout)       /* Arbitration lost, release bus and return */
107     {
108       SDA_HIGH;                /* Should be up anyway, but make sure */
109       i2cError = I2CERR_LOST;
110       I2CDumpError(i2cError);
111       return 1;
112     }
113   I2CDelay(I2CDELAY);
114   SCL_LOW;                    /* Pull SCL back down */
115   I2CDelay(I2CDELAY);                
116   return 0;                   /* OK */
117 }
118
119
120 /*
121  * Clock in one bit.
122  */
123
124 char BitInI2C(void)
125 {
126   char bin;
127   
128   //puts ("<BitInI2C>");
129
130   // SDA is opencollector, so:
131   SDA_HIGH;
132   
133   SCL_HIGH;                    /* Let SCL go up */
134   while(!SCL_IN)            /* Wait for other devices */
135     {
136       // should do a timeout here
137     }
138   bin = SDA_IN;             /* Read in data */
139   I2CDelay(I2CDELAY);
140   SCL_LOW;                    /* Pull SCL back up */
141   I2CDelay(I2CDELAY);
142   return bin;                 /* Return the sampled bit */
143 }
144
145
146 /*
147  * Send one byte on the bus. No start or stop conditions are generated here,
148  * but i2cError will be set according to the result.
149  * Returns 0 on success, 1 if we lose arbitration or if the slave doesn't
150  * acknowledge the byte. Check i2cError for the actual result on error.
151  */
152
153 char ByteOutI2C(char dat)
154 {
155   char bit_count;
156   
157   //puts ("<ByteOutI2C>");
158
159   bit_count = 8;
160   while(bit_count) {
161     if (dat & 0x80) {
162       if (BitOutI2C(1)) {
163         I2CDumpError(i2cError);
164         return 1;
165       }
166     } else {
167       if (BitOutI2C(0)) {
168         I2CDumpError(i2cError);
169         return 1;
170       }
171     }
172     dat <<= 1;
173     bit_count--;
174   }
175   
176   if (BitInI2C()) {
177     i2cError = I2CERR_NAK;
178     I2CDumpError(i2cError);
179     return 1;
180   }
181   return 0;
182 }
183
184
185 /*
186  * Reads one byte in from the slave. Ack must be 1 if this is the last byte
187  * to be read during this transfer, 0 otherwise (as per I2C bus specification,
188  * the receiving master must acknowledge all but the last byte during a
189  * transfer).
190  */
191
192 char I2CByteIn(char ack)
193 {
194   char bit_count, byte_in;
195   
196   //puts ("<I2CByteIn>");
197
198   bit_count = 8;
199   byte_in = 0;
200   
201   while(bit_count)
202     {
203       byte_in <<= 1;
204       if (BitInI2C()) byte_in |= 0x01;
205       bit_count--;
206     }
207   
208   BitOutI2C(ack);
209   SDA_HIGH;             /* Added 18-Jul-95 - thanks to Ray Bellis */
210  return byte_in;
211 }
212
213
214 /*
215  * Send 'count' bytes to slave 'addr'.
216  * Returns 0 on success. Stop condition is sent only when send_stop is true.
217  */
218
219 char I2CSendStop(char addr, char count, char send_stop)
220 {
221   char byteptr, byte_out;
222   
223   //puts ("<I2CSendStop>");
224
225   if (I2CStart()) return 1;
226   i2cError = 0;
227   
228   byte_out = addr & 0xfe;     /* Ensure that it's a write address */
229   count++;                    /* Include slave address to byte count */
230   byteptr = 0;
231   while(count)
232     {
233       if (ByteOutI2C(byte_out))
234         {
235           if (i2cError == I2CERR_NAK && send_stop) I2CStop();
236           return i2cError;
237         }
238       byte_out = i2cTransmitBuffer[byteptr];
239       byteptr++;
240       count--;
241     }
242   
243   if (send_stop) I2CStop();
244   return 0;
245 }
246
247
248 /*
249  * Read in 'count' bytes from slave 'addr'.
250  * Returns 0 on success.
251  */
252
253 char i2c_recv(char addr, char count)
254 {
255   char byteptr, byte_in;
256   
257   //puts ("<i2c_rec>");
258
259   if (I2CStart()) return 1;
260   i2cError = 0;
261   byteptr = 0;
262   
263   byte_in = addr | 0x01;
264   
265   if (ByteOutI2C(byte_in))
266     {
267       if (i2cError == I2CERR_NAK) I2CStop();
268       return i2cError;
269     }
270   
271   while(count)
272     {
273       count-=1;
274       if (count) {
275         byte_in = I2CByteIn(0);
276       } else {
277         byte_in = I2CByteIn(1);   /* No ACK during last byte */
278       }
279       i2cReceiveBuffer[byteptr] = byte_in;
280       byteptr++;
281     }
282   
283   I2CStop();
284   
285   return (i2cError ? 1 : 0);
286 }
287
288
289 /*
290  * Write 'tx_count' bytes to slave 'addr', then use a repeated start condition
291  * to read 'rx_count' bytes from the same slave during the same transfer.
292  * Returns 0 on success, 1 otherwise. On error, check i2cError for the actual
293  * error value.
294  */
295
296 char I2CSendReceive(char addr, char tx_count, char rx_count)
297 {
298   //puts ("<i2c_send_recv>");
299
300   if (I2CSendStop(addr, tx_count, 0))
301     {
302      /* If send fails, abort but don't send a stop condition if we lost
303          arbitration */
304       
305       if (i2cError != I2CERR_LOST) I2CStop();
306       return 1;
307     }
308   
309   SDA_HIGH; /* One of these may be low now, in which case the next */
310   SCL_HIGH; /* start condition wouldn't be detected so make */
311   I2CDelay(I2CDELAY); /*   sure that they're up and wait for one delay slot */
312   
313   if (i2c_recv((char)(addr|0x01), rx_count)) return 1;
314   return (i2cError ? 1 : 0);
315 }
316
317 /*
318  * Dump an error message.
319  */
320
321 void I2CDumpError(char error)
322 {
323 #ifdef DEBUG_I2C
324   switch(error)
325     {
326     case 0:
327       puts("I2C: OK.");
328       break;
329     case I2CERR_NAK:
330       puts("I2C: Slave didn't acknowledge");
331       break;
332     case I2CERR_LOST:
333       puts("I2C: Lost arbitration with another master");
334       break;
335     case I2CERR_TIMEOUT:
336       puts("I2C: Timeout on bus");
337       break;
338     case I2CERR_BUS:
339       puts("I2C: The bus is stuck");
340       break;
341     default:
342       puts("I2C: Unknown error");
343       break;
344     }
345 #endif
346 }
347
348 void I2CDelay(volatile long delay) {
349  while (delay--)
350    ;
351 }