From f1fb1de3fce7aab23e7e52bc8b93067dda2ee5dc Mon Sep 17 00:00:00 2001 From: Michel Date: Sun, 4 Apr 2010 15:36:17 +0100 Subject: [PATCH] TWI: Temp TWI changes with new IRQ system Signed-off-by: <> --- simavr/sim/sim_twi.c | 107 ++++++++++++++++++++++++++++++++----------- simavr/sim/sim_twi.h | 62 ++++++++++++++++--------- 2 files changed, 121 insertions(+), 48 deletions(-) diff --git a/simavr/sim/sim_twi.c b/simavr/sim/sim_twi.c index b5c19fb..b0eea39 100644 --- a/simavr/sim/sim_twi.c +++ b/simavr/sim/sim_twi.c @@ -25,9 +25,81 @@ #include #include "sim_twi.h" +static void twi_bus_master_irq_notify(struct avr_irq_t * irq, uint32_t value, void * param) +{ + switch (irq->irq) { + case TWI_MASTER_STOP: + bus->peer = NULL; + break; + case TWI_MASTER_START: + bus->peer = NULL; + bus->ack = 0; + break; + case TWI_MASTER_MISO: + bus->ack = 0; + break; + case TWI_MASTER_MOSI: + bus->ack = 0; + break; + case TWI_MASTER_ACK: + if (!peer) { + } + break; + } +} + +static void twi_bus_slave_irq_notify(struct avr_irq_t * irq, uint32_t value, void * param) +{ + twi_slave_t * slave = (twi_slave_t*)param; + twi_bus_t * bus = slave->bus; + switch (irq->irq) { + case TWI_SLAVE_MISO: + bus->latch = value; + break; + case TWI_SLAVE_ACK: + if (!bus->peer) { + bus->peer = slave; + printf("twi bus: slave %x selected\n", slave->address); + } + bus->ack = 0x80 | (value & 1); + break; + } +} + +static void twi_slave_master_irq_notify(struct avr_irq_t * irq, uint32_t value, void * param) +{ + twi_slave_t * slave = (twi_slave_t*)param; + switch (irq->irq) { + case TWI_MASTER_STOP: + if (slave->match) { + // we were target + } + slave->match = 0; + break; + case TWI_MASTER_START: + if ((value & 0xfe) == slave->address & 0xfe) { + if (slave->match) { + // restart + } + slave->match = 1; + avr_raise_irq(slave->irq + TWI_SLAVE_ACK, 1); + } + break; + case TWI_MASTER_MISO: + break; + case TWI_MASTER_MOSI: + break; + case TWI_MASTER_ACK: + break; + } +} + void twi_bus_init(twi_bus_t * bus) { memset(bus, 0, sizeof(twi_bus_t)); + avr_init_irq(bus->irq, 0, TWI_STATE_COUNT); + for (int i = 0; i < TWI_MASTER_STATE_COUNT; i++) + avr_irq_register_notify(bus->irq + i, twi_bus_master_irq_notify, bus); } void twi_bus_attach(twi_bus_t * bus, twi_slave_t * slave) @@ -36,40 +108,22 @@ void twi_bus_attach(twi_bus_t * bus, twi_slave_t * slave) slave->bus = bus; slave->next = bus->slave; bus->slave = slave; + + for (int i = 0; i < TWI_SLAVE_STATE_COUNT; i++) + avr_irq_register_notify(slave->irq + i, twi_bus_slave_irq_notify, slave); + for (int i = 0; i < TWI_MASTER_STATE_COUNT; i++) + avr_irq_register_notify(bus->irq + i, twi_slave_irq_notify, slave); } int twi_bus_start(twi_bus_t * bus, uint8_t address) { - // if we already have a peer, check to see if it's - // still matching, if so, skip the lookup - if (bus->peer) { - if (twi_slave_match(bus->peer, address)) - return bus->peer->event(bus->peer, address, TWI_START); - twi_bus_stop(bus); - } - - bus->peer = NULL; - twi_slave_t *s = bus->slave; - while (s) { - if (twi_slave_match(s, address)) { - if (s->event(s, address, TWI_START)) { - bus->peer = s; - s->byte_index = 0; - return 1; - } - } - s = s->next; - } - return 0; + avr_raise_irq(bus->irq + TWI_MASTER_START, address); + return bus->peer != NULL ? 1 : 0; } void twi_bus_stop(twi_bus_t * bus) { - if (bus->peer) { - bus->peer->event(bus->peer, 0, TWI_STOP); - bus->peer->byte_index = 0; - } - bus->peer = NULL; + avr_raise_irq(bus->irq + TWI_MASTER_STOP, 0); } int twi_bus_write(twi_bus_t * bus, uint8_t data) @@ -99,6 +153,7 @@ void twi_slave_init(twi_slave_t * slave, uint8_t address, void * param) memset(slave, 0, sizeof(twi_slave_t)); slave->address = address; slave->param = param; + } void twi_slave_detach(twi_slave_t * slave) diff --git a/simavr/sim/sim_twi.h b/simavr/sim/sim_twi.h index 0c841f2..41db043 100644 --- a/simavr/sim/sim_twi.h +++ b/simavr/sim/sim_twi.h @@ -27,42 +27,61 @@ #define SIM_TWI_H_ #include +#include "sim_irq.h" -enum twi_event { - TWI_START, - TWI_STOP, - // return non-zero if this slave address is handled by this slave - // if NULL, the "address" field is used instead. If this function - // is present, 'address' field is not used. - TWI_PROBE, - TWI_NACK /* Masker NACKed a receive byte. */ +/* + * The TWI system is designed to be representing the same state as + * a TWI/i2c bus itself. So each "state" of the bus is an IRQ sent + * by the master to the slave, with a couple sent from the + * slave to the master. + * This is designed to decorelate the operations on the "bus" so + * the firmware has time to "run" before acknowledging a byte, for + * example. + * + * IRQ Timeline goes as follow with an example transaction that + * does write addres, write registrer, read a byte after a i2c restart + * then stops the transaction. + * + * Master: START MOSI START MISO ACK STOP + * Slave: ACK ACK ACK MISO + */ +enum twi_state_e { + TWI_MASTER_STOP = 0, + TWI_MASTER_START, // master does a start with address + TWI_MASTER_MOSI, // master i2c write + TWI_MASTER_MISO, // master i2c read + TWI_MASTER_ACK, // master i2c ACK after a i2c read + TWI_MASTER_STATE_COUNT, + + TWI_SLAVE_MISO = 0, // slave i2c read. + TWI_SLAVE_ACK, // slave acknowledges TWI_MASTER_MOSI + TWI_SLAVE_STATE_COUNT, }; #define TWI_ADDRESS_READ_MASK 0x01 typedef struct twi_slave_t { + avr_irq_t irq[TWI_SLAVE_STATE_COUNT]; + struct twi_bus_t * bus; // bus we are attached to struct twi_slave_t * next; // daisy chain on the bus - void * param; // module private parameter - uint8_t address; // slave address (lowest bit is not used, it's for the W bit) - int byte_index; // byte index in the transaction (since last start, restart) - - // handle start conditionto address+w, restart means "stop" wasn't called - int (*event)(struct twi_slave_t* p, uint8_t address, enum twi_event event); - - // handle a data write, after a (re)start - int (*write)(struct twi_slave_t* p, uint8_t v); - - // handle a data read, after a (re)start - uint8_t (*read)(struct twi_slave_t* p); + uint32_t address; // can specify up to 4 matching addresses here + int match; // we are selected on the bus + int index; // byte index in the transaction + + uint8_t latch; // last received byte } twi_slave_t; typedef struct twi_bus_t { + avr_irq_t irq[TWI_MASTER_STATE_COUNT]; + struct twi_slave_t * slave; // daisy chain on the bus - struct twi_slave_t * peer; // during a transaction, this is the selected slave + + uint8_t latch; // last received byte + uint8_t ack; // last received ack } twi_bus_t; void twi_bus_init(twi_bus_t * bus); @@ -73,6 +92,5 @@ void twi_bus_stop(twi_bus_t * bus); void twi_slave_init(twi_slave_t * slave, uint8_t address, void * param); void twi_slave_detach(twi_slave_t * slave); -int twi_slave_match(twi_slave_t * slave, uint8_t address); #endif /* SIM_TWI_H_ */ -- 2.39.5