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.

5438 I2C interrupt

For some reason I am having problems with the 5438 recognizing interrupts  on the I2C ports. I know interrupts are working, I am using them for timing and USB without any problems.

Here is what I have.

I init with suggested code.

WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
  UCB0CTL1 |= UCSWRST;                      // Enable SW reset
  UCB0CTL0 = UCMODE_3 + UCSYNC;//    UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;     // I2C Master, synchronous mode
  UCB0CTL1 = UCSSEL_1 + UCSWRST;            // Use ACLK, keep SW reset
  UCB0BR0 = 48;                             // fSCL = ACLK(1.2mHz)/48 = ~84kHz
  UCB0BR1 = 0;
  UCB0I2CSA = 0x0B;                         // Slave Address is 048h
  UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
  UCB0IE |= UCSTPIE + UCSTTIE + UCRXIE + UCTXIE;

Port init is:

#define SetPort3  { P3SEL = 0xB6; P3OUT = 0x00; P3DIR = 0x49; P3REN = 0x00;}

P3.4 and P3.5 are used for USB comms and works fine.

ISR code is:(again from suggested code)

#pragma vector = USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
{
  switch(__even_in_range(UCB0IV,12))
  {
  case  0: break;                           // Vector  0: No interrupts
  case  2: break;                           // Vector  2: ALIFG
  case  4: break;                           // Vector  4: NACKIFG
  case  6: break;                           // Vector  6: STTIFG
  case  8: break;                           // Vector  8: STPIFG
 case 10:                                  // Vector 10: RXIFG
    RXByteCtrB0--;                            // Decrement RX byte counter
    if (RXByteCtrB0>0)
    {
      *PRxB0Data++ = UCB0RXBUF;               // Move RX data to address PRxData
      if (RXByteCtrB0 == 1)                   // Only one byte left?
        UCB0CTL1 |= UCTXSTP;                // Generate I2C stop condition
    }
    else
    {
      *PRxB0Data = UCB0RXBUF;                 // Move final RX data to PRxData
      __bic_SR_register_on_exit(LPM0_bits); // Exit active CPU
    }
    break;
  case 12:                                  // Vector 12: TXIFG
    if (TXByteCtrB0>0)                          // Check TX byte counter
    {
      UCB0TXBUF = *PTxB0Data++;               // Load TX buffer
      TXByteCtrB0--;                          // Decrement TX byte counter
    }
    else
    {
      UCB0CTL1 |= UCTXSTP;                  // I2C stop condition
      UCB0IFG &= ~UCTXIFG;                  // Clear USCI_B0 TX int flag
      __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
    }
  default: break;
  }
}

I am using a MSP-EXP5438 board talking to DeVaSys USB-I2CIO. The DeVaSys works with other applications and it does transmit when requested, but the MSP never gets an interrupt!!

Where am I going wrong?

Thanks in advance for your assistance.

GT

  • Two generic things about I2C.

    1) you need external pullups on SCL and SDA, usually ~10k. Th einternal pullups on teh 5438 are disabled if a pin is output pin, so they are off when data and clock are sent.
    2) the slave address to be written to UCxySA is only the upper 7 bits, right-justified. The LSB, that is part of the slave address in many I2C slave datasheets, is automatically added based on the UCTR bit. So f the slave has the addres 0x10/0x11 for write/read, the address to be used on the USCI is 0x08.

    On 2x family MSPs, the USCI has two interrupt vectors for RX and TX. There in I2C mode, both, RXIFG and TXIFG trigger the TX interrupt vector while status changes are going to the RX vector. On 5x family, however, the USCIA and USCIB each have their own interrupt vector, where all interrupt events are routed to.

    Gerry Tucker said:
    #define SetPort3  { P3SEL = 0xB6; P3OUT = 0x00; P3DIR = 0x49; P3REN = 0x00;}

    Why 0xb8? This enables UCB1SIMO/UCB1SDA too. Won't hurt, but is, well, unexpected.

    However, do you ever call the SetPort3 macro? The define itself is just a 'text replacement' instruction. and generates no code. Only if you do "SetPort3;" somewhere in main, it will insert the code into your program.

    Gerry Tucker said:
    UCB0IE |= UCSTPIE + UCSTTIE + UCRXIE + UCTXIE;
    UCSTPIE and UCSTTIE are only required when the USCI runs as slave or in multi-master mode. They are triggered if a different master creates a start or stop condition. You should rather enable the UCNACKIE. Which is triggered if you sent a start condition and slave address, but no slave responded. You won't ever get an RXIFG interrupt if no slave responded :)

    Gerry Tucker said:
    UCB0I2CSA = 0x0B;                         // Slave Address is 048h

    Now this really doesn't match. 0x0b will generate an address byte of 0x16 for write and 0x17 for read. But definitely not address a slave with address 0x48/0x49.

  • Thanks for your response.

    Some clarification .

    P3.0 UCB0STE and P3.3 UCB0CLK are used for driving a LCD. This works OK

    P3.4 UCA0TXD and P3.5 UCA0RXD are used for USB comms. This also works fine with    __interrupt void USCI_A0_ISR(void)

    P3.7UCB1SDA and P5.4 UCB1SCL will be used in the future for I2C Master.

    #define SetPort3  { P3SEL = 0xB6; P3OUT = 0x00; P3DIR = 0x49; P3REN = 0x00;} is called during initilization to set the pins.

    P3.1 UCB0SDA and P3.2 UCB0SCL are used as a slave device

    10K pullups are supplied by the DeVaSys Master.

    The 5438 UCB0 is supposed to be only a slave device. The address the DeVaSys is sending is 0x0B

     UCB0I2CSA = 0x0B;                        

    Sorry for the confusion The 5438 UCB0 is supposed to be only a slave device. The address the DeVaSys is sending is 0x0B not 0x48.

    If I scope the lines I do see a valid start condition being send from the DeVaSys device. but there is never a interrupt generated on the 5438!

    I am running in Debug mode using IAR and when I put a breakpoint  in the ISR at __interrupt void USCI_B0_ISR(void) it never seems to get there. No interrupt is ever seen!!

  • Gerry Tucker said:
    Sorry for the confusion The 5438 UCB0 is supposed to be only a slave device. The address the DeVaSys is sending is 0x0B not 0x48.


    So if the DeVaSys is sending  0x0a/0x0b (8-bit value) for slave write/read, then the MSPs slave address must be 0x05 (upper 7-bit value, right-justified), or else the USCI won't feel 'addressed'. And since it is the MSP itself who is addressed, the address needs to be written to UCB0I2COA (own address). UCB0I2CSA is unused in slave mode.

    Gerry Tucker said:
    UCB0CTL0 = UCMODE_3 + UCSYNC;//    UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;     // I2C Master, synchronous mode

    Here again, the comment was misguiding me. I didn't notice that you did not set the UCMST bit anymore and switched to slave mode. Else I had noticed the wrong usage of UCB0I2CSA earlier.
    p.s.: it isn't necessary on UCB to set the UCSYNC bit, as there is no ASYNC UART funcitonality and this bit is read-only and always set. It doesn't hurt, however.

**Attention** This is a public forum