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.

MSP 430 I2C

I'm using I2C to communicate with an I2C slave. The code first tells the slave which register it wants to read, then reads from that address using a repeat start. Now this code was working, but now has stopped working partly because I removed breakpoints from the code. It is stopping at next to last line below, checking to make sure Start was sent.

I have read that it could be a CCS issue, so I have re-installed (CCSv6.1.1) but no change in behavior.

void Read_ID(void)

{

while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
WriteByte(ID_ADDR);
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
__no_operation(); // Remain in LPM0 until all data are sent
UCB0CTL1 ^= UCTR; // Switch to receive.
UCB0CTL1 |= UCTXSTT; // Send Repeat START
while(UCB0CTL1 & UCTXSTT); // Start condition sent?
UCB0CTL1 |= UCTXSTP; // I2C stop condition

}

  • Hi,

    I noticed a semicolon at your next to last line after the while statement, thus the last line will never be reached. Remove the semicolon, and the program should work as intended.

    Sincerely,
    Sean
  • Hi Sean,

    Thanks for providing feedback Sean. The while statement is intended as a check to make sure the START command is sent, before sending the STOP command. It wasn't working properly before I put that check in, taking a cue from the sample TI I2C driver code.

    If I put a breakpoint in the I2C receive interrupt, then the code works as expected, even after I then remove the interrupt and hit continue. But if I remove the breakpoint and let it run freely in CCS from the get go, the code gets stuck at that line checking for START sent. Seems like a timing issue to me, but can't for the life of me figure out what it is at the moment.
  • Hi,

    There was an issue with START condition checking in the default driverlib library I2C repeated start. Refer to the attached I2C code as it fixes the issue. In the meantime, I will try to find out why the breakpoint will make the code work as intended.

    i2c_driver.zip

    Sincerely,

    Sean

  • Hi Sean,

    I should have been more detailed in my original post and mentioned the specific MSP430 I am  using, and so may have misled you when I mentioned driver code.

    I am using a MSP430F55xx and the specific TI I2C driver file I am referring to is "MSP430F55xx_uscib0_i2c_04.c." The file is also attached. In this file, you will see the check for Repeat START sent, followed by the STOP command.

    Thanks.

    MSP430F55xx_uscib0_i2c_04.c
    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    /* --COPYRIGHT--,BSD_EX
    * Copyright (c) 2012, 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.
    *
    *******************************************************************************
    *
    * MSP430 CODE EXAMPLE DISCLAIMER
    *
    * MSP430 code examples are self-contained low-level programs that typically
    * demonstrate a single peripheral function or device feature in a highly
    * concise manner. For this the code may rely on the device's power-on default
    * register values and settings such as the clock configuration and care must
    * be taken when combining code from several examples to avoid potential side
    * effects. Also see www.ti.com/grace for a GUI- and www.ti.com/msp430ware
    * for an API functional library-approach to peripheral configuration.
    *
    * --/COPYRIGHT--*/
    //******************************************************************************
    // MSP430F552x Demo - USCI_B0 I2C Master RX single bytes from MSP430 Slave
    //
    // Description: This demo connects two MSP430's via the I2C bus. The master
    // reads from the slave. This is the MASTER CODE. The data from the slave
    // transmitter begins at 0 and increments with each transfer. The received
    // data is in R5 and is checked for validity. If the received data is
    // incorrect, the CPU is trapped and the P1.0 LED will stay on. The USCI_B0
    // RX interrupt is used to know when new data has been received.
    // ACLK = n/a, MCLK = SMCLK = BRCLK = default DCO = ~1.045MHz
    //
    // ***to be used with "MSP430F55xx_uscib0_i2c_05.c" ***
    //
    // /|\ /|\
    // MSP430F5529 10k 10k MSP430F5529
    // slave | | master
    // ----------------- | | -----------------
    // -|XIN P3.0/UCB0SDA|<-|----+->|P3.0/UCB0SDA XIN|-
    // | | | | | 32kHz
    // -|XOUT | | | XOUT|-
    // | P3.1/UCB0SCL|<-+------>|P3.1/UCB0SCL |
    // | | | P1.0|--> LED
    //
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

  • Hello,

    I've referenced your code and the sample master RX MSPware example and do note the check conditions, I have reached out and asked for working sample code relating to repeat start and will get back to you ASAP.

    Sincerely,
    Sean

  • Hi,

    Try replacing UCB0CTL1 ^= UCTR; with UCB0CTL1 &= ~UCTR; to switch it to receive mode. Let me know if that solves the issue.

    Sincerely,
    Sean
  • Hi Sean,

    Actually I had already converted the code to what you posted. Admittedly, the original code that I posted was not exactly good form for setting the I2C for receive. I am including the slightly modified version to the one I originally posted below.

    void Read_ID(void)
    {
    while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
    UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
    WriteByte(ID_ADDR);
    __bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
    __no_operation(); // Remain in LPM0 until all data are sent
    UCB0CTL1 = (UCB0CTL1 & ~UCTR ) | UCTXSTT; // Switch to receive and send Repeat START.
    while(UCB0CTL1 & UCTXSTT); // Start condition sent?
    UCB0CTL1 |= UCTXSTP; // I2C stop condition
    }


    There was no difference in behavior.
  • Tim,

    Please provide the initialization code for the I2C as well as any additional hardware you have between the SDA and SCL lines.

    Thanks,
    Michael Arriete
  • Hi,

    I've also asked around for a working example of repeat start, please consult the USCIB0_I2C_RX_MultiByte_Poll function in the attached code.

    uscib0_i2c_drv.c
    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    /*-===========================================================================--
    --- MODULE : uscib0_i2c_drv.c
    --- VERSION : 2.20
    ---===========================================================================---
    --- Environment : Device : MSP430G2553
    --- Compiler/Assembler/IDE : CCS V5.2
    ---=========================================================================---*/
    #include "msp430g2553.h"
    #include "application.h"
    #include "spi_il.h"
    #include "stdtypes.h"
    //***** Definitions *****
    typedef enum
    {
    OK = 0,
    ERROR
    }I2C_BusState_T;
    //***** Function Prototypes *****
    #ifndef USING_I2C_INT
    I2C_BusState_T USCIB0RX_ISR_Poll(void);
    I2C_BusState_T USCIB0TX_ISR_Poll(void);
    #endif
    //***** Global Data *****
    u08 locSlaveAddr;
    u08 TXByteCtr;
    u08 RXByteCtr;
    u08 *PTxData;
    u08 *PRxData;
    Boolean MultiByteReadFG = FALSE;
    Boolean WaitforSTPCondition = FALSE;
    #ifdef USING_I2C_INT
    Boolean RPTCondition = FALSE;
    #endif
    /***********************************************************
    Function: USCIB0_I2C_Init
    */
    void USCIB0_I2C_Init(void)
    {
    P1SEL |= BIT6 + BIT7; // Assign I2C pins to USCI_B0
    P1SEL2|= BIT6 + BIT7; // Assign I2C pins to USCI_B0
    IE2 &= ~UCB0RXIE; // Disable RX interrupt
    IE2 &= ~UCB0TXIE; // Disable TX interrupt
    UCB0CTL1 |= UCSWRST; // Enable SW reset
    UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
    UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
    UCB0BR0 = 0xA0; // fSCL = SMCLK/160 = ~100kHz
    // UCB0BR0 = 0x28; // fSCL = SMCLK/40 = ~400kHz
    UCB0BR1 = 0;
    }
    /***********************************************************
    Function: USCIB0_I2C_Ready
    */
    I2C_BusState_T USCIB0_I2C_Ready(void)
    {
    // Configure a 50ms Timeout
    Timeout(5);
    while ( ( UCB0STAT & UCBBUSY ) && (Timer_CCR1_Get_Timeout_Counts()) );
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    uscib0_i2c_drv.h

    Sincerely,

    Sean

  • Hi Michael, Sean,

    Below is the initialization code for I2C. I am also including the clock initialization for 430 just in case. SDA and SCL lines should be connected directly between the two devices but I will double check with the hardware engineer.

    void I2CInit(void)
    {
    // Transmit init
    WDTCTL = WDTPW + WDTHOLD; // Stop WDT
    P3SEL |= 0x03; // Assign I2C pins to USCI_B0
    UCB0CTL1 |= UCSWRST; // Enable SW reset
    UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
    UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
    UCB0BR0 = 12; // fSCL = SMCLK/12 = ~100kHz
    UCB0BR1 = 0;
    UCB0I2CSA = MySlave_ADDR; // Slave Address is 029h

    //P1OUT &= ~0x01; // P1.0 = 0
    //P1DIR |= 0x01; // P1.0 output

    UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
    UCB0IE |= UCTXIE; // Enable TX interrupt
    UCB0IE |= UCRXIE; // Enable RX interrupt
    UCB0IE |= UCNACKIE; // Enable NAK interrupt
    }

    void InitClk(void)
    {
    P5SEL |= BIT4+BIT5; // Select XT1

    UCSCTL6 &= ~(XT1OFF); // XT1 On
    UCSCTL6 |= XCAP_3; // Internal load cap
    UCSCTL3 = 0; // FLL Reference Clock = XT1

    // Loop until XT1,XT2 & DCO stabilizes - In this case loop until XT1 and DCo settle
    do
    {
    UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG); // Clear XT2,XT1,DCO fault flags
    SFRIFG1 &= ~OFIFG; // Clear fault flags
    }while (SFRIFG1&OFIFG); // Test oscillator fault flag

    UCSCTL6 &= ~(XT1DRIVE_3); // Xtal is now stable, reduce drive strength
    UCSCTL4 |= SELA_0; // ACLK = LFTX1 (by default)
    }
  • Tim,

    Have you also included pull-up resistors on the SDA and SCL lines?

    Regards,
    Michael Arriete
  • Hi Michael,

    The value of the pull-up resistor is 4.7k. Thanks.
  • Hi Sean,

    I have taken a look at the included files and don't see anything different other than a lot of delays in most of the functions. Not sure of the reason for them. They also seem to be fairly long delays, but then I'm not familiar with that particular processor.

    Thanks.
  • Hi Tim,

    Have you tried adding a delay after sending the repeat start, I asked around and it might be a timing issue since setting a breakpoint fixes it.

    Sincerely,
    Sean
  • Hi Sean,

    I would agree that this might be a timing issue from the behavior, but don't understand it at the moment. I put in a delay as you suggested (50 ms) right after the repeat start and it did not make things any better. Actually, the read function got worse and no longer returned correct values.

    Thanks.
  • Hi Tim,

    Referring to section 38.3.4.2.2 of the I2C Master Receiver Mode,
    Repeated START
    The UCTXSTT bit must be set before the last data byte is received; that is, immediately after
    the UCRXIFG is set and the UCRXBUF with the second to last byte is read, the UCTXSTT
    bit should be set.
    www.ti.com/.../slau208o.pdf

    Sincerely,
    Sean
  • Hi Sean,

    As in the single byte receive example that I modeled the code from, I set UCTXSTT immediately followed by UCTXSTP which should fulfill the requirement you quoted. What I didn't understand was the delay or where the timing issue is, but in any case that didn't appear to help.

    If I misunderstood anything, let me know.

    Thanks.
  • Hi Sean, Michael,

    Since this seems to be related to timing, I took a look at the timing. What I found is that I can get I2C clock line to work correctly up to 5.46K Hz, but higher than that, the clock line falls apart. I'm using a 32.76K Hz watch oscillator from XT1. Any ideas for me?

    Thanks,
    Tim
  • Hi Tim,

    This might be an issue with clock stretching,
    Clock Stretching: Some devices don't support clock stretching and the MSP430 I2C interface stretches the clock when it needs time to respond. This issue is not easy to detect but it usually generates "weird" signals when looked with an oscilloscope (i.e. half clock cycles)

    Possible solutions to this issue include:
    Running the MSP430 faster, decreasing the I2C frequency, or minimizing the latency usually helps
    eUSCI has an early interrupt feature which also helps

    Sincerely,
    Sean

**Attention** This is a public forum