Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to recover from I2C bus collision BCLIF?
    primarykey
    data
    text
    <p>I posted this a couple of days ago on the Microchip Forum (<a href="http://www.microchip.com/forums/tm.aspx?m=602359" rel="noreferrer">here</a>) but the only response has been crickets. The I2C code below works most of the time but occasionally on power-up there is a bus collision (BCLIF) and the I2C module is unable to recover after the BCLIF. The I2C lines are pulled up by 3.3K ohms. Using REALICE and breakpoints I can see that <code>i2c_write()</code> resets BCLIF and returns FALSE when BCLIF is set. I have used a scope to verify that the I2C bus has flat-lined. Re-initializing the PIC18F25K20 I2C module (see <code>init_i2c()</code> below) when <code>i2c_write()</code> returns FALSE does not help. The PIC18F25K20 I2C is connected to a single slave device (MCP4018 I2C Digital POT). I have used this same code on previous PIC18 projects without issue so I replaced the MCP4018 suspecting a bad part but see no difference. Is there a way to reset the PIC18F25K20 I2C module when it is locked up? </p> <pre><code>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 &amp; 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 &lt;&lt;= 1; addr &amp;= 0xFE; /* send out address */ if (!write_byte(addr)) return(FALSE); /* send out register/cmd bytes */ for (i = 0; i &lt; reg_size; i++) { if (!write_byte(reg_ptr)) return(FALSE); } /* send out data bytes */ for (i = 0; i &lt; 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 &amp; 0x1F ) | ( SSPSTATbits.R_W ) ) ; /* check to make sure received ACK */ if (SSPCON2bits.ACKSTAT) return(FALSE); return(TRUE); } </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload