3.3 I2C Host Driver

3.3.1 Introduction

The MPLAB® Code Configurator (MCC) Melody Inter-Integrated Circuit (I2C) Host Driver generates a portable API to support a generic I2C host interface, and also two important MCC Melody Component concepts: configuration- and firmware-portability.

The I2C Host Driver requires a Peripheral Library (PLIB) dependency that is closely associated to an I2C hardware peripheral. On PIC® MCUs, this typically takes the form of a either an I2C or a MSSP (Master Synchronous Serial Port) hardware peripheral.

The I2C bus is a multi-host serial data communication busDevices communicate in a host/client environment where the host devices initiate the communication. A client device is controlled through addressing.

3.3.2 Required Header Files

For Host mode, include the following files in your application to use the I2C abstract driver:
#include <stdbool.h>
#include <stdint.h>
#include "mcc_generated_files/i2c_host/i2c_host_interface.h"

3.3.3 How to Use the I2C Host Driver

The I2C Host Driver can be used in polled or interrupt modes. Click the links to view the code snippets associated with each:

I2C Host Driver Use-Case examples:

Each of the following examples will illustrate how to communicate with an I2C device in Host mode. Both the polling mode and the interrupt mode is shown in two separate cases. In both cases the host device writes a value to the client device and reads it back. The client device used in this example has 16-bit registers, therefore both MSB and LSB are being transmitted.
  • I2C Host Polling Use-Case 1: In this I2C Host Polling example, a byte of data is written in to Client and read it back. Case 1: Data 0xAA is written in to Client at location 0x0010 and read the same back, using I2C1_Host.Write() and I2C1_Host.WriteRead() functions.
  • I2C Host Polling Use-Case 2: In this I2C Host Polling example, a byte of data is written in to Client and read it back. Case 2: Data 0x55 is written in to Client at location 0x0020 and read the same back using I2C1_Host.Write() and I2C1_Host.Read() functions.
  • I2C Host Interrupt Use-Case 1: In this I2C Host interrupt example, a byte of data is written in to Client and read it back. Case 1: Data 0xAA is written in to Client at location 0x0010 and read the same back, using I2C1_Host.Write() and I2C1_Host.WriteRead() functions.
  • I2C Host Interrupt Use-Case 2: In this I2C Host interrupt example, a byte of data is written in to Client and read it back. Case 2: Data 0x55 is written in to Client at location 0x0020 and read the same back using I2C1_Host.Write() and I2C1_Host.Read() functions.

3.3.4 I2C Host Driver Documentation

3.3.4.1 Module Documentation

3.3.4.1.1 I2C_HOST_DRIVER

Module description
Modules
I2C_HOST_INTERFACE

This file contains other data types for I2C module.

Module description

This file contains other data types for I2C module.

Version: I2C Driver Version 2.1.0
Data structures
I2C_HOST_EVENTS

This file contains other data types for I2C module.

Module description

This file contains other data types for I2C module.

Version: I2C Driver Version 2.1.0

3.3.4.1.2 I2C_host_example

I2C Host Basics

The Inter-Integrated Circuit (I2C) bus is a multi-host serial data communication bus. The devices communicate in a host/client environment where the host devices initiate the communication. A client receives commands/input/data through addressing.

The use-case code snippets explain the Interface APIs Usage for the below I2C Modes:
  • Host Examples Include files

  • Host Polling Example Case 1

  • Host Polling Example Case 2

  • Host Interrupt Example Case 1

  • Host Interrupt Example Case 2

I2C Host Examples

The examples below illustrate how to use the microcontroller as a I2C device in Host mode. The Polling mode and the Interrupt mode are shown in two separate cases, in which the host device writes a value and the client device reads it back. The client device used in this example has 16-bit registers, therefore both Most Significant Byte (MSB) and Least Significant Byte (LSB) are being transmitted.

All the host examples use include these files:

#include "mcc_generated_files/system/system.h"
#include "mcc_generated_files/i2c_host/i2c1.h"
#include "mcc_generated_files/i2c_host/i2c_host_interface.h"

I2C Host Polling Example Case 1

Data 0xAA is written to the client at location 0x0010 and read back, using the I2C1_Host.Write( ) and I2C1_Host.WriteRead( ) functions.

void I2C_host_example_polling_case_1(void)
{
    uint8_t clientAddr = 0x50; // 7-bit Client address
    uint8_t deviceRegAddrMsb = 0x00;    // MSB of Client location address
    uint8_t deviceRegAddrLsb = 0x10;    // LSB of Client location address

    // Desired write and read lengths
    uint8_t writeLength;
    uint8_t readLength;

    // Write and read data buffers (buffersize is set for some overhead)
    uint8_t transmitData[10] = {};
    uint8_t readData[10] = {};

    uint8_t waitCounter = 0;
  
    // Initializes Clock, Pins, Interrupts and I2C Initialize
    SYSTEM_Initialize();

    // Write to client device
    transmitData[0] = deviceRegAddrMsb;  // load MSB of Client location address
    transmitData[1] = deviceRegAddrLsb;  // load LSB of Client location address
    transmitData[2] = 0xAA;  // load data
    writeLength = 3; // 2 bytes of location address + 1 byte data

    if ( I2C1_Host.Write(clientAddr, transmitData, writeLength))
    {
        waitCounter = 100; // This value depends on the system clock, I2C clock and data length.                                                                                          
        while ( I2C1_Host.IsBusy())
        {
            I2C1_Host.Tasks();
            waitCounter--;              
        }

        if (  I2C1_Host.ErrorGet() == I2C_ERROR_NONE)
        {
            // Write operation is successful
        }
        else
        {
            // Error handling
        }
    }

    // Read from client device
    writeLength = 2; // 2 bytes of location address
    readLength = 1; // 1 byte read
    if (I2C1_Host.WriteRead(clientAddr, transmitData, writeLength, readData , readLength))
    {
        waitCounter = 100; // This value depends on the system clock, I2C clock and data length.                                                                                          
        while ( I2C1_Host.IsBusy())
        {
            I2C1_Host.Tasks();
            waitCounter--;              
        }

        if (  I2C1_Host.ErrorGet() == I2C_ERROR_NONE)
        {
            // WriteRead operation is successful
        }
        else
        {
            // Error handling
        }
    }
    
}

I2C Host Polling Example Case 2

Data 0x55 is written to the client at location 0x0020 and read back using the I2C1_Host.Write( ) and I2C1_Host.Read( ) functions.

void I2C_host_example_polling_case_2(void)
{
    uint8_t clientAddr = 0x50; // 7-bit Client address
    uint8_t deviceRegAddrMsb = 0x00;    // MSB of Client location address
    uint8_t deviceRegAddrLsb = 0x20;    // LSB of Client location address

    // Desired write and read lengths
    uint8_t writeLength;
    uint8_t readLength;

    // Write and read data buffers (buffersize is set for some overhead)
    uint8_t transmitData[10] = {};
    uint8_t readData[10] = {};

    uint8_t waitCounter = 0;

    // Initializes Clock, Pins, Interrupts and I2C Initialize
    SYSTEM_Initialize();


    // Write to client device
    transmitData[0] = 0x00;  // load MSB of Client location address
    transmitData[1] = 0x20;  // load LSB of Client location address
    transmitData[2] = 0x55;  // load data
    writeLength = 3; // 2 bytes of location address + 1 byte data

    if (I2C1_Host.Write(clientAddr, transmitData, writeLength))
    {
        waitCounter = 100; // This value depends on the system clock, I2C clock and data length.                                                                                          
        while (I2C1_Host.IsBusy())
        {
            I2C1_Host.Tasks();
            waitCounter--;              
        }

        if ( I2C1_Host.ErrorGet() == I2C_ERROR_NONE)
        {
            // Write operation is successful
        }
        else
        {
            // Error handling
        }
    }

    // Write which register we wish to read from
    writeLength = 2; // 2 bytes of location address
    if (I2C1_Host.Write(clientAddr, transmitData, writeLength))
    {
        waitCounter = 100; // This value depends on the system clock, I2C clock and data length.                                                                                          
        while (I2C1_Host.IsBusy())
        {
            I2C1_Host.Tasks();
            waitCounter--;              
        }

        if ( I2C1_Host.ErrorGet() == I2C_ERROR_NONE)
        {
            // Write operation is successful
        }
        else
        {
            // Error handling
        }
    }

    // Read from client device
    readLength = 1; // 1 byte read
    if (I2C1_Host.Read(clientAddr, readData, readLength))
    {
        waitCounter = 100; // This value depends on the system clock, I2C clock and data length.                                                                                          
        while (I2C1_Host.IsBusy())
        {
            I2C1_Host.Tasks();
            waitCounter--;              
        }

        if ( I2C1_Host.ErrorGet() == I2C_ERROR_NONE)
        {
            // Read operation is successful
        }
        else
        {
            // Error handling
        }
    }
}


I2C Host Interrupt Example Case 1

Data 0xAA is written to the client at location 0x0010 and read back using the I2C1_Host.Write( ) and I2C1_Host.WriteRead( ) functions.

void I2C_host_example_interrupt_case_1(void)
{
    uint8_t clientAddr = 0x50; // 7-bit Client address
    uint8_t deviceRegAddrMsb = 0x00;    // MSB of Client location address
    uint8_t deviceRegAddrLsb = 0x10;    // LSB of Client location address

    // Desired write and read lengths
    uint8_t writeLength;
    uint8_t readLength;

    // Write and read data buffers (buffersize is set for some overhead)
    uint8_t transmitData[10] = {};
    uint8_t readData[10] = {};


    // Initializes Clock, Pins, Interrupts and I2C Interface
    SYSTEM_Initialize();
    INTERRUPT_GlobalInterruptEnable();

    // Write to client device
    transmitData[0] = deviceRegAddrMsb;  // load MSB of Client location address
    transmitData[1] = deviceRegAddrLsb;  // load LSB of Client location address
    transmitData[2] = 0xAA;  // load data
    writeLength = 3;  // 2 bytes of location address + 1 byte data

    if(!I2C1_Host.Write(clientAddr, transmitData, writeLength))
    {
        // I2C bus busy, retry later
    }

    // Confirm write operation completed and check for error
    if(!I2C1_Host.IsBusy())
    {
        if ( I2C1_Host.ErrorGet() == I2C_ERROR_NONE)
        {
            // Write operation is successful
        }
        else
        {
            // Error handling
        }
    }

    // Read from client device
    writeLength = 2; // 2 bytes of location address
    readLength = 1; // 1 byte read
    if(I2C1_Host.WriteRead(clientAddr, transmitData, writeLength, readData , readLength))
    {
        // I2C bus busy, retry later
    }

    // Confirm write operation completed and check for error
    if(!I2C1_Host.IsBusy())
    {
        if ( I2C1_Host.ErrorGet() == I2C_ERROR_NONE)
        {
            // WriteRead operation is successful
        }
        else
        {
            // Error handling
        }
    }
}

I2C Host Interrupt Example Case 2

Data 0x55 is written to the client at location 0x0020 and read back using the I2C1_Host.Write( ) and I2C1_Host.Read( ) functions.

void I2C_host_example_interrupt_case_2(void)
  {
    uint8_t clientAddr = 0x50; // 7-bit Client address
    uint8_t deviceRegAddrMsb = 0x00;    // MSB of Client location address
    uint8_t deviceRegAddrLsb = 0x20;    // LSB of Client location address

    // Desired write and read lengths
    uint8_t writeLength;
    uint8_t readLength;

    // Write and read data buffers (buffersize is set for some overhead)
    uint8_t transmitData[10] = {};
    uint8_t readData[10] = {};


    // Initializes Clock, Pins, Interrupts and I2C Interface
    SYSTEM_Initialize();
    INTERRUPT_GlobalInterruptEnable();

    // Write to client device
    transmitData[0] = deviceRegAddrMsb;  // load MSB of Client location address
    transmitData[1] = deviceRegAddrLsb;  // load LSB of Client location address
    transmitData[2] = 0x55;  // load data
    writeLength = 2 + 1; // 2 bytes of location address + 1 byte data
    if(!I2C1_Host.Write(clientAddr, transmitData, writeLength))
    {
        // I2C bus busy, retry later
    }

    // Confirm write operation completed and check for error
    if(!I2C1_Host.IsBusy())
    {
        if ( I2C1_Host.ErrorGet() == I2C_ERROR_NONE)
        {
            // Write operation is successful
        }
        else
        {
            // Error handling
        }
    }

    // Write which register we wish to read from
    writeLength = 2; // 2 bytes of location address
    if(!I2C1_Host.Write(clientAddr, transmitData, writeLength))
    {
        // I2C bus busy, retry later
    }

    // Confirm write operation completed and check for error
    if(!I2C1_Host.IsBusy())
    {
        if ( I2C1_Host.ErrorGet() == I2C_ERROR_NONE)
        {
            // Write operation is successful
        }
        else
        {
            // Error handling
        }
    }

    // Read from client device
    readLength = 1; // 1 byte read
    if(!I2C1_Host.Read(clientAddr, readData, readLength)))
    {
        // I2C bus busy, retry later
    }

    // Confirm write operation completed and check for error
    if(!I2C1_Host.IsBusy())
    {
        if ( I2C1_Host.ErrorGet() == I2C_ERROR_NONE)
        {
            // Read operation is successful
        }
        else
        {
            // Error handling
        }
    }
}

3.3.4.2 Class Documentation

3.3.4.2.1 i2c_host_event_status_t Struct Reference

I2C Event Status Structure.

Member Data Documentation

The documentation for this struct was generated from the following file:

source/

i2c_host_event_types.h

address

uint16_t i2c_host_event_status_t::address

Pointer to write buffer

busy

bool i2c_host_event_status_t::busy

Software busy flag

errorState

i2c_host_error_t i2c_host_event_status_t::errorState

Error State

readLength

size_t i2c_host_event_status_t::readLength

Read buffer length

readPtr

uint8_t* i2c_host_event_status_t::readPtr

Pointer to read buffer

switchToRead

bool i2c_host_event_status_t::switchToRead

Switch i2c write to read mode

writeLength

size_t i2c_host_event_status_t::writeLength

Write buffer length

writePtr

uint8_t* i2c_host_event_status_t::writePtr

Pointer to write buffer

3.3.4.2.2 i2c_host_interface_t Struct Reference

Structure containing the function pointers of I2C drivers.

Detailed Description

Structure containing the function pointers of I2C drivers.

Section: Included Files

#include <i2c_host_interface.h>

The documentation for this struct was generated from the following file:

source/

i2c_host_interface.h

Public Attributes
  • void(* Initialize )(void)

  • void(* Deinitialize )(void)

  • bool(* Write )(uint16_t address, uint8_t *data, size_t dataLength)

  • bool(* Read )(uint16_t address, uint8_t *data, size_t dataLength)

  • bool(* WriteRead )(uint16_t address, uint8_t *writeData, size_t writeLength, uint8_t *readData, size_t readLength)

  • bool(* TransferSetup )(i2c_host_transfer_setup_t *setup, uint32_t srcClkFreq)

  • i2c_host_error_t(* ErrorGet )(void)

  • bool(* IsBusy )(void)

  • void(* CallbackRegister )(void(*callback)(void))

  • void(* Tasks )(void)

3.3.4.3 File Documentation

3.3.4.3.1 source/i2c_host_event_types.h File Reference

#include "i2c_host_types.h"
Detailed Description

I2C Generated Driver Event Header File

3.3.4.3.2 source/i2c_host_interface.h File Reference

#include <stdbool.h>
#include <stdint.h>
#include <xc.h>
#include "i2c_host_types.h"
Data structures
Detailed Description

I2C Generated Driver Interface Header File