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.

MSP430F5524: Unable to pause the code using the programmer

Part Number: MSP430F5524

The code running on my MSP430F5524 isn't responding to external inputs(such as a keypad) atter running for a short while. On certain occasions the code is able to enter the ISR(Timer, UART).

 On  putting the programmer, I am unable to pause the code. I am getting the message "Break at address "0xd00c4" with no debug information available, or outside of program code". 

Any idea why this is happening and how can I resolve this? Could the code be getting into a "bad state" because of not handling an interrupt/doing an illegal operation like dividing by 0? However, in case of not handling an interrupt the code should enter the "default" ISR provided by TI and enter into a LPM Mode( I have forgotten the exact name of this). 

The same code is working fine on other PCBs with the same schematic. Could this be a hardware issue in terms of design/layout?

We are in a critical stage of our project. Any help would be appreciated.

Thanks and Regards

Abhishek

  • Hi Abhishek,

    if trying to access the MSP430 via debugging tool, by pausing the code execution, and the result or message from the the tool stating the CPU is in an  non programmed memory space, it is probable the CPU jumped for some reasons to this address erroneously. This can have various reasons:

    1. Overclocking of the CPU. This might be a too high clock frequency. Or a too high clock frequency in respect of the used Vcore voltage.

    2. It could be a SW bug, e.g. an error in a pointer/jump address calculation.

    3. Dependent on the used clock source, this might be also HW related. If for some reasons e.g. with crystal or ceramic resonators the resulting clock contains glitches, or major duty cycle shifts, even a slow clock frequency can overclock the CPU, as not only the frequency but also the single pulse width is relevant.

    Best regards

    Peter

  • An update: On replacing the MCU things are working okay with the same code and hardware. It looks like more than a few MCUs are faulty. Could it be because of how it has been handled, stored by the distributor?

    Cheers

    Abhishek

  • Hello Abhishek,

    one possible root cause can be a partial damage or degradation of parameters due to ESD events. Of course an improper handling in terms of ESD protection could be one possibility.

    On the other hand, all devices are subject to certain variations of parameters. Thus if you're operating the device beyond the specified limits, some still might be able to cope with it, some not. This might be related to SW or HW, or combination of both.

    Of course also soldering, if executed improperly can result in device malfunctions.

    Thus as you see, there still multiple possible root causes, which would require further investigations, tracing down the failure mechanism, to understand where the failures are coming from.

    Best regards

    Peter

  • Hi Peter

    Thanks for your inputs. As of today, we are planning to replace the MCUs with new ones to solve the problem. If problems persist even with the new ones I will let you know.

    Thanks

    Abhishek

  • Hi Peter, 

    I am back with an update. 

    I am observing some inconsistent behaviour. For certain other ICs, the code runs fine for about 4-5 hours before getting corrupted. For some, on the other hand, it fails within a minute. There are also many ICs which work fine with the same code. For the ones that fail immediately I observed that they are happening after an I2C read-write is called.

    Could you please look at my code to see if there is something wrong that I am doing? Maybe there is an issue in the order of writing registers or something that is acceptable but not perfect because the code is giving inconsistent behaviour.

    Thanks and Regards

    Abhishek

    2742.i2cCode.c
    uint08 i2cUcb1PolledWrite(uint08 device_addr, uint08* write_data, uint08 num_bytes, uint08* bytes_written, uint08 timeout)
    /**
     * Writes data to the specified device address
     *
     * @param   device_addr   - I - 7 Bit device Address
     * @param   write_data    - I - Pointer to data buffer to be written to slave
     * @param   num_bytes     - I - Number of bytes to be written
     * @param   bytes_written - O - Actual number of bytes written to slave
     * @param   timeout       - I - Timeout max (in msec) between each transmitted byte
     *                              Timeout=0, permits an infinite timeout (not recommended). Max value = 65
     * @return  0 - Completed successfully 
     *          I2C_NO_ACK - Slave NAck'ed            
     *          I2C_WRITE_TIMEOUT - Slave did not respond before timeout period expired
     *          I2C_INVALID_TIMEOUT - timeout parameter is greater than 65
     *
     */
    {
      uint08 status;
      uint08* dataPtr = write_data;
      uint08 i;
      uint16 currentSr;
      uint08 intDisabled = 0;
      
      // check for argument validity
      if ( timeout > 65 )
        return I2C_INVALID_TIMEOUT;
        
      // since this version is polled, we don't want an interrupt firing
      //  and the ISR executing
      currentSr = __get_SR_register();
      if ( currentSr & GIE ) {
        intDisabled = 1;
        __disable_interrupt();
      }
      
      // turn on the timer
      TBCTL |= MC_2;
      i2cBaselineTimer = TBR;
      
      // write the slave address and configure i2c hardware
      UCB1CTL1 = UCSWRST;
      UCB1CTL1 = UCSSEL_2 + UCSWRST;
      UCB1I2CSA = device_addr>>1;
      UCB1CTL1 &= ~UCSWRST;
    
      // enable module interrupts and start the transfer
      UCB1IE |= UCNACKIE;
      UCB1IE |= UCTXIE;
      //IE2 |= UCB1TXIE;
      UCB1CTL1 |= UCTR + UCTXSTT;
      
      *bytes_written = 0;
      
      // special handling of 1 byte case
      if ( num_bytes == 1 ) {
        while ( (UCB1IFG & UCTXIFG) == 0 ) {
          status = i2cUcb1CheckNakTimeout(timeout, 1);
          
          if ( status != 0 ) {
            i2cUcb1Cleanup();
            if ( intDisabled )
              __enable_interrupt();
            return status;
          }
        }
        
        UCB1TXBUF = *dataPtr;
        while ( (UCB1IFG & UCTXIFG) == 0 ) {
          status = i2cUcb1CheckNakTimeout(timeout, 1);
          
          if ( status != 0 ) {
            i2cUcb1Cleanup();
            if ( intDisabled )
              __enable_interrupt();
            return status;
          }
        }
        *bytes_written = 1;
      }
      else {
        for ( i=0; i<num_bytes; i++ ) {    //can count down
          // spin until transmit buffer needs to be reloaded
          while ( (UCB1IFG & UCTXIFG) == 0 ) {
            status = i2cUcb1CheckNakTimeout(timeout, 1);
            
            if ( status != 0 ) {
              i2cUcb1Cleanup();
              if ( intDisabled )
                __enable_interrupt();
              return status;
            }
          }
          
          //UCB1IV &=~USCI_I2C_UCTXIFG;
          // load another data byte
          UCB1TXBUF = *dataPtr;
          
          // increment actual byte counter
          *bytes_written = *bytes_written + 1;
          
          // increment the pointer address
          dataPtr++;
          
          // take a new baseline timer value
          i2cBaselineTimer = TBR;
        }
      }
      
      // wait until the last byte has been transferred
      while ( (UCB1IFG & UCTXIFG) == 0 ) {
        status = i2cUcb1CheckNakTimeout(timeout, 1);
        
        if ( status != 0 ) {
          i2cUcb1Cleanup();
          if ( intDisabled )
            __enable_interrupt();
          return status;
        }
      }
      // generate a stop
      UCB1CTL1 |= UCTXSTP;
      //while (UCB1STAT & UCBBUSY){}
      //Trying to solve I2C 1 stuck issue
    
      if(UCB1STAT & UCBBUSY)
      {
    
          __delay_cycles(10000);  //Wait
          if (UCB1STAT & UCBBUSY)
          {
              testI2c1Busy++;
              UCB1CTL1 = UCSWRST;
              __delay_cycles(1000);
              UCB1CTL1 &= ~UCSWRST;
    
          }
      }
    
    
      // turn off the timer to save power
      TBCTL &= ~MC_2;
    
      UCB1IFG &= ~UCTXIFG;
    
      // no errors, all bytes transmitted
      UCB1IE &= ~UCNACKIE;
      UCB1IE &= ~UCTXIE;
      if ( intDisabled )
        __enable_interrupt();
      return 0;
    }
    
    uint08 i2cUcb0PolledWrite(uint08 device_addr, uint08* write_data, uint08 num_bytes, uint08* bytes_written, uint08 timeout)
    /**
     * Writes data to the specified device address
     *
     * @param   device_addr   - I - 7 Bit device Address
     * @param   write_data    - I - Pointer to data buffer to be written to slave
     * @param   num_bytes     - I - Number of bytes to be written
     * @param   bytes_written - O - Actual number of bytes written to slave
     * @param   timeout       - I - Timeout max (in msec) between each transmitted byte
     *                              Timeout=0, permits an infinite timeout (not recommended). Max value = 65
     * @return  0 - Completed successfully
     *          I2C_NO_ACK - Slave NAck'ed
     *          I2C_WRITE_TIMEOUT - Slave did not respond before timeout period expired
     *          I2C_INVALID_TIMEOUT - timeout parameter is greater than 65
     *
     */
    {
        uint08 status;
        uint08* dataPtr = write_data;
        uint08 i;
        uint16 currentSr;
        uint08 intDisabled = 0;
    
        // check for argument validity
        if (timeout > 1000)    //65 increased for testing
            return I2C_INVALID_TIMEOUT;
    
        // since this version is polled, we don't want an interrupt firing
        //  and the ISR executing
        currentSr = __get_SR_register();
        if (currentSr & GIE)
        {
            intDisabled = 1;
            __disable_interrupt();
        }
    
        // turn on the timer
        //TA1CTL |= MC_2;           use TA0R
        i2c0BaselineTimer = TA0R;
    
        // write the slave address and configure i2c hardware
        UCB0CTL1 = UCSWRST;
        UCB0CTL1 = UCSSEL_2 + UCSWRST;   //UCSSEL_2 by default
        UCB0I2CSA = (device_addr >> 1);
    
        //uint08 dAddr=device_addr, userAddr;
        ///intToStr((dAddr>>1),&userAddr);
        //sendUserMessage("device addr: ");
        //sendUserMessage(&userAddr);
    
        UCB0CTL1 &= ~UCSWRST;
    
        // enable module interrupts and start the transfer
        UCB0IE |= UCNACKIE;
        UCB0IE |= UCTXIE;
        //IE2 |= UCB1TXIE;
        UCB0CTL1 |= UCTR + UCTXSTT;
        //UCB0TXBUF = *dataPtr;        //for testing
    
        //temp sensor requires some delay to process comands
        if(device_addr == SI7060_SLAV_ADDR)
        {
            __delay_cycles(750);
        }
    
        sendUserMessage("Write Start sent\n\r");
        __delay_cycles(4000);
        //for debugging
        if(UCB0IFG & UCNACKIFG)
        {
            sendUserMessage("NACK after sending start\n\r");
            __delay_cycles(4000);
        }
        else
        {
            sendUserMessage("No NACK after sending start\n\r");
            __delay_cycles(4000);
        }
        *bytes_written = 0;
    
        // special handling of 1 byte case
        if(num_bytes == 1)
        {
            while ((UCB0IFG & UCTXIFG) == 0)
            {
                // when while loop is exited, it means transfer buffer is empty
                status = i2cUcb0CheckNakTimeout(timeout, 1);
    
                if (status != 0)
                {
                    i2cUcb0Cleanup();
                    if (intDisabled)
                        __enable_interrupt();
                    return status;
                }
            }
    
            UCB0TXBUF = *dataPtr;
            while ((UCB0IFG & UCTXIFG) == 0)
            {
                status = i2cUcb0CheckNakTimeout(timeout, 1);
    
                if (status != 0)
                {
                    i2cUcb0Cleanup();
                    if (intDisabled)
                        __enable_interrupt();
                    return status;
                }
            }
            *bytes_written = 1;
        }
        else
        {
            for (i = 0; i < num_bytes; i++)
            {         //can count down
                // spin until transmit buffer needs to be reloaded
                while((UCB0IFG & UCTXIFG) == 0)
                {
                    status = i2cUcb0CheckNakTimeout(timeout, 1);
    
                    if (status != 0)
                    {
    
                        char c;
                        intToStr(status, &c);
                        char arrC[2];
                        arrC[0] = c;
                        arrC[1] = '\0';
                        sendUserMessage("WritE failed, status: \r");
                        __delay_cycles(4000);
                        sendUserMessage(arrC);
                        sendUserMessage("\n\r");
    
                        i2cUcb0Cleanup();
                        if (intDisabled)
                            __enable_interrupt();
                        return status;
                    }
                }
    
                //UCB1IV &=~USCI_I2C_UCTXIFG;
                // load another data byte
                UCB0TXBUF = *dataPtr;
    
                sendUserMessage("wrote to txbuf: \r");
                __delay_cycles(4000);
    
                char d = 0;
                intToStr((*dataPtr), &d);
                char arrD[2];
                arrD[0] = d;
                arrD[1] = '\0';
                sendUserMessage(arrD);
                __delay_cycles(4000);
                sendUserMessage("\n\r");
    
                // increment actual byte counter
                *bytes_written = *bytes_written + 1;
    
                // increment the pointer address
                dataPtr++;
    
                // take a new baseline timer value
                i2c0BaselineTimer = TA0R;
            }
        }
    
        // wait until the last byte has been transferred
        while ((UCB0IFG & UCTXIFG) == 0)
        {
            status = i2cUcb0CheckNakTimeout(timeout, 1);
    
            if (status != 0)
            {
                __delay_cycles(4000);
                sendUserMessage("Failed after sending last byte, status: \n\r");
                char d = 0;
                intToStr((*dataPtr), &d);
                char arrD[2];
                arrD[0] = d;
                arrD[1] = '\0';
                sendUserMessage(arrD);
                i2cUcb0Cleanup();
                if (intDisabled)
                    __enable_interrupt();
                return status;
            }
        }
        // generate a stop
        UCB0CTL1 |= UCTXSTP;
        //while(UCB0STAT & UCBBUSY){};
    
    
        if(UCB0STAT & UCBBUSY)
        {
            __delay_cycles(10000); //Wait
            if(UCB0STAT & UCBBUSY)
            {
                testI2c0Busy++;
                UCB0CTL1 = UCSWRST;
                __delay_cycles(1000);
                UCB0CTL1 &= ~UCSWRST;
                //break;
            }
        }
    
        // turn off the timer to save power
        //TA1CTL &= ~MC_2;
    
        UCB0IFG &= ~UCTXIFG;
    
        // no errors, all bytes transmitted
        UCB0IE &= ~UCNACKIE;
        UCB0IE &= ~UCTXIE;
        if (intDisabled)
            __enable_interrupt();
        sendUserMessage("WRITE SUCCESSFUL\n\r");
        __delay_cycles(4000);
    
        return 0;
    }
    
    uint08 i2cUcb1PolledRead(uint08 device_addr, uint08* read_data, uint08 num_bytes, uint08* bytes_read, uint08 timeout)
    /**
     * Reads data from the specified device address
     *
     * @param   device_addr   - I - 7 Bit device Address
     * @param   read_data     - I - Pointer to buffer to hold received data from slave
     * @param   num_bytes     - I - Number of bytes to be read
     * @param   bytes_read    - O - Actual number of bytes read from slave
     * @param   timeout       - I - Timeout max (in msec) between each received byte
     *                              Timeout=0, permits an infinite timeout (not recommended). Max value = 65
     * @return  0 - Completed successfully 
     *          I2C_NO_ACK - Slave NAck'ed            
     *          I2C_TIMEOUT - Slave did not respond before timeout period expired
     *          I2C_INVALID_TIMEOUT - timeout parameter is greater than 65
     *
     */
    {
      uint08 status;
      uint08* dataPtr = read_data;
      uint08 i;
      uint16 currentSr;
      uint08 intDisabled = 0;
      
      // check for argument validity
      if ( timeout > 65 )
        return I2C_INVALID_TIMEOUT;
        
      // since this version is polled, we don't want an interrupt firing
      //  and the ISR taking over
      currentSr = __get_SR_register();
      if ( currentSr & GIE ) {
        intDisabled = 1;
        __disable_interrupt();
      }
        
      // turn on the timer
      TBCTL |= MC_2;
      i2cBaselineTimer = TBR;
    
      // write the slave address and kick off the transfer
    
      UCB1CTL1 = UCSWRST;
      UCB1CTL1 = UCSSEL_2 + UCSWRST;
      UCB1I2CSA = device_addr>>1;
      UCB1CTL1 &= ~UCSWRST;
      UCB1IE |= UCNACKIE;
      //IE2 |= UCB0RXIE;
    
      UCB1CTL1 |= UCTXSTT;
        
      if ( num_bytes == 1 ) {
        // spin until start condition cleared
        while ( UCB1CTL1 & UCTXSTT ) {
          status = i2cUcb1CheckNakTimeout(timeout, 1);
          
          if ( status != 0 ) {
            i2cUcb1Cleanup();
            if ( intDisabled )
              __enable_interrupt();
            return status;
          }
        }
        UCB1CTL1 |= UCTXSTP;
        while ( (UCB1IFG & UCRXIFG) == 0 ) {
          status = i2cUcb1CheckNakTimeout(timeout, 1);
          
          if ( status != 0 ) {
            i2cUcb1Cleanup();
            if ( intDisabled )
              __enable_interrupt();
            return status;
          }
        }
        *read_data = UCB1RXBUF;
        *bytes_read = 1;
      } else {
        *bytes_read = 0;
        
        for ( i=0; i<num_bytes; i++ ) {
          // spin until data is available
          while ( (UCB1IFG & UCRXIFG) == 0 ) {
            status = i2cUcb1CheckNakTimeout(timeout, 1);
            
            if ( status != 0 ) {
              i2cUcb1Cleanup();
              if ( intDisabled )
                __enable_interrupt();
              return status;
            }
          }
          
          // increment actual byte counter
          *bytes_read = *bytes_read + 1;
          
          // copy received byte
          *dataPtr = UCB1RXBUF;
          
          // increment the pointer address
          dataPtr++;
          
          // take a new baseline timer value
          i2cBaselineTimer = TBR;
      
          // send stop after the next byte
          if ( i == (num_bytes-2) )
        	  UCB1CTL1 |= UCTXSTP;
        }
      }    
      
      // turn off the timer to save power
      //while (UCB1STAT & UCBBUSY){}
    
      if(UCB1STAT & UCBBUSY)
        {
    
            __delay_cycles(10000);  //Wait
            if (UCB1STAT & UCBBUSY)
            {
                testI2c1Busy++;
                UCB1CTL1 = UCSWRST;
                __delay_cycles(1000);
                UCB1CTL1 &= ~UCSWRST;
    
            }
        }
      TBCTL &= ~MC_2;
      UCB1IE &= ~UCNACKIE;
      UCB1IE &= ~UCRXIE;
      //UCB0I2CIE &= ~UCNACKIE;
      //IE2 &= ~UCB0RXIE;
      
      // no errors, all bytes received
      if ( intDisabled )
        __enable_interrupt();
      return 0;
    }
    
    uint08 i2cUcb0ByteRead(uint08 device_addr, uint08* write_data, uint08 num_bytes_write, uint08* read_data, uint08* bytes_written, uint08* bytes_read, uint08 timeout)
    {
          /*
           * function to do random reads from EEPROM, Temperature Sensor, Digital Audio Amp
           * It involves first sending a write request followed by a read
           *
           */
        uint08 status;
        uint08* dataPtr = write_data;
        uint08 i;
        uint16 currentSr;
        uint08 intDisabled = 0;
    
        // check for argument validity
        if (timeout > 500)    //65, increased for testing
            return I2C_INVALID_TIMEOUT;
    
        // since this version is polled, we don't want an interrupt firing
        //  and the ISR executing
        currentSr = __get_SR_register();
        if (currentSr & GIE)
        {
            intDisabled = 1;
            __disable_interrupt();
        }
    
        // turn on the timer
        //TA1CTL |= MC_2;
        i2c0BaselineTimer = TA0R;
    
        // write the slave address and configure i2c hardware
        UCB0CTL1 = UCSWRST;
        UCB0CTL1 = UCSSEL_2 + UCSWRST;
        UCB0I2CSA = device_addr >> 1;
        UCB0CTL1 &= ~UCSWRST;
    
        // enable module interrupts and start the transfer
        UCB0IE |= UCNACKIE;
        UCB0IE |= UCTXIE;
        //IE2 |= UCB1TXIE;
        UCB0CTL1 |= UCTR + UCTXSTT; //ideally, it should be done before clearing UCSWRST
    
        if(1) //device_addr == SI7060_SLAV_ADDR
        {
            __delay_cycles(2000); //delay increased for testing
        }
    
    
        sendUserMessage("Read function, ST sent\n\r");
    
        __delay_cycles(1000);
        *bytes_written = 0;
    
        //check for NAK?
        status = i2cUcb0CheckNakTimeout(0, 1);
        if(status != 0)
        {
    
            i2cUcb0Cleanup();
            sendUserMessage("NAK after sending ST\n\r");
            __delay_cycles(1000);
            if (intDisabled)
                __enable_interrupt();
            return status;
        }
        //Write Address High and Address Low Bytes
    
        for(i = 0;i < num_bytes_write;i++)
        {    //can count down
             // spin until transmit buffer needs to be reloaded
            while ((UCB0IFG & UCTXIFG) == 0)   //is this checking for ACK?
            {
                status = i2cUcb0CheckNakTimeout(timeout, 1);
                if(status != 0)
                {
                    i2cUcb0Cleanup();
                    if (intDisabled)
                        __enable_interrupt();
                    return status;
                }
            }
    
            //UCB1IV &=~USCI_I2C_UCTXIFG;
            // load another data byte
            UCB0TXBUF = *dataPtr;
    
            // increment actual byte counter
            *bytes_written = *bytes_written + 1;
    
            // increment the pointer address
            dataPtr++;
    
            // take a new baseline timer value
            i2cBaselineTimer = TA0R;
    
            //sendUserMessage("wrote to txbuf\n\r");
            __delay_cycles(1000);
        }
    
        //Check for ACK ?
        while((UCB0IFG & UCTXIFG) == 0)
        {
            status = i2cUcb0CheckNakTimeout(timeout, 1);
    
            if(status != 0)
            {
                sendUserMessage("NACK after writing to txbuf\n\r");
                __delay_cycles(1000);
                i2cUcb0Cleanup();
                if (intDisabled)
                    __enable_interrupt();
                return status;
            }
        }
    
        //Send START followed by ControlByte for Receiver Mode
        UCB0CTL1 &= ~(UCTR);  //Clear the last bit -- is this required?
        UCB0I2CSA = device_addr >> 1;
        UCB0CTL1 |= UCTXSTT;  //Check if indeed receiver Mode
    
        //No. of bytes to be read is 1
    
        //check NACK?
    
        status = i2cUcb0CheckNakTimeout(0, 1);
        if(status != 0)
        {
            sendUserMessage("NACK after sending repeated start\n\r");
            __delay_cycles(1000);
            i2cUcb0Cleanup();
            if (intDisabled)
                __enable_interrupt();
            return status;
        }
    
        // spin until start condition cleared
        while(UCB0CTL1 & UCTXSTT)
        {
            status = i2cUcb0CheckNakTimeout(timeout, 1);
    
            if(status != 0)
            {
                sendUserMessage("Read Failed waiting for st clear\n\r");
                __delay_cycles(1000);
                i2cUcb0Cleanup();
                if (intDisabled)
                    __enable_interrupt();
                return status;
            }
        }
    
        //wait for data to be received
        while((UCB0IFG & UCRXIFG) == 0)
        {
            status = i2cUcb0CheckNakTimeout(timeout, 1);
    
            if(status != 0)
            {
                i2cUcb0Cleanup();
                if (intDisabled)
                    __enable_interrupt();
                return status;
            }
        }
    
        UCB0CTL1 |= UCTXNACK;       //send NACK after receiving a byte
        UCB0CTL1 |= UCTXSTP;        //finally send STOP
    
        *read_data = UCB0RXBUF;
        *bytes_read = 1;
    
        // turn off the timer to save power
        //while (UCB0STAT & UCBBUSY){}
    
    
        if(UCB0STAT & UCBBUSY)
        {
            __delay_cycles(10000); //Wait
            if (UCB0STAT & UCBBUSY)
            {
                testI2c0Busy++;
    
                UCB0CTL1 = UCSWRST;
                __delay_cycles(1000);
                UCB0CTL1 &= ~UCSWRST;
                //break;
            }
        }
    
        //TA1CTL &= ~MC_2;
        UCB0IFG &= ~UCTXIFG; //to cleasr TXIFG
        UCB0IE &= ~UCNACKIE;
        UCB0IE &= ~UCRXIE;
        //UCB0I2CIE &= ~UCNACKIE;
        //IE2 &= ~UCB0RXIE;
        t1 = TA0R;
        sendUserMessage("READ SUCCESSFUL\n\r");
        t2 = TA0R - t1;
        //__delay_cycles(1000);
        // no errors, all bytes received
        if (intDisabled)
            __enable_interrupt();
        return 0;
    }
    
    uint08 i2cUcb1CheckNakTimeout(uint08 timeout, uint08 check_nak)
    /**
     * 
     * @param   timeout   - I - Timeout max (in msec)
     *                          Timeout=0, permits an infinite timeout (not recommended). Max value = 65
     * @param   check_nak - I - Interrupt driven routines do not need to check for no acknowledge from
     *                          slave devices. 1=check for nak, 0=do not check for nak
     *
     * @return  0 - Completed successfully 
     *          I2C_NO_ACK - Slave NAck'ed            
     *          I2C_TIMEOUT - Slave did not respond before timeout period expired
     *
     */
    {
      uint16 currentTimerVal;
      uint16 timerDiff;
      
      // check for NAK
      if ( check_nak ) {
        if ( UCB1IFG & UCNACKIFG ) {
          // send a stop and clear the interrupt flag
        	UCB1CTL1 |= UCTXSTP;
        	 //while (UCB1STAT & UCBBUSY){};
            if (UCB1STAT & UCBBUSY)
            {
    
                    __delay_cycles(10000);  //Wait for 1s
    
                if (UCB1STAT & UCBBUSY)
                {
                    testI2c1Busy++;
                    UCB1CTL1 = UCSWRST;
                    __delay_cycles(1000);
                    UCB1CTL1 &= ~UCSWRST;
                    //break;
                }
    
            }
        	//UCB1IV &= ~USCI_I2C_UCNACKIFG;
        	 UCB1IFG &= ~UCNACKIFG;
        	TBCTL &= ~MC_2;
        	UCB1CTL1 = UCSWRST;
        	return I2C_NO_ACK;
        }
      }
    
      // do we need to check for timeout?
      if ( timeout != 0 ) {
        currentTimerVal = TBR;
    
        // check for TBR rollover since we baselined
        if ( currentTimerVal > i2cBaselineTimer )
          timerDiff = currentTimerVal - i2cBaselineTimer;
        else
          timerDiff = (65535 - i2cBaselineTimer) + currentTimerVal;
        
        // a count of 1000 is equal to 1ms, approximate with shift by 10
        // have we reached the timeout for this byte?
        //if ( (timerDiff>>10) > timeout ) {
        if ( (timerDiff >>10) >= (timeout) ) {
          // generate a stop and return the error flag
          TBCTL &= ~MC_2;
          UCB1CTL1 |= UCTXSTP;
          //while (UCB1STAT & UCBBUSY){};
          //trying to solve I2C stuck issue
          if(UCB1STAT & UCBBUSY)
          {
    
              __delay_cycles(10000);  //Wait
    
              if(UCB1STAT & UCBBUSY)
              {
                  testI2c1Busy++;
                  UCB1CTL1 = UCSWRST;
                  __delay_cycles(1000);
                  UCB1CTL1 &= ~UCSWRST;
                        //break;
              }
    
          }
    
          return I2C_TIMEOUT;
        }
      }
      
      // nak or timeout did not occur
      return 0;
    }
    
    uint08 i2cUcb0CheckNakTimeout(uint08 timeout, uint08 check_nak)
    /**
     *
     * @param   timeout   - I - Timeout max (in msec)
     *                          Timeout=0, permits an infinite timeout (not recommended). Max value = 65
     * @param   check_nak - I - Interrupt driven routines do not need to check for no acknowledge from
     *                          slave devices. 1=check for nak, 0=do not check for nak
     *
     * @return  0 - Completed successfully
     *          I2C_NO_ACK - Slave NAck'ed
     *          I2C_TIMEOUT - Slave did not respond before timeout period expired
     *
     */
    {
        uint16 currentTimerVal;
        uint16 timerDiff;
    
        // check for NAK
        if(check_nak)
        {
            if(UCB0IFG & UCNACKIFG)
            {
                // send a stop and clear the interrupt flag
                UCB0CTL1 |= UCTXSTP;
                //while(UCB0STAT & UCBBUSY){}
    
    
                if(UCB0STAT & UCBBUSY)
                {
                    __delay_cycles(10000); //Wait for 1sec
                    if(UCB0STAT & UCBBUSY)
                    {
                        testI2c0Busy++;
    
                        UCB0CTL1 = UCSWRST;
                        __delay_cycles(1000);
                        UCB0CTL1 &= ~UCSWRST;
                        //break;
                    }
                }
    
                //UCB1IV &= ~USCI_I2C_UCNACKIFG;
                UCB0IFG &= ~UCNACKIFG;
                //TA1CTL &= ~MC_2;
                UCB0CTL1 = UCSWRST;
                return I2C_NO_ACK;
            }
        }
    
        // do we need to check for timeout?
        if(timeout != 0)
        {
            currentTimerVal = TA0R;
    
            // check for TA1R rollover since we baselined
            if (currentTimerVal > i2c0BaselineTimer)
                timerDiff = currentTimerVal - i2c0BaselineTimer;
            else
                timerDiff = (65535 - i2c0BaselineTimer) + currentTimerVal;
    
            // Current TimerA0 frequency is 32768Hz (ACLK with ID_0)
            // A timer count of 33 corresponds to 1ms
    
            if((timerDiff >> 10) >= (timeout))
            {
                // generate a stop and return the error flag
                //TA1CTL &= ~MC_2;
                UCB0CTL1 |= UCTXSTP;
    
                if(UCB0STAT & UCBBUSY)           //while(UCB0STAT & UCBBUSY)
                {
    
                    testI2c0Busy++;
                    /*
                     P3SEL &= ~(MCU_UCB0_SDA|MCU_UCB0_SCL);
    
                     uint08 i;
                     for(i=0;i<100;i++)
                     {
                     P3OUT &= ~(MCU_UCB0_SDA|MCU_UCB0_SCL);
                     __delay_cycles(100);
                     P3OUT |= (MCU_UCB0_SDA|MCU_UCB0_SCL);
                     }
    
                     P3SEL |= (MCU_UCB0_SDA|MCU_UCB0_SCL);
                     */
                    UCB0CTL1 = UCSWRST;
                    __delay_cycles(1000);
                    UCB0CTL1 &= ~UCSWRST;
                }
    
                //while (UCB0STAT & UCBBUSY){};
    
                return I2C_TIMEOUT;
            }
        }
    
        // nak or timeout did not occur
        return 0;
    }
    
    void i2cUcb1Cleanup(void)
    /**
     * Cleanup after a failed transaction. Turn off the timer, disable interrupts,
     * and put the I2C hardware into reset.
     *
     */
    {
      // turn off the timer to save power
      TBCTL &= ~MC_2;
      
      // clear interrupt flags
      UCB1IFG &= ~UCTXIFG;
      //IFG2 &= ~UCB0TXIFG;
      
      // no errors, all bytes transmitted
      UCB1IE &= ~UCNACKIE;
      UCB1IE &= ~UCTXIE;
      //UCB0I2CIE &= ~UCNACKIE;
      //IE2 &= ~UCB0TXIE;
    
      // put i2c hardware into reset  
      UCB1CTL1 = UCSWRST;
    }
    
    void i2cUcb0Cleanup(void)
    /**
     * Cleanup after a failed transaction. Turn off the timer, disable interrupts,
     * and put the I2C hardware into reset.
     *
     */
    {
      // turn off the timer to save power
      //TA1CTL &= ~MC_2;
    
      // clear interrupt flags
      UCB0IFG &= ~UCTXIFG;
      //IFG2 &= ~UCB0TXIFG;
    
      // no errors, all bytes transmitted
      UCB0IE &= ~UCNACKIE;
      UCB0IE &= ~UCTXIE;
      //UCB0I2CIE &= ~UCNACKIE;
      //IE2 &= ~UCB0TXIE;
    
      // put i2c hardware into reset
      UCB0CTL1 = UCSWRST;
    }
    
    void i2cUcb1Setup(uint32 rate)
    {
    	i2cUcb1Init();
    	i2cUcb1SetClockrate(rate);
    	i2cUcb1ConfigTimer();
    
    }
    
    void i2cUcb0Setup(uint32 rate)
    {
        i2cUcb0Init();
        i2cUcb0SetClockrate(rate);
        //i2cUcb0SConfigTimer();    use timer of Remote itself
    
    }
    

  • Hello Abhishek,

    many thanks for your code. It is too complex to see something just from a top level point of view. On the other hand it contains not the clock and other core infrastructure settings. As mentioned before, it seems your CPU is jumping to some empty memory space locations. This could result from a miss configuration of modules like clock system and power management.

    I would recommend you checking these against our specification.

    The other area to look into is potential errata. Please check the errata sheet for I2C errata.

    Please find here also the link to an application report on debugging serial communication issues

    What I have also seen in your code, you're resetting the communication module on multiple instances. Is this really necessary? Of course on re-initialization of the settings, this should be done, but unless you're not changing the communication settings, this should not be necessary.

    Best regards

    Peter

  • Hi Peter,

    Thanks for going through the code. This was the existing code when I joined my workplace and because it was working, I let it be. I had been thinking of changing it as well. While it can be improved, there is no obvious error with it that should cause this behaviour, right?

    I might have diagnosed the cause of this. The MCLK frequency was 16MHz(through the internal DCO). On increasing or decreasing this frequency, the code is running fine in MCUs that were getting corrupted within seconds. As far as I know, the maximum frequency for MSP430F5524 is 25MHz. So, any idea why this could be happening? Could this simply be an issue with the ICs as discussed above(improper handling, ESD events etc.)?

    You have spoken about the clk frequency being too high for the Vcore voltage being used. Could you tell me more about Vcore voltage? How can I measure this? The MSP430 is being powered by 3.3V in our case and I have verified it manually at all the points where this voltage is being set.

    Here is the code where I am setting the MCLK frequency. Could you let me know if this is okay?

    UCSCTL3 |= SELREF_2;               // Set DCO FLL reference = REFO
    UCSCTL4 |= SELA_2;                   // Set ACLK = REFO
    UCSCTL0 = 0x0000;                    // Set lowest possible DCOx, MODx
    // Loop until XT1,XT2 & DCO stabilizes - In this case only DCO has to stabilize
    do
    {
    UCSCTL7 &= ~(XT2OFFG | XT1LFOFFG | DCOFFG);
    // Clear XT2,XT1,DCO fault flags
    SFRIFG1 &= ~OFIFG; // Clear fault flags
    }
    while (SFRIFG1&OFIFG); // Test oscillator fault flag

    __bis_SR_register(SCG0); // Disable the FLL control loop
    UCSCTL1 = DCORSEL_5; // Select DCO range 16MHz operation
    UCSCTL2 = FLLD_0 + 487; // Set DCO Multiplier for 16MHz // (487 + 1) * 32768 = 16MHz
    __bic_SR_register(SCG0); // Enable the FLL control loop

    // Worst-case settling time for the DCO when the DCO range bits have been
    // changed is n x 32 x 32 x f_MCLK / f_FLL_reference. See UCS chapter in 5xx
    // UG for optimization.
    // 32 x 32 x 16 MHz / 32,768 Hz = 500000 = MCLK cycles for DCO to settle

    __delay_cycles(500000);

    Thanks and Regards

    Abhishek

  • Hi Peter,

    An update: The Vcore voltage is about 1.4 Volts.

    Thanks and Regards

    Abhishek

  • Hi Abhishek,

    sorry for my late response. Last week I have been sick and still in the process of catching up with things.

    Based on the additional information you have provided, I have the suspicion, the Vcore handling and settings you're using in your code are not according to our specification.

    Please let me start with the Vcore setting. The device starts with Vcore setting PMMCOREV 0 after power on reset.  Especially, when trying to operate the device at higher frequencies, the Vcore setting has to be adjusted. From the information you have provided, I see you're using 16MHz in your system. According to the datasheet you need to use for 16MHz at least Vcore setting 2. From the measured Vcore in your last post, I assume you're sitting rather at Vcore = 0 (PMMCOREV). This means by far too low for a clocking with 16MHz. As of course we have margins in our design, some of the devices are able to operate at this too low Vcore, but for some it gets critical, as you're far off from the specification.

    The next point is the Vcore handling. As mentioned, you need to switch the PMM from Vcore 0 to Vcore 2. This has to be done using a certain recommended sequence. You can find it in the User's Guide, but for your convenience I am copying the main points here.

    Best regards

    Peter

  • Hi Peter

    I hope you get back to your best very soon.

    Thanks a lot for your detailed reply. I have holidays for the next 2-3 days. I'll go through your post again, try to implement the changes you have mentioned and get back to you. After reducing the clock speed to 12MHz, there has not been a single IC that has misbehaved so far (fingers crossed things won't change).

    Thanks

    Abhishek

  • Hi Abhishek,

    this result also indicates, the Vcore settings being a problem. Please keep in mind also with 12MHz you should set Vcore to setting 1, to be compliant with the datasheet specification, if it's not already the case, following also the sequence, when switching from Vcore 0 to Vcore 1, as described above.

    Best regards

    Peter

  • Hi Peter,

    Thanks for pointing this out to me. I simply wasn't aware of the concepts of PMM. I couldn't devote a lot of time to it today, but this is what I did. I copy-pasted the code to change core voltage present in the User Guide(pointed out by you) into a function and called it.

    SetVCoreUp(1);  //Change VCore voltage one level at a time

    SetVCoreUp(2);  //Change VCore voltage one level at a time

    It is now stuck in the while loop - while((PMMIFG & SVSMHDLYIFG )) == 0. I tried moving these two functions above and below the part where I am increasing the clock frequency to 16MHz, but the code continued to be stuck here. Is there anything that I am missing?

    Also, after reducing the CLK frequency to 12MHz, I haven't faced the issue despite not changing the Vcore voltage. Is it because the MCU is able to tolerate this despite the specification but 16MHz is way too over the limit?

    Thanks and Regards

    Abhishek

  • Hi Peter, 

    An Update. I commented out the two while loops where the code was stuck - while ((PMMIFG & SVSMHDLYIFG) == 0); and while ((PMMIFG & SVSMLDLYIFG) == 0);                             After this the function ran fine and the Vcore voltage changed to level 2. I verified the voltage level at the Vcore pin which was 1.8V. The MCU which was malfunctioning (within seconds) at a clock speed of 16MHz is now working fine. 

    I then felt that the corresponding interrupt bits(SVSMHDLYIFG and SVSMLDLYIFG) might not be getting set because the corresponding Interrupt Vector isn't enabled. I then added this line - PMMRIE |= (SVSMLDLYIE|SVSMHDLYIE);  But the code is jumping off to a random address preventing me from viewing the program state in the programmer after the execution of this line. (Update: This is an issue that is mentioned in the errata)

    (i) Is it fine if the two while loops are commented out ? I will leave this IC running for over 12-13 hours in this state and check tomorrow. The interrupt flags are getting set after setting SVSMHCTL to the require level.

    (ii) If not, anything that I am missing? Another thread suggested downloading the library from http://www.ti.com/tool/MSPWARE and using the functions there. There are a lot of functions there. I am yet to integrate that completely.

    (iii)I also saw that if the Vcore voltage is changed once, the settings are retained even after powering off the device. It's probably getting saved in the Flash, right?

    Thanks and Regards

    Abhishek

  • Hi Peter,

    An Update. I commented out the two while loops where the code was stuck - while ((PMMIFG & SVSMHDLYIFG) == 0); and while ((PMMIFG & SVSMLDLYIFG) == 0); After this the function ran fine and the Vcore voltage changed to level 2. I verified the voltage level at the Vcore pin which was 1.8V. The MCU which was malfunctioning (within seconds) at a clock speed of 16MHz is now working fine.

    I then felt that the corresponding interrupt bits(SVSMHDLYIFG and SVSMLDLYIFG) might not be getting set because the corresponding Interrupt Vector isn't enabled. I then added this line - PMMRIE |= (SVSMLDLYIE|SVSMHDLYIE); But the code is jumping off to a random address preventing me from viewing the program state in the programmer after the execution of this line.

    (i) Is it fine if the two while loops are commented out ? I will leave this IC running for over 12-13 hours in this state and check tomorrow.

    (ii) If not, anything that I am missing? Another thread suggested downloading the library from http://www.ti.com/tool/MSPWARE and using the functions there. There are a lot of functions there. I am yet to integrate that completely.

    (iii)I also saw that if the Vcore voltage is changed once, the settings are retained even after powering off the device. It's probably getting saved in the Flash, right?

    Thanks and Regards

    Abhishek

  • Hi Peter, 

    Another Update. The Vcore voltages I am observing at pin 17 after changing the PMMCOREVx are as follows

    PMMCOREV_0 - 1.4V                                                                                                                                                                                                                                                                 PMMCOREV_1 - 1.6V                                                                                                                                                                                                                                                          PMMCOREV_2 - 1.8V                                                                                                                                                                                                                                                            PMMCOREV_3 - 1.9V                       

    In the datasheet the graph for the frequency vs. voltage containing the required PMMCOREVx level had supply voltage on the x-axis. I am assuming it was referring to the 3.3V that is powering the MCU and not Vcore. Am I right? Is there a voltage range that Vcore is supposed to adhere to? Given that I am successfully able to change the PMMCOREVx (with the two lines commented as mentioned in the previous comment), should it not matter?

    Thanks and Regards

    Abhishek

  • Hi Abhishek,

    the typical values for the core voltages in active mode are

    PMMCOREV_0 - 1.4V            1.4V

    PMMCOREV_1 - 1.6V             1.6V

    PMMCOREV_2 - 1.8V             1.8V

    PMMCOREV_3 - 1.9V             1.9V

    so the values you measured match perfectly.

    In terms of of the while instructions and getting stuck there, there seems to be something wrong. Before going into debugging your code, please try MSP430F55xx_UCS_10.c code example from CCS. This switched the DCO to 25MHz and due to this contains the necessary switching for the Vcore.

    This should work with your device and HW. If not, we need to figure out why. This is btw a generic recommendation of mine, if something does not work, try to use one of our tested code examples, to check whether it works with your setup or not.

    Best regards

    Peter

  • Hi Peter,

    Apologies for the late reply. MSP430F55xx_UCS_10.c runs okay on my board (Pin 1.0 isn't connected to a LED but I put a breakpoint and checked). The SetVcoreUp( ) function in the code-snippet here doesn't have the two while loops in the beginning. So, this is identical to the function I had used with the while loops commented. 

    Also, the file MSP430F55xx_UCS_03.c seems to have a problem. The code uses a clock speed of 12MHz, but the Vcore voltage hasn't been increased. 

    Thanks

    Abhishek

  • Hi Abhishek,

    many thanks for the update. Also thanks you for pointing out the missing Vcore adjustment in MSP430F55xx_UCS_03.c. You're correct. This is definitely violating the device specification. I will file a bug on this.

    Regarding your statements on the MSP430F55xx_UCS_10.c I am not perfectly sure what while instructions you're speaking about. At least in my version of this code example, the "while ((PMMIFG & SVSMLDLYIFG) == 0);", which according to your previous post, your code way getting stuck in, are present in the "void SetVcoreUp (unsigned int level)" function, which is being called repeatedly, each time the Vcore is being modified.

    So please clarify this point. Many thanks in advance.

    Best regards

    Peter

  • Hi Peter,

    I am happy I was able to find a bug with the TI Example Code :)

    I find a difference between the SetVcoreUp() in MSP430F55xx_UCS_10.c and the one in the Programming Guide. In the former, once PMM registers are opened for access, two while loops are present -  

    // Make sure no flags are set for iterative sequences
    while ((PMMIFG & SVSMHDLYIFG) == 0);
    while ((PMMIFG & SVSMLDLYIFG) == 0);

    This is not present in MSP430F55xx_UCS_10.c or the one I have at least. I am not sure if there is a more recent version available. They are in a folder named slac300k. The further library structure is this way - slac300k/MSP430F55xx_Code_Examples/C/MSP430F55xx_UCS_10.c                                                                                                                                    Please find attached a picture of the function from the file I have.

    It's been a real pleasure posting and receiving replies from the forum, interacting with experts in the domain like you. Thanks a lot Peter!

    Cheers

    Abhishek

  • Hello Abhishek,

    many thanks for your feedback. I am happy to see you've been able to find the last missing point with our support. It's my pleasure to support professional users.

    So basically to summarize on top level, it has been on one hand the missing correct Vcore settings and on the other hand the missing opening of the PMM registers before manipulation.

    I will check our documentation on this, to make sure we have the correct recommendations there.

    Based on your feedback I am closing this thread.

    Best regards

    Peter

  • Hi Peter,

    One more(last?) question. The Vcore voltage is being increased now, but I am using the code with those two while loops commented(as per MSP430F55xx_UCS_10.c). Is this okay?The software programming guide has those two lines. As you know I had initially commented them just to resolve the infinite loops.

    Thanks and Regards

    Abhishek

  • Hi Abhishek,

    just to avoid misunderstandings on this point, the two while loops

     // Wait till SVM is settled
      while ((PMMIFG & SVSMLDLYIFG) == 0);
     ......
      // Wait till new level reached
      if ((PMMIFG & SVMLIFG))
        while ((PMMIFG & SVMLVLRIFG) == 0);

    are not commented out in our code example, means they are included and will be executed after code download to the device. And this is the recommended implementation, and that's how it should be also on your side.

    Best regards

    Peter

**Attention** This is a public forum