22.6.3 Host Reception (7-bit Address)

Host Reception (7-bit Address)

#include <xc.h>

#define mCLIENT_ADDRESS 0x4C

#define INIT 1
#define ADDRESS_PHASE 2
#define DATA_READ 3

#define PACKET_SIZE 10

volatile unsigned char phase = INIT;
volatile unsigned char hostReceived[PACKET_SIZE];
volatile unsigned char receivedCount = 0;

int main(void) {
    
    /*Configure I2C pins as digital*/

    //I2C module has Host and Client functionality which may both be active at the same time.
    //In this example, Host functionality will be configured and used.

    //Configure baud rate for SCL @ 100kHz from 1/2 bus UPB clock @ 4MHz
    I2C2LBRG = 16; //Set low-time baud rate
    I2C2HBRG = 16; //Set high-time baud rate

    /* Configure Bus IDle timeout*/
    I2C2CON2bits.BITE = 1;
    I2C2BITObits.BITOTMR = 76;

    /* Configured interrupt enable bits*/
    I2C2INTCbits.HACKSIE = 1;         // Assert HSTIF on ACK seq
    I2C2INTCbits.HDTXIE = 1;          // Assert HSTIF on TX
    I2C2INTCbits.HDRXIE = 1;          // Assert HSTIF on RX
    I2C2INTCbits.HSCIE = 1;           // Assert HSTIF on start
    I2C2INTCbits.HSTIE = 1;           // Assert I2CxIF when HSTIF is set
    I2C2CON2bits.SMEN = 1;            // Smart mode enabled
    I2C2CON2bits.ACKC = 0b10;         // ACK all the bytes expect last byte
    I2C2CON2bits.PSZ = PACKET_SIZE;   // Packet size
    I2C2CON2bits.EOPSC = 0b01;        // End of packet will be set after data bytes
    I2C2CON1bits.ON = 1;              // Enable I2C
    IFS2bits.I2C2IF = 0;              // Clear I2C general interrupt 
    IEC2bits.I2C2IE = 1;              // Enable I2C general interrupt 

    /*wait for bus idle */
    while (!I2C2STAT2bits.BITO);
    phase = ADDRESS_PHASE;
    I2C2CON1bits.SEN = 1;             // Send Start bit
    
    while (1) {
    
        //Once reception is complete, repeat the operation.
        if ((receivedCount >= PACKET_SIZE) && (I2C2STAT2bits.STOPE)) {
            
            I2C2STAT2bits.STOPE = 0;    //Clear STOPE flag to detect next STOP
            I2C2STAT2bits.STARTE = 0;   //Clear STARTE flag since last START condition
            
            receivedCount = 0;  //Reset receive buffer index
            
            I2C2CON1bits.RCEN = 0;          //Not yet receiving data on first transaction
            I2C2CON2bits.NDA = 0;           //Will send address first, next byte is not data
            I2C2CON2bits.PSZ = PACKET_SIZE; //Re-initialize packet size
            I2C2STAT2bits.EOP = 0;          //Clear end of packet bit
            
            /*wait for bus idle */
            while (!I2C2STAT2bits.BITO);
            phase = ADDRESS_PHASE;
            I2C2CON1bits.SEN = 1;           // Send Start bit
        }
    
    }
    
 
}

void __attribute__((interrupt, no_auto_psv)) _I2C2Interrupt(void) {
    IFS2bits.I2C2IF = 0;
    switch (phase) {
        case ADDRESS_PHASE: {
            /*Verify if start has been sent*/
            if (I2C2STAT2bits.STARTE) {
                phase = DATA_READ;
                /* Transmit client address with RW =1 , read client*/
                I2C2TRN = (mCLIENT_ADDRESS << 1) | 1;
            }
            break;
        }
        case DATA_READ: {
            /* Set NDA to indicate next byte is data */
            if (I2C2CON2bits.NDA != 1) {
                I2C2CON2bits.NDA = 1;
                /*Enable receive for the 1st time*/
                I2C2CON1bits.RCEN = 1;
            }
            /*Read the received data*/
            if (I2C2STAT1bits.RBF) {
                hostReceived[receivedCount++] = I2C2RCV;
            }
            /* If Packet size is 0, EOP will be asserted,send STOP on EOP*/
            if (I2C2STAT2bits.EOP == 1) {
                I2C2CON1bits.PEN = 1;
            } 
            break;
        }
    }
}