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.

MSP430F1611: I2C clock select issue

Part Number: MSP430F1611

Hello everybody,

I'm actually a bit confused. I'm trying to talk in I2C master mode to a not connected device. It is not connected due to some testing scenarios.

I'm using the following code:

#include <__cross_studio_io.h>
#include <msp430f1611.h>

// ---------------------------------------------------------------------------------------------------------------------
// Variables

int delay_counter = 0;

// ---------------------------------------------------------------------------------------------------------------------
// Main function

void main(void) {
  
  // Osc
  WDTCTL = WDT_ADLY_1000;                                                       // Watchdog timer 1000 ms
  //IE1 = WDTIE;                                                                  // Enable watchdog interrupt 
  BCSCTL1 &= ~XT2OFF;                                                           // Enable oscillator
  do {                                                                          // Delay for external clock
    IFG1 &= ~OFIFG;
    for (delay_counter = 0xFF; delay_counter > 0; delay_counter--);
  } while ((IFG1 & OFIFG) != 0);
  BCSCTL2 = SELM_2 + SELS;                                                      // External clock (8 MHz)
  
  // Ports
  // USART0 (I2C)
  P3SEL |= (BIT1 + BIT3);                                                       // Peripheral select
  
  // I2C LEVELSHIFTER
  P4SEL &= ~BIT1;                                                               // I/O select
  P4DIR |= BIT1;                                                                // P4.1 I2C-LEVELSHIFTER as output
  
  // USART 0
  U0CTL |= SWRST;                                                               // Init USART0 state machine
  U0CTL |= I2C + SYNC;                                                          // I2C mode at USART0
  U0CTL &= ~I2CEN;                                                              // Disable I2C
  
  // I2C
  I2CTCTL = I2CSSEL_1;                                                          // ACLK clock
  I2CPSC = 0x00;                                                                // Clock precaler /1
  I2CSCLH = 0x0A;                                                               // Shift clock HIGH
  I2CSCLL = 0x0A;                                                               // Shift clock LOW
  
  // EXPECTING:
  // ACLK = 32 kHz
  // PRESCALED WITH /1 => 32 kHz
  // HIGH = 5 x (I2CPSC + 1) = 5
  // LOW = 5 x (I2CPSC + 1) = 5
  // COMPLETE PERIOD: 10 => 3.2 kHZ
  
  // MEASURED: 250 kHz
  
  I2CNDAT = 0;                                                                  // Initialize with zero bytes
  U0CTL |= I2CEN;                                                               // Enable I2C
  U0CTL |= MST;                                                                 // Master mode for MSP
  
  I2CIE |= TXRDYIE + ARDYIE;                                                    // Interrupt enable
  
  P4OUT |= BIT1;                                                                // Enable I2C levelshifter by default
  
  // I2C write
  while (I2CDCTL & I2CBB);
  I2CSA = 0x1A;                                                                 // Slave address
  I2CNDAT = 0x01;                                                               // Save data lenght
  
  U0CTL |= MST;                                                                 // Enable master mode
  I2CTCTL |= I2CTRX;                                                            // Transmit mode
  I2CTCTL |= I2CSTT + I2CSTP;                                                   // Start condition and stop condition
  
  while(1) { };
  
}

void I2C_ISR(void) __interrupt[USART0TX_VECTOR] {
  
  switch(I2CIV) {
    case 8:                                                                     // Access ready interrupt
      break;
    case 12:                                                                    // Transmit ready interrupt
      I2CDRB = 0xAA;
      break;
    default:
      break;
  }
  
}

I'm using two different oscillators on my board. One with 8 MHz at X2IN (MCLK and SMCLK) and a 32.768 Hz oscillator at XIN (ACLK).

It seems, that it doesn't matter what clock source I am selecting with I2CSSELx, the result always stays the same. The first data on the I2C bus (which is the adress of the device) is clocked with 250 kHz.

Can somebody confirm this behavoir and tell me how to change it for use with the slower clock?

  • P.S.: Adding a "__bis_SR_register(LPM0_bits + GIE);" before the while loop does solve the strange behavior. Also as setting a break point to the while(1). When the FET Debugger stops the code execution on line 69, the slave address has already been sent with the correctly used ACLK. Without a breakpoint it does not use ACLK.
  • Hi Steven,

    Not possible to get 250KHz I2C clock from 32KHz ACLK, so I suspect strange here.
    What I would try first is to temporarily reconfigure P5.4, P5.5 and P5.6 (64 pin package) so you can output the MCLK, SMCLK and ACLK on those pins and verify the clock frequencies are there and correct.
  • Hello again,

    Thank you Dennis Lehman for your answer. I've done this now. All three clocks are running properly.

    Attached an output of ACLK (P5.6), triggered at the time of the first SCL output with ACLK (IC2SSEL_1) choosen:

    Zoom out:

    In comparison, if adding a break point @ while(1):

    This is the correct bahavior.

  • Interesting. Any what happens without any debugger connected to the system.
  • Hello,

    That is the same as wihtout any breakpoint.

    Thanks!

  • Hi Steven.

    On this device the ACLK is sourced from the external 32Khz clock, which can have significant startup time, depending on the crystal and capacitance in the circuit. I'm curious when the ACLK starts running compared to the MCLK and SMCLK. With the debugger attached, the MSP is already powered up long before you hit the breakpoint, so the 32Khz oscillator has had plenty of time to come to speed.

    Without the debugger attached, can you take another scope shot while monitoring the MCLK and ACLK?
    I want to see how long it takes for ACLK to start generating a clock signal.
    You must cycle power, not just reset the device.
    Let me know what you see.
  • Hello,

    I've modified my code so that the I2C data is being sent via watchdog timer interrupt, each 1000 ms.

    So the first time the data is sent looks like the following:

    You can see the SCL in yellow, ACLK in blue and MCLK in purple. Both clocks are running properly for a long time before. Tested without any debugger attached.

    New code:

    #include <__cross_studio_io.h>
    #include <msp430f1611.h>
    
    // ---------------------------------------------------------------------------------------------------------------------
    // Variables
    
    int delay_counter = 0;
    
    // ---------------------------------------------------------------------------------------------------------------------
    // Main function
    
    void main(void) {
      
      // WATCHDOG
      WDTCTL = WDT_ADLY_1000;                                                       // Watchdog timer 1000 ms
      IE1 = WDTIE;                                                                  // Enable watchdog interrupt 
      
      // OSC
      BCSCTL1 &= ~XT2OFF;                                                           // Enable oscillator
      do {                                                                          // Delay for external clock
        IFG1 &= ~OFIFG;
        for (delay_counter = 0xFF; delay_counter > 0; delay_counter--);
      } while ((IFG1 & OFIFG) != 0);
      BCSCTL2 = SELM_2 + SELS;                                                      // External clock (8 MHz)
      
      // USART0 (I2C) PORTS
      P3SEL |= (BIT1 + BIT3);                                                       // Peripheral select
      P5SEL |= (BIT4 + BIT5 + BIT6);
      P5DIR |= (BIT4 + BIT5 + BIT6);
      
      // MCLK and ACLK output
      P5SEL |= (BIT4 + BIT6);
      P5DIR |= (BIT4 + BIT6);
      
      // I2C LEVELSHIFTER
      P4SEL &= ~BIT1;                                                               // I/O select
      P4DIR |= BIT1;                                                                // P4.1 I2C-LEVELSHIFTER as output
      P4OUT |= BIT1;                                                                // Enable I2C levelshifter by default
      
      // USART0
      U0CTL |= SWRST;                                                               // Init USART0 state machine
      U0CTL |= I2C + SYNC;                                                          // I2C mode at USART0
      U0CTL &= ~I2CEN;                                                              // Disable I2C
      
      // I2C
      I2CTCTL = I2CSSEL_1;                                                          // ACLK clock
      I2CPSC = 0x00;                                                                // Clock precaler /1
      I2CSCLH = 0x00;                                                               // Shift clock HIGH
      I2CSCLL = 0x00;                                                               // Shift clock LOW
      
      U0CTL |= I2CEN;                                                               // Enable I2C
      U0CTL |= MST;                                                                 // Master mode for MSP
      
      I2CIE |= TXRDYIE + ARDYIE;                                                    // Interrupt enable
      
      _BIS_SR(GIE);                                                                 // Enable all interrupts
      
      while(1) { _NOP(); };
      
    }
    
    void watchdog_timer(void) __interrupt[WDT_VECTOR] {
      
      // I2C write
      while (I2CDCTL & I2CBB);
      I2CSA = 0x1A;                                                                 // Slave address
      I2CNDAT = 0x01;                                                               // Save data lenght
      
      U0CTL |= MST;                                                                 // Enable master mode
      I2CTCTL |= I2CTRX;                                                            // Transmit mode
      I2CTCTL |= I2CSTT + I2CSTP;                                                   // Start condition and stop condition
      
    }
    
    void I2C_ISR(void) __interrupt[USART0TX_VECTOR] {
      
      switch(I2CIV) {
        case 8:                                                                     // Access ready interrupt
          break;
        case 12:                                                                    // Transmit ready interrupt
          I2CDRB = 0xAA;
          break;
        default:
          break;
      }
      
    }
    

  • Hi Steven,

    Ok, you have officially stumped me :(
    Based on your latest code and waveforms, it appears to me that ACLK is not sourcing the I2C module.
    So this leaves the SMCLK as the suspect.

    So you have 8MHz on XT2 for MCLK and SMCLK.
    I2PSC divider = 1
    I2CSCLH = 0
    I2CSCLL = 0

    (according to the user's guide)
    I2CSCLH = 5 x (I2CPSC + 1) = 10
    I2CSCLL = 5 x (I2CPSC + 1) = 10

    This means your total I2C clock period is 20.
    Let's assume then that SMCLK is driving the I2C at 8MHz, then 8000000/20 = 400Khz, which when I look back at your original scope captures, It appears the SCL is running @ 400Khz.

    So can you set a break point somewhere after the I2C has been configured and verify the I2CTCTL register has bit 5 = 0, bit 4 = 1 (selects ACLK).
    While you do that, I'll see if I can get some help from one of the engineers that supports that family of devices.
  • Hello Dennis,

    Dennis Lehman said:
    So you have 8MHz on XT2 for MCLK and SMCLK.
    I2PSC divider = 1
    I2CSCLH = 0
    I2CSCLL = 0

    (according to the user's guide)
    I2CSCLH = 5 x (I2CPSC + 1) = 10
    I2CSCLL = 5 x (I2CPSC + 1) = 10

    This means your total I2C clock period is 20.

    I don't know if thats correct. when I2PSC = 1, that means the register is set to 0x00 (/1 divider). Shouldn't it be calculated to a total period of 10 instead of 20?

    When I am using SMCLK to clock my SCL, it seems that my calculation mentioned above is right, except for a few clock cycles too much. But I think this is the behavoir of the errata I2C14.

    MSP430F16111 Errata rev G: www.ti.com/.../slaz146g.pdf

    Dennis Lehman said:
    So can you set a break point somewhere after the I2C has been configured and verify the I2CTCTL register has bit 5 = 0, bit 4 = 1 (selects ACLK).
    While you do that, I'll see if I can get some help from one of the engineers that supports that family of devices.

    I've already verified with a breakpoint that my I2CTCTL is configured for the use of ACKL correctly.

    A damaged hardware can be excluded, I've tried it with 2 other controllers (same part number).

    Thanks so far for your help!

  • Hi Steven,

    Regarding the clock period, my understanding from the family user's guide, page 5-26, is the I2CSCLL sets the period of the SCL clock low and I2CSCLH sets the period SCL clock is high.  Together, they determine the overall period of the SCL clock frequency.

    And let me clarify my earlier point (I2CPSC divider = 1), I was trying to convey this as I2CPSC = '000'.

    So on your original clock settings your I2CPSC = '000' results in the I2CIN clock = 8Mhz .  Your I2CSCLL and I2CSCLH are then set to 10 each, which makes 20 (1/8MHz) clocks = 400Khz.

    I'm still working on trying to get an answer from our mature MCU team.

  • Hello Dennis,

    According to the family guide:

    Assuming that I2CPSC is 000h, the equation results in: 5 x (0 + 1) = 5, that makes 10 for low phase and high phase together, or am I wrong?

    Thank you!

  • Hi Steven,

    If you look at section 15.2.6, it shows that I2CSCLH and I2CSCLL determine the SCL clock signal frequency.

  • Hello Dennis,

    Yes, when setting I2CPSC to 002h this results in a SCL with I2CIN / 3 (see your Note example).

    Setting I2CPSC to 000h results in a SCL with I2CIN / 10, and not 20.

    I think the following settings apply to the example:

    I2CPSC = 002h
    I2CSCLH = 000h => 5 x
    I2CSCLL = 000h => 5 x

    Calculation: I2CCLK = [(I2CPSC + 1) x (I2CSCLH + 2)] + [(I2CPSC + 1) x (I2CSCLL + 2)] = [(2 + 1) x (5)] + [(2 + 1) x (5)] = 30

    And for a divider of /1:

    I2CPSC = 000h
    I2CSCLH = 000h => 5 x
    I2CSCLL = 000h => 5 x

    Calculation: I2CCLK = [(I2CPSC + 1) x (I2CSCLH + 2)] + [(I2CPSC + 1) x (I2CSCLL + 2)] = [(0 + 1) x (5)] + [(0 + 1) x (5)] = 10

    But this is not so important, unless the correct clock is being selected :-)

    Thanks!

  • Hi Steven,

    Yes, you are correct. Sorry for the confusion on this one. I have a setup now and can run your code. With 8MHz MCLK, SMCLK and 32Khz ACLK and the settings in your latest code, when I select ACLK (I2CSSEL_1) I see SCL = 3.3Khz, which is roughly a divide by 10. When I use I2CSSEL_2 and I2CSSEL_3 (SMCLK) my SCL is 625KHz, which is not close to the 800KHz expected from the 8Mhz SMCLK. So give me a little more time to track down some help for this device and I'll get back with answer to you.
  • Hi Dennis,

    Dennis Lehman said:
    When I use I2CSSEL_2 and I2CSSEL_3 (SMCLK) my SCL is 625KHz, which is not close to the 800KHz expected from the 8Mhz SMCLK

    Don't forget I2C14 errata. This behavoir is possible due to some I2CSCLL and I2CSCLH periods too much when using a primary clock with more than 1 MHz.

    Thank you :-)

  • Hi Steven,

    Confirmed - This issue is I2C14 in the errata.

    I tested as followed:

    I2CPSC     DIV       Measured freq     Expected

    0x07           8                100K                       100K

    0x06           7                114K                       114K

    0x05           6                133K                       133K

    0x04           5                160K                       160K

    0x03           4                200K                       200K

    0x02           3                268K                       267K

    0x01           2                362K                       400K (bad)

    0x00           1                609K                       800K (bad)

    So, per the errata, choose a divider such that our I2CIN is 1MHz or less.

    Does this work for you?  What is the I2CIN frequency you were trying to achieve?

  • Hi Dennis,

    I think a 100 kHz SCL is fine for most applications.

    But that is not the main issue here. The main issue is, that ACLK is not choosen correctly without a break-point or a low power mode (both after the I2C master TX).

    Indeed I don't need to use the ACLK anymore, because to obtain a 100 kHz SCL I can't use a 32 kHz ACLK (I have to use SMCLK), but the ACLK behavoir is nonetheless strange. And if I want to create an I2C SCL clock with ACLK for debugging purposes it should be founded out whats causing the strange behavoir.

    You said you were able to create a 3.3 kHz SCL with ACLK with my code? Or did you make any changes to it? MSP430F1611?

    Maybe there are some compiler related differences, a hex diff should disclose that.

    Thanks a lot so far for you friendly help!

  • Hi Steven,

    No problem with the help. Let me capture some screen shots to show what I have working.
  • Steven,

    I'm going to have to file an errata with our design team on this one.  You can see in my screen capture the various clocks and I2C activity.  If you look close, the I2C transaction starts out running with SMCLK for the first 4 clock cycles, then switches to the ACLK, which is divided down by 10 to 3.27khz.

    This screen capture is a zoom in around the time SMCLK is sourcing the I2C clock.

    Since this device appears to have an issue, is there a reason why you wouldn't consider using another device?

  • Hello Dennis,

    Since we have multiple sensor hardware using this device, we cannot switch over to a newer one.

    Nonetheless, we can use SMCLK to clock the I2C module for our application, so no worry.

    I am glad that I could help to discover a new errata for this device.

    Keep me up to date :-)

    Thanks!

**Attention** This is a public forum