5 #include <avr/interrupt.h>
6 #include <util/delay.h>
32 ST_ARBLOST_MATCH = 0x68,
34 ST_ARBLOST_GENMATCH = 0x78,
35 ST_SLAVE_RD_ACK = 0x80,
36 ST_SLAVE_RD_NACK = 0x88,
37 ST_SLAVE_GENRD_ACK = 0x90,
38 ST_SLAVE_GENRD_NACK = 0x98,
39 ST_SLAVE_STARTSTOP = 0xa0,
40 ST_SLAVE_SLA_WR_ACK = 0xa8,
41 ST_SLAVE_ARBLOST_WR_ACK = 0xb0,
42 ST_SLAVE_WR_ACK = 0xb8,
43 ST_SLAVE_WR_NACK = 0xc0,
44 ST_SLAVE_LAST_WR_ACK = 0xc8
56 static const char *evname[] = {
65 #define TWINT_BIT (1 << TWINT)
66 #define TWEA_BIT (1 << TWEA)
67 #define TWSTA_BIT (1 << TWSTA)
68 #define TWSTO_BIT (1 << TWSTO)
69 #define TWEN_BIT (1 << TWEN)
70 #define TWIE_BIT (1 << TWIE)
72 #define I2C_START() (TWCR = TWINT_BIT | TWSTA_BIT | TWEN_BIT | TWIE_BIT)
73 #define I2C_STOP() (TWCR = TWINT_BIT | TWSTO_BIT | TWEN_BIT | TWIE_BIT)
74 #define I2C_WRITE() (TWCR = TWINT_BIT | TWEN_BIT | TWIE_BIT)
75 #define I2C_READ_ACK() (TWCR = TWINT_BIT | TWEA_BIT | TWEN_BIT | TWIE_BIT)
76 #define I2C_READ_NACK() (TWCR = TWINT_BIT | TWEN_BIT | TWIE_BIT)
78 unsigned char i2c_addr, i2c_subaddr;
79 volatile unsigned char i2c_mode;
80 int i2c_seq, i2c_ndata;
81 unsigned char *i2c_data;
85 uint16_t evq[EVQ_SIZE];
86 volatile int evq_wr, evq_rd;
88 #define LOGNUM(x) EVLOG(EV_DEBUG, (x))
90 #define EVLOG(ev, data) \
92 if(ev != EV_DEBUG || dbgmode) { \
93 evq[evq_wr] = ((uint16_t)(ev) << 8) | (data); \
94 evq_wr = (evq_wr + 1) & (EVQ_SIZE - 1); \
95 if(evq_wr == evq_rd) { \
96 evq_rd = (evq_rd + 1) & (EVQ_SIZE - 1); \
101 /* serial input buffer */
102 static char input[64];
103 static unsigned char inp_cidx;
105 static unsigned char data[16];
107 static void (*async_func)(void);
109 static uint16_t dump_addr;
110 static int dump_count;
114 static void proc_cmd(char *input);
115 static void printstat(void);
116 static void printdump(void);
118 void i2c_write(unsigned char addr, unsigned char subaddr, unsigned char *data, int ndata);
119 void i2c_read(unsigned char addr, unsigned char subaddr, unsigned char *buf, int size);
121 void i2c_async(void (*donecb)(void));
122 void i2c_check_async(void);
124 void i2c_release(void);
125 void i2c_snoop(int onoff);
134 /* tri-state everything and disable pullups */
135 DDRB = 1; /* B0: activity LED */
136 DDRC = 0; /* I2C pins as inputs */
142 TWBR = 10; /* 10 with 1x prescaler should make it about 100khz */
143 TWSR = 0; /* prescaler 1x */
146 TWCR = 0; /* I2C disabled by default */
149 i2c_snoop(0); /* disable snooping by default */
154 printf("Starting i2c hack\n");
173 if(c == '\r' || c == '\n') {
178 } else if(inp_cidx < sizeof input - 1) {
179 input[inp_cidx++] = c;
183 /* read from queue and send over the serial port */
186 if(evq_wr != evq_rd) {
188 evq_rd = (evq_rd + 1) & (EVQ_SIZE - 1);
193 unsigned char ev = val >> 8;
195 printf("%02x: %02x\n", ev, val & 0xff);
197 printf("%s: %02x\n", evname[ev], val & 0xff);
204 static void proc_cmd(char *input)
208 if(strcmp(input, "dbg") == 0) {
212 } else if(strcmp(input, "nodbg") == 0) {
213 printf("OK nodbg\n");
216 } else if(strcmp(input, "start") == 0) {
217 printf("OK snooping\n");
220 } else if(strcmp(input, "stop") == 0) {
222 printf("OK stopped snooping\n");
224 } else if(strcmp(input, "av") == 0) {
227 /* AV switch (22): 0 0 SVO CMB1 CMB0 INA INB 0 */
229 i2c_write(0x8a, 0x22, data, 1);
232 } else if(strcmp(input, "rgb") == 0) {
235 /* Control 0 (2a): 0 IE2 RBL AKB CL3 CL2 CL1 CL0
236 * Control 1 (2b): 0 0 0 0 0 0 YUV HBL
240 i2c_write(0x8a, 0x2a, data, 1);
242 i2c_write(0x8a, 0x2b, data + 1, 1);
244 } else if(memcmp(input, "vol ", 4) == 0) {
245 int vol = atoi(input + 4);
246 if(vol < 1 || vol > 63) {
247 printf("ERR vol (%s)\n", input + 4);
250 i2c_write(0x8a, 0x1f, data, 1);
251 printf("OK volume: %d\n", vol);
254 } else if(memcmp(input, "sat", 3) == 0) {
256 data[0] = atoi(input + 3);
257 if(data[0] <= 0 || data[0] > 0x3f) {
260 i2c_write(0x8a, 0x1c, data, 1);
261 i2c_async(i2c_hold); /* hold I2C when done */
263 } else if(strcmp(input, "rel") == 0) {
264 printf("OK release\n");
267 } else if(strcmp(input, "status") == 0) {
268 i2c_read(0x8a, 0, data, 3);
269 i2c_async(printstat);
271 } else if(memcmp(input, "rd ", 3) == 0) {
272 dump_addr = strtol(input + 3, &endp, 16);
274 if(endp > input + 3 && dump_addr >= 0 && dump_addr < 2048) {
276 i2c_read(0xa0 | ((dump_addr >> 7) & 0xe), dump_addr & 0xff, data, 1);
277 i2c_async(printdump);
279 printf("ERR address: %s\n", input + 3);
282 } else if(memcmp(input, "dump ", 5) == 0) {
283 dump_addr = strtol(input + 5, &endp, 16);
285 if(endp > input + 5 && dump_addr >= 0 && dump_addr < 2048) {
288 i2c_read(0xa0 | ((dump_addr >> 7) & 0xe), dump_addr & 0xff, data, 16);
289 i2c_async(printdump);
291 printf("ERR address: %s\n", input + 5);
294 } else if(strcmp(input, "abort") == 0) {
295 if(i2c_mode != I2C_IDLE) {
300 printf("ERR i2c is idle\n");
304 printf("ERR command (%s)\n", input);
308 static void printstat(void)
310 printf("OK status: %02x %02x %02x\n", (unsigned int)data[0],
311 (unsigned int)data[1], (unsigned int)data[2]);
314 static void printdump(void)
317 while(dump_count > 0) {
318 printf("OK %03x:", dump_addr);
319 for(i=0; i<16; i++) {
320 if(i == 8) putchar(' ');
322 if(--dump_count >= 0) {
323 printf(" %02x", data[i]);
333 void i2c_write(unsigned char addr, unsigned char subaddr, unsigned char *data, int ndata)
335 i2c_addr = addr & 0xfe;
336 i2c_subaddr = subaddr;
337 i2c_mode = I2C_MASTER_WRITE;
344 void i2c_read(unsigned char addr, unsigned char subaddr, unsigned char *buf, int size)
346 i2c_addr = addr & 0xfe;
347 i2c_subaddr = subaddr;
348 i2c_mode = I2C_MASTER_READ;
355 void i2c_handle_send(void)
357 unsigned char state = TWSR & 0xf8;
359 //printf("DBG i2c state (%x)\n", (unsigned int)state);
363 case ST_REP_START: /* 0x10 */
364 /* repeated start, same as start, but also increment i2c_seq */
366 case ST_START: /* 0x8 */
367 /* start initiated, write the slave address */
368 //printf("DBG i2c SLA: %x\n", (unsigned int)i2c_addr);
373 case ST_SLA_W_ACK: /* 0x18 */
374 /* slave addr sent and ACKed, send subaddr or data */
376 /* this is the first packet, send subaddr */
385 /* done sending, send stop */
392 case ST_SLA_W_NACK: /* 0x20 */
393 /* slave addr sent but not ACKed, abort */
396 printf("i2c: NACK after SLA+W\n");
399 case ST_WR_ACK: /* 0x28 */
400 /* data (or subaddr) sent and ACKed, send more data (or restart) if available */
403 /* subaddr was sent, send repeated start */
407 /* data was sent, send more data or stop */
418 case ST_WR_NACK: /* 0x30 */
419 /* data (or subaddr) sent but not ACKed */
421 /* NACK after subaddr, abort */
422 printf("i2c: NACK after subaddr\n");
424 /* NACK after data */
426 printf("i2c: NACK with %d pending\n", i2c_ndata);
433 case ST_ARBLOST: /* 0x38 */
434 /* arbitration lost */
435 printf("i2c: arb lost\n");
439 case ST_INVALID: /* 0 */
440 printf("i2c: invalid start/stop\n");
446 printf("i2c: unexpected state (W): 0x%x\n", state);
452 void i2c_handle_recv(void)
454 unsigned char state = TWSR & 0xf8;
459 case ST_START: /* 0x8 */
460 TWDR = i2c_addr; /* start a *write* (we need to send the subaddress before reading) */
464 case ST_REP_START: /* 0x10 */
465 /* repeated start, now we can issue the actual read */
470 case ST_SLA_W_ACK: /* 0x18 */
471 /* SLA+W means we just started the write part, need to send the subaddress */
477 /* slave addr sent but not ACKed, abort */
480 printf("i2c: NACK after SLA+W (R)\n");
483 case ST_WR_ACK: /* 0x28 */
484 /* the subaddress write was ACKed, rep-start to issue the read */
489 /* the subaddress write was not ACKed, abort */
492 printf("i2c: NACK after subaddr (R)\n");
495 case ST_SLA_R_ACK: /* 0x40 */
496 /* SLA+R was ACKed send ACK to start receiving */
500 case ST_RD_ACK: /* 0x50 */
501 /* ... or last read was ACKed, again read next and ACK for more */
503 if(--i2c_ndata > 0) {
510 case ST_SLA_R_NACK: /* 0x48 */
511 /* SLA+R was sent but ACK was not received, abort */
514 printf("i2c: NACK after SLA+R\n");
517 case ST_RD_NACK: /* 0x58 */
518 /* read without ACK, we get this after we send a NACK, or this is the last byte (?) */
527 case ST_ARBLOST: /* 0x38 */
528 /* arbitration lost */
529 printf("i2c: arb lost\n");
533 case ST_INVALID: /* 0 */
534 printf("i2c: invalid start/stop\n");
540 printf("i2c: unexpected state (R): 0x%x\n", state);
549 case I2C_MASTER_WRITE:
553 case I2C_MASTER_READ:
564 void i2c_async(void (*donecb)(void))
569 void i2c_check_async(void)
571 if(async_func && i2c_mode == I2C_IDLE) {
579 TWCR = 0; /* make sure the AVR i2c hardware is disabled */
580 DDRC = 0x20; /* ... and drive SCL pin low */
584 void i2c_release(void)
591 #define PC_SCL_BIT (1 << PC_SCL)
592 #define PC_SDA_BIT (1 << PC_SDA)
594 static unsigned char pcprev, state;
595 static unsigned char value;
598 /* use PCINT12,13 to snoop i2c traffic */
599 void i2c_snoop(int onoff)
605 /* to stop snooping just disable the interrupt */
608 PCICR &= ~(1 << PCIE1);
614 TWCR = 0; /* make sure the i2c hw is disabled */
620 PCICR |= 1 << PCIE1; /* enable the pin-change interrupt */
621 PCMSK1 = (1 << PCINT12) | (1 << PCINT13);
639 unsigned char pinc, delta;
642 delta = pinc ^ pcprev;
645 if(delta & PC_SDA_BIT) {
646 if(pinc & PC_SCL_BIT) {
647 /* clock is high, so this is either a start or a stop */
648 if(pinc & PC_SDA_BIT) {
663 if(evq_wr != evq_rd) {
665 evq_rd = (evq_rd + 1) & (EVQ_SIZE - 1);
668 printf("%s\n", evname[ev]);
670 printf("%s: %02x\n", evname[ev], val & 0xff);
676 if(delta & PC_SCL_BIT) {
677 if(pinc & PC_SCL_BIT) {
678 /* clock is going high, shift SDA */
679 value = (value << 1) | ((pinc >> PC_SDA) & 1);
683 state = (value & 1) ? EV_SLA_R : EV_SLA_W;
684 EVLOG(state, value & 0xfe);
691 //EVLOG(state, value);