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");
}
}