Part Number: MSP430F5529
I'm writing a basic I2C library for the MSP430F5529, and I've noticed some conflicting information in the family reference manual for the MSP430F5xxx series. Under the I2C register description section, the UCTXSTT bit (which generates a START and also sends the peripheral address) reads as follows:
It says it is cleared immediately after the START and address are sent. However, in the section describing how to start communication with a peripheral, this is what it says (emphasis mine):
The problem is that this doesn't seem to be true. If I set a while loop to poll for UCTXSTT being cleared, it *always* passes, even if the peripheral has sent a NACK (I can see on my logic analyzer that it is indeed sending a NACK). So the information from the register description section seems to be true. If I send a START condition, and then go into checking for UCNACKIFG in UCB0IFG, even with a delay, this also gets skipped even when the peripheral is sending a nack:
UCB0CTL1 |= UCTR + UCTXSTT; // send a START and address
__delay_cycles(ACK_DELAY); // wait long enough for the peripheral to ack/nack
if (UCB0IFG & UCNACKIFG) { // peripheral n'acked on address
UCB0CTL1 |= UCTXSTP;
UCB0IFG &= ~UCTXIFG;
while(UCB0CTL1 & UCTXSTP) ; // wait for STOP to complete
return NACK_ADDR;
}
That ACK_DELAY is 450 cycles, which should be more than enough. What ends up happening in my code, then, is it goes to send data, loads data in the buffer, and THEN seems to detect a NACK and quit, even though we should have returned before trying to load data into the transmit buffer.
What is the proper way to handle this? How can I detect a NACK on address before loading the transmit buffer?
EDIT: Looking at the flow chart on page 1006 (right after the Transmitter Mode page) it seems we must load the TXBUF first, and then check for NACK on address. So, I tried using this mess:
case WRITE:
UCB0CTL1 |= UCTR + UCTXSTT; // send a START and address
UCB0TXBUF = *(data + i); // we have to send the first byte to be able to check if an address nack happened
__delay_cycles(ACK_DELAY); // wait long enough for the peripheral to ack/nack
if (!(UCB0CTL1 & UCTXSTT) && (UCB0IFG & UCNACKIFG)) {
UCB0CTL1 |= UCTXSTP;
while(UCB0CTL1 & UCTXSTP) ; // wait for STOP to complete
return NACK_ADDR;
}
for (i = 1; i < length; i++) {
UCB0TXBUF = *(data + i); // send data
if (UCB0IFG & UCNACKIFG) { // the peripheral nack'd
UCB0CTL1 |= UCTXSTP; // send a stop
UCB0IFG &= ~UCTXIFG;
while(UCB0CTL1 & UCTXSTP) ; // wait for STOP to complete
return NACK_DATA;
}
}
UCB0CTL1 |= UCTXSTP; // send stop
break;
But now we are somehow making it to the end of this switch statement, and so the function is returning SUCCESS even though it shouldn't even get past the first if statement! I am seriously confused as to why this is happening.
EDIT 2:
I was very close with my first edit, but I just needed to check UCTXIFG before sending data, then wait for UCTXSTT afterward:
case WRITE:
UCB0CTL1 |= UCTR + UCTXSTT; // send a START and address
while (!(UCB0IFG & UCTXIFG)) ; // wait until data can be written
UCB0TXBUF = *(data + i); // we have to send the first byte to be able to check if an address nack happened
while(UCB0CTL1 & UCTXSTT) ; // wait for start condition done
if (!(UCB0CTL1 & UCTXSTT) && (UCB0IFG & UCNACKIFG)) {
UCB0CTL1 |= UCTXSTP;
while(UCB0CTL1 & UCTXSTP) ; // wait for STOP to complete
return NACK_ADDR;
}
for (i = 1; i < length; i++) {
UCB0TXBUF = *(data + i); // send data
while(!(UCB0IFG & UCTXIFG)) ; // wait for buffer to be clear
if (UCB0IFG & UCNACKIFG) { // the peripheral nack'd
UCB0CTL1 |= UCTXSTP; // send a stop
while(UCB0CTL1 & UCTXSTP) ; // wait for STOP to complete
return NACK_DATA;
}
}
UCB0CTL1 |= UCTXSTP; // send stop
break;
Now I'm having a totally different issue with reads, but I'll work that out....

