Part Number: MSP432P401R
Hi,
I'm having some trouble reading data over I2C with the MSP432P401R. I'm working off of the i2c_master_rw_repeated_start_master_code nortos driverlib example project. Here is that code with a few modifications:
#include <ti/devices/msp432p4xx/driverlib/driverlib.h> /* Standard Defines */ #include <stdint.h> #include <stdbool.h> #include <string.h> /* Slave Address for I2C Slave */ #define SLAVE_ADDRESS 0x52 #define NUM_OF_REC_BYTES 2 /* Variables */ const uint8_t TXData[] = {0x32}; static uint8_t RXData[NUM_OF_REC_BYTES]; static volatile uint32_t xferIndex; static volatile bool stopSent; /* I2C Master Configuration Parameter */ const eUSCI_I2C_MasterConfig i2cConfig = { EUSCI_B_I2C_CLOCKSOURCE_SMCLK, // SMCLK Clock Source 3000000, // SMCLK = 3MHz EUSCI_B_I2C_SET_DATA_RATE_100KBPS, // Desired I2C Clock of 100khz 0, // No byte counter threshold EUSCI_B_I2C_NO_AUTO_STOP // No Autostop }; int main(void) { /* Disabling the Watchdog */ MAP_WDT_A_holdTimer(); /* Select Port 1 for I2C - Set Pin 6, 7 to input Primary Module Function, * (UCB0SIMO/UCB0SDA, UCB0SOMI/UCB0SCL). */ MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1, GPIO_PIN6 + GPIO_PIN7, GPIO_PRIMARY_MODULE_FUNCTION); stopSent = false; memset(RXData, 0xFF, NUM_OF_REC_BYTES); /* Initializing I2C Master to SMCLK at 100khz with no autostop */ MAP_I2C_initMaster(EUSCI_B0_BASE, &i2cConfig); /* Specify slave address */ MAP_I2C_setSlaveAddress(EUSCI_B0_BASE, SLAVE_ADDRESS); /* Enable I2C Module to start operations */ MAP_I2C_enableModule(EUSCI_B0_BASE); MAP_Interrupt_enableInterrupt(INT_EUSCIB0); /* Making sure the last transaction has been completely sent out */ while (MAP_I2C_masterIsStopSent(EUSCI_B0_BASE)); MAP_Interrupt_enableSleepOnIsrExit(); /* Send start and the first byte of the transmit buffer. */ MAP_I2C_masterSendMultiByteStart(EUSCI_B0_BASE, TXData[0]); /* Sent the first byte, now we need to initiate the read */ xferIndex = 0; MAP_I2C_masterReceiveStart(EUSCI_B0_BASE); MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0); // MAP_PCM_gotoLPM0InterruptSafe(); while (1); } /******************************************************************************* * eUSCIB0 ISR. The repeated start and transmit/receive operations happen * within this ISR. *******************************************************************************/ void EUSCIB0_IRQHandler(void) { uint_fast16_t status; status = MAP_I2C_getEnabledInterruptStatus(EUSCI_B0_BASE); MAP_I2C_clearInterruptFlag(EUSCI_B0_BASE, status); /* Receives bytes into the receive buffer. If we have received all bytes, * send a STOP condition */ if (status & EUSCI_B_I2C_RECEIVE_INTERRUPT0) { if (xferIndex == NUM_OF_REC_BYTES - 2) { MAP_I2C_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0); MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_STOP_INTERRUPT); /* * Switch order so that stop is being set during reception of last * byte read byte so that next byte can be read. */ MAP_I2C_masterReceiveMultiByteStop(EUSCI_B0_BASE); RXData[xferIndex++] = MAP_I2C_masterReceiveMultiByteNext( EUSCI_B0_BASE); } else { RXData[xferIndex++] = MAP_I2C_masterReceiveMultiByteNext( EUSCI_B0_BASE); } } else if (status & EUSCI_B_I2C_STOP_INTERRUPT) { // MAP_Interrupt_disableSleepOnIsrExit(); MAP_I2C_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_STOP_INTERRUPT); } }
I'm a little confused as to how the code in the interrupt handler works. Specifically this section:
if (status & EUSCI_B_I2C_RECEIVE_INTERRUPT0) { if (xferIndex == NUM_OF_REC_BYTES - 2) { MAP_I2C_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0); MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_STOP_INTERRUPT); /* * Switch order so that stop is being set during reception of last * byte read byte so that next byte can be read. */ MAP_I2C_masterReceiveMultiByteStop(EUSCI_B0_BASE); RXData[xferIndex++] = MAP_I2C_masterReceiveMultiByteNext( EUSCI_B0_BASE); } else { RXData[xferIndex++] = MAP_I2C_masterReceiveMultiByteNext( EUSCI_B0_BASE); } }
The most confusing part to me is why the stop function is called before the receive next byte function. With this code I get the following activity on my I2C bus:
Which would be good, except I don't understand why the last byte is NAK. Additionally, with this code, the second index of my rxArray is not updated with the received value.
So my attempt to fix this was by editing the interrupt handler :
if (status & EUSCI_B_I2C_RECEIVE_INTERRUPT0) { RXData[xferIndex++] = MAP_I2C_masterReceiveMultiByteNext(EUSCI_B0_BASE); if (xferIndex == NUM_OF_REC_BYTES ) { MAP_I2C_masterReceiveMultiByteStop(EUSCI_B0_BASE); MAP_I2C_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0); MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_STOP_INTERRUPT); } }
This works more like what I would expect, except this reads an additional byte which is also NAK.
So clearly, I'm misunderstanding something about how I2C works on the MSP432. I would appreciate it very much if someone could help me figure out what that is.
Thanks,
Adam