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