Actually I try to set up a TWI slave with the ATmega328PB (2 TWI ports).
The master is running with Peter Fleurys I2C library on a ATmega328P (1 TWI port).
With the master I'm checking, if the TWI slave is available on a specific address:
/************************************************************************* Issues a start condition and sends address and transfer direction. return 0 = device accessible, 1= failed to access device *************************************************************************/ unsigned char i2c_start(unsigned char address) { uint8_t twst; // send START condition TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); // wait until transmission completed while(!(TWCR & (1<<TWINT))); // check value of TWI Status Register. Mask prescaler bits. twst = TW_STATUS & 0xF8; if ( (twst != TW_START) && (twst != TW_REP_START)) return 1; // send device address TWDR = address; TWCR = (1<<TWINT) | (1<<TWEN); // wail until transmission completed and ACK/NACK has been received while(!(TWCR & (1<<TWINT))); // check value of TWI Status Register. Mask prescaler bits. twst = TW_STATUS & 0xF8; if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1; return 0; }/* i2c_start */
This works fine, as you can see on the picture of the scope (attached).
Now the problem is, that the slave should give an acknowledge, and, as I understand the procedure, should release the SDA-line level back to high (green line).
But SDA is still beeing pulled low by the slave. If I switch off the slave mcu (SDA released), then suddenly the master reports that the slave would be available...
The slave is initialized this way:
void init_twi_slave(uint8_t adr) { TWAR0= adr << 1; // set twi slave address (skip over TWGCE bit) TWCR0 &= ~(1<<TWSTA)|(1<<TWSTO); TWCR0|= (1<<TWEA) | (1<<TWEN)|(1<<TWIE); buffer_adr=0xFF; sei(); }
When the master is requesting the slave, the ISR of the slave comes up with the TW_STATUS = 0xA8 (..I send TW_STATUS over UART to check)
ISR (TWI0_vect) { .... ... case TW_ST_SLA_ACK: // 0xA8: SLA+R received, ACK returned case TW_ST_DATA_ACK: // 0xB8: data transmitted, ACK received if (i2c_state == 1) { i2c_slave_action(0); // Call Read I2C Action (rw_status = 0) TWDR = regdata; // Store data in TWDR register i2c_state = 0; // Reset I2C State } TWCR |= (1<<TWINT); // Clear TWINT Flag break; case TW_ST_DATA_NACK: // 0xC0: data transmitted, NACK received case TW_ST_LAST_DATA: // 0xC8: last data byte transmitted, ACK received case TW_BUS_ERROR: // 0x00: illegal start or stop condition default: TWCR |= (1<<TWINT); // Clear TWINT Flag }
Doesn't TW_STATUS = 0xA8 mean, that the mcu should have already released the SDA line?
Any ideas, how to fix this or where I'm going wrong?
Many Thanks!