Commit 3bb82a30b8eaa3a6abc868b7ad5c1dbcd6ae7d88
authorMichel Pollet <buserror@gmail.com>
Mon, 12 Aug 2013 10:32:55 +0000 (11:32 +0100)
committerMichel Pollet <buserror@gmail.com>
Thu, 5 Sep 2013 12:58:31 +0000 (13:58 +0100)
This is not working fully right now.

Also changed the MOSI/MISO names for the IRQ, as they make no sense when
using the master/slave TWI.

Signed-off-by: Michel Pollet <buserror@gmail.com>
3 files changed:
examples/parts/i2c_eeprom.c
simavr/sim/avr_twi.c
simavr/sim/avr_twi.h

index ca70dfd788132b39103f3e82f01e4bbd21fdc065..7b119d456b331a470dd1fe0817d5f26404a93136 100644 (file)
@@ -63,7 +63,7 @@ i2c_eeprom_in_hook(
                if ((p->addr_base & p->addr_mask) == (v.u.twi.addr & p->addr_mask)) {
                        // it's us !
                        p->selected = v.u.twi.addr;
-                       avr_raise_irq(p->irq + TWI_IRQ_MISO,
+                       avr_raise_irq(p->irq + TWI_IRQ_INPUT,
                                        avr_twi_irq_msg(TWI_COND_ACK, p->selected, 1));
                }
        }
@@ -79,7 +79,7 @@ i2c_eeprom_in_hook(
                 */
                if (v.u.twi.msg & TWI_COND_WRITE) {
                        // address size is how many bytes we use for address register
-                       avr_raise_irq(p->irq + TWI_IRQ_MISO,
+                       avr_raise_irq(p->irq + TWI_IRQ_INPUT,
                                        avr_twi_irq_msg(TWI_COND_ACK, p->selected, 1));
                        int addr_size = p->size > 256 ? 2 : 1;
                        if (p->index < addr_size) {
@@ -105,7 +105,7 @@ i2c_eeprom_in_hook(
                        if (p->verbose)
                                printf("eeprom READ data 0x%04x: %02x\n", p->reg_addr, p->ee[p->reg_addr]);
                        uint8_t data = p->ee[p->reg_addr++];
-                       avr_raise_irq(p->irq + TWI_IRQ_MISO,
+                       avr_raise_irq(p->irq + TWI_IRQ_INPUT,
                                        avr_twi_irq_msg(TWI_COND_READ, p->selected, data));
                        p->reg_addr &= (p->size -1);
                        p->index++;
@@ -114,8 +114,8 @@ i2c_eeprom_in_hook(
 }
 
 static const char * _ee_irq_names[2] = {
-               [TWI_IRQ_MISO] = "8>eeprom.out",
-               [TWI_IRQ_MOSI] = "32<eeprom.in",
+               [TWI_IRQ_INPUT] = "8>eeprom.out",
+               [TWI_IRQ_OUTPUT] = "32<eeprom.in",
 };
 
 void
@@ -130,7 +130,7 @@ i2c_eeprom_init(
        memset(p, 0, sizeof(*p));
        memset(p->ee, 0xff, sizeof(p->ee));
        p->irq = avr_alloc_irq(&avr->irq_pool, 0, 2, _ee_irq_names);
-       avr_irq_register_notify(p->irq + TWI_IRQ_MOSI, i2c_eeprom_in_hook, p);
+       avr_irq_register_notify(p->irq + TWI_IRQ_OUTPUT, i2c_eeprom_in_hook, p);
 
        p->size = size > sizeof(p->ee) ? sizeof(p->ee) : size;
        if (data)
@@ -145,9 +145,9 @@ i2c_eeprom_attach(
 {
        // "connect" the IRQs of the eeprom to the TWI/i2c master of the AVR
        avr_connect_irq(
-               p->irq + TWI_IRQ_MISO,
-               avr_io_getirq(avr, i2c_irq_base, TWI_IRQ_MISO));
+               p->irq + TWI_IRQ_INPUT,
+               avr_io_getirq(avr, i2c_irq_base, TWI_IRQ_INPUT));
        avr_connect_irq(
-               avr_io_getirq(avr, i2c_irq_base, TWI_IRQ_MOSI),
-               p->irq + TWI_IRQ_MOSI );
+               avr_io_getirq(avr, i2c_irq_base, TWI_IRQ_OUTPUT),
+               p->irq + TWI_IRQ_OUTPUT );
 }
index 1b4b8ea7406f0f8f23ae0f5d14e3274941139537..de086a7d3f2b3f0a4388fa8b25075f1ef5346b05 100644 (file)
@@ -69,7 +69,7 @@
 #define TWI_NO_STATE               0xF8  // No relevant state information available; TWINT = �0�
 #define TWI_BUS_ERROR              0x00  // Bus error due to an illegal START or STOP condition
 
-#define AVR_TWI_DEBUG 0
+#define AVR_TWI_DEBUG 1
 
 static inline void
 _avr_twi_status_set(
@@ -79,7 +79,7 @@ _avr_twi_status_set(
 {
        avr_regbit_setto_raw(p->io.avr, p->twsr, v);
 #if AVR_TWI_DEBUG
-       AVR_TRACE(avr, "%s %02x\n", __func__, v);
+       AVR_TRACE(p->io.avr, "%s %02x\n", __func__, v);
 #endif
        avr_raise_irq(p->io.irq + TWI_IRQ_STATUS, v);
        if (interrupt)
@@ -161,7 +161,8 @@ avr_twi_write(
                }
                AVR_TRACE(avr, "TWEN: %d\n", twen);
                if (avr->data[p->r_twar]) {
-                       AVR_TRACE(avr, "TWEN Slave: %02x & %02x\n", avr->data[p->r_twar], avr->data[p->r_twamr]);
+                       AVR_TRACE(avr, "TWEN Slave: %02x&%02x\n", avr->data[p->r_twar] >> 1, avr->data[p->r_twamr] >> 1);
+                       p->state |= TWI_COND_SLAVE;
                }
        }
        if (!twen)
@@ -179,7 +180,7 @@ avr_twi_write(
 #endif
                if (p->state) { // doing stuff
                        if (p->state & TWI_COND_START) {
-                               avr_raise_irq(p->io.irq + TWI_IRQ_MOSI,
+                               avr_raise_irq(p->io.irq + TWI_IRQ_OUTPUT,
                                                avr_twi_irq_msg(TWI_COND_STOP, p->peer_addr, 1));
                        }
                }
@@ -198,12 +199,53 @@ avr_twi_write(
                p->state = TWI_COND_START;
        }
 
-       if (cleared &&
+       int data = cleared &&
                        !avr_regbit_get(avr, p->twsta) &&
-                       !avr_regbit_get(avr, p->twsto)) {
+                       !avr_regbit_get(avr, p->twsto);
+       
+       if (!data)
+               return;
+
+       int do_read = p->peer_addr & 1;
+       int do_ack = avr_regbit_get(avr, p->twea) != 0;
+       
+       if (p->state & TWI_COND_SLAVE) {
+               // writing or reading a byte
+               if (p->state & TWI_COND_ADDR) {
+#if AVR_TWI_DEBUG
+                       if (do_read)
+                               AVR_TRACE(avr, "I2C slave READ byte\n");
+                       else
+                               AVR_TRACE(avr, "I2C slave WRITE byte\n");
+#endif
+                       if (do_read) {
+                               if (p->state & TWI_COND_WRITE)  {
+                                       avr_raise_irq(p->io.irq + TWI_IRQ_OUTPUT,
+                                               avr_twi_irq_msg(TWI_COND_READ | TWI_COND_ACK, p->peer_addr, avr->data[p->r_twdr]));
+                               }
+#if AVR_TWI_DEBUG
+                               else
+                                       AVR_TRACE(avr, "I2C latch is not ready, do nothing\n");
+#endif
+                       } else {
+                               avr_raise_irq(p->io.irq + TWI_IRQ_OUTPUT,
+                                       avr_twi_irq_msg(TWI_COND_ACK, p->peer_addr, 0));
+                       }
+                       avr_raise_irq(p->io.irq + TWI_IRQ_OUTPUT,
+                                       avr_twi_irq_msg(TWI_COND_ADDR + (do_ack ? TWI_COND_ACK : 0), p->peer_addr, avr->data[p->r_twdr]));
+               } else {        // address, acknowledge it
+                       p->state |= TWI_COND_ADDR;
+                       avr_raise_irq(p->io.irq + TWI_IRQ_OUTPUT,
+                                       avr_twi_irq_msg(
+                                               TWI_COND_ADDR | 
+                                                       (do_ack ? TWI_COND_ACK : 0) |
+                                                       (p->state & TWI_COND_WRITE ? TWI_COND_READ : 0), 
+                                               p->peer_addr, avr->data[p->r_twdr]));
+               }
+       } else {
+       
                // writing or reading a byte
                if (p->state & TWI_COND_ADDR) {
-                       int do_read = p->peer_addr & 1;
 #if AVR_TWI_DEBUG
                        if (do_read)
                                AVR_TRACE(avr, "I2C READ byte from %02x\n", p->peer_addr);
@@ -213,18 +255,19 @@ avr_twi_write(
                        // a normal data byte
                        uint8_t msgv = do_read ? TWI_COND_READ : TWI_COND_WRITE;
 
-                       if (avr_regbit_get(avr, p->twea))
+                       if (do_ack)
                                msgv |= TWI_COND_ACK;
 
                        p->state &= ~TWI_COND_ACK;      // clear ACK bit
 
+                       AVR_TRACE(avr, "state %02x want %02x\n", p->state, msgv);
                        // if the latch is ready... as set by writing/reading the TWDR
-                       if ((p->state & msgv)) {
+                       if (p->state & msgv) {
 
                                // we send an IRQ and we /expect/ a slave to reply
                                // immediately via an IRQ to set the COND_ACK bit
                                // otherwise it's assumed it's been nacked...
-                               avr_raise_irq(p->io.irq + TWI_IRQ_MOSI,
+                               avr_raise_irq(p->io.irq + TWI_IRQ_OUTPUT,
                                                avr_twi_irq_msg(msgv, p->peer_addr, avr->data[p->r_twdr]));
 
                                if (do_read) { // read ?
@@ -253,7 +296,7 @@ avr_twi_write(
                        // we send an IRQ and we /expect/ a slave to reply
                        // immediately via an IRQ tp set the COND_ACK bit
                        // otherwise it's assumed it's been nacked...
-                       avr_raise_irq(p->io.irq + TWI_IRQ_MOSI,
+                       avr_raise_irq(p->io.irq + TWI_IRQ_OUTPUT,
                                        avr_twi_irq_msg(TWI_COND_START, p->peer_addr, 0));
 
                        if (p->peer_addr & 1) { // read ?
@@ -342,6 +385,8 @@ avr_twi_irq_input(
        avr_twi_msg_irq_t msg;
        msg.u.v = value;
 
+       AVR_TRACE(avr, "%s %08x\n", __func__, value);
+
        // receiving an attempt at waking a slave
        if (msg.u.twi.msg & TWI_COND_START) {
                p->state = 0;
@@ -353,7 +398,10 @@ avr_twi_irq_input(
                        p->peer_addr = msg.u.twi.addr & mask;
                        if (p->peer_addr == ((avr->data[p->r_twar] >> 1) & mask)) {
                                // address match, we're talking
-                               p->state = TWI_COND_ADDR | TWI_COND_SLAVE;
+                               p->state = TWI_COND_SLAVE;
+                               // INVERSE logic here
+                               if (!(msg.u.twi.msg & TWI_COND_WRITE))
+                                       p->peer_addr |= 1;
                                _avr_twi_delay_state(p, 9, 
                                        msg.u.twi.msg & TWI_COND_WRITE ?
                                                TWI_SRX_ADR_ACK : TWI_STX_ADR_ACK );
@@ -362,6 +410,7 @@ avr_twi_irq_input(
                        // "general call" address
                        AVR_TRACE(avr, "I2C slave start without address?\n");
                        if (avr->data[p->r_twar] & 1) {
+                               // TODO
                        }
                }
        }
@@ -380,25 +429,32 @@ avr_twi_irq_input(
                else
                        p->state &= ~TWI_COND_ACK;
        }
-       // receive a data byte from a slave
-       if (msg.u.twi.msg & TWI_COND_READ) {
+       if (p->state & TWI_COND_SLAVE) {
+               if (msg.u.twi.msg & TWI_COND_WRITE) {
+                       avr->data[p->r_twdr] = msg.u.twi.data;
+                       _avr_twi_delay_state(p, 9, TWI_SRX_ADR_DATA_ACK );
+               }
+       } else {
+               // receive a data byte from a slave
+               if (msg.u.twi.msg & TWI_COND_READ) {
 #if AVR_TWI_DEBUG
-               AVR_TRACE(avr, "I2C received %02x\n", msg.u.twi.data);
+                       AVR_TRACE(avr, "I2C received %02x\n", msg.u.twi.data);
 #endif
-               avr->data[p->r_twdr] = msg.u.twi.data;
+                       avr->data[p->r_twdr] = msg.u.twi.data;
+               }
        }
 }
 
 void avr_twi_reset(struct avr_io_t *io)
 {
        avr_twi_t * p = (avr_twi_t *)io;
-       avr_irq_register_notify(p->io.irq + TWI_IRQ_MISO, avr_twi_irq_input, p);
+       avr_irq_register_notify(p->io.irq + TWI_IRQ_INPUT, avr_twi_irq_input, p);
        p->state = p->peer_addr = 0;
 }
 
 static const char * irq_names[TWI_IRQ_COUNT] = {
-       [TWI_IRQ_MISO] = "8<miso",
-       [TWI_IRQ_MOSI] = "32>mosi",
+       [TWI_IRQ_INPUT] = "8<input",
+       [TWI_IRQ_OUTPUT] = "32>output",
        [TWI_IRQ_STATUS] = "8>status",
 };
 
index a1396e220677e844ca2f098706e656e7ca42b23f..8b37ba3940307bd5ea315009a4defd9c75aa9ee2 100644 (file)
@@ -31,8 +31,8 @@ extern "C" {
 //#include "sim_twi.h"
 
 enum {
-       TWI_IRQ_MISO = 0,
-       TWI_IRQ_MOSI,
+       TWI_IRQ_INPUT = 0,
+       TWI_IRQ_OUTPUT,
        TWI_IRQ_STATUS,
        TWI_IRQ_COUNT
 };