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.

TCA6424 READ sequence question

Other Parts Discussed in Thread: TCA6424, TCA6424A, MSP430G2553

I'm having difficulties responding to the INT from the TCA6424 we're using.

Configuration and Polarity program in fine.  No failures at all.  The first cycle of reads work fine.  Then, that's it, all writes fail.  The sequence:

1: Program Configuration and Polarity
2: Send command 0x0 (read register 0)
3: Read back a byte
4: Send command 0x1 (read register 1)
5: Read back a byte
6: Send command 0x2 (read register 2)
7: Read back a byte


*interrupt*
1: Send command 0x0 (read register 0)

-- At this point, writing a byte out to I2C fails --

Code to write to I2C:

        // Just read a single byte and return
        USCI_B_I2C_masterSingleReceiveStartWithTimeout(I2C_BASE, I2C_TIMEOUT);
        //*pBuf = USCI_B_I2C_masterSingleReceive(I2C_BASE);
        retVal = localReadByte(I2C_BASE, pBuf);
        USCI_B_I2C_clearInterruptFlag(I2C_BASE, USCI_B_I2C_RECEIVE_INTERRUPT);
        __enable_interrupt();
        return retVal;

static int localReadByte(unsigned int DevAddr, unsigned char *pBuf)
{
    long nTimeout = I2C_TIMEOUT;

    // Polling RXIFG0 if RXIE is not enabled

    if (!(HWREG8(DevAddr + OFS_UCBxIE) & UCRXIE))
            while (!(HWREG8(DevAddr + OFS_UCBxIFG) & UCRXIFG))
                if(--nTimeout <= 0)
                    return 0;

    // Read a byte.

    *pBuf = HWREG8(DevAddr + OFS_UCBxRXBUF);

    return 1;
}

My confusion is whether or not I need to send a NAK at the end of every read transaction, and whether or not this would make the TCA6424 stop responding if I didn't.

Can some kind soul help clarify the reading process? Thanks!

Ed Averill

  • Hello Ed,

    I would be happy to help you out.

    To answer your question: No, you do not need to send a NACK at the end of every read transaction. The TCA6424 does not care whether you send a NACK or an ACK when sending data to the master.

    By any chance, can you acquire a scope shot of the SDA and SCL lines during the send command 0x0 which causes the bus to stop responding? I'm curious to see if the bus gets latched low, or if the command is being sent the wrong way.

    Unfortunately, I am not an expert with programming (I am a hardware guy), but is this device a MSP430?
  • Yes, we have an MSP430 as Master on the bus, the TCA6424 is the SLAVE at its default address.

    I'll try pulling out the NAKs and seeing if that makes a difference.

    I'm not sure if I can get a scope shot, my hardware guys says there might be vias we can probe but the pins on the MSP and TCA are both pretty tiny and we don't have a needle-tip pod.. I'll see what I can discover.

    Thanks for the response!

    Ed Averill
  • Hello Ed,

    I'd like to chime in and verify with you the following:
    1) This is the TCA6424 and not the TCA6424A?

    2) Are you following the read procedure as outlined on page 25 of the TCA6424 data sheet? After your address with write enabled to the device, you send the command byte you should get an ACK from the slave, you then send a repeated start with the read bit high and then data will flow from the slave.

    Just starting at the basics, since it seems like you are unable to get any data at all out of the device.

    One interesting thing I notice in your code is how you use HWREG8 function for what seems to be reading local registers. Is there a reason you choose this method instead of addressing the register directly?
  • Hello again! The forum was having issues...

    I'm stealing from Driverlib code to create a red-with-timeout, which doesn't exist for single byte reads, it uses the HWREG8 macro (copy-and-pasted).

    And yes, it is the TCA6424A, sorry!

    I *think* I'm following the ref guide, but there's some weirdness and I suspect it's my lack of understanding:

    First, the address. We have it at the default, which should be (binary) 0100010 (hex 0x22).  The read/write bit follows, and this is where I think I'm getting confused. Should I set the USCI I2C target address as 0x22, or shift that up a bit and append the read/write bit, or is there some other way I should be getting that out?  I'm setting 0x22 into the UCB1I2CSA, and I get SOMETHING back..

    I can't find any good example code on the Web or I'd not be posting in here.

    Thanks for all the help!

    Ed Averill

  • Hello Ed,

    I noticed some issues with the forum earlier as well, but all seems to be well again.

    Thanks for clearing up that you're using the TCA6424A. You have not mentioned which MSP430 you're using, so I am going to assume the standard MSP430G2553.

    Let's walk through the procedure and make sure we're not missing anything. I'll apologize now for the long post.

    1) The following is section 17.3.4.2.1 of the MSP430x2xxx Family User's Guide, it explains what we must do in order to send data to the slave (in this case the 0x00 command to read the input port 0 register of the TCA6424A with auto increment disabled.):

    2) Following the suggested procedure, we need to enter the target address. You are correct in writing 0x22 to UCB1I2CSA. You only put the address, right justified. See snippet from the MSP430x2xxx family user guide manual:

    2) I will assume that UCSLA10 is already cleared (set to 0) for 7-bit address mode. Next, we are instructed to tell the MSP430 whether we want to read or write by setting the UCTR bit appropriately in the UCB1CTL1 register, and set the UCTXSTT bit to generate a start condition. Transmitter = write. Receiver = read. In this case, we are transmitting the command byte, so we want to set UCTR to 1 (write/transmitter). I would do it with:

    UCB1CTL1 |= UCTR + UCTXSTT;

     (Assuming your defines have been set up, otherwise you can use UCB1CTL1 |= 0x12; to set the bits)

    3) Now the MSP430 should generate a start condition and send the slave address with the R/!W bit set to 0 (telling slave we want to write to it). Once the slave acknowledges. Your interrupts should already have been configured. At this point, we will wait (can put the MSP430 into a sleep mode while we wait for the slave to acknowledge), and when the slave acknowledges, the UCB1TXIFG bit will be set in the UCBIFG1 register (but if your interrupts are setup, this should go to the appropriate interrupt vector and you can check for this case in the interrupt routine). Once the UCB1TXIFG bit is set, this means that the MSP430 has received an acknowledge and is ready to send data/command byte to the slave. You should write your command byte to the UCB1TXBUF register (0x00 in this case). Clear the UCB1TXIFG flag and go back to sleep. Once the MSP430 has moved the command byte from the buffer to the shift register, the UCB1TXBUF flag will be set again and you will be back at your interrupt routine. Since we do not want to transfer any more data after this, we will want to set up the MSP430 to do a repeated start and read from the slave device.

    4) Once we get the UCB1TXIFG flag after writing the command byte to the buffer, we need to change the I2C settings for master receiver mode as outlined in the user guide:

    5) Since the slave address is already set, we can leave that alone, and instead change the UCTR register to receiver (read) similar to what we did in step 2. I would do it with: 

    UCB1CTL1 &= ~UCTR;
    
    UCB1CTL1 |= UCTXSTT; 

    The above 2 lines will be needed since we must clear the UCTR bit and set the UCTXSTT flag to tell the MCU to do a repeated start after the slave acknowledges the command byte.

    Once this is done, it is just a waiting process to receive the data. However, since we only want to receive 1 byte, we must follow the instructions outlined in the master-receiver section and poll the UCTXSTT flag until it gets cleared, and then set the stop bit UCTXSTP.

    While I would not suggest this for production because it will force your MSP430 to sit in an interrupt routine for an extended period of time doing nothing, the code suggestion should work. I would suggest you use a timer or something to periodically poll the register for this bit to be cleared, so you don't waste CPU cycles idling).

    This code would go after you set the UCB1CTL1 register for the receiver mode and the start bit.

    while (UCB1CTL1 & UCTXSTT); // Will make MSP430 sit at this line until UCTXSTT becomes 0
    
    UCB1CTL1 |= UCTXSTP;    // Set the stop bit, which tells MSP430 to NACK after the next data byte received

    After the stop bit has been set, you can go to sleep while we wait for the byte to be received.

    6) Once we receive the interrupt for the UCB1RXIFG flag, this means we have received our first byte from the slave. Since we set the stop bit, the MSP430 should've NACKed and then sent a stop command on the bus, releasing the bus. We can read our data received from the UCB1RXBUF register.

  • Darn, I owe you a box of doughnuts!

    I'm off to try all that now.. and again, thanks a TON for your incredibly detailed replay!!

    Ed Averill
  • Ed,

    Not a problem, hopefully it helps you and any others that might have the same question.

    Regards,
    Jonathan
  • PERFECT! Stable writes and reads all around, no issues, rock solid. Buy yourself some doughnuts!