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.

RTC failure using MSP430f2132 with I2C interface

Other Parts Discussed in Thread: MSP430F2132, MSP430F5529

Hi,

            I am using MSP430f2132 to interface RTC(ISL1208-->slave address 1101111x) I2C interface. My problem is when i am using I2C in master mode it is not giving ACK after START genertion sometimes i observed that UCTXSTT is not setted, i tried with example codes also but i didnt get the solution.Please tell me where i am  doing wrong?.

thank u.

---> Code :

#include  "msp430x21x2.h"

typedef unsigned char u8;
typedef unsigned int  u16;

/* RTC Slave addresses */
#define RTC_I2C_WRITE_DE   0xDE
#define RTC_I2C_READ_DF    0xDF

/* RTC register addresses */
#define RTC_SEC_REG_ADDR    0x00
#define RTC_MIN_REG_ADDR    0x01
#define RTC_HR_REG_ADDR     0x02
#define RTC_DAY_REG_ADDR    0x06
#define RTC_DATE_REG_ADDR   0x03
#define RTC_MON_REG_ADDR    0x04
#define RTC_YR_REG_ADDR     0x05

#define RTC_CTL_REG_ADDR    0x07
#define RTC_SEC_BIT_CH      0x80    /* Clock Halt (in Register 0)   */
#define RTC_CTL_BIT_RTCF    0x01    /* Rate select 0             */
#define RTC_CTL_BIT_BAT     0x02    /* Rate select 1             */
#define RTC_CTL_BIT_WRTC    0x10    /* Square Wave Enable     */
#define RTC_CTL_BIT_ARST    0x80    /* Output Control            */

u8 sec_gc;
u8 min_gc;
u8 hour_gc;
u8 mday_gc;
u8 mon_gc;
u16 year_gi;
u8 wday_gc;

volatile u8 tx_index = 0;
volatile u8 rx_index = 0;
volatile u8 TxByte_gc = 0;
volatile u16 delaytime_gi = 0;
volatile u8 rx_gf = 0, tx_gf = 0;
volatile u8 TxByte2PC = 0;

u8 temp_lc;
u16 index = 0;

u8 RTCSetBuff[] = {0x03, 0x05, 0x07, 0x09, 0x02, 0x09, 0x05};
u8 RTCRxBuff[10];

void tx_uart0_byte(u8 );
void delay(u16 );
void RTC_Write(void);
void RTC_Read(void);
u8 bcd2bin (u8 );
u8 bin2bcd (u16 );

void main (void)
{
//__bic_SR_register(GIE);            // interrupt disable

 tx_index  = 0;
 rx_index  = 0;
 WDTCTL    = WDTPW + WDTHOLD;               // Stop WDT
 P1DIR   |= 0x01;

// CLK Init
 BCSCTL1   = CALBC1_1MHZ;       // Set DCO
 DCOCTL    = CALDCO_1MHZ;

// Timer Init
 TA0CCTL0  = CCIE;                          // TA0CCR0 interrupt enabled
 TA0CCR0   = 1000;
 TA0CTL    = TASSEL_2 + MC_1;               // SMCLK, upmode

// UART Tx/Rx Init
 P3SEL    |= 0x30;                      // P3.4,5 = USCI_A0 TXD/RXD
 UCA0CTL1 |= UCSSEL_2;                     // SMCLK
 UCA0BR0   = 104;                          // 1MHz 9600
 UCA0BR1   = 0;                            // 1MHz 9600
 UCA0MCTL  = UCBRS0;                       // Modulation UCBRSx = 1
 UCA0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**

// UART in I2C mode Init
 P3SEL    |= 0x06;                      // P3.4,5 = USCI_A0 TXD/RXD
 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 = (RTC_I2C_WRITE_DE >> 1);
 UCB0CTL1 &= ~UCSWRST;                    // Clear SW reset, resume operation
 UCB0I2CIE|= UCSTPIE  + UCSTTIE;

 __bis_SR_register(GIE);           // interrupt enable


 while(1)
 {
  P1OUT ^= 0x01;
  RTC_Write();
  P1OUT ^= 0x01;
 }
}


// Timer0_A0 interrupt service routine   // Timer0_A0 ISR
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A (void)
{
 //P1OUT ^= 0x01;                            // Toggle P1.0
 delaytime_gi++;
}

#pragma vector = USCIAB0TX_VECTOR    // UART_Tx_ISR
__interrupt void uart0_tx (void)
{
 if(rx_gf == 1)
 {
  UCB0TXBUF = TxByte_gc;
  IFG2   &= ~UCB0TXIFG;
  rx_gf = 0;
 }

 if(tx_gf == 1)
 {
  tx_gf = 0;

  if((IFG2 & UCB0TXIFG) == UCB0TXIFG)
  {
   IFG2   &= ~UCB0TXIFG;                     // Clear USCI_B0 TX int flag
   UCB0TXBUF = TxByte_gc;
   tx_index += 1;
  }

  if(tx_index == 7)
  {
   UCB0CTL1 |= UCTXSTP;            // I2C stop condition
      while (UCB0CTL1 & UCTXSTP);

   IFG2   &= ~UCB0TXIFG;         // Clear USCI_B0 TX int flag
  }
 }
}

#pragma vector = USCIAB0RX_VECTOR   // UART_Rx_ISR
__interrupt void uart0_rx (void)
{
// UCB0STAT &= ~(UCSTPIFG + UCSTTIFG);

 if(rx_index > 6)
 {
      UCB0CTL1 |= UCTXSTP;                  // Generate I2C stop condition
   while (UCB0CTL1 & UCTXSTP);
 }

 IFG2 &= ~UCA0RXIFG;

 RTCRxBuff[rx_index] = UCA0RXBUF;
 rx_index = rx_index + 1;
}

void RTC_Write(void)
{

 if ((UCB0STAT & (~UCBBUSY)) == 0)
 {

  UCB0CTL1 |= (UCTXSTT | UCTR);                  // I2C start condition
  while (UCB0CTL1 & UCTXSTT);                    // Loop until I2C STT is sent

  if(UCB0STAT & UCNACKIFG)
  {                     // waiting until data sent or NACK
    UCB0CTL1 |= UCTXSTP;                            // Generate STOP
    while (UCB0CTL1 & UCTXSTP);                      // Ensure stop condition got sent
  }

  tx_index = 0;

  while(tx_index < 7)
  {
   tx_gf = 1;
   TxByte_gc = bin2bcd(RTCSetBuff[tx_index]);
   IE2 |= UCB0TXIE;
   __bis_SR_register(GIE);           // interrupt enable

   delay(20);
  }
 }
}

void RTC_Read(void)
{
 UCB0CTL1 |= UCTR + UCTXSTT;                    // I2C start condition
 while (UCB0CTL1 & UCTXSTT);

 UCB0I2CSA = (RTC_I2C_WRITE_DE >> 1);           // Slave Address is 0xDEh(right justified 0xBC)

 TxByte_gc = bin2bcd(RTC_SEC_REG_ADDR);
 rx_gf = 1;
 IE2 |= UCB0TXIE;
 __bis_SR_register(GIE);           // interrupt enable

 rx_gf = 1;
 UCB0CTL1 &= ~UCTR;
 UCB0CTL1 |= UCTXSTT;
 UCB0I2CSA = (RTC_I2C_READ_DF >> 1);
 while (UCB0CTL1 & UCTXSTT);

 rx_index = 0;
 while (rx_index < 7)
 {
  IE2 |= UCB0RXIE;
  __bis_SR_register(GIE);           // interrupt enable
 }

}
void tx_uart0_byte(u8 data_lc)
{
 TxByte2PC = data_lc;
 IE2 |= UCA0TXIE;
}

void delay(u16 delaytime_li)
{
 delaytime_gi = 0;
 while(delaytime_gi < delaytime_li);
}

u8 bcd2bin (u8 n)
{
    return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F));
}

u8 bin2bcd (u16 n)
{
    return (((n / 10) << 4) | (n % 10));
}

  • prem kumar said:
    (ISL1208-->slave address 1101111x

    This could be your problem. The 'address' to use for the I2C hardware is just the fixed 7 bits without the 'x' bit. The hardware automatically adds the UCTR bit as 8th bit when sending a start condition. So the address to use is simply 1101111 or 0x6f.

    So if you wrote the 8 bit value, the master addressed a wrong slave whcih of course did not answer, so no ACK after the start.

    If the STT bit is not reset even after some time, it might indicate that 'someone' holds the clock line low. This will stall the bus until the clock is released and used by slaves to allow them to prepare for the answer. It does, however, also happen if there are no pullups on the I2C lines. (the MSPs internal pullups won't work for I2C) THen the clock line will stay low and stall the bus.

  • Thank you..Jens-Michael Gross.

    I changed my device address but still it is not working and busy bit is always high before start condition..how can i detect which device is pulling clock signal low because i am using only RTC with microcontroller...

     P3SEL    |= 0x06;                      // P3.4,5 = USCI_A0 TXD/RXD
     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 = 0x6f;       //
     UCB0CTL0 &= (~UCSLA10);
     UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset,resume operation
     UCB0I2CIE|= UCSTPIE  + UCSTTIE;

     __bis_SR_register(GIE); 

    while(1)
     {

    write_rtc();

    }

    void write_rtc(void)
    {
     if ((UCB0STAT & (~UCBBUSY)) == (~UCBBUSY))
     {
      UCB0CTL1 |= UCTR + UCTXSTT;             // I2C TX, start condition
      while (UCB0CTL1 & UCTXSTT);             // Loop until I2C STT is sent
      
      while(!(IFG2 & UCB0TXIFG));
      UCB0TXBUF = 0x00;
      while (UCB0CTL1 & UCTXSTT);
      
      while(!(IFG2 & UCB0TXIFG));
      UCB0TXBUF = 0x09;
      while (UCB0CTL1 & UCTXSTT);

    }

    }

    #pragma vector = USCIAB0TX_VECTOR    // UART_Tx_ISR
    __interrupt void uart0_tx (void)
    {
     if((IFG2 & UCB0TXIFG) == UCB0TXIFG)
     {
      UCB0TXBUF = TxByte_gc;
      IFG2   &= ~UCB0TXIFG;                     // Clear USCI_B0 TX int flag
     }

    }

  • Did you add the external pullups? I2C devices are not supposed to actively pull the data and clock lines high, only low. And th itnernal pullups of the MSP, even if activated, are way too weak for proper operation.

    The pullups should be in the range of 10k to VCC each.

     

     

  • Hello -

    I have been successful in writing to the ISL1208 - I found that first you need to write to address 7 (Control Register). I have been setting 2 bits, WRTC and ARST. (write 0x7 with value of 0x90)

    I have then "kicked off" the timer by writing a value into the "Seconds" register. (Write 0x00 with a value of 0x10)

    I can then go into read mode, and see the seconds tick up...0, 1, 2, 3,...

    HOWEVER, on 2 different chips now, I do not stop counting at 60, instead the count goes to 90 before the minute increments.

    BTW, I have do use 10K pull-ups.

    I thought maybe my problem initially was low voltage on the ISL1208 chip - I was seeing about 2.7 volts on my MSP430F5529 FET board.

    However, now that we have real target boards and the voltages are 3.3 volts, I am still seeing the problem on the Intersil chip. I do have a query into Intersil, but if anyone has some experience with this chip and can tell me why I am getting 90 seconds / minute, please let me know!

    And yes, the I2C address is 0x6F.

    Regards,

    Todd Anderson

  • Todd Anderson said:
    HOWEVER, on 2 different chips now, I do not stop counting at 60, instead the count goes to 90 before the minute increments.

    That's weird. I know from the 8583 RTC that it produces erroneous outputs if you write (or have after poiwer-up) a wrong hour or minute in teh BCD coded registers. Then it counts to weird values. (e.g. the ten seconds count to 9 before rolling over instead of rolling over after 6)

    Maybe you have to initialize it better, or your initial write of 0x10 is wrong because it has side effects to other registers.

    The datasheet should tell you such details, at least a recommended init sequence.

  • Actually, it is a strange behavior - when you look at the counts in HEX, they count 0,1,2,3,4,5,6,7,8,9 --> 0x10, 0x11...0x19 --> 0x20...0x59 --> 0x00

    This is little weird, but now knowing that, the chip behaves as "stated." (I switched to hexadecimal several years ago.)

    Also, register 2 has a MIL bit that you must set if you want 0-23 hours -- but when you read the register, it is distubingly set as the MSB, so you need to add a mask to get the actual "military" time.

    Regards,

    Todd Anderson

  • Ah, that's clear now. It's using BCD format. Commonly used on RTCs.

    BCD measn BinaryCodedDecimal. Some processors even have internal assembly support for this.

    It measn that each 4 bits (a nibble) represent a decimal digit. You can read the binary values as if they were 2/4 digit (byte/word) decimal numbers.

    So the 'real' binary value would be 10*(x>>4)+x&0xf.

    Even teh MSP has some BCD instructions: Check the users guide for the DADD instruction, or DADCX and DADDX.

    The internal RTC_A module in teh MSP 5x series also uses BCD format for date/time (calendar mode) and on the RTC_B module are even conversion registers for binary-> BCD and BCD->Binary.

  • Hi can you please post the working code of ISL. I am facing similiar problem in isl1220 . Where my STT bit is not resetting.

     

    Thanks

  • I am also facing similar problem of start bit not getting clear. Please inform me how u guys were able to solve it. please post the code if possible...

**Attention** This is a public forum