1.21.10 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 |