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.

tms320f28075: I2C interface to BQ40z60 - works with breakpoint in ISR

Part Number: TMS320F28075
Other Parts Discussed in Thread: BQ40Z60

I'm interfacing a TI BQ40z60 chip (SMB) using the 28075's I2C.  I'm using TI-RTOS with interrupts (init'ed with Hwi_construct) being generated for both FIFO full as well as the general interrupt for NACK, ARDY and SCD.  If I put a breakpoint at the beginning of my general interrupt and hit continue every time the interrupt is hit, everything works great.  If I don't, I get a variety of NACKs and stop bit not occurring in reasonable time.  I'm puzzled what hitting a breakpoint is doing that causes the interface to work. Here are some relevant code snips:

void I2CB_Init(void)
{
    I2cbRegs.I2CMDR.all &= ~0x0020;     // Put I2C in reset

    I2cbRegs.I2CSAR.all = 0x006a;     // Slave address

   // PLL Clock / CPU clock is 120 MHz
   I2cbRegs.I2CPSC.all = 9;          // Prescaler - need 7-12 Mhz on module clk.  9 => 120/(9+1) = 12 MHz
   // SMBus works from 10k - 100kHz.  Dividing clock by 200 (I2CCLKL + I2CCLKLH + 10) gives 60 kHz
   // 10 is an adjustment factor based on I2CPSC
   I2cbRegs.I2CCLKL = 150; //200            // NOTE: must be non zero
   I2cbRegs.I2CCLKH = 150;  //200          // NOTE: must be non zero
   I2cbRegs.I2CIER.all = 0x26;       // Enable SCD & ARDY & NACK__interrupts

   I2cbRegs.I2CFFTX.all = 0;
   I2cbRegs.I2CFFTX.all = 0x6000; // use FIFOs
   I2cbRegs.I2CFFRX.all = 0;
   I2cbRegs.I2CFFRX.all = 0x202A; // Reset + Enable Rx Interrupt + Interrupt Level


   I2cbRegs.I2CMDR.all = 0x0020;     // Take I2C out of reset
                                     // Stop I2C when suspended
   return;
}

Void i2cBIsr(UArg arg)
{
    Uint16 IntSource = I2cbRegs.I2CISRC.all;

    // Interrupt source = stop condition detected
    if(IntSource == I2C_SCD_ISRC)
    {
        bqLog[logEntry++] = 15 | (dataIndex << 4) + (I2cbRegs.I2CFFRX.bit.RXFFST << 8);
        logEntry %= LOG_LENGTH;
        // if there is still data in the FIFO, get it
        if (I2cbRegs.I2CFFRX.bit.RXFFST != 0)
        {
            bqLog[logEntry++] = 8 | (dataIndex << 4) + (I2cbRegs.I2CFFRX.bit.RXFFST << 8);
            logEntry %= LOG_LENGTH;
            i2cB_FIFO_Isr(0);
        }

        I2cbRegs.I2CSTR.bit.SCD = 1; // clear SCD

        if ((BQ_MsgStatus == ADDR_MSG_SENT) && (dataQueries[dataIndex].type44Msg))
        {
            I2cbRegs.I2CCNT = 1;
            I2cbRegs.I2CDXR.all = 0x44;
            I2cbRegs.I2CMDR.all = 0x2e20; // 0x6e20; //  0x2620; // Send data
            BQ_MsgStatus = TYPE_44_SENT;
            bqLog[logEntry++] = 6 | (dataIndex << 4);
            logEntry %= LOG_LENGTH;
        }
        else if(BQ_MsgStatus == TYPE_44_SENT)
        {
            I2cbRegs.I2CCNT = dataQueries[dataIndex].respLen;    // Setup how many bytes to expect
            I2cbRegs.I2CMDR.all = 0x2C20;         // Send restart as master receiver
            BQ_MsgStatus = READING_DATA;
            bqLog[logEntry++] = 7 | (dataIndex << 4);
            logEntry %= LOG_LENGTH;
        }
        else if (READING_DATA == BQ_MsgStatus)
        {
            BQ_MsgStatus = COMM_IDLE;
            bqLog[logEntry++] = 9 | (dataIndex << 4);
            logEntry %= LOG_LENGTH;
        }
    }

    //
    // Interrupt source = Register Access Ready
    // This __interrupt is used to determine when the EEPROM address setup
    // portion of the read data communication is complete. Since no stop bit is
    // commanded, this flag tells us when the message has been sent instead of
    // the SCD flag. If a NACK is received, clear the NACK bit and command a
    // stop. Otherwise, move on to the read data portion of the communication.
    //
    else if(IntSource == I2C_ARDY_ISRC)
    {
        if ((BQ_MsgStatus == ADDR_MSG_SENT) && (!dataQueries[dataIndex].type44Msg))
        {
            // for non-type 44s, we send the restart instead of stop then a new start
            I2cbRegs.I2CCNT = dataQueries[dataIndex].respLen;    // Setup how many bytes to expect
            I2cbRegs.I2CMDR.all = 0x2C20;         // Send restart as master receiver
            BQ_MsgStatus = READING_DATA;
            bqLog[logEntry++] = 10 | (dataIndex << 4);
            logEntry %= LOG_LENGTH;
        }
        else
        {
            I2cbRegs.I2CSTR.bit.ARDY = 1;
            bqLog[logEntry++] = 13 | (dataIndex << 4);
            logEntry %= LOG_LENGTH;
        }
    }
    else if (IntSource == I2C_NACK_ISRC)
    {
        I2cbRegs.I2CSTR.bit.NACK = 1;
        BQ_MsgStatus = COMM_IDLE;
        bqLog[logEntry++] = 11 | (dataIndex << 4);
        logEntry %= LOG_LENGTH;
    }
    else
    {
       //
       // Generate some error due to invalid __interrupt source
       //
       asm("   ESTOP0");
    }
}

  • NOTE: the comment before ARDY interrupt section is from me stealing from the EEPROM example and isn't accurate
  • Rob,

    Are you trying to say you never get FIFO interrupts when you don't hit the breakpoint?

    Regards,
    Manoj
  • The interface is a bit complicated.  The type 0x44 messages require multiple I2C steps before I expect to receive data.  I frequently don't get far enough where I should get FIFO interrupts.  However, you are correct that if I don't set a breakpoint in the main I2C ISR then I don't get FIFO interrupts.  But it shouldn't.  There's no received data.

    What I'm really trying to say is that unless I set a breakpoint in the main I2C ISR (i2cBISR), I don't get the stop-bits I should and don't receive data. 

    For the type 0x44 messages, what should happen is that I send (in hex):

    44 02 AL AH [stop bit] (AL = address low, AH = address high)

    44 [stop bit]

    I then set I2CCNT to the expected receive length and send a restart.

    With a breakpoint at the top of i2cBISR, that works fine.  After the restart, the data comes in, the FIFO ISR is hit for the one message that is above the FIFO threshold.  Otherwise, there is a stop bit after the data comes in and I check in i2cBISR for any data that might be stranded in the FIFO.  However, without the breakpoint at the top of i2cBISR, I get a NACK after the first message or else I never get the stop bit interrupt after the 2nd message.  I do not get to the place of setting I2CCNT and then getting data in.

    I hope this is clearer.

  • Rob,

    Based on your message, it looks like you are not receiving STOP bit from BQ40z60. Did you probe on SDAA pin?

    From your code, I2C module is configured as slave device and I2C waits for I2C interrupt caused by receiving STOP bit from BQ40z60. Am I correct?

    Regards,
    Manoj

  • I have not probed the SDA pin. Good idea.

    I'm not a slave device. In the init function, I come out of reset that way. But I initiate transmissions with an initial master write (MDR register is 0x2E20). Then read as a master as well (MDR = 0x2C20).
  • Rob,

    But, you are configuring your MDR register = 0x2E20 and MDR register = 0x2C20 in i2cBIsr (ISR routine). But, how will it get to ISR routine in the first place.

    Regards,
    Manoj
  • This is called every second or so to kick off the whole process. This is run off a timer and the operation should complete in the ISR. The dataQueries is an array of messages that I round robin through.

    Uint16 BQ_ReadData(void)
    {
    //
    // Wait until the STP bit is cleared from any previous master communication.
    // Clearing of this bit by the module is delayed until after the SCD bit is
    // set. If this bit is not checked prior to initiating a new message, the
    // I2C could get confused.
    //
    if(I2cbRegs.I2CMDR.bit.STP == 1)
    {
    return I2C_STP_NOT_READY_ERROR;
    }

    I2cbRegs.I2CSAR.all = 0x0B;

    if(BQ_MsgStatus == COMM_IDLE)
    {
    //
    // Check if bus busy
    //
    if(I2cbRegs.I2CSTR.bit.BB == 1)
    {
    return I2C_BUS_BUSY_ERROR;
    }

    if (dataQueries[dataIndex].type44Msg)
    {
    I2cbRegs.I2CCNT = 4;
    I2cbRegs.I2CDXR.all = 0x44; // cmd 44
    I2cbRegs.I2CDXR.all = 2; // 2 bytes following

    I2cbRegs.I2CDXR.all = dataQueries[dataIndex].cmdNum; // Ad & 0xFF;
    I2cbRegs.I2CDXR.all = 0; // Ad >> 8;
    I2cbRegs.I2CMDR.all = 0x2E20; // Send data to setup EEPROM address
    }
    else
    {
    I2cbRegs.I2CCNT = 1;
    I2cbRegs.I2CDXR.all = dataQueries[dataIndex].cmdNum; // Ad & 0xFF;
    I2cbRegs.I2CMDR.all = 0x2620; // Send data to setup EEPROM address
    }

    }

    return I2C_SUCCESS;

    }
  • Sorry,

    I didn't get what you are trying to convey.

    Regards,
    Manoj