-/*
- * I2C (TWI) master interface.
+/*
+ * I2C (TWI) master interface.
*/
#include "common.h"
#include <avr/interrupt.h>
-#include <util/delay.h>
#include <string.h>
#include "config.h"
* TWSTO: TWI STOP Condition Bit
* TWEN: TWI Enable Bit
* TWIE: TWI Interrupt Enable
- *
+ *
* (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
* (1<<TWEN)|(1<<TWIE)|(1<<TWINT)| (1<<TWEA)
* (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
- *
+ *
* default:
* (1<<TWEN)| (1<<TWINT)| (1<<TWSTO)
- *
+ *
* Init:
* (1<<TWEN)
- *
+ *
* start read/write:
* (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
* (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
* (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
* (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
- *
+ *
* wait ready:
* (1<<TWIE)|(1<<TWSTO)
*
*
*
- *i2c_result
+ *i2c_result
*
* 0b10000000 Busy (Transmission in progress)
* 0b01000000 Timeout
- * 0b00001000 Start transmitted
+ * 0b00001000 Start transmitted
* 0b00000100 Slave acknowledged address
* 0b00000010 Data byte(s) transmitted/received
* 0b00000001 Transmission completed
#define TWI_C_DISABLE 0x00
#define TWI_C_ENABLE (1<<TWEN)
-
-
+
+
typedef struct i2c_msg_s {
uint8_t stat;
#define XMIT_DONE (1<<0)
tmp_stat = xmit.stat;
uint8_t twsr = TWSR;
-
+
switch (twsr & 0xf8) {
case TWI_START:
break;
case TWI_MTX_ADR_ACK:
- tmp_stat |= ADDR_ACK;
-
- if (tmp_idx < xmit.len) { /* all bytes transmited? */
- TWDR = xmit.buf[tmp_idx];
- ++tmp_idx;
- next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT);
- } else {
- tmp_stat |= XMIT_DONE;
- tmp_stat &= ~BUSY;
- next_twcr = (1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO);
- }
- break;
-
case TWI_MTX_DATA_ACK:
- tmp_stat |= DATA_ACK;
+ if ((twsr&0xf8) == TWI_MTX_ADR_ACK)
+ tmp_stat |= ADDR_ACK;
+ else
+ tmp_stat |= DATA_ACK;
if (tmp_idx < xmit.len) { /* all bytes transmited? */
TWDR = xmit.buf[tmp_idx];
tmp_stat &= ~BUSY;
next_twcr = (1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO);
}
-
break;
case TWI_MTX_DATA_NACK:
next_twcr = (1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO);
break;
- case TWI_MRX_ADR_ACK:
- tmp_stat |= ADDR_ACK;
- n = xmit.len-1;
- if (tmp_idx < n) {
- next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA);
- } else {
- next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT);
- }
- break;
-
case TWI_MRX_DATA_ACK:
- tmp_stat |= DATA_ACK;
xmit.buf[tmp_idx] = TWDR;
++tmp_idx;
+ /* fall thru */
+ case TWI_MRX_ADR_ACK:
+ if ((twsr&0xf8) == TWI_MRX_ADR_ACK)
+ tmp_stat |= ADDR_ACK;
+ else
+ tmp_stat |= DATA_ACK;
+
n = xmit.len-1;
if (tmp_idx < n) {
next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA);
} else {
-
next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT);
}
break;
xmit.buf[tmp_idx] = TWDR;
++tmp_idx;
/* fall thru */
-
default:
tmp_stat &= ~BUSY;
next_twcr = (1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO);
{
twps = 0;
uint32_t tmp_twbr = F_CPU /2 / speed - 8;
-
+
while (tmp_twbr > 255) {
tmp_twbr >>= 4;
twps += 1;
debug_cond((twps > 3), "*** TWCLK too low: %lu Hz\n", speed);
twbr = (uint8_t) tmp_twbr;
+
+ PRR0 &= ~_BV(PRTWI);
_init();
}
{
uint32_t timer = get_timer(0);
uint8_t timeout = 0;
-
+
do {
if (get_timer(timer) >= 30) {
timeout = TIMEOUT;
#if DEBUG_I2C
dump_ram((uint8_t *) &xmit, 4, "=== i2c_wait ready: (done)");
_delay_ms(30);
-#endif
+#endif
return xmit.stat;
}
for (n = len + i; i < n; i++)
xmit.buf[i] = *buffer++;
xmit.len = i;
-
+
#if DEBUG_I2C
dump_ram((uint8_t *) &xmit, 0x20, "=== i2c_send");
_delay_ms(30);
-#endif
+#endif
/* Enable TWI, TWI int and initiate start condition */
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA);
uint8_t *buffer, uint_fast8_t len)
{
int rc;
-
+
if ((alen > 2) || (1 + alen + len > CONFIG_SYS_I2C_BUFSIZE)) {
debug("** i2c_write: buffer overflow, alen: %u, len: %u\n",
alen, len);
return -1;
}
-
+
i2c_send(chip, addr, alen, buffer, len);
rc = i2c_waitready();
alen, len);
return -1;
}
-
+
if (alen != 0) {
i2c_send(chip, addr, alen, NULL, 0);
- }
+ }
rc = i2c_recv(chip, buffer, len);
return !((rc & (XMIT_DONE|DATA_ACK)) == (XMIT_DONE|DATA_ACK));