I am writing a basic I2C slave as part of my code on a 20-pin 8-bit PIC16f MCU. As best as I can tell, this microcontroller has a module that watches the I2C bus and only updates my registers if there are incoming message addressed to the PIC — I can't interact with any other messages. The master is a CPU running a linux kernel and some other software. From the CPU, I can run a I2C probe script that just tries to read from every possible device address on the I2C chain (bus).
I'm having trouble getting the PIC to respond to any probing. I've written the simplest I2C code I can manage — it should just blink the LEDs whenever the device gets any sort of I2C message directed at it.
I hooked the lines up to the oscilloscope and was able to confirm that traffic is coming through the clock and data lines when I probe the chain.
My code is below. My compiler is the free version (without optimizations) of Microchip's XC8. I'm using the newest version (v1.34) for Windows.
Am I missing any initialization or configuration steps necessary to get my PIC to see incoming I2C messages?
#include <xc.h> /* XC8 General Include File */
#include <pic16lf1709.h> /* Definitions of I/O pins */
#pragma config WDTE = OFF // disable watchdog timer, for simplicity
// I2C address is 7 bits: 1111110
#define I2C_ADDRESS 0x7E
typedef unsigned char byte;
void main(void) {
/* configure MSSP module */
TRISBbits.TRISB4 = 1; // set SDA to input
TRISBbits.TRISB6 = 1; // set SCL to input
SSPCON1bits.SSPEN = 1; // enable SSP module
SSPCON1bits.SSPM = 0x6; // SSP is in I2C slave mode, 7-bit addressing
SSP1ADD = I2C_ADDRESS<<1; // set the device address (left-aligned)
SSPCON1bits.CKP = 1; // release clock
TRISC = 0x00; // set LEDs to output
PORTC = 0xFF; // initialize LEDs to OFF
while(1) {
byte ssp_buf; // for the data we read from the bus
if(SSPSTATbits.BF) { // if the I2C buffer is not empty
PORTC = 0x00; // turn on LEDs for a moment
for(int i=0; i<100; i++) _delay(250);
PORTC = 0xFF; // turn them back off
ssp_buf = SSPBUF; // read the buffer
// BF flag is cleared by hardware
}
SSPCON1bits.CKP = 1; // finally, release clock
}
}
Best Answer
There are several I/O connection features that are in use by different PICs. The PIC that you're using has the following features (as copied from the heading of the relevant chapters of the data sheet):
You should read the relevant parts of the data sheet, and set up all I/O configuration registers needed for your configuration. In this case, setting up ANSELB to enable the digital inputs, and setting up the PPS registers to route the input & output functions of the I2C module to the desired pins is missing. Also, the PPS registers are protected from undesired changes, so there is a locking mechanism you have to use before you could access the registers.
After making the changes above, the code should look something like this. Note that since the I2C messages aren't being properly acknowledged yet, the device may not be "visible" to the master, but you should at least see the light blink.