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.

MSP430G - Repeated Start on I2C using USI

Hi. I was wondering whether it is possible to implement a repeated start I2C command on the USI of the MSP430G series. None of the code examples seem to show it, unless I have missed something. Perhaps it is not possible with the architecture, particularly the low power design with a default state of "high" on both clock and data? Thanks.

  • The USI support for I2C is rather limited.

    Start and stop condition are generated by writing the required line state to the MSB of USISRL while SCL i shigh, and then shortly making the latch transparent (which will output and latch the MSB immediately without clock signal. This high-to-low or low-to-high transition is the start or stop condition.

    So you can generate as many start and stop condition as you want. Note that SDA going high again after a start condition while SCL is still high, is an immediate stop condition. So it is (naturally) impossible to have two start conditions in a series. You'd have to produce a clock cycle to pull SDA high again without generating a stop before the next start.

    To have a repeated start condition, it is necessary, that either you responded with a NACK to the last byte you received or the slave responded with a NACK to the last byte you sent or you generate a surplus clock cycle with a high-bit, so SDA is high when SCL goes high. Else you cannot generate a repeated start.
    A stop condition can be only produces when the last transmitted bit was low, so either you or the slave responded with an ACK or you generated a surplus low bit.

    It's valid to generate a dummy (re)start condition after the last clock cycle (which migh tnot be noticed because SDA is still low), just the follow it with a stop condition.
    A slave ACK, however, will not be removed from the bus (and therefore prevent a stop condition) unless you provide an additional clock cycle.

    It's rather complex stuff.

    See section 14.2.4.2 to 14.2.4.7 in the 2x family users guide for all that has been published about this. :(

    USI I2c is not much more than what you'd do for a plain software I2C, mixed with a clock generator and a shift register. It wasn't even worth its own chapter in the users guide. ;)
    I'm happy I never had to deal with this in my projects.
    The USCI I2C, however, is a completely different thing.

  • Thanks Jens-Michael! At least I know where things stand now! Yes looks complicated to do and probably not worth the risk. Being able to do a repeated start would have meant I could do a faster burst mode transfer from the accelerometer I am interfacing with and avoid timing issues - but cest la vie!

  • Just FYI,

    If interested you can check out the USI code Library on www.msp430.com --> code examples tab.

    The master code examples have a parameter 'multi' that lets the USI decide if a stop needs to be sent or not.

    If multi = 1, then no stop i sent and the next transaction sends a restart.

    Regards,

    Priya

  • Jens-Michael,

    Jens-Michael Gross said:

    To have a repeated start condition, it is necessary, that either you responded with a NACK to the last byte you received or the slave responded with a NACK to the last byte you sent or you generate a surplus clock cycle with a high-bit, so SDA is high when SCL goes high. Else you cannot generate a repeated start.
    A stop condition can be only produces when the last transmitted bit was low, so either you or the slave responded with an ACK or you generated a surplus low bit.

    It's valid to generate a dummy (re)start condition after the last clock cycle (which migh tnot be noticed because SDA is still low), just the follow it with a stop condition.
    A slave ACK, however, will not be removed from the bus (and therefore prevent a stop condition) unless you provide an additional clock cycle.

    Thank you so much for explaining this clearly.

    I figured that if you want to do a repeated start after receiving an ACK from the slave, you have to:

    1. set USIOE to 1;
    2. Load MSB of USISRL with 1 (for example USISRL = 0xFF);
    3. set USICNT to 1 to generate a surplus clock cycle

    An example of this is in slac463a, under msp430g2x21_usi_16.c


  • Dear Priya,

    I tried this part of the example with and I/O Expander (PCF8574) and I noticed that the program executes all lines but it didn't send anything  via IIC bus.

    I would like to know if I made a mistake in this code.

    Thanks for your advice,

    Andres Rada.

     

    #include<msp430g2231.h>

    #include "USI_I2CMaster.h"

    unsigned char TxData0[] = {8};

    int StatusCallback(unsigned char c);  

     

    void main(void)

    {

      int i;

      WDTCTL = WDTPW+WDTHOLD;                   // Stop watchdog

      if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF)                                     

      {  

        while(1);                               // If calibration constants erased

                                                // do not load, trap CPU!!

      } 

      BCSCTL1 = CALBC1_1MHZ;                    // Load DCO constants

      DCOCTL = CALDCO_1MHZ;

      P1DIR |= 0x01;                            // P1.0 as output (LED)

      P1OUT = 0x00;

     

      /* Initialize USI module, clock ~ SMCLK/128 */

      TI_USI_I2C_MasterInit(USIDIV_7+USISSEL_2+USICKPL, StatusCallback); 

     

      /* Acknowledge polling function - LED blinks continuously until slave device 

      provides an ACK 

      TI_USI_I2CSelect(unsigned char SlaveAddress) */

      while(TI_USI_I2CSelect(0x20))

      { 

        P1OUT ^= 0x01;                          // Toggle LED

        for (i = 0; i < 0x3000; i++);           // Delay

      }

     

      P1OUT =0;                                 // Slave acknowledged, LED off

     

      /* Transmit data to the EEPROM device, prefixed by page address 0x01 

       TI_USI_I2CWrite(SlaveAddress, Length, Multi, TxData) */

      __disable_interrupt();

      TI_USI_I2CWrite(0x20,1,0,TxData0);

      __bis_SR_register(LPM0_bits + GIE);

     

      /* Acknowledge polling function - loops continuously until slave device 

      provides an ACK */

      while(TI_USI_I2CSelect(0x20));              

     

      /* This function can be used to end any open I2C transaction.

      Use only if I2C transaction was left open previously by setting stop

      condition bit =1 */

      TI_USI_I2CStop();                          

     

      P1OUT |= 0x01;                            // data valid, LED on

      while(1);                                 // program ends here

     

    int StatusCallback(unsigned char c)

    {

      return TI_USI_EXIT_LPM;                   // Exit active for next transfer

    }

  • Don't you think posting the question in one thread is enough?

**Attention** This is a public forum