diff options
Diffstat (limited to 'avr/i2c.c')
-rw-r--r-- | avr/i2c.c | 91 |
1 files changed, 50 insertions, 41 deletions
@@ -99,12 +99,17 @@ uint8_t buf[CONFIG_SYS_I2C_BUFSIZE]; } i2c_msg_t; -static i2c_msg_t xmit; +static volatile i2c_msg_t xmit; ISR(TWI_vect) { - uint8_t next_twcr; + uint8_t tmp_stat; uint8_t tmp_idx; + uint8_t next_twcr; + uint8_t n; + + tmp_idx = xmit.idx; + tmp_stat = xmit.stat; uint8_t twsr = TWSR; @@ -112,62 +117,59 @@ ISR(TWI_vect) case TWI_START: case TWI_REP_START: - xmit.idx = 0; /* reset xmit_buf index */ - xmit.stat = BUSY | START; + tmp_stat = BUSY | START; + tmp_idx = 0; /* reset xmit_buf index */ - tmp_idx = xmit.idx; if (tmp_idx < xmit.len) { /* all bytes transmited? */ TWDR = xmit.buf[tmp_idx]; - xmit.idx = ++tmp_idx; + ++tmp_idx; next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT); } else { - xmit.stat |= XMIT_DONE; - xmit.stat &= ~BUSY; + tmp_stat |= XMIT_DONE; + tmp_stat &= ~BUSY; next_twcr = (1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO); } break; case TWI_MTX_ADR_ACK: - xmit.stat |= ADDR_ACK; + tmp_stat |= ADDR_ACK; - tmp_idx = xmit.idx; if (tmp_idx < xmit.len) { /* all bytes transmited? */ TWDR = xmit.buf[tmp_idx]; - xmit.idx = ++tmp_idx; + ++tmp_idx; next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT); } else { - xmit.stat |= XMIT_DONE; - xmit.stat &= ~BUSY; + tmp_stat |= XMIT_DONE; + tmp_stat &= ~BUSY; next_twcr = (1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO); } break; case TWI_MTX_DATA_ACK: - xmit.stat |= DATA_ACK; + tmp_stat |= DATA_ACK; - tmp_idx = xmit.idx; if (tmp_idx < xmit.len) { /* all bytes transmited? */ TWDR = xmit.buf[tmp_idx]; - xmit.idx = ++tmp_idx; + ++tmp_idx; next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT); } else { - xmit.stat |= XMIT_DONE; - xmit.stat &= ~BUSY; + tmp_stat |= XMIT_DONE; + tmp_stat &= ~BUSY; next_twcr = (1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO); } break; case TWI_MTX_DATA_NACK: - xmit.stat |= XMIT_DONE; - xmit.stat &= ~BUSY; + tmp_stat |= XMIT_DONE; + tmp_stat &= ~BUSY; next_twcr = (1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO); break; case TWI_MRX_ADR_ACK: - xmit.stat |= ADDR_ACK; - tmp_idx = xmit.idx; - if (tmp_idx < xmit.len-1) { + 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); @@ -175,11 +177,11 @@ ISR(TWI_vect) break; case TWI_MRX_DATA_ACK: - xmit.stat |= DATA_ACK; - tmp_idx = xmit.idx; + tmp_stat |= DATA_ACK; xmit.buf[tmp_idx] = TWDR; - xmit.idx = ++tmp_idx; - if (tmp_idx < xmit.len-1) { + ++tmp_idx; + n = xmit.len-1; + if (tmp_idx < n) { next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA); } else { @@ -188,19 +190,21 @@ ISR(TWI_vect) break; case TWI_MRX_DATA_NACK: - xmit.stat |= ADDR_ACK | DATA_ACK; + tmp_stat |= ADDR_ACK | DATA_ACK; - tmp_idx = xmit.idx; xmit.buf[tmp_idx] = TWDR; - xmit.idx = ++tmp_idx; + ++tmp_idx; /* fall thru */ default: - xmit.stat &= ~BUSY; + tmp_stat &= ~BUSY; next_twcr = (1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO); break; } + xmit.stat = tmp_stat; + xmit.idx = tmp_idx; + #ifdef DEBUG_I2C debug("|%02x", twsr); #endif @@ -217,32 +221,37 @@ static uint8_t twbr; static void _init(void) { xmit.stat = 0; -#ifdef DEBUG_I2C - memset((void *) xmit.buf, 0xdf, sizeof(xmit.buf)); -#endif /* Disable TWI, disable TWI interrupt. */ /* (Reset TWI hardware state machine.) */ TWCR = TWI_C_DISABLE; _delay_us(5); +#ifdef DEBUG_I2C + memset((void *) xmit.buf, 0xdf, sizeof(xmit.buf)); +#endif - TWBR = twbr; TWDR = 0xff; - TWCR = TWI_C_ENABLE + twps; + TWBR = twbr; + TWSR = twps & 0x03; + TWCR = TWI_C_ENABLE; } void i2c_init(uint32_t speed) { twps = 0; - uint32_t tmptwbr = F_CPU /2 / speed - 8; + uint32_t tmp_twbr = F_CPU /2 / speed - 8; - while (tmptwbr > 255) { - tmptwbr >>= 4; + while (tmp_twbr > 255) { + tmp_twbr >>= 4; twps += 1; } - debug_cond((twps > 3), "TWCLK too low: %lu Hz\n", speed); + debug_cond((twps > 3), "*** TWCLK too low: %lu Hz\n", speed); + + twbr = (uint8_t) tmp_twbr; + + debug("*** i2c_init: i2c_speed: %lu, twbr: %u, twps: %u\n", + speed, twbr, twps); - twbr = (uint8_t) tmptwbr; _init(); } |