3 Slave Mode Code Example

MSSP in I2C Slave Mode shows the use of the MSSP in 7-bit I2C Slave mode. The example uses an Interrupt Service Routine (ISR) to determine whether the master intends to read data from or write data to the slave, and react accordingly. A PICkit™ Serial Analyzer tool, which includes a graphical user interface (GUI), was used as the master device for simplicity. The GUI allows a user to read data from or write data to specific address locations within the slave.

MSSP in I2C Slave Mode

#define ARRAY_CNT        32               // Number of bytes in array

uint8_t slaveAddress = 0x30;                    // 7-bit slave address
uint8_t index =           0;                    // Array pointer
uint8_t temp =            0;                    // Temp register
uint8_t regAdd =          1;                    // First data byte was reg add

uint8_t i2cArray[ARRAY_CNT] = 
{0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88,
0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0xFA,
0xEA, 0xDA, 0xCA, 0xBA, 0xFB, 0xFC, 0xFD, 0xFE,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};

void I2C_Initialize(void)
{
    SSP1STATbits.SMP = 1;                        // Disable slew control
    SSP1CON1bits.SSPM = 0b0110;                  // 7-bit slave mode
    SSP1CON2bits.SEN = 1;                        // Enable clock stretching
    SSP1CON3bits.SBCDE = 1;                      // Enable BCLIF
    SSP1ADD = slaveAddress;                      // Load slave address
    SSP1CON1bits.SSPEN = 1;                      // Enable the module

    PIR3bits.BCL1IF = 0;                         // Clear Bus Collision IF
    PIR3bits.SSP1IF = 0;                         // Clear SSP interrupt flag
    PIE3bits.BCL1IE = 1;                         // Enable BCLIF
    PIE3bits.SSP1IE = 1;                         // Enable SSPIF
    INTCONbits.PEIE = 1;                         // Enable periph interrupts
    INTCONbits.GIE = 1;                          // Enable global interrupts
}

void __interrupt() ISR(void)
{
    if(PIR3bits.SSP1IF)                         // Check for SSPIF
    {
        if(SSP1STATbits.R_nW == 1)              // Master read (slave transmit)
        {
            SSP1BUF = i2cArray[index++];        // Load array value
            SSP1CON1bits.CKP = 1;               // Release clock stretch
        }
        if(SSP1STATbits.R_nW == 0)              // Master write (slave receive)
        {
            if(SSP1STATbits.D_nA == 0)          // Last byte was an address
            {
                regAdd = 1;                     // Next byte register address
                temp = SSP1BUF;                 // Clear BF
                SSP1CON1bits.CKP = 1;           // Release clock stretch
            }
            if(SSP1STATbits.D_nA == 1)          // Last byte was data
            {
                if(regAdd == 1)                 // Last byte was register add
                {
                    index = SSP1BUF;            // Load register address
                    regAdd = 0;                 // Next byte will be true data
                }
                else
                {
                    if(index < ARRAY_CNT)              // Within boundaries?
                    {
                        i2cArray[index++] = SSP1BUF;   // Yes, read SSP1BUF
                    }
                    else
                    {
                        temp = SSP1BUF;                // No, discard data
                    }
                }
                SSP1CON1bits.CKP = 1;                  // Release clock stretch
            }
        }
    }
    if(PIR3bits.BCL1IF == 1)
    {
        temp = SSP1BUF;                            // Clear BF
        PIR3bits.BCL1IF = 0;                       // Clear BCLIF
        SSP1CON1bits.CKP = 1;                      // Release clock stretching
    }
    PIR3bits.SSP1IF = 0;                           // Clear SSP1IF
}