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.

How easy is it to damage the USCI on an MSP430 (F2618)?

I'm writing code for the MSP430, right now I'm sending commands in over USB (connected to a PC via a virtual serial port) that talk to either a real-time clock (M41T81S) over I2C  or an SD card over SPI , both on USCI B0. This is on a development board from Pumpkin that has digital control lines so that when the MSP430 is talking SPI, those signals don't show up on the I2C lines, and when the MSP430 is talking I2C, the SD card is disabled, so there's no problem sharing B0.

It was working fine and then one day all communication over USCI B0 freaked out, and now even if I go back to a previous version of my code, it still has serious problems.  Anything I do with the SD card fails (unfortunately that's down inside a third-party driver so I have no details) but I can see that when I try to talk to the RTC, the first byte gets sent but is immediately followed by a NACK.

After many different trials, I put in a bunch of debug code that stores the values of registers at key points during the process, and then when/if it fails I can output the whole shebang; this lets me debug the I2C code without disrupting its timing by spitting out a bunch of debug information over the USB port while it's talking I2C.  What I'm seeing is odd - I set everything up and start the transmission (UCB0CTL1 |= (UCTR | UCTXSTT)), the transmit interrupt fires immediately (as expected) but in the very first ISR, UCB0CTL1 is 0x92 which means somebody has set the stop bit, and it wasn't me - I've been over my code with a fine-tooth comb, and put debugger breakpoints on every line of code that sets the stop bit, and none of them are firing.  Is this expected behavior?  Does the MSP430 set its own stop bit under some error situations?

Then, when I created a small sample program to just talk to the RTC, it failed in a different way - the BUSY bit never goes away after initialization.

So the bigger question is this - why does code that worked last week, not work this week?  Is it possible that my code did some sort of inappropriate setup, and damaged the MSP430?  I'm going to find a replacement MSP430 so I can test out this theory, but don't have one yet.  For example, if there is too much pullup resistance on the I2C lines, can the MSP430 be damaged due to excessive current?

I'll attach some sample code too, it's a stripped-down version of what I'm trying to do, that only tries to talk to the RTC.  It's inside a semi-RTOS called Salvo, but I'm not using any of the RTOS features.  Is it possible that my current I2C code is so extremely timing-sensitive that some small change (it's warmer here this week) broke my code?

Thanks for any and all advice,

Chris

MAIN INITIALIZATION CODE

--------------------------------------

  // Stop watch dog timer for now
  WDTCTL = WDTPW + WDTHOLD;    

  // Keep interrupts off for now...
  __disable_interrupt();
 
  // All CSK control signals are active LOW.  (Note: CSK = CubeSat Kit, that's the name of the Pumpkin board I'm using)
  P1OUT  =  0xFF;
  P2OUT  =  0xFF;
  P3OUT  =  0xFF;
  P4OUT  =  0xFF;
  P5OUT  =  0xFF;
  P6OUT  =  0xFF;
 
  // Clock initialization. Requires only 32.768kHz LFXTAL
  DCOCTL=CALDCO_8MHZ;  //0x60;         //DCO.1,DCO.0, DCO=0x03
  BCSCTL1=CALBC1_8MHZ; //0x84;         //XT2OFF,RSEL.2
  BCSCTL2=0x00;

  // Set up to run MCLK at HFXTAL rate
  BCSCTL1 &= ~XT2OFF;                  // Turn on XT2

  do {                                 // Wait for XT2 to stablize
    IFG1 &= ~OFIFG;                    // Clear OSC fault flag
    for (i = 0xFFF; i > 0; i--);       // Time for flag to set
  } while ((IFG1 & OFIFG) == OFIFG);   // OSCFault flag still set?

  BCSCTL2 |= SELS;                     // SMCLK = XTAL2 (7.3728MHz)
 
  // Set up TimerA0 to run at system tick rate
  TACTL  = TASSEL0 + TACLR;            // SMCLK, clear TAR

  CCTL0  = CCIE;                       // CCR0 interrupt enabled
  CCR0   = SYSTEM_TIMER_RELOAD;        // SYSTEM_TIMER_RELOAD; //should match the value in config.h
  TACTL |= MC1;                        // Start Timer_A in continuous mode

  // Set up timer B to use ACLK with a /8 divider in continuous mode, ends up with 4096 ticks per second.
  TBCTL = (3 << 6) | TBSSEL_1 | MC_2;

  // This main code then kicks off the actual task, I only have one task, and the first thing that task does is the I2C code coming next:

I2C CODE

--------------

  int status = 0;
  unsigned int uTimer, uElapse;

  __enable_interrupt();

  P3SEL |= SDA_PIN + SCL_PIN;                 // Assign I2C pins to USCI_B0

  // Make sure SD card is disabled
  P3SEL &= ~BIT0; // Set P3.0 to be NOT USCI
  P3DIR |= BIT0;  // Set P3.0 to output
  P3OUT |= BIT0; //  Set P3.0 high (so SD card is inactive)

  UCB0CTL1 = UCSWRST;                         // Enable SW reset
  UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;       // I2C Master, synchronous mode
  UCB0CTL1 = UCSSEL_2 + UCSWRST;              // Use SMCLK, keep SW reset
  UCB0BR0 = I2C_PRESCALE;                     // set prescaler
  UCB0BR1 = 0;
  UCB0I2CSA = RTC_ADDRESS;                  // set slave address
  UCB0CTL1 &= ~UCSWRST;                       // Clear SW reset, resume operation

  // Give things a little time to settle down (I added this later, not sure if it helps)
  uTimer = TBR;
  for (;;)
  {
    if (TBR - uTimer > 10)   // 4096 ticks per second, so this waits about 2.5 msec
      break;
  }

  // UCSWRST has cleared UCB0RXIE and UCB0TXIE but it's not clear
  // whether UCB0I2CIE has also been cleared.
  UCB0I2CIE = UCNACKIE;
  IE2 |= UCB0TXIE;                             // Enable TX ready interrupt
 
  uTimer = TBR;
  for (;;)
  {
    if (!(UCB0STAT & UCBBUSY))
      break;
    uElapse = TBR - uTimer;
    if (uElapse > 250 * 4)   // Wait 250 msec
    {
      status = 103;       // <--------------- It fails right here, BUSY but never goes away
      break;
    }
  }


  • In your code above, you enable a lot of interrupts. What does your ISR code do to handle them?

    However, you didn't actually start a transfer, so UCBUSY should be clear. I'm not sure what happens when the clock line is low when it shouldn't. Maybe this is detected and sets the busy bit. (I don't have access to the datasheets from home)
    It's possible that your pullups failed, which will inhibit I2C transfer.

    What do the other status bits say?

**Attention** This is a public forum