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