Other Parts Discussed in Thread: MSP430F5529, CC430F5137, MSP430WARE, MSP430F5510
good morning everyone.
I took a pause in datasheet parsing only to find another bug, this time in the MSP430 DRIVERLIB.
bug description:
the USCI_B_I2C_masterReceiveMultiByteFinish() and USCI_B_I2C_masterReceiveMultiByteFinishWithTimeout() functions from DRIVERLIB/MSP430F5xx_6xx/usci_b_i2c.c v2.91.13.01 perform a read from the OFS_UCBxRXBUF register before the UCRXIFG flag is asserted. the consequences are that all the read operations that use those two functions will provide pure garbage.
proposed bug fix for the first function (patch):
--- driverlib/MSP430F5xx_6xx/usci_b_i2c.c 2020-02-27 20:48:53.000000000 +0200
+++ atlas430/driverlib/MSP430F5xx_6xx/usci_b_i2c.c 2021-12-05 17:33:18.264094116 +0200
@@ -446,16 +446,16 @@ uint8_t USCI_B_I2C_masterReceiveMultiByt
//Send stop condition.
HWREG8(baseAddress + OFS_UCBxCTL1) |= UCTXSTP;
- //Capture data from receive buffer after setting stop bit due to
- //MSP430 I2C critical timing.
- receiveData = HWREG8(baseAddress + OFS_UCBxRXBUF);
-
//Wait for Stop to finish
while (HWREG8(baseAddress + OFS_UCBxCTL1) & UCTXSTP);
//Wait for RX buffer
while (!(HWREG8(baseAddress + OFS_UCBxIFG) & UCRXIFG));
+ //Capture data from receive buffer after setting stop bit due to
+ //MSP430 I2C critical timing.
+ receiveData = HWREG8(baseAddress + OFS_UCBxRXBUF);
+
return receiveData;
}
to note is that this function appears 4 more times in this driverlib archive for different families and eusci/usci flavors and in all other places the read operation happens AFTER the IFG is checked.
unit test performed between a msp430f5529/cc430f5137 and a Cypress FM24V10 external i2c fram chip:
8 bytes written, 8 bytes read, repeated once.
Legend:
"i2c write" simply writes a buffer containing "0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8" to the external fram chip
"i2c read" simply attempts to read 8 bytes from the same address of the external fram chip, and the unpatched USCI_B_I2C_masterReceiveMultiByteFinish() is used when the last byte is being read.
"(prog)" what the buffer inside the firmware contains
"(wire)" what can be seen with a logic analyzer on the wire
"[foo]" explanation
in an ideal world the 'i2c read' must provide the exact same buffer as what has been written with 'i2c write' since the start address for both functions is the same.
i2c write (prog): 0xa1 0xa2 0xa3 0xa4 0xa5 0xa6 0xa7 0xa8 [ok]
i2c write (wire): 0xa1 0xa2 0xa3 0xa4 0xa5 0xa6 0xa7 0xa8 ACK [ok]
i2c read (wire): 0xa1 0xa2 0xa3 0xa4 0xa5 0xa6 0xa7 0xa8 NACK [ok]
i2c read (prog): 0xa1 0xa2 0xa3 0xa4 0xa5 0xa6 0xa7 0xa7 [last byte is read wrong]
i2c write (prog): 0xa1 0xa2 0xa3 0xa4 0xa5 0xa6 0xa7 0xa8 [ok]
i2c write (wire): 0xa1 0xa2 0xa3 0xa4 0xa5 0xa6 0xa7 0xa8 ACK [ok]
i2c read (wire): 0xa1 0xa2 0xa3 0xa4 0xa5 0xa6 0xa7 NACK [fail, a NAK is issued after the 7-th byte, not the 8-th one]
i2c read (prog): 0xa8 0xa1 0xa2 0xa3 0xa4 0xa5 0xa6 0xa6 [0xa8 is garbage from last read operation, remaining bytes are shifted]
TLDR: so without the patch the two functions provide garbage, with the patch tested on CC430F5137 and MSP430F5529 everything is great. please fix.