📄 i2c.c
字号:
}
//! I2C (TWI) interrupt service routine
SIGNAL(SIG_2WIRE_SERIAL)
{
// read status bits
unsigned char status = inb(TWSR) & TWSR_STATUS_MASK;
i2c_data = TWCR;
i2c_code = TWSR & TW_NO_INFO;
twi_had_isr = 1;
switch(status)
{
// Master General
case TW_START: // 0x08: Sent start condition
case TW_REP_START: // 0x10: Sent repeated start condition
// send device address
i2cSendByte(I2cDeviceAddrRW);
//outb(TWDR, I2cDeviceAddrRW);
//outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
break;
// Master Transmitter & Receiver status codes
case TW_MT_SLA_ACK: // 0x18: Slave address acknowledged
case TW_MT_DATA_ACK: // 0x28: Data acknowledged
if(I2cSendDataIndex < I2cSendDataLength)
{
// send i2c_data
i2cSendByte( I2cSendData[I2cSendDataIndex++] );
//outb(TWDR, I2cSendData[I2cSendDataIndex++]);
//outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
}
else
{
// transmit stop condition, enable SLA ACK
i2cSendStop();
//outb(TWCR, inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWSTO)|BV(TWEA));
// set state
I2cState = I2C_IDLE;
}
break;
case TW_MR_DATA_NACK: // 0x58: Data received, NACK reply ssued
// store final received i2c_data byte
I2cReceiveData[I2cReceiveDataIndex++] = inb(TWDR);
// continue to transmit STOP condition
case TW_MR_SLA_NACK: // 0x48: Slave address not acknowledged
case TW_MT_SLA_NACK: // 0x20: Slave address not acknowledged
case TW_MT_DATA_NACK: // 0x30: Data not acknowledged
// transmit stop condition, enable SLA ACK
i2cSendStop();
//outb(TWCR, inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWSTO)|BV(TWEA));
// set state
I2cState = I2C_IDLE;
break;
case TW_MT_ARB_LOST: // 0x38: Bus arbitration lost
//case TW_MR_ARB_LOST: // 0x38: Bus arbitration lost
// release bus
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
// set state
I2cState = I2C_IDLE;
// release bus and transmit start when bus is free
//outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWSTA));
break;
case TW_MR_DATA_ACK: // 0x50: Data acknowledged
// store received i2c_data byte
I2cReceiveData[I2cReceiveDataIndex++] = inb(TWDR);
// fall-through to see if more bytes will be received
case TW_MR_SLA_ACK: // 0x40: Slave address acknowledged
if(I2cReceiveDataIndex < (I2cReceiveDataLength-1))
// i2c_data byte will be received, reply with ACK (more bytes in transfer)
i2cReceiveByte(TRUE);
//outb(TWCR, inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
else
// i2c_data byte will be received, reply with NACK (final byte in transfer)
i2cReceiveByte(FALSE);
//outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
break;
// Slave Receiver status codes
case TW_SR_SLA_ACK: // 0x60: own SLA+W has been received, ACK has been returned
case TW_SR_ARB_LOST_SLA_ACK: // 0x68: own SLA+W has been eceived, ACK has been returned
case TW_SR_GCALL_ACK: // 0x70: GCA+W has been received, ACK has been returned
case TW_SR_ARB_LOST_GCALL_ACK: // 0x78: GCA+W has been eceived, ACK has been returned
// we are being addressed as slave for writing (i2c_data will be received from master)
// set state
I2cState = I2C_SLAVE_RX;
// prepare buffer
I2cReceiveDataIndex = 0;
// receive i2c_data byte and return ACK
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
break;
case TW_SR_DATA_ACK: // 0x80: i2c_data byte has been received, ACK has been returned
case TW_SR_GCALL_DATA_ACK: // 0x90: i2c_data byte has been received, ACK has been returned
// get previously received i2c_data byte
I2cReceiveData[I2cReceiveDataIndex++] = inb(TWDR);
// check receive buffer status
if(I2cReceiveDataIndex < I2C_RECEIVE_DATA_BUFFER_SIZE)
{
// receive i2c_data byte and return ACK
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
}
else
{
// receive i2c_data byte and return NACK
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
}
break;
case TW_SR_DATA_NACK: // 0x88: i2c_data byte has been received, NACK has been returned
case TW_SR_GCALL_DATA_NACK: // 0x98: i2c_data byte has been received, NACK has been returned
// receive i2c_data byte and return NACK
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
break;
case TW_SR_STOP: // 0xA0: STOP or REPEATED START has been received while addressed as slave
// switch to SR mode with SLA ACK
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
// i2c receive is complete, call i2cSlaveReceive
if(i2cSlaveReceive) i2cSlaveReceive(I2cReceiveDataIndex, I2cReceiveData);
// set state
I2cState = I2C_IDLE;
break;
// Slave Transmitter
case TW_ST_SLA_ACK: // 0xA8: own SLA+R has been received, ACK has been returned
case TW_ST_ARB_LOST_SLA_ACK: // 0xB0: GCA+R has been eceived, ACK has been returned
// we are being addressed as slave for reading (i2c_data must be transmitted back o master)
// set state
I2cState = I2C_SLAVE_TX;
// request i2c_data from application
if(i2cSlaveTransmit)
I2cSendDataLength = i2cSlaveTransmit(I2C_SEND_DATA_BUFFER_SIZE, I2cSendData);
// reset i2c_data index
I2cSendDataIndex = 0;
// fall-through to transmit first i2c_data byte
case TW_ST_DATA_ACK: // 0xB8: i2c_data byte has been ransmitted, ACK has been received
// transmit i2c_data byte
outb(TWDR, I2cSendData[I2cSendDataIndex++]);
if(I2cSendDataIndex < I2cSendDataLength)
// expect ACK to i2c_data byte
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
else
// expect NACK to i2c_data byte
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
break;
case TW_ST_DATA_NACK: // 0xC0: i2c_data byte has been ransmitted, NACK has been received
case TW_ST_LAST_DATA: // 0xC8:
// all done
// switch to open slave
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
// set state
I2cState = I2C_IDLE;
break;
// Misc
case TW_NO_INFO: // 0xF8: No relevant state information
// do nothing
break;
case TW_BUS_ERROR: // 0x00: Bus error due to illegal start or top condition
// reset internal hardware and release bus
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWSTO)|BV(TWEA));
// set state
I2cState = I2C_IDLE;
break;
}
}
void neweprom_init(void) {
/* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */
#if defined(TWPS0)
/* has prescaler (mega128 & newer) */
TWSR = 0;
#endif
TWBR = 6;
}
int neweprom_read_byte(uint16_t eeaddr, char *buf)
{
uint8_t n = 0;
restart:
if (n++ >= MAX_TRIES)
return -1;
begin:
// send start cond.
TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
while (!(TWCR & (1 << TWINT)));
if (TW_STATUS == TW_MT_ARB_LOST) goto begin;
if ( (TW_STATUS != TW_REP_START) && (TW_STATUS != TW_START)) {
return -1;
}
// send 0xa0
// 0xa0 = 1010 000 0
// 4 bits: <a..device-indentifier>
// 3 bits: <device-address set with chip pins>
// last bit: <0..write>
TWDR = 0xa0;
TWCR = (1 << TWINT) | (1 << TWEN);
while (!(TWCR & (1 << TWINT)));
if (TW_STATUS == TW_MT_SLA_NACK) goto restart;
if (TW_STATUS == TW_MT_ARB_LOST) goto begin;
if (TW_STATUS != TW_MT_SLA_ACK) goto error;
// send low 8 bits of eeaddr
TWDR = eeaddr;
TWCR = (1 << TWINT) | (1 << TWEN);
while (!(TWCR & (1 << TWINT)));
if (TW_STATUS == TW_MT_DATA_NACK) goto restart;
if (TW_STATUS == TW_MT_ARB_LOST) goto begin;
if (TW_STATUS != TW_MT_DATA_ACK) goto error;
// send high 8 bits of eeaddr
TWDR = eeaddr << 8;
TWCR = (1 << TWINT) | (1 << TWEN);
while (!(TWCR & (1 << TWINT)));
if (TW_STATUS == TW_MT_DATA_NACK) goto restart;
if (TW_STATUS == TW_MT_ARB_LOST) goto begin;
if (TW_STATUS != TW_MT_DATA_ACK) goto error;
// send start cond.
TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
while (!(TWCR & (1 << TWINT)));
if (TW_STATUS == TW_MT_ARB_LOST) goto begin;
if ( (TW_STATUS != TW_REP_START) && (TW_STATUS != TW_START)) {
return -1;
}
// send 0xa1
// 0xa0 = 1010 000 1
// 4 bits: <a..device-indentifier>
// 3 bits: <device-address set with chip pins>
// last bit: <1..read>
TWDR = 0xa1;
TWCR = (1 << TWINT) | (1 << TWEN);
while (!(TWCR & (1 << TWINT)));
if (TW_STATUS == TW_MR_SLA_NACK) goto quit;
if (TW_STATUS == TW_MR_ARB_LOST) goto begin;
if (TW_STATUS != TW_MR_SLA_ACK) goto error;
// start read transmission
TWCR = (1 << TWINT) | (1 << TWEN);
while (!(TWCR & (1 << TWINT)));
switch ((twst = TW_STATUS)) {
case TW_MR_DATA_NACK:
// FALLTHROUGH
case TW_MR_DATA_ACK:
*buf = TWDR;
break;
default:
goto error;
}
quit:
//stop condition
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
return 1;
error:
//stop condition
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
return -1;
}
int new_eprom_write_byte(uint16_t eeaddr, char buf) {
uint8_t n = 0;
restart:
if (n++ >= MAX_TRIES)
return -1;
begin:
// start cond.
TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
while (!(TWCR & (1 << TWINT)));
if (TW_STATUS == TW_MT_ARB_LOST) goto begin;
if ( (TW_STATUS != TW_REP_START) && (TW_STATUS != TW_START)) {
return -1;
}
// send 0xa0
// 0xa0 = 1010 000 0
// 4 bits: <a..device-indentifier>
// 3 bits: <device-address set with chip pins>
// last bit: <0..write>
TWDR = 0xa0;
TWCR = (1 << TWINT) | (1 << TWEN);
while (!(TWCR & (1 << TWINT)));
if (TW_STATUS == TW_MT_SLA_NACK) goto restart;
if (TW_STATUS == TW_MT_ARB_LOST) goto begin;
if (TW_STATUS != TW_MT_SLA_ACK) goto error;
// send low 8 bits of eeaddr
TWDR = eeaddr;
TWCR = (1 << TWINT) | (1 << TWEN);
while (!(TWCR & (1 << TWINT)));
if (TW_STATUS == TW_MT_DATA_NACK) goto quit;
if (TW_STATUS == TW_MT_ARB_LOST) goto begin;
if (TW_STATUS != TW_MT_DATA_ACK) goto error;
// send high 8 bits of eeaddr
TWDR = eeaddr << 8;
TWCR = (1 << TWINT) | (1 << TWEN);
while (!(TWCR & (1 << TWINT)));
if (TW_STATUS == TW_MT_DATA_NACK) goto quit;
if (TW_STATUS == TW_MT_ARB_LOST) goto begin;
if (TW_STATUS != TW_MT_DATA_ACK) goto error;
// put byte into i2c_data register and start transmission
TWDR = buf;
TWCR = (1 << TWINT) | (1 << TWEN);
while (!(TWCR & (1 << TWINT)));
if (TW_STATUS != TW_MT_DATA_ACK) goto error;
quit:
// send stop condition
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
return 1;
error:
// send stop condition
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
return -1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -