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));
}
}
*/
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) {
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++;
}
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
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)
{
// "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 );
}
#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(
{
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)
}
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)
#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));
}
}
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);
// 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 ?
// 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 ?
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;
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 );
// "general call" address
AVR_TRACE(avr, "I2C slave start without address?\n");
if (avr->data[p->r_twar] & 1) {
+ // TODO
}
}
}
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",
};