22.6.2 Host Transmission (10-bit Address)

Host Transmission (10-bit Address)

#include <xc.h>

#define INIT 0
#define ADDRESS_PHASE_UPPER_10BIT 1
#define ADDRESS_PHASE_LOWER_10BIT 2
#define DATA_WRITE 3

#define PACKET_SIZE 10

#define mCLIENT_ADDRESS 0x14C

unsigned char hostTransmit[PACKET_SIZE] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA};
unsigned char transmittedCount = 0;
unsigned char phase = INIT;

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.HSCIE = 1;           // Assert HSTIF on start
    I2C2INTCbits.HSTIE = 1;           // Assert I2CxIF when HSTIF is set
    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_UPPER_10BIT;
    I2C2CON1bits.SEN= 1; // Send Start bit
 
 
    while(1) {
        
        //If data transmission is complete, repeat the operation.      
        if ((transmittedCount >= PACKET_SIZE) && (I2C2STAT2bits.STOPE)) {
            
            I2C2STAT2bits.STOPE = 0;    //Clear STOPE flag to detect next STOP
            I2C2STAT2bits.STARTE = 0;   //Clear STARTE flag since last START condition
            
            transmittedCount = 0;       //Start transmitting from start of data buffer
            
            I2C2CON2bits.NDA = 0;       //Will send address first, next byte is not data
            I2C2STAT2bits.EOP = 0;      //Clear end of packet bit
            I2C2CON2bits.PSZ = PACKET_SIZE; //Re-initialize packet size
            
            //Wait for bus idle
            while (!I2C2STAT2bits.BITO);
            phase = ADDRESS_PHASE_UPPER_10BIT;
            I2C2CON1bits.SEN = 1; // Send Start bit
            
        }
    }
}
 
void __attribute__((interrupt, no_auto_psv)) _I2C2Interrupt(void)
{
    IFS2bits.I2C2IF = 0;
    switch(phase)
    {
        case ADDRESS_PHASE_UPPER_10BIT: {
            /*Verify if start has been sent*/
            if(I2C2STAT2bits.STARTE)
            {
                /* Transmit client address with RW =0 , writing to client*/
                I2C2TRN = ((((mCLIENT_ADDRESS >> 8) & 0x03)<< 1) | 0 ) + 0b11110000; 
                phase = ADDRESS_PHASE_LOWER_10BIT;
            }
            break;
        }
        case ADDRESS_PHASE_LOWER_10BIT: {
            /*Verify if the upper 10bit address is ACKed*/
            if (I2C2STAT1bits.ACKSTAT ==0)
            {
            I2C2TRN = mCLIENT_ADDRESS & 0xFF ; 
            phase = DATA_WRITE;
            }
            break;
        }
        case DATA_WRITE: {
            /* Set NDA to indicate next byte is data */ 
            if(I2C2CON2bits.NDA !=1)
            {
                I2C2CON2bits.NDA = 1;
            }
            /* If Packet size is 0, EOP will be asserted, send STOP on EOP*/ 
            if(I2C2STAT2bits.EOP)
            {
                I2C2CON1bits.PEN =1; 
            }
            else
            {
                if ((I2C2STAT1bits.ACKSTAT ==0) && (!I2C2STAT1bits.TBF) && (!I2C2STAT1bits.TRSTAT))
                { 
                    I2C2TRN = hostTransmit[transmittedCount++]; // Send data to client
                }
            }
            break;
        }
    }
}