How to recover from an I2C BCLIF tire collision?

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; /* 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 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 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); } 
+7
source share
4 answers

This Errata must be added to the PIC18F25K20 errors.

PIC18F2455 / 2550/4455/4550 Rev. A3 Silicon Exceptions

17 Module: MSSP

It was noted that after turning on the Reset power, I2C mode may not initialize correctly by simply configuring the SCL and SDA pins as inputs or outputs. This was seen only in a few unique systems of environments.

Testing a statistically significant sample of the pre-production system, in the voltage and current range of the application power supply, should indicate whether the system is susceptible to this issue.

Work around

Before setting up the module for I2C operation:

  • Set the SCL and SDA pins as output by clearing their corresponding TRIS bits.
  • Force disable SCL and SDA by clearing the corresponding LAT bit.
  • When saving LAT bits, configure SCL and SDA as inputs by setting their TRIS bits.

Once this is done, use SSPCON1 and SSPCON2 is logged in to configure the correct I2C mode as before.

+9
source

The same error, it seems, also applies to the PIC18F26K20 / SS (version B3), you also need to add errors to it.

+2
source

I do not know your features, but I ran into a problem when the microcontroller exited reset earlier (long before Vdd stabilized on the I2C bus). Thus, uController started reading / writing data before the target could function normally, causing all possible I2C problems.

+2
source

This error also helped me with I2C hanging on the PIC18F27J53 (but in my case I also needed to unlock the I2C bus blocked by the SGP30 device, an example code is here: https://github.com/esp8266/Arduino/issues/1025#issuecomment- 158667929 ) I finally decided to implement a routine that executes restart-unstuck-restart, which is called when the launch condition fails (the code fragment of my I2C stack):

 eI2Cerr i2c_do_RUR(void) { //performs restart-unstuck-restart eI2Cerr eRetVal; eRetVal = i2c_do_restart(); if (eRetVal == I2C_ERR_TIMEOUT_RSEN_COLLISION) { i2c_unstuck(true); //true=performs also I2C bus unlock eRetVal = i2c_do_restart(); } return(eRetVal); } 

I2C seems stable and works well now.

0
source

Source: https://habr.com/ru/post/897778/


All Articles