1.1.11 I2C SMBUS

The I2C SMBUS PLIB support I2C Master, I2C Slave, SMBUS Master and SMBUS Slave modes.

Using the Library

I2C Master mode - The below example uses the I2C peripheral library to write an array of values to the I2C Serial EEPROM and verify the value written by reading the values back and comparing it to the value written.
#include <string.h>
#define LED_ON()                       LED5_Set()
#define LED_OFF()                      LED5_Clear()

#define APP_AT24MAC_DEVICE_ADDR             0x0054
#define APP_AT24MAC_MEMORY_ADDR             0x00
#define APP_AT24MAC_MEMORY_ADDR1            0x00
#define APP_TRANSMIT_DATA_LENGTH            6
#define APP_ACK_DATA_LENGTH                 1
#define APP_RECEIVE_DUMMY_WRITE_LENGTH      2
#define APP_RECEIVE_DATA_LENGTH             4

static uint8_t testTxData[APP_TRANSMIT_DATA_LENGTH] =
{
    APP_AT24MAC_MEMORY_ADDR,APP_AT24MAC_MEMORY_ADDR1,
    'M','C','H','P',
};

static uint8_t  testRxData[APP_RECEIVE_DATA_LENGTH];

typedef enum
{
    APP_STATE_EEPROM_STATUS_VERIFY,
    APP_STATE_EEPROM_WRITE,
    APP_STATE_EEPROM_WAIT_WRITE_COMPLETE,
    APP_STATE_EEPROM_CHECK_INTERNAL_WRITE_STATUS,
    APP_STATE_EEPROM_READ,
    APP_STATE_EEPROM_WAIT_READ_COMPLETE,
    APP_STATE_VERIFY,
    APP_STATE_IDLE,
    APP_STATE_XFER_SUCCESSFUL,
    APP_STATE_XFER_ERROR

} APP_STATES;

typedef enum
{
    APP_TRANSFER_STATUS_IN_PROGRESS,
    APP_TRANSFER_STATUS_SUCCESS,
    APP_TRANSFER_STATUS_ERROR,
    APP_TRANSFER_STATUS_IDLE,

} APP_TRANSFER_STATUS;

void APP_I2CCallback(uintptr_t context )
{
    APP_TRANSFER_STATUS* transferStatus = (APP_TRANSFER_STATUS*)context;

    if(I2C0_ErrorGet() == I2C_ERROR_NONE)
    {
        if (transferStatus)
        {
            *transferStatus = APP_TRANSFER_STATUS_SUCCESS;
        }
    }
    else
    {
        if (transferStatus)
        {
            *transferStatus = APP_TRANSFER_STATUS_ERROR;
        }
    }
}

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

int main ( void )
{
    APP_STATES state = APP_STATE_EEPROM_STATUS_VERIFY;
    volatile APP_TRANSFER_STATUS transferStatus = APP_TRANSFER_STATUS_ERROR;
    uint8_t ackData = 0;

    /* Initialize all modules */
    SYS_Initialize ( NULL );

    while(1)
    {
        /* Check the application's current state. */
        switch (state)
        {
            case APP_STATE_EEPROM_STATUS_VERIFY:

                /* Register the TWIHS Callback with transfer status as context */
                I2C0_CallbackRegister( APP_I2CCallback, (uintptr_t)&transferStatus );

               /* Verify if EEPROM is ready to accept new requests */
                transferStatus = APP_TRANSFER_STATUS_IN_PROGRESS;
                I2C0_Write(APP_AT24MAC_DEVICE_ADDR, &ackData, APP_ACK_DATA_LENGTH);

                state = APP_STATE_EEPROM_WRITE;
                break;

            case APP_STATE_EEPROM_WRITE:

                if (transferStatus == APP_TRANSFER_STATUS_SUCCESS)
                {
                    /* Write data to EEPROM */
                    transferStatus = APP_TRANSFER_STATUS_IN_PROGRESS;
                    I2C0_Write(APP_AT24MAC_DEVICE_ADDR, &testTxData[0], APP_TRANSMIT_DATA_LENGTH);
                    state = APP_STATE_EEPROM_WAIT_WRITE_COMPLETE;
                }
                else if (transferStatus == APP_TRANSFER_STATUS_ERROR)
                {
                    /* EEPROM is not ready to accept new requests. 
                     * Keep checking until the EEPROM becomes ready. */
                    state = APP_STATE_EEPROM_STATUS_VERIFY;
                }
                break;

            case APP_STATE_EEPROM_WAIT_WRITE_COMPLETE:

                if (transferStatus == APP_TRANSFER_STATUS_SUCCESS)
                {
                    /* Read the status of internal write cycle */
                    transferStatus = APP_TRANSFER_STATUS_IN_PROGRESS;
                    I2C0_Write(APP_AT24MAC_DEVICE_ADDR, &ackData, APP_ACK_DATA_LENGTH);
                    state = APP_STATE_EEPROM_CHECK_INTERNAL_WRITE_STATUS;
                }
                else if (transferStatus == APP_TRANSFER_STATUS_ERROR)
                {
                    state = APP_STATE_XFER_ERROR;
                }
                break;

             case APP_STATE_EEPROM_CHECK_INTERNAL_WRITE_STATUS:

                if (transferStatus == APP_TRANSFER_STATUS_SUCCESS)
                {
                    state = APP_STATE_EEPROM_READ;
                }
                else if (transferStatus == APP_TRANSFER_STATUS_ERROR)
                {
                    /* EEPROM's internal write cycle is not complete. Keep checking. */
                    transferStatus = APP_TRANSFER_STATUS_IN_PROGRESS;
                    I2C0_Write(APP_AT24MAC_DEVICE_ADDR, &ackData, APP_ACK_DATA_LENGTH);
                }
                break;

            case APP_STATE_EEPROM_READ:

                transferStatus = APP_TRANSFER_STATUS_IN_PROGRESS;
                /* Read the data from the page written earlier */
                I2C0_WriteRead(APP_AT24MAC_DEVICE_ADDR, &testTxData[0], APP_RECEIVE_DUMMY_WRITE_LENGTH,  &testRxData[0], APP_RECEIVE_DATA_LENGTH);

                state = APP_STATE_EEPROM_WAIT_READ_COMPLETE;

                break;

            case APP_STATE_EEPROM_WAIT_READ_COMPLETE:

                if (transferStatus == APP_TRANSFER_STATUS_SUCCESS)
                {
                    state = APP_STATE_VERIFY;
                }
                else if (transferStatus == APP_TRANSFER_STATUS_ERROR)
                {
                    state = APP_STATE_XFER_ERROR;
                }
                break;

            case APP_STATE_VERIFY:

                if (memcmp(&testTxData[2], &testRxData[0], APP_RECEIVE_DATA_LENGTH) != 0 )
                {
                    /* It means received data is not same as transmitted data */
                    state = APP_STATE_XFER_ERROR;
                }
                else
                {
                    /* It means received data is same as transmitted data */
                    state = APP_STATE_XFER_SUCCESSFUL;
                }
                break;

            case APP_STATE_XFER_SUCCESSFUL:
            {
                LED_ON();
                break;
            }
            case APP_STATE_XFER_ERROR:
            {
                LED_OFF();
                break;
            }
            default:
                break;
        }
    }
}
I2C slave mode - The below example uses the I2C peripheral library in slave mode and emulates an EEPROM of 512 bytes.
#define EEPROM_PAGE_SIZE_BYTES                  256
#define EEPROM_PAGE_SIZE_MASK                   0xFF
#define EEPROM_SIZE_BYTES                       512

typedef enum
{
    EEPROM_CMD_WRITE,
    EEPROM_CMD_IDLE,
}EEPROM_CMD;

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;
    /* wrBuffer - holds the incoming data from the I2C master */
    uint8_t                     wrBuffer[EEPROM_PAGE_SIZE_BYTES];
    /* wrBufferIndex - Index into the wrBuffer[] */
    uint16_t                    wrBufferIndex;
    /* wrAddr - indicates the starting address of the EEPROM emulation memory to write to */
    volatile uint16_t           wrAddr;
    /* nWrBytes - indicates the number of bytes to write to EEPROM emulation buffer */
    volatile uint8_t            nWrBytes;
    /* internalWriteInProgress - indicates that EEPROM is busy with internal writes */
    bool                        internalWriteInProgress;
    /* eepromCommand - used to trigger write to the EEPROM emulation buffer */
    EEPROM_CMD                  eepromCommand;
}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_SERCOM_I2C_Callback ( I2C_SLAVE_TRANSFER_EVENT event, uintptr_t contextHandle )
{
    bool isSuccess = true;

    switch(event)
    {
        case I2C_SLAVE_TRANSFER_EVENT_ADDR_MATCH:
            if ((I2C0_TransferDirGet() == I2C_SLAVE_TRANSFER_DIR_WRITE) && (eepromData.internalWriteInProgress == true))
            {
                /* EEPROM is busy. Send NAK */
                isSuccess = false;
            }
            else
            {
                /* Reset the indexes */
                eepromData.addrIndex = 0;
                eepromData.wrBufferIndex = 0;
            }
            break;

        case I2C_SLAVE_TRANSFER_EVENT_RX_READY:
            /* Read the data sent by I2C Master */
            if (eepromData.addrIndex < 2)
            {
                ((uint8_t*)&eepromData.currentAddrPtr)[eepromData.addrIndex++] = I2C0_ReadByte();
            }
            else
            {
                eepromData.wrBuffer[(eepromData.wrBufferIndex & EEPROM_PAGE_SIZE_MASK)] = I2C0_ReadByte();
                eepromData.wrBufferIndex++;
            }
            break;

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

        case I2C_SLAVE_TRANSFER_EVENT_STOP_BIT_RECEIVED:
            if (eepromData.wrBufferIndex > 0)
            {
                if (eepromData.wrBufferIndex > EEPROM_PAGE_SIZE_BYTES)
                {
                    eepromData.wrBufferIndex = EEPROM_PAGE_SIZE_BYTES;
                }
                eepromData.wrAddr = eepromData.currentAddrPtr;
                eepromData.nWrBytes = eepromData.wrBufferIndex;

                /* Update the current address pointer to allow for sequential read */
                eepromData.currentAddrPtr += eepromData.wrBufferIndex;

                /* Reset the indexes */
                eepromData.addrIndex = 0;
                eepromData.wrBufferIndex = 0;

                /* Set busy flag to send NAK for any write requests */
                eepromData.internalWriteInProgress = true;
                eepromData.eepromCommand = EEPROM_CMD_WRITE;
            }
            break;
        default:
            break;
    }

    return isSuccess;
}

void EEPROM_StateMachine(void)
{
    switch(eepromData.eepromCommand)
    {
        case EEPROM_CMD_WRITE:
            memcpy(&EEPROM_EmulationBuffer[eepromData.wrAddr], &eepromData.wrBuffer[0], eepromData.nWrBytes);
            eepromData.internalWriteInProgress = false;
            eepromData.eepromCommand = EEPROM_CMD_IDLE;
            break;
        case EEPROM_CMD_IDLE:
            /* Do Nothing */
            break;
    }
}

int main ( void )
{
    /* Initialize all modules */
    SYS_Initialize ( NULL );
    eepromData.eepromCommand = EEPROM_CMD_IDLE;
    I2C0_CallbackRegister(APP_SERCOM_I2C_Callback, 0);
    while ( true )
    {
        EEPROM_StateMachine();
    }
    /* Execution should not come here during normal operation */
    return ( EXIT_FAILURE );
}
SMBUS Host mode - The below example uses the SMBUS peripheral library and demonstrates how application can use the various APIs available to read and write data when the peripheral is configured in master mode.
#define I2C_SLAVE_ADDR                 0x54

typedef enum
{
    HOST_STATE_WRITE_BYTE = 0,
    HOST_STATE_WRITE_WORD,
    HOST_STATE_WRITE_BLOCK,
    HOST_STATE_READ_BYTE,
    HOST_STATE_READ_WORD,
    HOST_STATE_READ_BLOCK,
    HOST_STATE_WRITE_READ_BLOCK,
    HOST_STATE_WAIT_FOR_TRANSFER_DONE,
    HOST_STATE_ERROR,
    HOST_STATE_SUCCESS,
}HOST_STATE;

typedef enum
{
    HOST_CMD_WRITE_BYTE,
    HOST_CMD_WRITE_WORD,
    HOST_CMD_WRITE_BLOCK,
    HOST_CMD_READ_BYTE,
    HOST_CMD_READ_WORD,
    HOST_CMD_READ_BLOCK,
    HOST_CMD_WRITE_READ_BLOCK,
}HOST_CMD;

volatile bool transferDone = false;
volatile uint32_t nBytesRead = 0;
bool blockRead = false;
uint32_t nBytesRequested = 0;
uint8_t wrBuffer[50] = {0};
uint8_t rdBuffer[50] = {0};

volatile HOST_STATE state = HOST_STATE_WRITE_BYTE;
HOST_STATE nextState;

void i2cSMB0HostEventHandler (I2C_SMB_HOST_TRANSFER_EVENT event, uintptr_t contextHandle)
{
    switch(event)
    {
        case I2C_SMB_HOST_TRANSFER_EVENT_RX_READY:
            nBytesRead = I2CSMB0_HostBufferRead(rdBuffer);
            break;

        case I2C_SMB_HOST_TRANSFER_EVENT_DONE:
            transferDone = true;
            break;

        case I2C_SMB_HOST_TRANSFER_EVENT_ERROR:
            state = HOST_STATE_ERROR;
            break;
            
        default:
            break;
    }
        
}

int main ( void )
{        
    uint32_t i = 0;
    uint32_t data = 1;
    
    /* Initialize all modules */
    SYS_Initialize ( NULL );
    
    I2CSMB0_HostCallbackRegister(i2cSMB0HostEventHandler, 0);
        
    while (1)
    {
        switch(state)
        {
            case HOST_STATE_WAIT_FOR_TRANSFER_DONE:
                if (transferDone == true)
                {
                    transferDone = false;
                    state = nextState;

                    if (nBytesRequested > 0)
                    {
                        i = 0;
                        data = 1;
                        
                        if (blockRead == true)
                        {
                            // for block reads, the first byte indicates the number of bytes transmitted by the slave
                            nBytesRead =  rdBuffer[i++];    
                            blockRead = false;
                        }                        
                        if (nBytesRead != nBytesRequested)
                        {
                            state = HOST_STATE_ERROR;
                            break;
                        }
                        while (nBytesRequested--)
                        {
                            if (rdBuffer[i++] != data++)
                            {
                                state = HOST_STATE_ERROR;
                                break;
                            }                            
                        }

                        nBytesRequested = 0;
                    }
                }
                break;
                
            case HOST_STATE_WRITE_BYTE:
                wrBuffer[0] = 1;
                I2CSMB0_HostWriteByte(I2C_SLAVE_ADDR, HOST_CMD_WRITE_BYTE, wrBuffer);
                state = HOST_STATE_WAIT_FOR_TRANSFER_DONE;
                nextState = HOST_STATE_READ_BYTE;
                break;
                
            case HOST_STATE_READ_BYTE:
                nBytesRequested = 1;
                I2CSMB0_HostReadByte(I2C_SLAVE_ADDR, HOST_CMD_READ_BYTE);
                state = HOST_STATE_WAIT_FOR_TRANSFER_DONE;
                nextState = HOST_STATE_WRITE_WORD;
                break;

            case HOST_STATE_WRITE_WORD:
                wrBuffer[0] = 1;
                wrBuffer[1] = 2;
                I2CSMB0_HostWriteWord(I2C_SLAVE_ADDR, HOST_CMD_WRITE_WORD, wrBuffer);
                state = HOST_STATE_WAIT_FOR_TRANSFER_DONE;
                nextState = HOST_STATE_READ_WORD;
                break;
                
            case HOST_STATE_READ_WORD:
                nBytesRequested = 2;
                I2CSMB0_HostReadWord(I2C_SLAVE_ADDR, HOST_CMD_READ_WORD);
                state = HOST_STATE_WAIT_FOR_TRANSFER_DONE;
                nextState = HOST_STATE_WRITE_BLOCK;
                break;

            case HOST_STATE_WRITE_BLOCK:
                for (uint32_t i = 0; i < 32; i++)
                {
                    wrBuffer[i] = i+1;
                }
                I2CSMB0_HostWriteBlock(I2C_SLAVE_ADDR, HOST_CMD_WRITE_BLOCK, wrBuffer, 32);
                state = HOST_STATE_WAIT_FOR_TRANSFER_DONE;
                nextState = HOST_STATE_READ_BLOCK;
                break;
                
            case HOST_STATE_READ_BLOCK:
                nBytesRequested = 32;
                blockRead = true;
                I2CSMB0_HostReadBlock(I2C_SLAVE_ADDR, HOST_CMD_READ_BLOCK);
                state = HOST_STATE_WAIT_FOR_TRANSFER_DONE;
                nextState = HOST_STATE_WRITE_READ_BLOCK;
                break;
                     
            case HOST_STATE_WRITE_READ_BLOCK:
                nBytesRequested = 32;
                blockRead = true;
                I2CSMB0_HostWriteReadBlock(I2C_SLAVE_ADDR, HOST_CMD_WRITE_READ_BLOCK, wrBuffer, 32);
                state = HOST_STATE_WAIT_FOR_TRANSFER_DONE;
                nextState = HOST_STATE_SUCCESS;
                break;

            case HOST_STATE_SUCCESS:
                break;
                
            case HOST_STATE_ERROR:
                break;
        }
    }
    

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

    return ( EXIT_FAILURE );
}
SMBUS Target mode - The below example uses the SMBUS peripheral library and demonstrates how application can use the various APIs available to read and write data when the peripheral is configured in slave mode.
typedef enum
{
    HOST_CMD_WRITE_BYTE,
    HOST_CMD_WRITE_WORD,
    HOST_CMD_WRITE_BLOCK,
    HOST_CMD_READ_BYTE,
    HOST_CMD_READ_WORD,
    HOST_CMD_READ_BLOCK,
    HOST_CMD_WRITE_READ_BLOCK,
}HOST_CMD;

volatile uint8_t targetRxBuffer[100];
volatile uint8_t targetTxBuffer[100];
volatile uint32_t nBytesRead = 0;
volatile uint32_t nDataBytes = 0;
volatile HOST_CMD command;

bool i2cSMB0TargetEventHandler (I2C_SMB_TARGET_TRANSFER_EVENT event, uintptr_t contextHandle)
{
    switch (event)
    {
        case I2C_SMB_TARGET_TRANSFER_EVENT_RX_READY:
            nBytesRead = I2CSMB0_TargetBufferRead((void*)targetRxBuffer);
            command = targetRxBuffer[1];
            if (command == HOST_CMD_WRITE_BYTE)
            {
                nDataBytes = 1;        
                targetTxBuffer[0] = targetRxBuffer[2];
            }
            else if (command == HOST_CMD_WRITE_WORD)
            {
                nDataBytes = 2;            
                targetTxBuffer[0] = targetRxBuffer[2];
                targetTxBuffer[1] = targetRxBuffer[3];
            }
            else if ((command == HOST_CMD_WRITE_BLOCK) || (command == HOST_CMD_WRITE_READ_BLOCK))
            {
                nDataBytes = targetRxBuffer[2];
                targetTxBuffer[0] = nDataBytes;
                memcpy((void*)&targetTxBuffer[1], (void*)&targetRxBuffer[3], nDataBytes);
                nDataBytes = nDataBytes + 1;
            }                        
            break;
        case I2C_SMB_TARGET_TRANSFER_EVENT_TX_READY:
            I2CSMB0_TargetBufferWrite((void*)targetTxBuffer, nDataBytes);
            break;
        case I2C_SMB_TARGET_TRANSFER_EVENT_ERROR:
            break;
        case I2C_SMB_TARGET_TRANSFER_EVENT_DONE:
            break;
        default:
            break;
    }
    return true;
}

int main ( void )
{
    /* Initialize all modules */
    SYS_Initialize ( NULL );
    
    I2CSMB0_TargetCallbackRegister(i2cSMB0TargetEventHandler, 0);
    
    I2CSMB0_TargetStart();

    while (1)
    {
        /* Do nothing */
    }

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

    return ( EXIT_FAILURE );
}

Library Interface

I2C Mode

Table 1-1. Functions
Name Description Master mode Slave mode
I2CSMBx_Initialize Initializes given instance of I2C SMBUS peripheral. Yes Yes
I2CSMBx_Read Reads data from the slave. Yes No
I2CSMBx_Write Writes data to the slave. Yes No
I2CSMBx_WriteRead Write and Read data from I2C Slave. Yes No
I2CSMBx_IsBusy Returns the Peripheral busy status. Yes Yes
I2CSMBx_ErrorGet Returns the I2C error that occurred on the bus. Yes Yes
I2CSMBx_TransferSetup Dynamic setup of I2C Peripheral. Yes No
I2CSMBx_CallbackRegister Sets the pointer to the function (and it's context) to be called when the given I2C's transfer events occur. Yes Yes
I2CSMBx_ReadByte Read the received I2C byte No Yes
I2CSMBx_WriteByte Write a data byte to I2C master No Yes
I2CSMBx_TransferDirGet Returns the I2C transfer direction. No Yes
I2CSMBx_LastByteAckStatusGet Returns the ACK status of the last byte written to the I2C master. No Yes
I2CSMBx_StatusFlagsGet Returns the status register No Yes
I2CSMBx_StatusFlagsReset Resets the status register bits No Yes
I2CSMBx_TransferAbort Aborts an ongoing transfer Yes No
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_CALLBACK Typedef Defines the data type and function signature for the I2C peripheral callback function in I2C master mode. Yes No
I2C_SLAVE_TRANSFER_EVENT Enum Defines the enum for the I2C slave transfer event No Yes
I2C_SLAVE_TRANSFER_DIR Enum Defines the enum for I2C data transfer direction 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
I2C_SLAVE_ACK_STATUS Enum Defines the enum for the I2C slave acknowledgement. No Yes
I2C_TRANSFER_SETUP Struct I2C transfer setup data structure Yes No
SMBUS Mode
Table 1-2. Functions
Name Description Host Mode Target Mode
I2CSMBx_Initialize Initializes given instance of I2C SMBUS peripheral. Yes Yes
I2CSMBx_HostReadByte Reads a data byte from slave Yes No
I2CSMBx_HostReadWord Reads a data word from slave Yes No
I2CSMBx_HostWriteByte Writes data to the slave. Yes No
I2CSMBx_HostWriteBlock Writes a block of data to the slave. Yes No
I2CSMBx_HostReadBlock Reads a block of data from the slave Yes No
I2CSMBx_HostWriteWord Writes word data to the slave. Yes No
I2CSMBx_HostWriteReadBlock Writes block followed by a read block from the slave Yes No
I2CSMBx_HostWriteBlock Writes a block of data to the slave. Yes No
I2CSMBx_HostTransferSetup Dynamic setup of I2C Peripheral in SMBUS host mode Yes No
I2CSMBx_HostTransferCountGet Returns the transfer count for the last transfer Yes No
I2CSMBx_HostIsBusy Returns the Peripheral busy status. Yes No
I2CSMBx_HostErrorGet Returns the I2C error that occurred on the bus. Yes No
I2CSMBx_HostCallbackRegister Sets the pointer to the function (and it's context) to be called when the given I2C's transfer events occur. Yes No
I2CSMBx_HostBufferRead Reads data from the internal buffer and into the application buffer Yes No
I2CSMBx_TargetTransferDirGet Returns the I2C transfer direction. No Yes
I2CSMBx_TargetStart Configures the DMA and starts the target in receive mode No Yes
I2CSMBx_TargetIsBusy Returns the Peripheral busy status. No Yes
I2CSMBx_TargetErrorGet Returns the I2C error that occurred on the bus. No Yes
I2CSMBx_TargetCallbackRegister Sets the pointer to the function (and it's context) to be called when the given I2C's transfer events occur. No Yes
I2CSMBx_TargetBufferWrite Copies the data to be transmitted into the PLIBs internal buffer No Yes
I2CSMBx_TargetBufferRead Reads the received data from internal buffer into the application buffer No Yes
Table 1-3. Data types and constants
Name Type Description Host mode Target mode
I2C_SMB_HOST_TRANSFER_SETUP Struct I2C Transfer Setup Data Structure Yes No
I2C_SMB_HOST_TRANSFER_EVENT Enum Defines the enum for the I2C SMBUS host transfer events. Yes No
I2C_SMB_HOST_ERROR Macro

Defines macros associated with I2C error in SMBUS Host mode

Yes No
I2C_SMB_HOST_CALLBACK Typedef Defines the data type and function signature for the I2C SMBUS host mode callback function. Yes No
I2C_SMB_TARGET_TRANSFER_EVENT Enum Defines the enum for the I2C SMBUS target transfer events No Yes
I2C_SMB_TARGET_TRANSFER_DIR Enum Defines the enum for the I2C SMBUS Target mode transfer direction No Yes
I2C_SMB_TARGET_ERROR Macro Defines macros associated with I2C error in SMBUS Target mode No Yes
I2C_SMB_TARGET_CALLBACK Typedef Defines the data type and function signature for the I2C SMBUS Target mode callback function. No Yes