1 /* This implemenation is based on an example I once grabbed from
3 Don't know who wrote it, but is has been hacked so heavily, he/she wouldn't
6 //#define DEBUG_I2C ==> DON'T DO THIS, THIS IS A LIBRARY <==
14 // we are (ab)using the CAN CTX and CRX for serial data and serial clock
15 #define SCL_HIGH (P5 |= 1)
16 #define SCL_LOW (P5 &= ~1)
17 #define SDA_HIGH (P5 |= 2)
18 #define SDA_LOW (P5 &= ~2)
20 #define SDA_OUT(b) (b ? SDA_HIGH : SDA_LOW)
21 #define SDA_IN ((P5>>1)&1)
28 #define I2CERR_OK 0 /* No error */
29 #define I2CERR_NAK 1 /* No ACK from slave */
30 #define I2CERR_LOST 2 /* Arbitration lost */
31 #define I2CERR_BUS 3 /* Bus is stuck (not used yet) */
32 #define I2CERR_TIMEOUT 4 /* Timeout on bus */
34 char i2cTransmitBuffer[I2C_BUFSIZE]; /* Global transfer buffers */
35 char i2cReceiveBuffer[I2C_BUFSIZE];
37 static char i2cError = 0; /* Last error */
41 void I2CDelay(volatile long delay) {
46 void I2CDumpError(char error);
49 * Makes sure that the bus is in a known condition. Returns 1 on success,
50 * 0 if some other device is pulling on the bus.
60 return (SCL_IN && SDA_IN);
65 * Generates a start condition on the bus. Returns 0 on success, 1 if some
66 * other device is holding the bus.
74 SDA_LOW; /* Pull SDA down... */
76 SCL_LOW; /* ...and then SCL -> start condition. */
83 * Generates a stop condition on the bus. Returns 0 on success, 1 if some
84 * other device is holding the bus.
90 SCL_HIGH; /* Let SCL go up */
92 SDA_HIGH; /* ...and then SDA up -> stop condition. */
95 return (SCL_IN && SDA_IN); /* Both will be up, if everything is fine */
101 * Returns 0 on success, 1 if we lose arbitration.
104 char BitOutI2C(unsigned char bout)
106 SDA_OUT(bout); /* Put data out on SDA */
108 SCL_HIGH; /* Let SCL go up */
109 while(!SCL_IN) /* Wait until all other devices are ready */
111 // should do a timeout here
114 if (SDA_IN != bout) /* Arbitration lost, release bus and return */
116 SDA_HIGH; /* Should be up anyway, but make sure */
117 i2cError = I2CERR_LOST;
118 I2CDumpError(i2cError);
122 SCL_LOW; /* Pull SCL back down */
136 // SDA is opencollector, so:
139 SCL_HIGH; /* Let SCL go up */
140 while(!SCL_IN) /* Wait for other devices */
142 // should do a timeout here
144 bin = SDA_IN; /* Read in data */
146 SCL_LOW; /* Pull SCL back up */
148 return bin; /* Return the sampled bit */
153 * Send one byte on the bus. No start or stop conditions are generated here,
154 * but i2cError will be set according to the result.
155 * Returns 0 on success, 1 if we lose arbitration or if the slave doesn't
156 * acknowledge the byte. Check i2cError for the actual result on error.
159 char ByteOutI2C(char dat)
167 I2CDumpError(i2cError);
172 I2CDumpError(i2cError);
181 i2cError = I2CERR_NAK;
182 I2CDumpError(i2cError);
190 * Reads one byte in from the slave. Ack must be 1 if this is the last byte
191 * to be read during this transfer, 0 otherwise (as per I2C bus specification,
192 * the receiving master must acknowledge all but the last byte during a
196 char I2CByteIn(char ack)
198 char bit_count, byte_in;
206 if (BitInI2C()) byte_in |= 0x01;
211 SDA_HIGH; /* Added 18-Jul-95 - thanks to Ray Bellis */
217 * Send 'count' bytes to slave 'addr'.
218 * Returns 0 on success. Stop condition is sent only when send_stop is true.
221 char I2CSendStop(char addr, char count, char send_stop)
223 char byteptr, byte_out;
225 if (I2CStart()) return 1;
228 byte_out = addr & 0xfe; /* Ensure that it's a write address */
229 count++; /* Include slave address to byte count */
233 if (ByteOutI2C(byte_out))
235 if (i2cError == I2CERR_NAK && send_stop) I2CStop();
238 byte_out = i2cTransmitBuffer[byteptr];
243 if (send_stop) I2CStop();
249 * Read in 'count' bytes from slave 'addr'.
250 * Returns 0 on success.
253 char i2c_recv(char addr, char count)
255 char byteptr, byte_in;
257 if (I2CStart()) return 1;
261 byte_in = addr | 0x01;
263 if (ByteOutI2C(byte_in))
265 if (i2cError == I2CERR_NAK) I2CStop();
273 byte_in = I2CByteIn(0);
275 byte_in = I2CByteIn(1); /* No ACK during last byte */
277 i2cReceiveBuffer[byteptr] = byte_in;
283 return (i2cError ? 1 : 0);
288 * Write 'tx_count' bytes to slave 'addr', then use a repeated start condition
289 * to read 'rx_count' bytes from the same slave during the same transfer.
290 * Returns 0 on success, 1 otherwise. On error, check i2cError for the actual
294 char I2CSendReceive(char addr, char tx_count, char rx_count)
296 if (I2CSendStop(addr, tx_count, 0))
298 /* If send fails, abort but don't send a stop condition if we lost
301 if (i2cError != I2CERR_LOST) I2CStop();
305 SDA_HIGH; /* One of these may be low now, in which case the next */
306 SCL_HIGH; /* start condition wouldn't be detected so make */
307 I2CDelay(I2CDELAY); /* sure that they're up and wait for one delay slot */
309 if (i2c_recv((char)(addr|0x01), rx_count)) return 1;
310 return (i2cError ? 1 : 0);
314 * Dump an error message.
317 void I2CDumpError(char error)
326 puts("I2C: Slave didn't acknowledge");
329 puts("I2C: Lost arbitration with another master");
332 puts("I2C: Timeout on bus");
335 puts("I2C: The bus is stuck");
338 puts("I2C: Unknown error");
342 error; // hush the compiler