幾天前我在Microchip論壇發佈了這個消息(here),但唯一的迴應是蟋蟀。 下面的I2C代碼大部分時間工作,但偶爾在上電時會出現總線衝突(BCLIF),I2C模塊無法在BCLIF後恢復。 I2C線上拉3.3K歐姆。 使用REALICE和斷點我可以看到i2c_write()
重置BCLIF並在BCLIF置位時返回FALSE。 我已經使用示波器來驗證I2C總線是否平整。 當i2c_write()
返回FALSE時,重新初始化PIC18F25K20 I2C模塊(請參閱下面的init_i2c()
)不會有幫助。 PIC18F25K20 I2C連接到單個從器件(MCP4018 I2C數字POT)。 我在以前的PIC18項目中使用了相同的代碼而沒有問題,所以我更換了MCP4018懷疑壞的部分,但沒有看到任何區別。 PIC18F25K20 I2C模塊在鎖定時是否有復位的方法?如何恢復I2C總線衝突BCLIF?
void init_i2c(I2C_BAUD_RATE baud_rate, float freq_mhz)
{
UINT32 freq_cycle;
/* Reset i2c */
SSPCON1 = 0;
SSPCON2 = 0;
PIR2bits.BCLIF = 0;
/* Set baud rate */
/* SSPADD = ((Fosc/4)/Fscl) - 1 */
freq_cycle = (UINT32) ((freq_mhz * 1e6)/4.0);
if (baud_rate == I2C_1_MHZ)
{
SSPADD = (UINT8) ((freq_cycle/1000000L) - 1);
SSPSTATbits.SMP = 1; /* disable slew rate for 1MHz operation */
}
else if (baud_rate == I2C_400_KHZ)
{
SSPADD = (UINT8) ((freq_cycle/400000L) - 1);
SSPSTATbits.SMP = 0; /* enable slew rate for 400kHz operation */
}
else /* default to 100 kHz case */
{
SSPADD = (UINT8) ((freq_cycle/100000L) - 1);
SSPSTATbits.SMP = 1; /* disable slew rate for 1MHz operation */
}
/* Set to Master Mode */
SSPCON1bits.SSPM3 = 1;
SSPCON1bits.SSPM2 = 0;
SSPCON1bits.SSPM1 = 0;
SSPCON1bits.SSPM0 = 0;
/* Enable i2c */
SSPCON1bits.SSPEN = 1;
}
BOOL i2c_write(UINT8 addr, const void *reg, UINT16 reg_size, const void *data, UINT16 data_size)
{
UINT16 i;
const UINT8 *data_ptr, *reg_ptr;
/* convert void ptr to UINT8 ptr */
reg_ptr = (const UINT8 *) reg;
data_ptr = (const UINT8 *) data;
/* check to make sure i2c bus is idle */
while ((SSPCON2 & 0x1F) | (SSPSTATbits.R_W))
;
/* initiate Start condition and wait until it's done */
SSPCON2bits.SEN = 1;
while (SSPCON2bits.SEN)
;
/* check for bus collision */
if (PIR2bits.BCLIF)
{
PIR2bits.BCLIF = 0;
return(FALSE);
}
/* format address with write bit (clear last bit to indicate write) */
addr <<= 1;
addr &= 0xFE;
/* send out address */
if (!write_byte(addr))
return(FALSE);
/* send out register/cmd bytes */
for (i = 0; i < reg_size; i++)
{
if (!write_byte(reg_ptr))
return(FALSE);
}
/* send out data bytes */
for (i = 0; i < data_size; i++)
{
if (!write_byte(data_ptr))
return(FALSE);
}
/* initiate Stop condition and wait until it's done */
SSPCON2bits.PEN = 1;
while(SSPCON2bits.PEN)
;
/* check for bus collision */
if (PIR2bits.BCLIF)
{
PIR2bits.BCLIF = 0;
return(FALSE);
}
return(TRUE);
}
BOOL write_byte(UINT8 byte)
{
/* send out byte */
SSPBUF = byte;
if (SSPCON1bits.WCOL) /* check for collision */
{
return(FALSE);
}
else
{
while(SSPSTATbits.BF) /* wait for byte to be shifted out */
;
}
/* check to make sure i2c bus is idle before continuing */
while ((SSPCON2 & 0x1F) | (SSPSTATbits.R_W))
;
/* check to make sure received ACK */
if (SSPCON2bits.ACKSTAT)
return(FALSE);
return(TRUE);
}
我看不到將SDA和SCL引腳配置爲輸入的代碼。 –
您是否可以嘗試交換啓動條件啓動並首先檢查i2c_write()中的總線衝突,並在出現此問題之間連續幾次執行此功能,並且有一些小的延遲時間?然後會發生什麼? –
另外,如果您的示波器帶有自動觸發器,它可能非常方便,因此您可以監視上電後SDA線的行爲。數據表說明:*如果在開始條件開始時,SDA和SCL引腳已經採樣爲低電平,或者如果在啓動條件期間,SCL線在SDA線驅動爲低電平之前被採樣爲低電平,則會發生總線衝突總線衝突中斷標誌BCLIF置1,中斷啓動條件並將I2C模塊復位到空閒狀態*。 –