I am struggling to get I2C working using the most recent DriverLib (contained in MspWare 1.90.00.03 to talk to an HMC5883L magnometer. (FWIW, it works fine with other MCU's, so it isn't a dead IC)
I am able to set the configuration registers, but any attempts to read data result in receiving one byte, and then the launchpad sending a NACK and ending the read. The communication (viewed by protocol analyzer) looks like this:
Decoding I2C serial bus transactions between the X1 and X2 cursors Please wait... START 0x3C Control Byte: Slave Address 1E Write ACK 0x47 ACK STOP START 0x3D Control Byte: Slave Address 1E Read ACK 0x 0 ACK 0x 0 NACK START 0x3C Control Byte: Slave Address 1E Write ACK 0x 0 ACK 0x67 ACK STOP START 0x3D Control Byte: Slave Address 1E Read ACK 0x20 ACK 0x83 NACK START 0x3C Control Byte: Slave Address 1E Write ACK 0x 0 ACK 0x 7 ACK STOP START 0x3D Control Byte: Slave Address 1E Read ACK 0x20 ACK 0x83 NACK START 0x3C Control Byte: Slave Address 1E Write ACK 0x 0 ACK 0x27 ACK STOP
Every send seems to work, but every read is failing. Here is the code I am using to try to read data:
uint8_t I2C_masterReadMultiple(uint8_t hmcRegister, uint8_t rxData[],
uint16_t rxLength, uint32_t timeout) {
uint8_t byte = 0;
uint16_t passedInLength = rxLength;
if (rxLength < 1) {
if (BackChannel_Connected())
BackChannel_WriteLine("Bad length passed in.");
return STATUS_FAIL;
}
USCI_B_I2C_setMode(HMCI2C_BASE, USCI_B_I2C_TRANSMIT_MODE);
USCI_B_I2C_disableInterrupt(HMCI2C_BASE, USCI_B_I2C_RECEIVE_INTERRUPT);
USCI_B_I2C_enableInterrupt(HMCI2C_BASE, USCI_B_I2C_TRANSMIT_INTERRUPT);
if (USCI_B_I2C_masterMultiByteSendStartWithTimeout(HMCI2C_BASE, hmcRegister,
timeout) == STATUS_FAIL) {
if (BackChannel_Connected())
BackChannel_WriteLine("Sending register address to slave failed.");
return STATUS_FAIL;
}
USCI_B_I2C_setMode(HMCI2C_BASE, USCI_B_I2C_RECEIVE_MODE);
USCI_B_I2C_disableInterrupt(HMCI2C_BASE, USCI_B_I2C_TRANSMIT_INTERRUPT);
USCI_B_I2C_enableInterrupt(HMCI2C_BASE, USCI_B_I2C_RECEIVE_INTERRUPT);
USCI_B_I2C_masterMultiByteReceiveStart(HMCI2C_BASE); //Not sure if needed
while (rxLength > 1) {
rxLength--;
while (~USCI_B_I2C_RECEIVE_INTERRUPT & UCRXIFG)
;
rxData[byte++] = USCI_B_I2C_masterMultiByteReceiveNext(HMCI2C_BASE);
}
while (~USCI_B_I2C_RECEIVE_INTERRUPT & UCRXIFG)
;
if (USCI_B_I2C_masterMultiByteReceiveFinishWithTimeout(
HMCI2C_BASE, (uint8_t *) (*rxData + byte), timeout) == STATUS_SUCCESS) {
rxLength = passedInLength;
return rxLength;
}
return STATUS_FAIL;
}
Failure always occurs on the last call to USCI_B_I2C_masterMultiByteReceiveFinishWithTimeout (part of the Driver Library) which is:
//*****************************************************************************
//
//! \brief Finishes multi-byte reception at the Master end with timeout
//!
//! This function is used by the Master module to initiate completion of a
//! multi-byte reception. This function does the following: - Receives the
//! current byte and initiates the STOP from Master to Slave
//!
//! \param baseAddress is the base address of the I2C Master module.
//! \param rxData is a pointer to the location to store the received byte at
//! master end
//! \param timeout is the amount of time to wait until giving up
//!
//! Modified bits are \b UCTXSTP of \b UCBxCTL1 register.
//!
//! \return STATUS_SUCCESS or STATUS_FAILURE of the transmission process.
//
//*****************************************************************************
bool USCI_B_I2C_masterMultiByteReceiveFinishWithTimeout(uint16_t baseAddress,
uint8_t *rxData, uint32_t timeout) {
assert(timeout > 0);
uint32_t timeout2 = timeout;
//Send stop condition.
HWREG8(baseAddress + OFS_UCBxCTL1) |= UCTXSTP;
//Capture data from receive buffer after setting stop bit due to
//MSP430 I2C critical timing.
*rxData = (HWREG8(baseAddress + OFS_UCBxRXBUF));
//Wait for Stop to finish
while ((HWREG8(baseAddress + OFS_UCBxCTL1) & UCTXSTP) && --timeout)
;
//Check if transfer timed out, then reset
if (timeout == 0)
return STATUS_FAIL;
timeout = timeout2;
// Wait for RX buffer
while ((!(HWREG8(baseAddress + OFS_UCBxIFG) & UCRXIFG)) && --timeout)
;
//Check if transfer timed out
if (timeout == 0) {
_nop();
return STATUS_FAIL;
}
return STATUS_SUCCESS;
}
The failure always occurs by timing out while waiting for the STOP condition.
What am I doing wrong? Why isn't the MSP430 detecting the stop condition? Why is it generating a NACK?