]> cloudbase.mooo.com Git - z180-stamp.git/blame - avr/i2c.c
working connect command, new sleep command
[z180-stamp.git] / avr / i2c.c
CommitLineData
61b0cfe9 1
04a63b0d
L
2/*
3 * I2C (TWI) master interface.
61b0cfe9
L
4 */
5
6#include "common.h"
7#include <avr/interrupt.h>
61b0cfe9
L
8#include <string.h>
9
10#include "config.h"
11#include "timer.h"
12#include "debug.h"
13#include "i2c.h"
14
f14850db
L
15#define DEBUG_I2C 0
16
17#define debug_i2c(fmt, args...) \
18 debug_cond(DEBUG_I2C, fmt, ##args)
19
61b0cfe9
L
20
21/* General TWI Master status codes */
22#define TWI_START 0x08 /* START has been transmitted */
23#define TWI_REP_START 0x10 /* Repeated START has been transmitted */
24#define TWI_ARB_LOST 0x38 /* Arbitration lost */
25
26/* TWI Master Transmitter status codes */
27#define TWI_MTX_ADR_ACK 0x18 /* SLA+W has been transmitted and ACK received */
28#define TWI_MTX_ADR_NACK 0x20 /* SLA+W has been transmitted and NACK received */
29#define TWI_MTX_DATA_ACK 0x28 /* Data byte has been transmitted and ACK received */
30#define TWI_MTX_DATA_NACK 0x30 /* Data byte has been transmitted and NACK received */
31
32/* TWI Master Receiver status codes */
33#define TWI_MRX_ADR_ACK 0x40 /* SLA+R has been transmitted and ACK received */
34#define TWI_MRX_ADR_NACK 0x48 /* SLA+R has been transmitted and NACK received */
35#define TWI_MRX_DATA_ACK 0x50 /* Data byte has been received and ACK transmitted */
36#define TWI_MRX_DATA_NACK 0x58 /* Data byte has been received and NACK transmitted */
37
38/* TWI Miscellaneous status codes */
39#define TWI_NO_STATE 0xF8 /* No relevant state information available */
40#define TWI_BUS_ERROR 0x00 /* Bus error due to an illegal START or STOP condition */
41
42
43/*
44 * TWINT: TWI Interrupt Flag
45 * TWEA: TWI Enable Acknowledge Bit
46 * TWSTA: TWI START Condition Bit
47 * TWSTO: TWI STOP Condition Bit
48 * TWEN: TWI Enable Bit
49 * TWIE: TWI Interrupt Enable
04a63b0d 50 *
61b0cfe9
L
51 * (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
52 * (1<<TWEN)|(1<<TWIE)|(1<<TWINT)| (1<<TWEA)
53 * (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
04a63b0d 54 *
61b0cfe9
L
55 * default:
56 * (1<<TWEN)| (1<<TWINT)| (1<<TWSTO)
04a63b0d 57 *
61b0cfe9
L
58 * Init:
59 * (1<<TWEN)
04a63b0d 60 *
61b0cfe9
L
61 * start read/write:
62 * (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
63 * (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
64 * (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
65 * (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
04a63b0d 66 *
61b0cfe9
L
67 * wait ready:
68 * (1<<TWIE)|(1<<TWSTO)
69 *
70 *
71 *
04a63b0d 72 *i2c_result
61b0cfe9
L
73 *
74 * 0b10000000 Busy (Transmission in progress)
75 * 0b01000000 Timeout
04a63b0d 76 * 0b00001000 Start transmitted
61b0cfe9
L
77 * 0b00000100 Slave acknowledged address
78 * 0b00000010 Data byte(s) transmitted/received
79 * 0b00000001 Transmission completed
80 *
81 *
82 *----------------------------------------------------------------------
83 */
84
85#define TWI_C_DISABLE 0x00
86#define TWI_C_ENABLE (1<<TWEN)
87
04a63b0d
L
88
89
61b0cfe9
L
90 typedef struct i2c_msg_s {
91 uint8_t stat;
92 #define XMIT_DONE (1<<0)
93 #define DATA_ACK (1<<1)
94 #define ADDR_ACK (1<<2)
95 #define START (1<<3)
96 #define TIMEOUT (1<<6)
97 #define BUSY (1<<7)
98 uint8_t idx;
99 uint8_t len;
100 uint8_t buf[CONFIG_SYS_I2C_BUFSIZE];
101} i2c_msg_t;
102
35e9ec0c 103static volatile i2c_msg_t xmit;
61b0cfe9
L
104
105ISR(TWI_vect)
106{
35e9ec0c 107 uint8_t tmp_stat;
61b0cfe9 108 uint8_t tmp_idx;
35e9ec0c
L
109 uint8_t next_twcr;
110 uint8_t n;
111
112 tmp_idx = xmit.idx;
113 tmp_stat = xmit.stat;
61b0cfe9
L
114
115 uint8_t twsr = TWSR;
04a63b0d 116
61b0cfe9
L
117 switch (twsr & 0xf8) {
118
119 case TWI_START:
120 case TWI_REP_START:
35e9ec0c
L
121 tmp_stat = BUSY | START;
122 tmp_idx = 0; /* reset xmit_buf index */
61b0cfe9 123
61b0cfe9
L
124 if (tmp_idx < xmit.len) { /* all bytes transmited? */
125 TWDR = xmit.buf[tmp_idx];
35e9ec0c 126 ++tmp_idx;
61b0cfe9
L
127 next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT);
128 } else {
35e9ec0c
L
129 tmp_stat |= XMIT_DONE;
130 tmp_stat &= ~BUSY;
61b0cfe9
L
131 next_twcr = (1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO);
132 }
133 break;
134
135 case TWI_MTX_ADR_ACK:
61b0cfe9 136 case TWI_MTX_DATA_ACK:
85787726
L
137 if ((twsr&0xf8) == TWI_MTX_ADR_ACK)
138 tmp_stat |= ADDR_ACK;
139 else
140 tmp_stat |= DATA_ACK;
61b0cfe9 141
61b0cfe9
L
142 if (tmp_idx < xmit.len) { /* all bytes transmited? */
143 TWDR = xmit.buf[tmp_idx];
35e9ec0c 144 ++tmp_idx;
61b0cfe9
L
145 next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT);
146 } else {
35e9ec0c
L
147 tmp_stat |= XMIT_DONE;
148 tmp_stat &= ~BUSY;
61b0cfe9
L
149 next_twcr = (1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO);
150 }
61b0cfe9
L
151 break;
152
153 case TWI_MTX_DATA_NACK:
35e9ec0c
L
154 tmp_stat |= XMIT_DONE;
155 tmp_stat &= ~BUSY;
61b0cfe9
L
156 next_twcr = (1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO);
157 break;
158
61b0cfe9 159 case TWI_MRX_DATA_ACK:
61b0cfe9 160 xmit.buf[tmp_idx] = TWDR;
35e9ec0c 161 ++tmp_idx;
85787726
L
162 /* fall thru */
163 case TWI_MRX_ADR_ACK:
164 if ((twsr&0xf8) == TWI_MRX_ADR_ACK)
165 tmp_stat |= ADDR_ACK;
166 else
167 tmp_stat |= DATA_ACK;
168
35e9ec0c
L
169 n = xmit.len-1;
170 if (tmp_idx < n) {
61b0cfe9
L
171 next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA);
172 } else {
61b0cfe9
L
173 next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT);
174 }
175 break;
176
177 case TWI_MRX_DATA_NACK:
35e9ec0c 178 tmp_stat |= ADDR_ACK | DATA_ACK;
61b0cfe9 179
61b0cfe9 180 xmit.buf[tmp_idx] = TWDR;
35e9ec0c 181 ++tmp_idx;
61b0cfe9 182 /* fall thru */
61b0cfe9 183 default:
35e9ec0c 184 tmp_stat &= ~BUSY;
61b0cfe9
L
185 next_twcr = (1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO);
186 break;
187 }
188
35e9ec0c
L
189 xmit.stat = tmp_stat;
190 xmit.idx = tmp_idx;
191
f14850db 192 debug_i2c("|%02x", twsr);
61b0cfe9
L
193 TWCR = next_twcr;
194}
195
196
197/*------------------------------------------------------------------*/
198
199static uint8_t twps;
200static uint8_t twbr;
201
202
203static void _init(void)
204{
205 xmit.stat = 0;
61b0cfe9
L
206
207 /* Disable TWI, disable TWI interrupt. */
208 /* (Reset TWI hardware state machine.) */
209 TWCR = TWI_C_DISABLE;
210 _delay_us(5);
f14850db 211#if DEBUG_I2C
35e9ec0c
L
212 memset((void *) xmit.buf, 0xdf, sizeof(xmit.buf));
213#endif
61b0cfe9 214
61b0cfe9 215 TWDR = 0xff;
35e9ec0c
L
216 TWBR = twbr;
217 TWSR = twps & 0x03;
218 TWCR = TWI_C_ENABLE;
61b0cfe9
L
219}
220
221void i2c_init(uint32_t speed)
222{
223 twps = 0;
35e9ec0c 224 uint32_t tmp_twbr = F_CPU /2 / speed - 8;
04a63b0d 225
35e9ec0c
L
226 while (tmp_twbr > 255) {
227 tmp_twbr >>= 4;
61b0cfe9
L
228 twps += 1;
229 }
35e9ec0c
L
230 debug_cond((twps > 3), "*** TWCLK too low: %lu Hz\n", speed);
231
232 twbr = (uint8_t) tmp_twbr;
04a63b0d
L
233
234 PRR0 &= ~_BV(PRTWI);
61b0cfe9
L
235 _init();
236}
237
238
239int_fast8_t i2c_waitready(void)
240{
241 uint32_t timer = get_timer(0);
242 uint8_t timeout = 0;
04a63b0d 243
61b0cfe9
L
244 do {
245 if (get_timer(timer) >= 30) {
246 timeout = TIMEOUT;
247 _init();
248 }
249 } while ((TWCR & ((1<<TWIE)|(1<<TWSTO))) != 0 && !timeout);
250
251 xmit.stat |= timeout;
252
f14850db 253#if DEBUG_I2C
61b0cfe9
L
254 dump_ram((uint8_t *) &xmit, 4, "=== i2c_wait ready: (done)");
255 _delay_ms(30);
04a63b0d 256#endif
61b0cfe9
L
257 return xmit.stat;
258}
259
f14850db 260static
61b0cfe9
L
261int i2c_send(uint8_t chip, uint16_t addr, uint8_t alen, uint8_t *buffer, int8_t len)
262{
263 uint8_t i, n;
264 uint8_t rc;
265
266 rc = i2c_waitready();
267 if ((rc & (BUSY | TIMEOUT)) != 0)
268 return rc;
269
270 xmit.stat = BUSY;
271 xmit.buf[0] = chip<<1;
272 for (i = 1; i < alen+1; i++) {
273 xmit.buf[i] = (uint8_t) addr;
274 addr >>= 8;
275 }
276 for (n = len + i; i < n; i++)
277 xmit.buf[i] = *buffer++;
278 xmit.len = i;
04a63b0d 279
f14850db 280#if DEBUG_I2C
61b0cfe9
L
281 dump_ram((uint8_t *) &xmit, 0x20, "=== i2c_send");
282 _delay_ms(30);
04a63b0d 283#endif
61b0cfe9
L
284 /* Enable TWI, TWI int and initiate start condition */
285 TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA);
286
287 rc = xmit.stat;
288
289 return rc;
290}
291
f14850db 292static
61b0cfe9
L
293int i2c_recv(uint8_t chip, uint8_t *buffer, int8_t len)
294{
295 uint8_t rc;
296
297 rc = i2c_waitready();
298 if ((rc & (BUSY | TIMEOUT)) != 0)
299 return rc;
300
301 xmit.stat = BUSY;
302 xmit.len = len + 1;
303 xmit.buf[0] = (chip<<1) | 1;
304
f14850db 305#if DEBUG_I2C
61b0cfe9
L
306 dump_ram((uint8_t *) &xmit, 0x20, "=== i2c_recv: before start");
307 _delay_ms(30);
308#endif
309 /* Enable TWI, TWI int and initiate start condition */
310 TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA);
311 rc = i2c_waitready();
312
f14850db 313#if DEBUG_I2C
61b0cfe9
L
314 dump_ram((uint8_t *) &xmit, 0x20, "=== i2c_recv: after completion");
315 _delay_ms(30);
316#endif
317 if (rc & DATA_ACK) {
318 /* at least 1 byte received */
319 for (uint8_t i=1, n=xmit.idx; i < n; i++)
320 *buffer++ = xmit.buf[i];
321 }
322
323 return rc;
324}
325
326/*
327 * Read/Write interface:
328 * chip: I2C chip address, range 0..127
329 * addr: Memory (register) address within the chip
330 * alen: Number of bytes to use for addr (typically 1, 2 for larger
331 * memories, 0 for register type devices with only one
332 * register)
333 * buffer: Where to read/write the data
334 * len: How many bytes to read/write
335 *
336 * Returns: 0 on success, not 0 on failure
337 */
338
339int i2c_write(uint8_t chip, unsigned int addr, uint_fast8_t alen,
340 uint8_t *buffer, uint_fast8_t len)
341{
342 int rc;
04a63b0d 343
61b0cfe9
L
344 if ((alen > 2) || (1 + alen + len > CONFIG_SYS_I2C_BUFSIZE)) {
345 debug("** i2c_write: buffer overflow, alen: %u, len: %u\n",
346 alen, len);
347 return -1;
348 }
04a63b0d 349
61b0cfe9
L
350 i2c_send(chip, addr, alen, buffer, len);
351 rc = i2c_waitready();
61b0cfe9
L
352
353 return (rc & XMIT_DONE) != 0;
354}
355
356int i2c_read(uint8_t chip, unsigned int addr, uint_fast8_t alen,
357 uint8_t *buffer, uint_fast8_t len)
358{
359 int rc;
360
361 if ((alen > 2) || (1 + len > CONFIG_SYS_I2C_BUFSIZE)) {
362 debug("** i2c_read: parameter error: alen: %u, len: %u\n",
363 alen, len);
364 return -1;
365 }
04a63b0d 366
61b0cfe9
L
367 if (alen != 0) {
368 i2c_send(chip, addr, alen, NULL, 0);
04a63b0d 369 }
61b0cfe9 370 rc = i2c_recv(chip, buffer, len);
61b0cfe9
L
371
372 return !((rc & (XMIT_DONE|DATA_ACK)) == (XMIT_DONE|DATA_ACK));
373}
374
375
376