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.

I2C

Other Parts Discussed in Thread: MSP430F2416, PCF8574A, PCF8574

Hi

I am trying to read/write EEPROM from MSP430f2416 on I2C via PCA9547(8-channel I2C bus mux). The slave addr for the mux is (1110 XXXX), and I am using the 7-bit addressing mode. I am not receiving any acknowledgment from the slave after I send the address bits. I tried right/left alignment of the 8-bit addr on the 7bit register...but nothing seems to work.

Looking for some valuable advice.

 

Yogi

  • Yogi,

    I would like to clarify one point that you said: the register is an 8-bit register, and when we put a 7-bit value into an 8-bit register it gets justified in a specific way, but not all manufacturers or users may expect it to get justified the other way.  Have you tried to simply shift the address that one puts in the register?  That’s the only way to get two “mis-matched” devices to align.

  • Hi Brandon,

    I tried shifting the address...no luck. The PCA9547(8 channel I2C bus mux) address is 1110 XXXX, ..I tried all kind of shifting possible but still not receiving an ack. 

    I can see the Start condition, and the address going out on the bus (I have a scope with I2C capability). I would greatly appreciate your help on this.

     

    Yogi

     

     

  • Yogi,

    What value of pull-ups do you have on the I2C bus? We recommend 10K for each line. Also You should make sure what the minimum threshold is (probably in the d/s) for the slave device to recognize a digital high/low. Perhaps the slave device cannot "understand" the '430?

    I recommend the following to rule out any simple setup mistakes with the MSP430: take a simple code with 10K pull ups from the web, www.ti.com/msp430codeexamples and try to set up a simple communication with 2 MSP430s. If you are able to do that then you know the issue has nothing to do with simple setup stuff and you can focus on how the slave needs to see it's address.

    Are there any other devices on the I2C bus that could be interfering? This is not a multi-master setup, correct? If it is please note the associated bug in the errata.

     

  • Are you using any of the sample I2C code supplied by TI? I have worked with the USI version of the code and had no issues. The sample code usually is well documented as to how to set up specific device addresses.

  • Hi BrandonAzbell ,

             i'm using  PCF8574P  to interface 7 segment display  with MSP430F2274micro controller.  i am also  using a example  program  "msp430x22x4_uscib0_i2c_02 "  from " slac123d.zib "  zib file. As per the diagram in the program i have connected the hardware.  

     

    Hardware details:

    Pullup resistors = 10k(for scl),10k(for sda) , connected with VCC of 2274 (refered  diagram in the program)

    PCF8574p slave address : 0x20 ->>>  A0=A1=A2=VSS, grounded

    P0 pin of PCF8574P is connected to ground, [VSS]

    p1,p2,p3  pins of PCF8574P is connected to supply [VCC]

    p4-p7 pins of PCF8574P is connected to 4 pins of 7 segment display , the common pin of 7 segment display is connected to supply

    according to the program  if PCF8574P IC  gets  zero voltage in P0/p1/p2/P3 then one of this segment in P4/P5/P6/P7 segment must glow [ 7 segment is common anode type ].but  if  I run the program the I/O pins PCF8574 P0-P7 is getting voltage 3.35V [ VCC]

    so, no 7segment is glowing??????????

    can somebody provide me the reason for the problem or the proper Master( Transmit mode ) code with PCF interface .....

     

     

     

     

    //******************************************************************************
    //  MSP430F22x4 Demo - USCI_B0 I2C Master Interface to PCF8574, Read/Write
    //
    //  Description: I2C communication with a PCF8574 in read and write mode is
    //  demonstrated. PCF8574 port P is configured with P0-P3 input, P4-P7. Read
    //  P0-P3 input data is written back to Port P4-P7. This example uses the
    //  RX ISR and generates an I2C restart condition while switching from
    //  master receiver to master transmitter.
    //  ACLK = n/a, MCLK = SMCLK = TACLK = BRCLK = default DCO = ~1.2MHz
    //
    //                                MSP430F22x4
    //                              -----------------
    //                  /|\ /|\ /|\|              XIN|-
    //                  10k 10k  | |                 |
    //       PCF8574     |   |   --|RST          XOUT|-
    //       ---------   |   |     |                 |
    //  --->|P0    SDA|<-|---+---->|P3.1/UCB0SDA     |
    //  --->|P1       |  |         |                 |
    //  --->|P2       |  |         |                 |
    //  --->|P3    SCL|<-+---------|P3.2/UCB0SCL     |
    //  <---|P4       |            |                 |
    //  <---|P5       |            |                 |
    //  <---|P6       |            |                 |
    //  <---|P7       |            |                 |
    //   +--|A0,A1,A2 |            |                 |
    //   |  |         |            |                 |
    //  \|/
    //
    //  Andreas Dannenberg
    //  Texas Instruments Inc.
    //  March 2006
    //  Built with CCE Version: 3.2.0 and IAR Embedded Workbench Version: 3.41A
    //******************************************************************************
    #include "msp430x22x4.h"

    void main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;                 // Stop Watchdog Timer
      P3SEL |= 0x06;                            // Assign I2C pins to USCI_B0
      UCB0CTL1 |= UCSWRST;                      // Enable SW reset
      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 = 0x20;                         // Set slave address
      UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
      IE2 |= UCB0RXIE;                          // Enable RX interrupt
      TACCTL0 = CCIE;                           // TACCR0 interrupt enabled
      TACTL = TASSEL_2 + MC_2;                  // SMCLK, contmode

      while (1)
      {
        __bis_SR_register(CPUOFF + GIE);        // CPU off, interrupts enabled
        UCB0CTL1 &= ~UCTR;                      // I2C RX
        UCB0CTL1 |= UCTXSTT;                    // I2C start condition
        while (UCB0CTL1 & UCTXSTT);             // Loop until I2C STT is sent
        UCB0CTL1 |= UCTR + UCTXSTT;             // I2C TX, start condition
        __bis_SR_register(CPUOFF + GIE);        // CPU off, interrupts enabled
        while (UCB0CTL1 & UCTXSTT);             // Loop until I2C STT is sent
        UCB0CTL1 |= UCTXSTP;                    // I2C stop condition after 1st TX
      }
    }

    #pragma vector = TIMERA0_VECTOR
    __interrupt void TA0_ISR(void)
    {
      __bic_SR_register_on_exit(CPUOFF);        // Exit LPM0
    }

    // USCI_B0 Data ISR
    #pragma vector = USCIAB0TX_VECTOR
    __interrupt void USCIAB0TX_ISR(void)
    {
      UCB0TXBUF = (UCB0RXBUF << 4) | 0x0f;      // Move RX data to TX
      __bic_SR_register_on_exit(CPUOFF);        // Exit LPM0
    }

     

    any help could be welcomed on this issue.....

  • Hi Brandon ,

             i'm using  PCF8574P  to interface 7 segment display  with MSP430F2274micro controller.  i am also  using a example  program  "msp430x22x4_uscib0_i2c_02 "  from " slac123d.zib "  zib file. As per the diagram in the program i have connected the hardware.  

     

    Hardware details:

    Pullup resistors = 10k(for scl),10k(for sda) , connected with VCC of 2274 (refered  diagram in the program)

    PCF8574p slave address : 0x20 ->>>  A0=A1=A2=VSS, grounded

    P0 pin of PCF8574P is connected to ground, [VSS]

    p1,p2,p3  pins of PCF8574P is connected to supply [VCC]

    p4-p7 pins of PCF8574P is connected to 4 pins of 7 segment display , the common pin of 7 segment display is connected to supply

    according to the program  if PCF8574P IC  gets  zero voltage in P0/p1/p2/P3 then one of this segment in P4/P5/P6/P7 segment must glow [ 7 segment is common anode type ].but  if  I run the program the I/O pins PCF8574 P0-P7 is getting voltage 3.35V [ VCC]

    so, no 7segment is glowing??????????

    can somebody provide me the reason for the problem or the proper Master( Transmit mode ) code with PCF interface .....

     

     

     

     

    //******************************************************************************
    //  MSP430F22x4 Demo - USCI_B0 I2C Master Interface to PCF8574, Read/Write
    //
    //  Description: I2C communication with a PCF8574 in read and write mode is
    //  demonstrated. PCF8574 port P is configured with P0-P3 input, P4-P7. Read
    //  P0-P3 input data is written back to Port P4-P7. This example uses the
    //  RX ISR and generates an I2C restart condition while switching from
    //  master receiver to master transmitter.
    //  ACLK = n/a, MCLK = SMCLK = TACLK = BRCLK = default DCO = ~1.2MHz
    //
    //                                MSP430F22x4
    //                              -----------------
    //                  /|\ /|\ /|\|              XIN|-
    //                  10k 10k  | |                 |
    //       PCF8574     |   |   --|RST          XOUT|-
    //       ---------   |   |     |                 |
    //  --->|P0    SDA|<-|---+---->|P3.1/UCB0SDA     |
    //  --->|P1       |  |         |                 |
    //  --->|P2       |  |         |                 |
    //  --->|P3    SCL|<-+---------|P3.2/UCB0SCL     |
    //  <---|P4       |            |                 |
    //  <---|P5       |            |                 |
    //  <---|P6       |            |                 |
    //  <---|P7       |            |                 |
    //   +--|A0,A1,A2 |            |                 |
    //   |  |         |            |                 |
    //  \|/
    //
    //  Andreas Dannenberg
    //  Texas Instruments Inc.
    //  March 2006
    //  Built with CCE Version: 3.2.0 and IAR Embedded Workbench Version: 3.41A
    //******************************************************************************
    #include "msp430x22x4.h"

    void main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;                 // Stop Watchdog Timer
      P3SEL |= 0x06;                            // Assign I2C pins to USCI_B0
      UCB0CTL1 |= UCSWRST;                      // Enable SW reset
      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 = 0x20;                         // Set slave address
      UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
      IE2 |= UCB0RXIE;                          // Enable RX interrupt
      TACCTL0 = CCIE;                           // TACCR0 interrupt enabled
      TACTL = TASSEL_2 + MC_2;                  // SMCLK, contmode

      while (1)
      {
        __bis_SR_register(CPUOFF + GIE);        // CPU off, interrupts enabled
        UCB0CTL1 &= ~UCTR;                      // I2C RX
        UCB0CTL1 |= UCTXSTT;                    // I2C start condition
        while (UCB0CTL1 & UCTXSTT);             // Loop until I2C STT is sent
        UCB0CTL1 |= UCTR + UCTXSTT;             // I2C TX, start condition
        __bis_SR_register(CPUOFF + GIE);        // CPU off, interrupts enabled
        while (UCB0CTL1 & UCTXSTT);             // Loop until I2C STT is sent
        UCB0CTL1 |= UCTXSTP;                    // I2C stop condition after 1st TX
      }
    }

    #pragma vector = TIMERA0_VECTOR
    __interrupt void TA0_ISR(void)
    {
      __bic_SR_register_on_exit(CPUOFF);        // Exit LPM0
    }

    // USCI_B0 Data ISR
    #pragma vector = USCIAB0TX_VECTOR
    __interrupt void USCIAB0TX_ISR(void)
    {
      UCB0TXBUF = (UCB0RXBUF << 4) | 0x0f;      // Move RX data to TX
      __bic_SR_register_on_exit(CPUOFF);        // Exit LPM0
    }

     

    any help could be welcomed on this issue.....

  • According to the PC8574 data sheet, pins 1, 2, and 3 of the device are the I2C address pins. If you are setting them to VCC, the address bits (A1 A2 A3) are 111 not 000. So you need to send device address 0x27 not 0x20. Also make sure you have a PC9574 and not a PC7584A device. They have different address bytes requirements.

  • Grr!! I mean PCF8574 ( address is 0100xxx) or PCF8574A ( adress is 0111xxx)

  • Hi,

            i have not connected A2,A1,A0 to VCC . i connected to VSS(0V)only but input pin of PCF8574 P1,P2,P3 is connected to VCC . please refer the diagram once again....

     

    note:

     

    PCF8574p slave address : 0x20 ->>>  A0=A1=A2=VSS, grounded

    P0 pin of PCF8574P is connected to ground, [VSS]

    p1,p2,p3  pins of PCF8574P is connected to supply [VCC]

    p4-p7 pins of PCF8574P is connected to 4 pins of 7 segment display , the common pin of 7 segment display is connected to supply

     

  • whetherHi,

           This  code is for Mater Transmitter only i am not reading any data from 8574 I/O pins.  The A0,A1,A2 is now connected to VCC , so, slave address is 0X27.one more doubt is whether we have to give 0x47 or 0x27 as slave address ...

    For your Reference:

     

    configuration

     

                         Mode : Master Tranmitter

                    A0,A1,A2 = VCC

                    7 segment is connected to  8574 I/O pins

                    Pullup resistor 10k



    /*-----------start--------------*/

    #include "msp430xG46x.h"

    unsigned char i=0;

    void main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;                 // Stop Watchdog Timer

      P3SEL |= 0x06;                            // Assign I2C pins to USCI_B0
      UCB0CTL1 |= UCSWRST;                      // Enable SW reset
      UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;     // I2C Master, synchronous mode
      UCB0CTL1 = UCSSEL_2 + UCSWRST;            // Use SMCLK, keep SW reset
      UCB0BR0 = 11;                             // fSCL = SMCLK/11 = 95.3kHz
      UCB0BR1 = 0;
      UCB0I2CSA = 0x27;                         // Set slave address
      UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
      IE2 |=  UCB0TXIE;                          // Enable RX interrupt
      TACCTL0 = CCIE;                           // TACCR0 interrupt enabled
      TACTL = TASSEL_2 + MC_2;                  // SMCLK, contmode

      while (1)
      {
        UCB0CTL1 |= UCTR+UCTXSTT;               // I2C TX, start condition
        __bis_SR_register(CPUOFF + GIE);        // CPU off, interrupts enabled
        while (UCB0CTL1 & UCTXSTT);             // Loop until I2C STT is sent
        UCB0CTL1 |= UCTXSTP;                    // I2C stop condition after 1st TX
      }
    }

    #pragma vector = TIMERA0_VECTOR
    __interrupt void TA0_ISR(void)
    {
      __bic_SR_register_on_exit(CPUOFF);        // Exit LPM0
    }

    // USCI_B0 Data ISR
    #pragma vector = USCIAB0TX_VECTOR
    __interrupt void USCIAB0TX_ISR(void)
    {
      UCB0TXBUF ^= 0xff;      // data to TX
      __bic_SR_register_on_exit(CPUOFF);        // Exit LPM0
    }


    /*--------------------end------------------*/

     

     

  • guru said:
    slave address is 0X27.one more doubt is whether we have to give 0x47 or 0x27 as slave address ...

    One source of confusion is that in all I2C manuals, the slave address is presented including the R/W bit as MSB. In the form of YYYYXXXW with Y being the fixed and X the pin-addressable variable part and W the R/W bit.

    The MSP requires the plain address part in the lower 7 bits of the slave address register. So only 0YYYYXXX has to be written as address. The R/W bit will be automatically added by the hardware (and bit7 of the written address is ignored) depending on the R/W bit when the start condition is initiated.
    As a result, no rewrite of the slave address is required if the direction of the transfer is changed, allowing code to be address-independent :)

    Otherwise it would be 0x4e/0x4f :)

    Anyway, in your code you should wait after setting the UCTXSTP bit until the bit clears and the stop is executed, before going into the next loop and send a new start.

    Also, I'm not completely sure about the order of interrupts and the stop condition. The code sleeps until awaken by either timer or TX interrupt (which can lead to confusion). Then you wait for STT clear. depending on the I2C speed, it is not guaranteed that you set the stop bit before the TX interrupt is executed once more and a second byte is already in the output queue. Actually that's waht I'd expect, since after TXBUF is written to, its content is moved to the output shift register and another TX interrupt follows immediately. And the second byte will immediately revert the changes you jus tmade, resulting in a glow of the output (actually it is some sort of PWM mode with a low duty-cycle of ~20%)

  • Hi,

           i got this this code from TI website and i modified it for MASTER TRANSMIT  MODE .. but even if i use without any modification in the code I2C is not working .. i also don't understand the flow of program ..kindly help me out... especially in the program they have enabled interrupt for   IE2 |= UCB0RXIE;  but in the ISR they are using USCIAB0TX_VECTOR do you think that it will produce TX interrupt??????

     

     

    //******************************************************************************
    //  MSP430F22x4 Demo - USCI_B0 I2C Master Interface to PCF8574, Read/Write
    //
    //  Description: I2C communication with a PCF8574 in read and write mode is
    //  demonstrated. PCF8574 port P is configured with P0-P3 input, P4-P7. Read
    //  P0-P3 input data is written back to Port P4-P7. This example uses the
    //  RX ISR and generates an I2C restart condition while switching from
    //  master receiver to master transmitter.
    //  ACLK = n/a, MCLK = SMCLK = TACLK = BRCLK = default DCO = ~1.2MHz
    //
    //                                MSP430F22x4
    //                              -----------------
    //                  /|\ /|\ /|\|              XIN|-
    //                  10k 10k  | |                 |
    //       PCF8574     |   |   --|RST          XOUT|-
    //       ---------   |   |     |                 |
    //  --->|P0    SDA|<-|---+---->|P3.1/UCB0SDA     |
    //  --->|P1       |  |         |                 |
    //  --->|P2       |  |         |                 |
    //  --->|P3    SCL|<-+---------|P3.2/UCB0SCL     |
    //  <---|P4       |            |                 |
    //  <---|P5       |            |                 |
    //  <---|P6       |            |                 |
    //  <---|P7       |            |                 |
    //   +--|A0,A1,A2 |            |                 |
    //   |  |         |            |                 |
    //  \|/
    //
    //  Andreas Dannenberg
    //  Texas Instruments Inc.
    //  March 2006
    //  Built with CCE Version: 3.2.0 and IAR Embedded Workbench Version: 3.41A
    //******************************************************************************
    #include "msp430x22x4.h"

    void main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;                 // Stop Watchdog Timer
      P3SEL |= 0x06;                            // Assign I2C pins to USCI_B0
      UCB0CTL1 |= UCSWRST;                      // Enable SW reset
      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 = 0x20;                         // Set slave address
      UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
      IE2 |= UCB0RXIE;                          // Enable RX interrupt
      TACCTL0 = CCIE;                           // TACCR0 interrupt enabled
      TACTL = TASSEL_2 + MC_2;                  // SMCLK, contmode

      while (1)
      {
        __bis_SR_register(CPUOFF + GIE);        // CPU off, interrupts enabled
        UCB0CTL1 &= ~UCTR;                      // I2C RX
        UCB0CTL1 |= UCTXSTT;                    // I2C start condition
        while (UCB0CTL1 & UCTXSTT);             // Loop until I2C STT is sent
        UCB0CTL1 |= UCTR + UCTXSTT;             // I2C TX, start condition
        __bis_SR_register(CPUOFF + GIE);        // CPU off, interrupts enabled
        while (UCB0CTL1 & UCTXSTT);             // Loop until I2C STT is sent
        UCB0CTL1 |= UCTXSTP;                    // I2C stop condition after 1st TX
      }
    }

    #pragma vector = TIMERA0_VECTOR
    __interrupt void TA0_ISR(void)
    {
      __bic_SR_register_on_exit(CPUOFF);        // Exit LPM0
    }

    // USCI_B0 Data ISR
    #pragma vector = USCIAB0TX_VECTOR
    __interrupt void USCIAB0TX_ISR(void)
    {
      UCB0TXBUF = (UCB0RXBUF << 4) | 0x0f;      // Move RX data to TX
      __bic_SR_register_on_exit(CPUOFF);        // Exit LPM0
    }

  • Hi,

           i got this this code from TI website   .. even if i use same code i2c is working [ i have done connection as per diagram ] .. i also don't understand the flow of program ..kindly help me out... especially in the program they have enabled interrupt for   IE2 |= UCB0RXIE;  but in the ISR they are using  USCIAB0TX_VECTOR do you think that it will produce TX interrupt flag if we don;t enable interrupt for that ??????

     

    THIS IS THE TI CODE .....

    //******************************************************************************
    //  MSP430F22x4 Demo - USCI_B0 I2C Master Interface to PCF8574, Read/Write
    //
    //  Description: I2C communication with a PCF8574 in read and write mode is
    //  demonstrated. PCF8574 port P is configured with P0-P3 input, P4-P7. Read
    //  P0-P3 input data is written back to Port P4-P7. This example uses the
    //  RX ISR and generates an I2C restart condition while switching from
    //  master receiver to master transmitter.
    //  ACLK = n/a, MCLK = SMCLK = TACLK = BRCLK = default DCO = ~1.2MHz
    //
    //                                MSP430F22x4
    //                              -----------------
    //                  /|\ /|\ /|\|              XIN|-
    //                  10k 10k  | |                 |
    //       PCF8574     |   |   --|RST          XOUT|-
    //       ---------   |   |     |                 |
    //  --->|P0    SDA|<-|---+---->|P3.1/UCB0SDA     |
    //  --->|P1       |  |         |                 |
    //  --->|P2       |  |         |                 |
    //  --->|P3    SCL|<-+---------|P3.2/UCB0SCL     |
    //  <---|P4       |            |                 |
    //  <---|P5       |            |                 |
    //  <---|P6       |            |                 |
    //  <---|P7       |            |                 |
    //   +--|A0,A1,A2 |            |                 |
    //   |  |         |            |                 |
    //  \|/
    //
    //  Andreas Dannenberg
    //  Texas Instruments Inc.
    //  March 2006
    //  Built with CCE Version: 3.2.0 and IAR Embedded Workbench Version: 3.41A
    //******************************************************************************
    #include "msp430x22x4.h"

    void main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;                 // Stop Watchdog Timer
      P3SEL |= 0x06;                            // Assign I2C pins to USCI_B0
      UCB0CTL1 |= UCSWRST;                      // Enable SW reset
      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 = 0x20;                         // Set slave address
      UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
      IE2 |= UCB0RXIE;                          // Enable RX interrupt
      TACCTL0 = CCIE;                           // TACCR0 interrupt enabled
      TACTL = TASSEL_2 + MC_2;                  // SMCLK, contmode

      while (1)
      {
        __bis_SR_register(CPUOFF + GIE);        // CPU off, interrupts enabled
        UCB0CTL1 &= ~UCTR;                      // I2C RX
        UCB0CTL1 |= UCTXSTT;                    // I2C start condition
        while (UCB0CTL1 & UCTXSTT);             // Loop until I2C STT is sent
        UCB0CTL1 |= UCTR + UCTXSTT;             // I2C TX, start condition
        __bis_SR_register(CPUOFF + GIE);        // CPU off, interrupts enabled
        while (UCB0CTL1 & UCTXSTT);             // Loop until I2C STT is sent
        UCB0CTL1 |= UCTXSTP;                    // I2C stop condition after 1st TX
      }
    }

    #pragma vector = TIMERA0_VECTOR
    __interrupt void TA0_ISR(void)
    {
      __bic_SR_register_on_exit(CPUOFF);        // Exit LPM0
    }

    // USCI_B0 Data ISR
    #pragma vector = USCIAB0TX_VECTOR
    __interrupt void USCIAB0TX_ISR(void)
    {
      UCB0TXBUF = (UCB0RXBUF << 4) | 0x0f;      // Move RX data to TX
      __bic_SR_register_on_exit(CPUOFF);        // Exit LPM0
    }

  • guru said:
    i also don't understand the flow of program

    This example code, while there are many comments, does nto really explain what the code DOES. The comments rather explain what each line does (and which is obvious anyway).
    Also, the code mixes different things (sending and receiving, usage of the I2C protocol as well as interrupt handling) without explaining the logic of the different parts. Also, there are unnecessary 'smart' things with (intentional) side-effects without explaining they how and why. And of course there is no handling of any error conditions. So if something goes wrong, you have bo idea why the code is not working.

    I have no idea, why the timer is used. The only explanation is to induce a delay at startup (using implicit init conditions) and to cause a wakeup every now and then, hoping it will not interfere with the I2C code timing. If so, it only works because the running time of the I2C main loop is shorter than the delay between two timer interrupts. Else the whole thing will crash.

    Let's ignore the init part. It does what the comments say (and what is obvious). The only important thing here is that the SWRST bit needs to be set while the I2C hardware is configured. Which does not (AFAIK) include the slave address.

    Let's look at the loop.

    The first LPM time (by setting CPUOFF bit) is ended by the expiration of the timer. Hopefully the timer won't trigger again until the loop has ended and we're here again.

    The TX bit is cleared, so the hardware will run in RX mode, retrieving bytes from the slave.

    The start sequence is initiated. At this point, the hardware will send a start condition, send the slave address and the R/W bit and wait for the ACK from the slave.

    Now the software waits until the start sequence has ended. Here the software assumes that the ACK does always come. If not, we're hosed.

    Now the write bit is set and another start sequence is initiated. At this point, the software assumes that receiving of the first byte has already started. It only has because the I2C clock is fast compared to MCLK. With a faster MCLK, it is possible that receiving hasn't started yet and the program won't receive anything at all.
    But since receiving has (coincidentally) started, it will first continue the receiving of a byte before the (re)start is sent.

    Now the CPU goes into LPM again.

    When the byte has been received, RXIFG is set (but does not trigger an interrupt), then the (re)start sequence begins, which clears TXBUF and sets TXIFG.

    It is important to know that on 2x USCI, the TX ISR handles RX and TX interrupt (both!) for A and B module, while the RX ISR handles error conditions and slave handshaking (start received, NACK received, input overflow etc.). THis is especially confusing if the A modules uses UART or SPI while the B module handles I2C.
    The 5 USCI handles all (RX, TX, errors) in the same ISR, but in separate ISRs for A and B module.

    So when the TX interrupt fires (immediately after initiating the restart), the ISR copies the received byte from RXBUF into TXBUF and wakes up the CPU.

    Now the program waits for the start sequence having ended. This is done at the beginning of the start sequence (before the slave address has been sent) and therefore the CPU does a long busy-waiting loop. It renders the usage of LPM in this demo mostly useless, other than for some synchronisation purposes (whcih could be done by polling the busy-bits as well and less confusing)

    Now the start sequence has ended (hopefully without error, with the slave properly responding). Set program sets the the UCTXSTP bit, requesting a stop. This is done (hopefully9 after sending of the first byte has begun (or it will never be sent). But then, the moment the sending has begun, the TX ISR has been called a second time, reading RXBUF again, writing another byte to TXBUF, Which only in this example has no side-effect, but can mess up a real application )e.g. when the byte to be sent comes from a different source than RXBUF which has side-effects).
    The second byte isn't sent, however, because the STP bit has been set before sending of the second byte has begun (remember, we're still on the start of the first byte sending, at which the content of TXBUF has moved to the output shift register and TXBUF was freed for the next byte).

    So after the first byte was sent, a stop condition is generated. At this point, the CPU has already reached the Beginning of the loop and is sleeping, waiting for another timer interrupt.

    So after all, on this particular processor, the code does what it is inteded to do, but it ha so many assumptions and (effectles in this case) side-effects that it cannot be easily ported into own projects.

     

    This example (as many others) is rather a 'we proved that it works somehow' demo than a 'you can use this as base for your own projects' example.

  • Hi Michael ,

          now , i understand the problem thanks for your swift reply.... Michael   do you have any MASTER TRANSMIT CODE which is more reliable for project or to get started with I2C .

    I want to interface pcf8574 with MSP430 4XX or 2XX family ...

  • guru said:
    do you have any MASTER TRANSMIT CODE which is more reliable for project or to get started with I2C .

    I want to interface pcf8574 with MSP430 4XX or 2XX family ...


    Sorry, I never worked with the 2x or 4x line. And on the 1x, I wrote my own I2C functions, as the old USART I2C hardware was way too complex for the task I had (interfacing an PCF8583 RTC). It seemed to take more code to keep the hardware from doing what I don't want than to write my own code to make the GPIO pins do what I want. Of course it didn't address most exceptions, but well, the end result was mostly compatible with the ATMega128 I2C hardware which I also had to address an PCF8583 (only the 4 low-leve functions or start/stop/send/receive were different, and not the whole mid-level concept.)

    The Code I wrote now is for the 5438 (which differs a bit from the 2x/4x USCI and even more from the USI I2C) is not ISR based and fairly complex. It handles the whole I2C transfer more in the way of a stram device. You open the device (giving address and interface to use, the 5438 has 4), write, read, whatever, then you close it again. Sending of start/stop/repeated start, change of transfer direction, all this is handled by the 4 low-level functions.
    The transfer isn't optimized for throughput and blocking, but it perfectly serves the purpose of reading/setting an RTC time or similar tasks with low byte count and/or changing directions. It isn't suited best for large data transfers, however. (I use SPi for this anyway, as it is MUCH faster)

    I fear it would be of no use here, and even if, my employer surely wouldn't like if I posted the code he paid me for :)

     

**Attention** This is a public forum