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