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.

MSP430F5510, SDA is held high, SCL is low and UCBBUSY is always set.

Other Parts Discussed in Thread: MSP430F5510

Hi,

Many posts talk about a UCBBUSY always set because of SDA line held low by a slave.

My problem is the opposite, the UCBBUSY is set but the SDA line is always high.

I use the USCI I2C Master Library without DMA support (I modified it to fit to MSP430F5510).

Any known solution is wellcome !

 

this is my source code :

 


#include <msp430f5510.h>                           // more devices are possible

#include "i2c_engine.h"
#include "..\tools\timer.h"

signed char byteCtr;
unsigned char *TI_receive_field;
unsigned char *TI_transmit_field;

//------------------------------------------------------------------------------
// void TI_USCI_I2C_receiveinit(unsigned char slave_address,
//                              unsigned char prescale)
//
// This function initializes the USCI module for master-receive operation.
//
// IN:   unsigned char slave_address   =>  Slave Address
//       unsigned char prescale        =>  SCL clock adjustment
//-----------------------------------------------------------------------------
void TI_USCI_I2C_receiveinit(unsigned char slave_address,
                             unsigned char prescale){
  P4SEL |= SDA_PIN + SCL_PIN;                 // Assign I2C pins to USCI_B1
  UCB1CTL1 = UCSWRST;                        // Enable SW reset
  UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC;       // I2C Master, synchronous mode
  UCB1CTL1 = UCSSEL_2 + UCSWRST;              // Use SMCLK, keep SW reset
  UCB1BR0 = prescale;                         // set prescaler
  UCB1BR1 = 0;
  UCB1I2CSA = slave_address;                  // set slave address
  UCB1CTL1 &= ~UCSWRST;                       // Clear SW reset, resume operation
  UCB1IE |= UCNACKIE + UCRXIE;               // Enable RX interrupt
}


//------------------------------------------------------------------------------
// void TI_USCI_I2C_transmitinit(unsigned char slave_address,
//                               unsigned char prescale)
//
// This function initializes the USCI module for master-transmit operation.
//
// IN:   unsigned char slave_address   =>  Slave Address
//       unsigned char prescale        =>  SCL clock adjustment
//------------------------------------------------------------------------------
void TI_USCI_I2C_transmitinit(unsigned char slave_address,
                          unsigned char prescale){
  P4SEL |= SDA_PIN + SCL_PIN;                 // Assign I2C pins to USCI_B0
  UCB1CTL1 = UCSWRST;                        // Enable SW reset
  UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC;       // I2C Master, synchronous mode
  UCB1CTL1 = UCSSEL_2 + UCSWRST;              // Use SMCLK, keep SW reset
  UCB1BR0 = prescale;                         // set prescaler
  UCB1BR1 = 0;
  UCB1I2CSA = slave_address;                  // Set slave address
  UCB1CTL1 &= ~UCSWRST;                       // Clear SW reset, resume operation
  UCB1IE |= UCNACKIE + UCTXIE;
}

//------------------------------------------------------------------------------
// void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field)
//
// This function is used to start an I2C commuincation in master-receiver mode.
//
// IN:   unsigned char byteCount  =>  number of bytes that should be read
//       unsigned char *field     =>  array variable used to store received data
//------------------------------------------------------------------------------
void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field){
  TI_receive_field = field;
  if ( byteCount == 1 ){
    byteCtr = 0 ;
    __disable_interrupt();
    UCB1CTL1 |= UCTXSTT;                      // I2C start condition
    while (UCB1CTL1 & UCTXSTT);               // Start condition sent?
    UCB1CTL1 |= UCTXSTP;                      // I2C stop condition
    __enable_interrupt();
  } else if ( byteCount > 1 ) {
    byteCtr = byteCount - 2 ;
    UCB1CTL1 |= UCTXSTT;                      // I2C start condition
  } else
    while (1);                                // illegal parameter
}

//------------------------------------------------------------------------------
// void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field)
//
// This function is used to start an I2C commuincation in master-transmit mode.
//
// IN:   unsigned char byteCount  =>  number of bytes that should be transmitted
//       unsigned char *field     =>  array variable. Its content will be sent.
//------------------------------------------------------------------------------
void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field){
  TI_transmit_field = field;
  byteCtr = byteCount;
  UCB1CTL1 |= UCTR + UCTXSTT;                 // I2C TX, start condition
}

//------------------------------------------------------------------------------
// unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address)
//
// This function is used to look for a slave address on the I2C bus. 
//
// IN:   unsigned char slave_address  =>  Slave Address
// OUT:  unsigned char                =>  0: address was not found,
//                                        1: address found
//------------------------------------------------------------------------------
unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address){
  unsigned char slaveadr_bak, ucb0i2cie, returnValue;
  ucb0i2cie = UCB1IE   ;                      // restore old UCB1IE
  slaveadr_bak = UCB1I2CSA;                   // store old slave address
  UCB1IE &= ~ UCNACKIE;                       // no NACK interrupt
  UCB1I2CSA = slave_address;                  // set slave address
  UCB1IE &= ~(UCTXIE + UCRXIE);               // no RX or TX interrupts
  __disable_interrupt();
  UCB1CTL1 |= UCTR + UCTXSTT + UCTXSTP;       // I2C TX, start condition
  while (UCB1CTL1 & UCTXSTP);                 // wait for STOP condition
 
  returnValue = !(UCB1IFG & UCNACKIFG);
  __enable_interrupt();
  UCB1I2CSA = slaveadr_bak;                   // restore old slave address
  UCB1IE = ucb0i2cie;                      // restore old UCB1CTL1
  return returnValue;                         // return whether or not
                                              // a NACK occured
}

//------------------------------------------------------------------------------
// unsigned char TI_USCI_I2C_notready()
//
// This function is used to check if there is commuincation in progress.
//
// OUT:  unsigned char  =>  0: I2C bus is idle,
//                          1: communication is in progress
//------------------------------------------------------------------------------
unsigned char TI_USCI_I2C_notready(){
  return (UCB1STAT & UCBBUSY);
}


#pragma vector = USCI_B1_VECTOR
__interrupt void USCIAB1RX_ISR(void)
{
  if (UCB1IFG & UCNACKIFG){            // send STOP if slave sends NACK
    UCB1CTL1 |= UCTXSTP;
    UCB1STAT &= ~UCNACKIFG;
  }

  if (UCB1IFG & UCRXIFG){
    if ( byteCtr == 0 ){
      UCB1CTL1 |= UCTXSTP;                    // I2C stop condition
      *TI_receive_field = UCB1RXBUF;
      TI_receive_field++;
    }
    else {
      *TI_receive_field = UCB1RXBUF;
      TI_receive_field++;
      byteCtr--;
    }
  }
  if (UCB1IFG & UCTXIFG){
    if (byteCtr == 0){
      UCB1CTL1 |= UCTXSTP;                    // I2C stop condition
      UCB1IFG &= ~UCTXIFG;                     // Clear USCI_B0 TX int flag
    }
    else {
      UCB1TXBUF = *TI_transmit_field;
      TI_transmit_field++;
      byteCtr--;
    }
  }
}


  • It would have been nice if you had marked the parts you changed.
    Also, for which MSP was teh lib originally? A 2x device? The USCI on 2x devices had the interrupt vectors arrange differently: A and B module shared the same interrupt for RX and TX respectively, while on 5x devices each module has its own vector with RX and TX combined. SO maybe the interrupt vectors need to be reprogrammed too.

    Are you sure you have configured the ports correctly? SDA_PIN and SCL_PIN need to be adjusted as well as the port itself.

  • Jens-Michael Gross said:
    It would have been nice if you had marked the parts you changed.

    You're right, I only modified the register names, the USCI used (originaly B0)  and the interrupt vector.

     

    Jens-Michael Gross said:
    Also, for which MSP was teh lib originally? A 2x device?

    That's true, it was a F2x.

    Jens-Michael Gross said:
    Are you sure you have configured the ports correctly? SDA_PIN and SCL_PIN need to be adjusted as well as the port itself.

    It's done.

     

    The bug happen when I release the UCSWRST of UCB1CTL register. The bus appear busy whereas the SDA is high and SCL is low.

  • bertrand Badonnel said:

    Also, for which MSP was the lib originally? A 2x device?


    That's true, it was a F2x.[/quote] So you need to rewrite the ISRs. what was split over two ISRs on teh 2x devices, is now handled by one ISR on the 5x family.

    bertrand Badonnel said:
    when I release the UCSWRST of UCB1CTL register. The bus appear busy whereas the SDA is high and SCL is low.

    Since you didn't write UCSTT or similar, teh module should be inactive. UCBUSY being set is likely a direct result of SCL being low.
    YO do have pullup resistors on SDA and SCL? I2C is an open collector bus. It measn that all peers are only pulling to low or going high-impedance. Nobody pulls the lines hig actively. You require a pullup resistor. And you cannot use the internal pullups as they are too weak and also deactivated when the port pin is in putput direction (which it is for SCL all the time in master mode, and temporarily for SDA also, if the MSP is sending).

    On 2x family, the internal pullups are active even if the port pin is set to output direction. (they are still too weak for a reliable high speed or multi-slave I2C operation)

  • Jens-Michael Gross said:
    YO do have pullup resistors on SDA and SCL?

    Yes I do, both SDA and SCL lines are pulled up with 5k6 resistors.

     

    Does the prescaler is important in my case? I'm not sure of his value.

  • bertrand Badonnel said:
    Does the prescaler is important in my case? I'm not sure of his value.

    The clock frequency is almost totally unimportant. The I2C master provides the clock and therefore any frequency will fit. (the original I2C spec says 10kHz to 100kHz, newer go up to 400kHz or even 1MHz, but only a few slaves - with internal timeout - complain if the frequency is below 10kHz)

    The only important thing is that there IS a clock frequency at all. If not, the state machine will enter the first step in the protocol and then wait forever for the next clock pulse.

    bertrand Badonnel said:
    both SDA and SCL lines are pulled up with 5k6 resistors.

    So what is the level of thses two when teh MSP is in reset state (and its outputs are high impedance)? If SCL is still low, then you have a problem with your PCB or with the slave device.

  • Jens-Michael Gross said:
    If SCL is still low, then you have a problem with your PCB or with the slave device.

     

    You're right !!

    I got zero ohm between SCL and GND.

  • bertrand Badonnel said:
    I got zero ohm between SCL and GND.

    Well, that's a bit less than expected, and definitely less than allowed :)

  • Thanks a lot for your help.

     

     

  • Hi bertrand,

    I am breaking my head on this i2C code for the F5510 as the original source was indeed for the F2619. How were your results finally? Did the code you posted finally work-out? Still get errors reported and I do not find the  "i2c_engine.h" anywhere.

    I wonder how you finally had your code complete.

    Thanks,

    Arnoud

  • can u plz send me main() program for above code

**Attention** This is a public forum