I posted this a couple of days ago on the Microchip forum ( here ), but the only answer was crickets. The I2C code below works most of the time, but sometimes when the power is turned on, a bus collision (BCLIF) occurs and the I2C module cannot recover from BCLIF. I2C lines rise by 3.3 thousand ohms. Using REALICE and breakpoints, I see that i2c_write()
resets BCLIF and returns FALSE when BCLIF is set. I used the area to check that the I2C bus has a flat shell. Re-initializing the I2C PIC18F25K20 module (see init_i2c()
below) when i2c_write()
returns FALSE does not help. The PIC18F25K20 I2C is connected to one slave device (MCP4018 I2C Digital POT). I used the same code in previous PIC18 projects without problems, so I replaced MCP4018, suspecting the bad part, but I see no difference. Is there a way to reset the PIC18F25K20 I2C module when it is locked?
void init_i2c(I2C_BAUD_RATE baud_rate, float freq_mhz) { UINT32 freq_cycle; SSPCON1 = 0; SSPCON2 = 0; PIR2bits.BCLIF = 0; freq_cycle = (UINT32) ((freq_mhz * 1e6) / 4.0); if (baud_rate == I2C_1_MHZ) { SSPADD = (UINT8) ((freq_cycle / 1000000L) - 1); SSPSTATbits.SMP = 1; } else if (baud_rate == I2C_400_KHZ) { SSPADD = (UINT8) ((freq_cycle / 400000L) - 1); SSPSTATbits.SMP = 0; } else { SSPADD = (UINT8) ((freq_cycle / 100000L) - 1); SSPSTATbits.SMP = 1; } SSPCON1bits.SSPM3 = 1; SSPCON1bits.SSPM2 = 0; SSPCON1bits.SSPM1 = 0; SSPCON1bits.SSPM0 = 0; 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; reg_ptr = (const UINT8 *) reg; data_ptr = (const UINT8 *) data; while ( ( SSPCON2 & 0x1F ) | ( SSPSTATbits.R_W ) ) ; SSPCON2bits.SEN = 1; while (SSPCON2bits.SEN) ; if (PIR2bits.BCLIF) { PIR2bits.BCLIF = 0; return(FALSE); } addr <<= 1; addr &= 0xFE; if (!write_byte(addr)) return(FALSE); for (i = 0; i < reg_size; i++) { if (!write_byte(reg_ptr)) return(FALSE); } for (i = 0; i < data_size; i++) { if (!write_byte(data_ptr)) return(FALSE); } SSPCON2bits.PEN = 1; while(SSPCON2bits.PEN) ; if (PIR2bits.BCLIF) { PIR2bits.BCLIF = 0; return(FALSE); } return(TRUE); } BOOL write_byte(UINT8 byte) { SSPBUF = byte; if (SSPCON1bits.WCOL) { return(FALSE); } else { while(SSPSTATbits.BF) ; } while ( ( SSPCON2 & 0x1F ) | ( SSPSTATbits.R_W ) ) ; if (SSPCON2bits.ACKSTAT) return(FALSE); return(TRUE); }
source share