I have been attempting to utilize Peter Fleury's I2C Library to have an ATmega328P communicate with a few I2C peripherals. I have already gotten the Master Transmitter working with a 4x20 LCD (NHD-0420D3Z-FL-GBW) and written a few wrapper functions to control it without a hitch. I know that the attached files are a mess, this project has become a bit of a dumping ground for me to play with new peripherals.
I am having trouble with reading data from a secondary device (specifically the MCP9808); my code hangs whenever a read operation is attempted. I have found that the TWINT check in i2c_readAck() is the problem, but I am not sure why. I checked TWSR and TWCR at various points through read16() and the results are in the comments below. The while loop in i2c_readAck() is where things get stuck. (TWCR & (1<<TWINT)) seems to be the culprit but this check is directly from the library and mentioned in the ATmega328p datasheet to wait for TWINT to be set (which it is right above this check).
Can someone point me in the right direction or provide some insight as to what I am doing wrong or misconstruing? I have been attacking this for a few days and can't seem to get over this hurdle.
Note that I commented out the i2c_read() calls in readTempC() so I could attempt to debug the issue.
unsigned char i2c_readAck(void) { TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA); // Wait for TWINT Flag set. This indicates that the DATA has been // transmitted, and ACK/NACK has been received. while (!(TWCR & (1<<TWINT))) ; /*software hangs here*/ return TWDR; }/* i2c_readAck */
static inline void init() { TWSR = (1<<TWPS1) | (1<<TWPS0); // PRESCALER = 64 TWBR = ((F_CPU/SCL_CLOCK) - 16) / 128; } static inline uint16_t read16(uint16_t reg) { uint16_t val = 0; //TWSR = 0x20 -> SLA+W transmitted, NACK received //TWCR = 0x84 -> TWINT, TWEN i2c_start(AMBIENT_TEMP_ADDR + I2C_WRITE); //TWSR = 0x30 -> data byte transmitted, NACK received //TWCR = 0x84 -> TWINT, TWEN i2c_write(reg); //TWSR = 0x48 -> SLA+R transmitted, NACK received //TWCR = 0x84 -> TWINT, TWEN i2c_rep_start(AMBIENT_TEMP_ADDR + I2C_READ); val = readAck(); /* val = i2c_read(1); val <<= 8; val |= i2c_read(0); */ i2c_stop(); return val; } static double readTempC(void) { uint16_t t = read16(0x05); double temp = t & 0x0FFF; temp /= 16.0; if (t & 0x1000) temp -= 256; return temp; }
Thanks.