This has me absolutely stumped, I've looked over the data sheet, user's guide, errata sheet and have no idea what I did wrong or how to do anything about it.
Some context:
This I2C implementation uses polling (See issue USCI29 in SLAZ440H)
No repeated start conditions are used (See issue USCI35 in SLAZ440H)
Bus speed is 100KHz with 4.7k pull-up resistors, P1.6 jumper is removed. I'm using the launchpad for the MSP430G2 series, rev 1.5.
The goal of this application is to read from register INTCAPB on an MCP23018, when INTB (connected to P2.2) interrupts. The P2 interrupt sets a software flag, and this triggers a write to set the register address then a subsequent read from register INTCAPB.
Yes, I have read Solutions to Common eUSCI and USCI Serial Communication Issues on MSP430™ MCUs (SLAA734) and the I2C example code for my device. I tried the TI I2C implementation and the I2C interrupts resulted in a call to the TRAPINT, trapping the program counter.
Now to the symptoms:
As you can see from the logic analyzer output, at first the START and STOP conditions are within I2C spec and are acknowledged. They remain so until the end of the most recent write transaction. Neither the slave, nor the logic analyzer recognize the following read transaction.
Setting a breakpoint right after the STOP condition seems to fix the issue by leaving a massive gap between the STOP and START condition but I haven't been able to resolve the issue otherwise. When debugging I've found this is the offending code:
if (status & I2C_REG_SET) { // If setting the register counter for a later read operation if (status & KEYPAD_READ) { // If reading the state of the keypad // MCP23018's address will already be loaded if (UCB0TXBUF == INTCAPB) { // If the last byte sent was INTCAPB // Control byte was successfully sent // Now the STOP condition can be sent, wait 4.7us, then send START condition as a receiver status &= ~I2C_REG_SET; // Reset I2C_REG_SET bit, the counter was successfully sent UCB0CTL1 |= UCTXSTP; // Send STOP condition while(UCB0CTL1 & UCTXSTP); // Ensure STOP condition is finished before proceeding __delay_cycles(Tbuf); // Delay 4.7us (1/SMCLK * 75) UCB0CTL1 &= ~UCTR; // Become reciever UCB0CTL1 |= UCTXSTT; // Send START condition } else { // Otherwise: UCB0TXBUF = INTCAPB; // Send INTCAPB as the register number byte i2c_i = INTCAPB; // Update the master's copy of the register iterator __delay_cycles(Tbuf); // Delay 4.7us (1/SMCLK * 75) } } }