This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Part Number: MSP432P401R
Tool/software: Code Composer Studio
Hi all,
The problem with the i2c driver is I can't do a write after a single byte read.
I've tested and can read 2, 4, up to 32 bytes after a write, no problem, but if I do a read 1 byte, the next write waits for a transmit interrupt that never occurs.
I can clear the error by doing another write followed by then write then reading more than 1 byte - which sometimes fails and sometimes does not, and sometimes this takes two write-read cycles to clear.
Using bus pirate to write / read the i2c bus or single byte reads is not a problem (i.e. generating independent ground truth), which more or less leads me to conclude it is a problem with the 432 chip or with the driverlib.
Using this forum, I see other people have had the same or similar problems- that appear unresolved, which leads me to conclude that is just might be a real problem and not me.
Any help - in either direction - from you to me or from me to you? I can run tests, I can send you code, whatever...
thx,
bob s.
I just found a bug (my own) on the transmit side - always transmitting 0 and not the intended data, however this does not affect the problem I'm seeing on the receive side.
Thanks Robert. I still need to digest the earlier posts. I have put together an example based upon the example that you cite but I need to touch base with the designers because there appears to be an issue in knowing when to set the stop if only one byte is being received. You will find a 'hack' in my code to try and time the setting of the stop within the receive byte per the TRM ( Figure 24-13). Please let me know if you have any questions about the code.
Best Regards,
Chris
/* * ------------------------------------------- * MSP432 DriverLib - v3_50_00_02 * ------------------------------------------- * * --COPYRIGHT--,BSD,BSD * Copyright (c) 2016, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * --/COPYRIGHT--*/ /****************************************************************************** * MSP432 I2C - EUSCI_B0_BASE I2C Master TX bytes to MSP432 Slave - Repeated Start * * Description: This demo connects two MSP432 's via the I2C bus. The master * transmits to the slave. This is the MASTER CODE. It continuously * transmits an array of data and demonstrates how to implement an I2C * master transmitter sending multiple bytes followed by a repeated start, * followed by a read of multiple bytes. This is a common operation for * reading register values from I2C slave devices such as sensors. The * transaction for the I2C that is written looks as follows: * * ________________________________________________________________ * | Start | | | Start | | | * | 0x48Addr | 0x04 | 0x00 | 0x48Addr | <10 Byte Read> | Stop | * | W | | | R | | | * |__________|______|______|__________|___________________|_______| * * ACLK = n/a, MCLK = HSMCLK = SMCLK = BRCLK = default DCO = ~8.0MHz * * /|\ /|\ * MSP432P401 10k 10k MSP432P401 * slave | | master * ----------------- | | ----------------- * | P1.6/UCB0SDA|<-|----+->|P1.6/UCB0SDA | * | | | | | * | | | | | * | P1.7/UCB0SCL|<-+------>|P1.7/UCB0SCL | * | | | | * * Author: Timothy Logan *****************************************************************************/ /* DriverLib Defines */ #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 0x48 #define NUM_OF_TX_BYTES 2 /* * minimum number is 2, otherwise special handling is needed. */ #define NUM_OF_RX_BYTES 2 //#define NUM_OF_RX_BYTES_IS_ONE /* Variables */ const uint8_t TXData[NUM_OF_TX_BYTES] = {NUM_OF_TX_BYTES, NUM_OF_RX_BYTES}; static uint8_t RXData[NUM_OF_RX_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 8000000, // SMCLK = 8MHz 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) { volatile uint32_t ii; /* Disabling the Watchdog */ MAP_WDT_A_holdTimer(); MAP_FPU_enableModule(); /* Set the core voltage level to VCORE1 */ MAP_PCM_setCoreVoltageLevel(PCM_VCORE0); /* Set 2 flash wait states for Flash bank 0 and 1*/ MAP_FlashCtl_setWaitState(FLASH_BANK0, 0); MAP_FlashCtl_setWaitState(FLASH_BANK1, 0); /* Initializes Clock System */ MAP_CS_setDCOFrequency(8000000); //8Mhz MAP_CS_initClockSignal(CS_MCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1 ); MAP_CS_initClockSignal(CS_HSMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1); MAP_CS_initClockSignal(CS_SMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1); MAP_CS_initClockSignal(CS_ACLK, CS_REFOCLK_SELECT, CS_CLOCK_DIVIDER_1); MAP_CS_initClockSignal(CS_BCLK, CS_REFOCLK_SELECT, CS_CLOCK_DIVIDER_1); /* 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, 0x00, NUM_OF_RX_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); /* Set Master in transmit mode */ MAP_I2C_setMode(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_MODE); /* Enable I2C Module to start operations */ MAP_I2C_enableModule(EUSCI_B0_BASE); /* Enable and clear the interrupt flag */ MAP_I2C_clearInterruptFlag(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0 + EUSCI_B_I2C_RECEIVE_INTERRUPT0); //Enable master Receive interrupt /* * */ // MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0); MAP_Interrupt_enableSleepOnIsrExit(); MAP_Interrupt_enableInterrupt(INT_EUSCIB0); while (1) { /* Making sure the last transaction has been completely sent out */ // while (MAP_I2C_masterIsStopSent(EUSCI_B0_BASE) == EUSCI_B_I2C_SENDING_STOP); /* * Set and reset the eUSCI */ // MAP_I2C_disableModule(EUSCI_B0_BASE); // MAP_I2C_clearInterruptFlag(EUSCI_B0_BASE, 0xFFFFFFFFFFFFFFFF); // MAP_I2C_enableModule(EUSCI_B0_BASE); /* Send start and the first byte of the transmit buffer. We have to send * two bytes to clean out whatever is in the buffer from a previous * send */ MAP_I2C_masterSendStart(EUSCI_B0_BASE); // MAP_I2C_masterSendMultiByteStart(EUSCI_B0_BASE, TXData[0]); // MAP_I2C_masterSendMultiByteNext(EUSCI_B0_BASE, TXData[0]); MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0); /* While the stop condition hasn't been sent out... */ while(!stopSent) { MAP_PCM_gotoLPM0InterruptSafe(); } stopSent = false; } } /******************************************************************************* * 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); /* If we reached the transmit interrupt, it means we are at index 1 of * the transmit buffer. When doing a repeated start, before we reach the * last byte we will need to change the mode to receive mode, set the start * condition send bit, and then load the final byte into the TXBUF. */ if (status & EUSCI_B_I2C_TRANSMIT_INTERRUPT0) { MAP_I2C_masterSendMultiByteNext(EUSCI_B0_BASE, TXData[xferIndex++]); if(xferIndex == NUM_OF_TX_BYTES) { MAP_I2C_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0); /* * Debug to get to work * wait until IFG is set before continuing on */ while (!BITBAND_PERI(EUSCI_B_CMSIS(EUSCI_B0_BASE)->IFG, EUSCI_B_IFG_TXIFG0_OFS)) ; MAP_I2C_setMode(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_MODE); xferIndex = 0; MAP_I2C_masterReceiveStart(EUSCI_B0_BASE); #ifdef NUM_OF_RX_BYTES_IS_ONE /* * Once the start is complete, the recieve will happen automatically * during this receive the stop condition must be set. Waiting for * start bit to be automatically cleared is too short and waiting for * rx ifg is too short (and not recommended). */ while (BITBAND_PERI(EUSCI_B_CMSIS(EUSCI_B0_BASE)->CTLW0, EUSCI_B_CTLW0_TXSTT)) ; __delay_cycles(1000); /* * top is being set during reception of last byte * read byte so that next byte can be read */ MAP_I2C_masterReceiveMultiByteStop(EUSCI_B0_BASE); MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_STOP_INTERRUPT); #else MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0); #endif } } /* Receives bytes into the receive buffer. If we have received all bytes, * send a STOP condition */ #ifndef NUM_OF_RX_BYTES_IS_ONE if (status & EUSCI_B_I2C_RECEIVE_INTERRUPT0) { /* * This does not make any sense when NUM_OF_RX_BYTES is 1 */ if(xferIndex == NUM_OF_RX_BYTES - 2) { /* * Let's try triggering last byte from STOP instead of RXIFG */ 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); } } #endif /* * Add stop handler */ if (status & EUSCI_B_I2C_STOP_INTERRUPT) { RXData[xferIndex] = MAP_I2C_masterReceiveMultiByteNext(EUSCI_B0_BASE); MAP_I2C_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_STOP_INTERRUPT); MAP_I2C_setMode(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_MODE); xferIndex = 0; stopSent = true; MAP_Interrupt_disableSleepOnIsrExit(); } }
/* * ------------------------------------------- * MSP432 DriverLib - v3_50_00_02 * ------------------------------------------- * * --COPYRIGHT--,BSD,BSD * Copyright (c) 2016, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * --/COPYRIGHT--*/ /****************************************************************************** * MSP432 I2C - EUSCI_B0_BASE I2C Master TX bytes to MSP432 Slave - Repeated Start * * Description: This demo connects two MSP432 's via the I2C bus. The master * transmits to the slave. This is the SLAVE CODE. It continuously * transmits an array of data and demonstrates how to implement an I2C * master transmitter sending multiple bytes followed by a repeated start, * followed by a read of multiple bytes. This is a common operation for * reading register values from I2C slave devices such as sensors. The * transaction for the I2C that is written looks as follows: * * ________________________________________________________________ * | Start | | | Start | | | * | 0x48Addr | 0x04 | 0x00 | 0x48Addr | <10 Byte Read> | Stop | * | W | | | R | | | * |__________|______|______|__________|___________________|_______| * * ACLK = n/a, MCLK = HSMCLK = SMCLK = BRCLK = default DCO = ~3.0MHz * * /|\ /|\ * MSP432P401 10k 10k MSP432P401 * slave | | master * ----------------- | | ----------------- * | P1.6/UCB0SDA|<-|----+->|P1.6/UCB0SDA | * | | | | | * | | | | | * | P1.7/UCB0SCL|<-+------>|P1.7/UCB0SCL | * | | | | * * Author: CTS *****************************************************************************/ /* DriverLib Includes */ #include <ti/devices/msp432p4xx/driverlib/driverlib.h> /* Standard Includes */ #include <stdint.h> #include <stdbool.h> /* Application Defines */ #define SLAVE_ADDRESS 0x48 #define NUM_OF_RX_BYTES 2 #define NUM_OF_TX_BYTES 10 /* Application Variables */ static volatile uint8_t RXData[NUM_OF_RX_BYTES]; static volatile uint32_t xferIndex, txferMax; const uint32_t TXData[NUM_OF_TX_BYTES + 1] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x10 }; int main(void) { /* Disabling the Watchdog */ MAP_WDT_A_holdTimer(); xferIndex = 0; /* 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); P1->OUT |= (BIT6+BIT7); // lazy pullups P1->REN |= (BIT6+BIT7); /* eUSCI I2C Slave Configuration */ MAP_I2C_initSlave(EUSCI_B0_BASE, SLAVE_ADDRESS, EUSCI_B_I2C_OWN_ADDRESS_OFFSET0, EUSCI_B_I2C_OWN_ADDRESS_ENABLE); /* Enable the module and enable interrupts */ MAP_I2C_enableModule(EUSCI_B0_BASE); MAP_I2C_clearInterruptFlag(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0); MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0); MAP_Interrupt_enableInterrupt(INT_EUSCIB0); MAP_Interrupt_enableSleepOnIsrExit(); MAP_Interrupt_enableMaster(); /* Sleeping while not in use */ while (1) { MAP_PCM_gotoLPM0(); } } /******************************************************************************* * 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); /* RXIFG */ if (status & EUSCI_B_I2C_RECEIVE_INTERRUPT0) { RXData[xferIndex++] = MAP_I2C_slaveGetData(EUSCI_B0_BASE); /* Resetting the index if we are at the end */ if (xferIndex == NUM_OF_RX_BYTES) { txferMax = RXData[NUM_OF_RX_BYTES-1]; xferIndex = 0; MAP_I2C_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0); MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_START_INTERRUPT); } } /* TXIFG */ if (status & EUSCI_B_I2C_TRANSMIT_INTERRUPT0) { MAP_I2C_slavePutData(EUSCI_B0_BASE, TXData[xferIndex++]); /* Resetting the index if we are at the end */ if (xferIndex == txferMax) { xferIndex = 0; MAP_I2C_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0); MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0); } } /* STIFG */ if (status & EUSCI_B_I2C_START_INTERRUPT) { MAP_I2C_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_START_INTERRUPT); MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0); } }
Hi, Chris,
Thank you for acknowledging the issue.
In the example you sent, the "stop-interrupt" call tmade in the interrupt handler occurs at the next-to-last byte read.
My issue is, for a single byte read, there is NO "next-to-last" byte.
Am I understanding the code and your explanation correctly?
If I modify my code to enable EUSCI_B_I2C_STOP_INTERRUPT, and make the stop-interrupt call on the last byte, will this solve the problem as is,
or do I need to make a dummy read to actually trigger the stop interrupt?
bob s.
Hi,
I have something usable now, which is basically a tailoring of your code + what I was using from the other examples.
I noticed you are using core freq 8Mhz, and I am using core 48 Mhz. This affects the value of the delays.
Given that embedded devices should NEVER lock up, when you push your example to an official release, you might want to rewrite your wait loops.
Here's what I've done that provides feedback if status never comes true, and this type of thing occurs in multiple spots in the driver:
for (ii=0; ii<5; ii++)
{
/*
* Not sure if it is an error if the bit never comes true but
* definitely don't want to lock up
*/
__delay_cycles(1000);
if (BITBAND_PERI(EUSCI_B_CMSIS(EUSCI_B2_BASE)->CTLW0, EUSCI_B_CTLW0_TXSTT))
{
; // still waiting
}
else
{
match_f = true; // ready
break; // exit loop
}
}
if (!match_f)
i2c_tmo2_f = true;
**Attention** This is a public forum