pic18lf57k42 and I2C1
I have a couple of PIC18LF56K42 designs with working I2C Master code (using only I2C1). I copied this code to a new design using 57K42 and both I2C ports. I duplicated the I2C1 code for I2C2 with appropriate changes for register names and port pins. Initialization, and first states of my I2C write state machine are below.
Fosc is 64MHz and the I2C clock comes from T6 with 2MHz rollover giving 400KHz SCL. This has worked fine on the 56K42. On the 57K42, I found that I2C2 didn't receive ACKs. I figured with more endpoints, maybe 2.2K pullups were too big, although the scope didn't show obvious issues and I was somewhat skeptical of this.
The BIG problem, however, is that I2C1 fails completely at 400KHz. As soon as I2C1CON0bits.S=1; is executed, the I2C bus spits out continuous clocks with SDA carrying repeated data (maybe address, it's physically hard to probe this design). The TXBE bit never goes high and MMA never goes low after .S=1 so state i2c_wr1 never checks for error or writes data to I2C1TXB. I2C1CNT never counts down from 2.
A coworker had some MCC generated code that worked. The only significant difference from my code was running the buses at 100KHz. I changed the I2C clock to 500KHz (for 100KHz SCL) and now both I2C buses work fine.
56K42 and 57K42 share a datasheet, but perhaps there's some silicon differences besides RAM and Flash. Anyone else seen oddities in I2C operation on the 57K42? I had zero difficulties with the 56K42. I'm going to try other SCL frequencies, and try to look closer at bus on the scope.
void init_i2c (void) {
T6CLK = 0x01; // CLK = Fosc/4 (16MHz)
T6PR = 7; // output = 16MHz / (7+1) = 2MHz
T6HLT = 0x00; // pre not sync, rising edge, clk not sync, SW ctrl
T6CON = 0x80; // T6 on, pre 1:1, post 1:1
I2C1CON0 = 0x04; // mode 7 bit master
I2C1CON1 = 0x80; // ACKCNT=1(nack), ACKDT=0(ack), sck stretch allow
I2C1CON2 = 0x00; // ACNT=0 GCEN=0 FME=0 ADB=0 SDAHT 300n, BFRET=0
I2C1CLK = 0x08; // CLK TMR6 post-scaled output (2MHz)
I2C1CON0 = 0x84; // I2C Enbld, mode 7 bit master
I2C1PIR = 0; // Clear all the error flags
I2C1ERR = 0;
I2C2CON0 = 0x04; // mode 7 bit master
I2C2CON1 = 0x80; // ACKCNT=1(nack), ACKDT=0(ack), sck stretch allow
I2C2CON2 = 0x00; // ACNT=0 GCEN=0 FME=0 ADB=0 SDAHT 300n, BFRET=0
I2C2CLK = 0x08; // CLK TMR6 post-scaled output (2MHz)
I2C2CON0 = 0x84; // I2C Enbld, mode 7 bit master
I2C2PIR = 0; // Clear all the error flags
I2C2ERR = 0;
}
case i2c_wstart:
if (I2C1STAT0bits.MMA == 0) { // if I2C not busy
I2C1ADB1 = i2c1addr; // write operation
I2C1CNT = 2; // eeadr (0) + ptr (1) + data (1)
I2C1CON0bits.S = 1; // start the transfer
PC1IF = 0;
I2C1TXB = i2c1_reg; // register ptr
i2c1fault = 0;
i2c1_st = i2c_wr1;
}
break;
case i2c_wr1:
if (I2C1STAT1bits.TXBE) {
if (I2C1CON1bits.ACKSTAT == 1) { // no ack received
I2C1CNT = 0;
I2C1STAT1bits.CLRBF = 1; // clear buffer since no ack
i2c1fault = 1;
i2c1_st = i2c_error;
} else {
I2C1TXB = i2c1_wval;
i2c1_st = i2c_wr2;
}
}