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.

PCA9539: Random data read

Part Number: PCA9539
Other Parts Discussed in Thread: MSP430F4784,

Hi,

I'm currently using PCA9539 I/O expander. interfacing with MSP430F4784, using I2C.

when the IC power up (3.3), does INT pin initially low ? even though pull up is connected (10k).

Does INT pin gets High only after reading input register ?.

below is the program .

here whenever I'm reading input register  1 the UCB0RXBUF gives 2 bytes 

but in a loop bytes of data[0] & data[1] are swaping continuously.

So that I can't read a particular bit of a byte.

what would be the issue?

please kindly help me with this

uint8_t data[2];


void i2c_beginTx(uint8_t address)
{
    UCB0I2CSA = address;
    UCB0CTL1 |= UCTR + UCTXSTT;
    while((UCB0STAT & UCNACKIFG));
}

void i2c_write(uint8_t byte)
{
    UCB0TXBUF = byte;
    while((UCB0STAT & UCNACKIFG));
    __delay_cycles(5000);
}

void i2c_read(uint8_t address, uint8_t reg, uint8_t len)
{
    int i;
    UCB0I2CSA = address;
    UCB0CTL1 |= UCTR + UCTXSTT;
    while((UCB0STAT & UCNACKIFG));
    UCB0TXBUF = reg;
    __delay_cycles(5000);
    UCB0CTL1 |= UCTXSTP;

    UCB0I2CSA = address;
    UCB0CTL1 &= ~UCTR;
    UCB0CTL1 |= UCTXSTT;
    while((UCB0STAT & UCNACKIFG));
    for(i=0;i<len;i++)
    {
        data[i] = UCB0RXBUF;
        __delay_cycles(5000);
    }
    UCB0CTL1 |= UCTXNACK;
    UCB0CTL1 |= UCTXSTP;

}

void read(uint8_t address, uint8_t len)
{
    UCB0I2CSA = address;
   UCB0CTL1 &= ~UCTR;
   UCB0CTL1 |= UCTXSTT;
   while((UCB0STAT & UCNACKIFG));
   for(i=0;i<len;i++)
   {
       data[i] = UCB0RXBUF;
       __delay_cycles(5000);
   }
   UCB0CTL1 |= UCTXNACK;
   UCB0CTL1 |= UCTXSTP;
}

void i2c_stop()
{
    UCB0CTL1 |= UCTXSTP;
}

int main()
{
    WDTCTL = WDTPW | WDTHOLD;

    SCFQCTL |= SCFQ_4M;
    SCFI0 |= FN_2;
    FLL_CTL0 |= DCOPLUS;

    do
    {
        IFG1 &= ~OFIFG;
        __delay_cycles(5000);
    }while(IFG1 & OFIFG);


    P1DIR |= BIT1;
    P1SEL |= BIT1;

    P1DIR |= BIT4;
    P1SEL |= BIT4;

    P3SEL |= BIT1 + BIT2; // i2c pins

    basic_tmr();

    P9DIR |= BIT5; //LED blink
    P9OUT &= ~BIT5;

    P5DIR |= BIT5; // led
    P5OUT &= ~BIT5;

    P5DIR |= BIT4; // led 
    P5OUT &= ~BIT4;

   
    P10DIR |= BIT6; // reset IO EXP
    P10OUT &= ~BIT6;

    __delay_cycles(500);

    P10OUT |= BIT6;


    UCB0CTL1 |= UCSWRST;
    UCB0CTL0 |= UCMST + UCMODE_3 + UCSYNC;
    UCB0CTL1 |= UCSSEL_2 + UCSWRST;
    UCB0BR0 = 20;
    UCB0BR1 = 0;
    UCB0CTL1 &= ~UCSWRST;

    __delay_cycles(100000);

    i2c_beginTx(0x77);
    i2c_write(0x06);
    i2c_write(0x60);
    i2c_write(0xFF);
    i2c_stop();

    __delay_cycles(50000);
    
    i2c_read(0x77, 0x01, 2);
    
    /** interrupt  pin **/
       P1DIR &= ~BIT5;
       P1IE |= BIT5;
       P1IES |= BIT5;

       __bis_SR_register(GIE);
    while(1)
    {

        P5OUT ^= BIT4;
        __delay_cycles(1000000);

        if(a == 1)
        {
            read(0x77, 2);
            if((data[0] & (1<<5)) == 1)
            {
                a = 0;

                P9OUT ^= BIT5;
                __delay_cycles(1000000);
            }
        }


    }

}

#pragma vector=PORT1_VECTOR
__interrupt void port_1_ISR(void)
{

    if(P1IFG & BIT5)
    {
        read(0x77, 2);
        if((data[0] & (1<<5)) == 0)
        {
            __delay_cycles(10000000);
            P5OUT |= BIT5;
            __delay_cycles(10000000);
            P5OUT &= ~BIT5;

            a = 1;
        }
        P1IFG &= ~BIT5;
    }
}

  • when the IC power up (3.3), does INT pin initially low ? even though pull up is connected (10k).

    Does INT pin gets High only after reading input register ?.

    It can be asserted low if the state of the pins on the p-ports change after the POR circuit is toggled during power up. Generally placing strong pull-up/pull-down resistors on the p-ports can prevent this from happening. 

    but in a loop bytes of data[0] & data[1] are swaping continuously.

    Do you have a scopeshot of the I2C read transaction we could look at when you're reading data 0 and data 1 from our device? 

    I'm not too well versed with code but I can take a look at the analog waveforms on the I2C communication to see if something looks amiss. If the data is swapping, It may be because you aren't resetting the pointer to the input register after each read. The register address of the I2C device is likely auto incrementing after each read. 

    -Bobby

  • A 5000-cycle wait does not properly synchronize with the state machine; test for TXIFG/RXIFG before accessing TXBUF/RXBUF instead. And you should probably not read without writing the register address (I²C has no error correction or detection).

    Use functions like this:

    void i2c_beginTx(uint8_t address)
    {
        while (UCB0CTL1 & UCTXSTP) ;
        UCB0I2CSA = address;
        UCB0CTL1 |= UCTR | UCTXSTT;
    }
    
    void i2c_write(uint8_t byte)
    {
        while (!(IFG2 & UCB0TXIFG)) ;
        UCB0TXBUF = byte;
    }
    
    void i2c_stop()
    {
        while (!(IFG2 & UCB0TXIFG)) ;
        UCB0CTL1 |= UCTXSTP;
        IFG2 &= ~UCB0TXIFG;
    }
    
    void i2C_read(uint8_t address, uint8_t reg, unsigned int len)
    {
        unsigned int i;
        
        while (UCB0CTL1 & UCTXSTP) ;
    
        UCB0I2CSA = address;
        UCB0CTL1 |= UCTR | UCTXSTT;
        while (!(IFG2 & UCB0TXIFG)) ;
        UCB0TXBUF = reg;
        while (!(IFG2 & UCB0TXIFG)) ;
    
        IFG2 &= ~UCB0TXIFG;
        UCB0CTL1 &= ~UCTR;
        UCB0CTL1 |= UCTXSTT;
        for (i = 0; i < len; i++)
        {
            if (i == len - 1)
                UCB0CTL1 |= UCTXSTP;
            while (!(IFG2 & UCB0RXIFG)) ;
            data[i] = UCB0RXBUF;
        }
    }