1.11.12 Inter-Integrated Circuit - I2C

The I2C PLIB can be configured in master or slave mode.

I2C master mode The I2C peripheral library supports the following I2C transfers:

Master Write: The master writes a block of data to the slave Master Read: The master reads a block of data from the slave Master Write/Read: The master writes and then reads back a block of data from slave.

Additionally, a forced write API allows writes even if the address or data is NACKed by the slave.

The block of data is transferred in a non-blocking manner using a peripheral interrupt. Application can either use a callback or IsBusy API to check for completion of data transfer.

I2C slave mode

I2C slave PLIB works with peripheral interrupt enabled. Application must register a callback, to get notified of the I2C events such as address match, transmitter ready, receiver ready etc.

I2C Master mode

// Following code demonstrates I2C write operation using polling method

#define APP_SLAVE_ADDR 0x0057
#define NUM_BYTES      10

uint8_t myWriteData [NUM_BYTES] = {'1', '0', ' ', 'B', 'Y', 'T', 'E', 'S', '!', '!',};

int main(void)
{
	/* Initialize all modules */
    SYS_Initialize ( NULL );
	
    /* Write data to the I2C Slave */
    I2C1_Write(APP_SLAVE_ADDR, &myWriteData[0], NUM_BYTES);

    /* Poll and wait for the transfer to complete */
    while(I2C1_IsBusy());

    /* Check if any error occurred */
    if(I2C1_ErrorGet() == I2C_ERROR_NONE)
    {
        //Transfer is completed successfully
    }
    else
    {
        //Error occurred during transfer.
    }
	...
}
// Following code demonstrates I2C write operation using callback method

#define APP_SLAVE_ADDR 0x0057
#define NUM_BYTES      10

uint8_t myWriteData [NUM_BYTES] = {'1', '0', ' ', 'B', 'Y', 'T', 'E', 'S', '!', '!',};

void I2C1_Callback(uintptr_t context)
{
    if(I2C1_ErrorGet() == I2C_ERROR_NONE)
    {
        //Transfer is completed successfully
    }
    else
    {
        //Error occurred during transfer.
    }
}

int main(void)
{
	/* Initialize all modules */
    SYS_Initialize ( NULL );
	
    /* Register Callback function */
    I2C1_CallbackRegister(I2C1_Callback, (uintptr_t)NULL);

    /* Submit Write Request */
    I2C1_Write(APP_SLAVE_ADDR, &myWriteData[0], NUM_BYTES);
	
	...
}

I2C Slave mode

This example uses the I2C peripheral library in slave mode and emulates an EEPROM of 512 bytes. There are two pages each of size 256 bytes. I2C slave expects two bytes of memory address from the I2C master and the memory address can range from 0x00 to 0x1FF.

#define EEPROM_PAGE_SIZE_BYTES                  256
#define EEPROM_PAGE_SIZE_MASK                   0xFF
#define EEPROM_SIZE_BYTES                       512

// *****************************************************************************
// *****************************************************************************
// Section: Main Entry Point
// *****************************************************************************
// *****************************************************************************

typedef struct
{
    /* currentAddrPtr - to allow for sequential read (from the current address) */
    uint16_t                    currentAddrPtr;
    /* addrIndex - used to copy 2 bytes of EEPROM memory address */
    uint8_t                     addrIndex;        
}EEPROM_DATA;

EEPROM_DATA         eepromData;

uint8_t EEPROM_EmulationBuffer[EEPROM_SIZE_BYTES] =
{
    0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
    0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
    0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
    0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
    0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
    0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
    0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
    0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
    0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
    0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
    0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
    0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
    0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
    0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
    0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
    0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff,

    0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
    0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
    0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
    0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
    0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
    0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
    0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
    0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
    0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
    0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
    0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
    0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
    0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
    0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
    0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
    0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
};

bool APP_I2C_SLAVE_Callback ( I2C_SLAVE_TRANSFER_EVENT event, uintptr_t contextHandle )
{
    bool isSuccess = true;

    switch(event)
    {
        case I2C_SLAVE_TRANSFER_EVENT_ADDR_MATCH:
            
            /* Reset the index. MSB address is sent first followed by LSB. */
            eepromData.addrIndex = 2;
            
            break;

        case I2C_SLAVE_TRANSFER_EVENT_RX_READY:
            /* Read the data sent by I2C Master */
            if (eepromData.addrIndex > 0)
            {
                ((uint8_t*)&eepromData.currentAddrPtr)[--eepromData.addrIndex] = I2C1_ReadByte();
            }
            else
            {
                EEPROM_EmulationBuffer[eepromData.currentAddrPtr++] = I2C1_ReadByte();
                
                /* If exceeding the page boundary, rollover to the start of the page */
                if ((eepromData.currentAddrPtr % EEPROM_PAGE_SIZE_BYTES) == 0)
                {
                    eepromData.currentAddrPtr -= EEPROM_PAGE_SIZE_BYTES;
                }                                                              
            }
            break;

        case I2C_SLAVE_TRANSFER_EVENT_TX_READY:
            
            /* Provide the EEPROM data requested by the I2C Master */
            I2C1_WriteByte(EEPROM_EmulationBuffer[eepromData.currentAddrPtr++]);
            if (eepromData.currentAddrPtr >= EEPROM_SIZE_BYTES)
            {
                eepromData.currentAddrPtr = 0;
            }
            break;
        
        default:
            break;
    }

    return isSuccess;
}

int main ( void )
{
    /* Initialize all modules */
    SYS_Initialize ( NULL );

    I2C1_CallbackRegister(APP_I2C_SLAVE_Callback, 0);

    while ( true )
    {
        
    }

    /* Execution should not come here during normal operation */

    return ( EXIT_FAILURE );
}

Library Interface

I2C Mode

Functions

Name Description Master mode Slave mode
I2Cx_Initialize Initializes the instance of the I2C peripheral in either master or slave mode Yes Yes
I2Cx_Read Reads data from the slave Yes No
I2Cx_Write Writes data to the slave Yes No
I2Cx_WriteRead Write and Read data from Slave Yes No
I2Cx_WriteForced Forced write data to the slave Yes No
I2Cx_IsBusy Returns the Peripheral busy status Yes Yes
I2Cx_ErrorGet Returns the I2C error that occurred on the bus Yes Yes
I2Cx_TransferSetup Dynamic setup of I2C Peripheral Yes No
I2Cx_CallbackRegister Sets the pointer to the function (and it's context) to be called when the given I2C's transfer events occur Yes Yes
I2Cx_ReadByte Read the received I2C byte No Yes
I2Cx_WriteByte Write a data byte to I2C master No Yes
I2Cx_TransferDirGet Returns the I2C transfer direction No Yes
I2Cx_LastByteAckStatusGet Returns the ACK status of the last byte written to the I2C master No Yes

Data types and constants

Name Type Description Master mode Slave mode
I2C_ERROR Enum Defines the possible errors that the I2C peripheral can generate in I2C master mode Yes No
I2C_TRANSFER_SETUP Struct I2C transfer setup data structure Yes No
I2C_CALLBACK Typedef Defines the data type and function signature for the I2C peripheral callback function in I2C master mode Yes No
I2C_SLAVE_TRANSFER_DIR Enum Defines the enum for I2C data transfer direction No Yes
I2C_SLAVE_ACK_STATUS Enum Defines the enum for the I2C acknowledgement No Yes
I2C_SLAVE_TRANSFER_EVENT Enum Defines the enum for the I2C slave transfer event No Yes
I2C_SLAVE_ERROR Enum Defines errors associated with I2C in slave mode No Yes
I2C_SLAVE_CALLBACK Typedef Defines the data type and function signature for the I2C Slave callback function No Yes