/****************************************************************************
TWI State codes
****************************************************************************/
-// General TWI Master staus codes
+// General TWI Master status codes
#define TWI_START 0x08 // START has been transmitted
#define TWI_REP_START 0x10 // Repeated START has been transmitted
#define TWI_ARB_LOST 0x38 // Arbitration lost
-// TWI Master Transmitter staus codes
-#define TWI_MTX_ADR_ACK 0x18 // SLA+W has been tramsmitted and ACK received
-#define TWI_MTX_ADR_NACK 0x20 // SLA+W has been tramsmitted and NACK received
-#define TWI_MTX_DATA_ACK 0x28 // Data byte has been tramsmitted and ACK received
-#define TWI_MTX_DATA_NACK 0x30 // Data byte has been tramsmitted and NACK received
+// TWI Master Transmitter status codes
+#define TWI_MTX_ADR_ACK 0x18 // SLA+W has been transmitted and ACK received
+#define TWI_MTX_ADR_NACK 0x20 // SLA+W has been transmitted and NACK received
+#define TWI_MTX_DATA_ACK 0x28 // Data byte has been transmitted and ACK received
+#define TWI_MTX_DATA_NACK 0x30 // Data byte has been transmitted and NACK received
-// TWI Master Receiver staus codes
-#define TWI_MRX_ADR_ACK 0x40 // SLA+R has been tramsmitted and ACK received
-#define TWI_MRX_ADR_NACK 0x48 // SLA+R has been tramsmitted and NACK received
-#define TWI_MRX_DATA_ACK 0x50 // Data byte has been received and ACK tramsmitted
-#define TWI_MRX_DATA_NACK 0x58 // Data byte has been received and NACK tramsmitted
+// TWI Master Receiver status codes
+#define TWI_MRX_ADR_ACK 0x40 // SLA+R has been transmitted and ACK received
+#define TWI_MRX_ADR_NACK 0x48 // SLA+R has been transmitted and NACK received
+#define TWI_MRX_DATA_ACK 0x50 // Data byte has been received and ACK transmitted
+#define TWI_MRX_DATA_NACK 0x58 // Data byte has been received and NACK transmitted
-// TWI Slave Transmitter staus codes
+// TWI Slave Transmitter status codes
#define TWI_STX_ADR_ACK 0xA8 // Own SLA+R has been received; ACK has been returned
#define TWI_STX_ADR_ACK_M_ARB_LOST 0xB0 // Arbitration lost in SLA+R/W as Master; own SLA+R has been received; ACK has been returned
#define TWI_STX_DATA_ACK 0xB8 // Data byte in TWDR has been transmitted; ACK has been received
#define TWI_STX_DATA_NACK 0xC0 // Data byte in TWDR has been transmitted; NOT ACK has been received
#define TWI_STX_DATA_ACK_LAST_BYTE 0xC8 // Last data byte in TWDR has been transmitted (TWEA = �0�); ACK has been received
-// TWI Slave Receiver staus codes
+// TWI Slave Receiver status codes
#define TWI_SRX_ADR_ACK 0x60 // Own SLA+W has been received ACK has been returned
#define TWI_SRX_ADR_ACK_M_ARB_LOST 0x68 // Arbitration lost in SLA+R/W as Master; own SLA+W has been received; ACK has been returned
#define TWI_SRX_GEN_ACK 0x70 // General call address has been received; ACK has been returned
#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
static inline void
_avr_twi_status_set(
int interrupt)
{
avr_regbit_setto_raw(p->io.avr, p->twsr, v);
+#if AVR_TWI_DEBUG
+ printf("_avr_twi_status_set %02x\n", v);
+#endif
avr_raise_irq(p->io.irq + TWI_IRQ_STATUS, v);
if (interrupt)
avr_raise_interrupt(p->io.avr, &p->twi);
uint8_t twint = avr_regbit_get(avr, p->twi.raised);
avr_core_watch_write(avr, addr, v);
-
- printf("avr_twi_write %02x START:%d STOP:%d ACK:%d INT:%d TWSR:%02x\n", v,
+#if AVR_TWI_DEBUG
+ printf("avr_twi_write %02x START:%d STOP:%d ACK:%d INT:%d TWSR:%02x (state %02x)\n", v,
avr_regbit_get(avr, p->twsta),
avr_regbit_get(avr, p->twsto),
avr_regbit_get(avr, p->twea),
avr_regbit_get(avr, p->twi.raised),
- avr_regbit_get_raw(p->io.avr, p->twsr));
-
+ avr_regbit_get_raw(p->io.avr, p->twsr), p->state);
+#endif
if (twen != avr_regbit_get(avr, p->twen)) {
twen = !twen;
if (!twen) { // if we were running, now now are not
avr_regbit_clear(avr, p->twea);
avr_regbit_clear(avr, p->twsta);
avr_regbit_clear(avr, p->twsto);
- avr_clear_interrupt(avr, p->twi.vector);
+ avr_clear_interrupt(avr, &p->twi);
avr_core_watch_write(avr, p->r_twdr, 0xff);
_avr_twi_status_set(p, TWI_NO_STATE, 0);
p->state = 0;
if (!twsto && avr_regbit_get(avr, p->twsto)) {
// generate a stop condition
+#if AVR_TWI_DEBUG
printf("<<<<< I2C stop\n");
-
+#endif
if (p->state) { // doing stuff
if (p->state & TWI_COND_START) {
avr_raise_irq(p->io.irq + TWI_IRQ_MOSI,
p->state = 0;
}
if (!twsta && avr_regbit_get(avr, p->twsta)) {
+#if AVR_TWI_DEBUG
printf(">>>>> I2C %sstart\n", p->state & TWI_COND_START ? "RE" : "");
+#endif
// generate a start condition
if (p->state & TWI_COND_START)
_avr_twi_delay_state(p, 3, TWI_REP_START);
!avr_regbit_get(avr, p->twsto)) {
// writing or reading a byte
if (p->state & TWI_COND_ADDR) {
- if (p->peer_addr & 1)
+ int do_read = p->peer_addr & 1;
+#if AVR_TWI_DEBUG
+ if (do_read)
printf("I2C READ byte from %02x\n", p->peer_addr);
else
printf("I2C WRITE byte %02x to %02x\n", avr->data[p->r_twdr], p->peer_addr);
+#endif
// a normal data byte
- uint8_t msgv = p->peer_addr & 1 ? TWI_COND_READ : TWI_COND_WRITE;
+ uint8_t msgv = do_read ? TWI_COND_READ : TWI_COND_WRITE;
+
if (avr_regbit_get(avr, p->twea))
msgv |= TWI_COND_ACK;
p->state &= ~TWI_COND_ACK; // clear ACK bit
- // 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_twi_irq_msg(msgv, p->peer_addr, avr->data[p->r_twdr]));
+ // if the latch is ready... as set by writing/reading the TWDR
+ if ((p->state & msgv)) {
- if (p->peer_addr & 1) { // read ?
- _avr_twi_delay_state(p, 9,
- msgv & TWI_COND_ACK ?
- TWI_MTX_DATA_ACK : TWI_MTX_DATA_NACK);
- } else {
- _avr_twi_delay_state(p, 9,
- p->state & TWI_COND_ACK ?
- TWI_MTX_DATA_ACK : TWI_MTX_DATA_NACK);
+ // 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_twi_irq_msg(msgv, p->peer_addr, avr->data[p->r_twdr]));
+
+ if (do_read) { // read ?
+ _avr_twi_delay_state(p, 9,
+ msgv & TWI_COND_ACK ?
+ TWI_MRX_DATA_ACK : TWI_MRX_DATA_NACK);
+ } else {
+ _avr_twi_delay_state(p, 9,
+ p->state & TWI_COND_ACK ?
+ TWI_MTX_DATA_ACK : TWI_MTX_DATA_NACK);
+ }
}
-
+#if AVR_TWI_DEBUG
+ else
+ printf("I2C latch is not ready, do nothing\n");
+#endif
} else {
+#if AVR_TWI_DEBUG
printf("I2C Master address %02x\n", avr->data[p->r_twdr]);
+#endif
// send the address
p->state |= TWI_COND_ADDR;
p->peer_addr = avr->data[p->r_twdr];
avr_twi_irq_msg(TWI_COND_START, p->peer_addr, 0));
if (p->peer_addr & 1) { // read ?
+ p->state |= TWI_COND_READ; // always allow read to start with
_avr_twi_delay_state(p, 9,
p->state & TWI_COND_ACK ?
TWI_MRX_ADR_ACK : TWI_MRX_ADR_NACK);
TWI_MTX_ADR_ACK : TWI_MTX_ADR_NACK);
}
}
+ p->state &= ~TWI_COND_WRITE;
}
}
/*
- * prevent code from rewriting out status bits, since we actualy use them!
+ * Write data to the latch, tell the system we have something
+ * to send next
+ */
+static void
+avr_twi_write_data(
+ struct avr_t * avr,
+ avr_io_addr_t addr,
+ uint8_t v,
+ void * param)
+{
+ avr_twi_t * p = (avr_twi_t *)param;
+
+ avr_core_watch_write(avr, addr, v);
+ // tell system we have something in the write latch
+ p->state |= TWI_COND_WRITE;
+}
+
+/*
+ * Read data from the latch, tell the system can receive a new byte
+ */
+static uint8_t
+avr_twi_read_data(
+ struct avr_t * avr,
+ avr_io_addr_t addr,
+ void * param)
+{
+ avr_twi_t * p = (avr_twi_t *)param;
+
+ // tell system we can receive another byte
+ p->state |= TWI_COND_READ;
+ return avr->data[p->r_twdr];
+}
+
+/*
+ * prevent code from rewriting out status bits, since we actually use them!
*/
static void
avr_twi_write_status(
// receiving an acknowledge bit
if (msg.u.twi.msg & TWI_COND_ACK) {
+#if AVR_TWI_DEBUG
printf("I2C received ACK:%d\n", msg.u.twi.data & 1);
+#endif
if (msg.u.twi.data & 1)
p->state |= TWI_COND_ACK;
else
}
// receive a data byte from a slave
if (msg.u.twi.msg & TWI_COND_READ) {
+#if AVR_TWI_DEBUG
printf("I2C received %02x\n", msg.u.twi.data);
+#endif
avr->data[p->r_twdr] = msg.u.twi.data;
}
}
}
static const char * irq_names[TWI_IRQ_COUNT] = {
- [TWI_IRQ_MISO] = "8<mosi",
- [TWI_IRQ_MOSI] = "32>miso",
+ [TWI_IRQ_MISO] = "8<miso",
+ [TWI_IRQ_MOSI] = "32>mosi",
[TWI_IRQ_STATUS] = "8>status",
};
avr_io_setirqs(&p->io, AVR_IOCTL_TWI_GETIRQ(p->name), TWI_IRQ_COUNT, NULL);
avr_register_io_write(avr, p->twen.reg, avr_twi_write, p);
+ avr_register_io_write(avr, p->r_twdr, avr_twi_write_data, p);
+ avr_register_io_read(avr, p->r_twdr, avr_twi_read_data, p);
avr_register_io_write(avr, p->twsr.reg, avr_twi_write_status, p);
}
+uint32_t
+avr_twi_irq_msg(
+ uint8_t msg,
+ uint8_t addr,
+ uint8_t data)
+{
+ avr_twi_msg_irq_t _msg = {
+ .u.twi.msg = msg,
+ .u.twi.addr = addr,
+ .u.twi.data = data,
+ };
+ return _msg.u.v;
+}