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