2.122 Two-wire Interface - TWIHS

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

TWIHS master mode

The TWIHS peripheral library supports the following TWIHS 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.

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.

TWIHS slave mode

TWIHS slave PLIB can be configured with peripheral interrupt enabled or disabled. When peripheral interrupt is enabled, application must register a callback, to get notified of the TWIHS events such as address match, transmitter ready, receiver ready etc. When peripheral interrupt is disabled, PLIB provides APIs to read the interrupt status flags. Application can call this API to determine the TWIHS event and then use the ReadByte/WriteByte APIs to read/write over the TWIHS bus

TWIHS Master mode

// Following code demonstrates TWIHS 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 TWIHS Slave */
    TWIHS1_Write(APP_SLAVE_ADDR, &myWriteData[0], NUM_BYTES);

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

    /* Check if any error occurred */
    if(TWIHS1_ErrorGet() == TWIHS_ERROR_NONE)
    {
        //Transfer is completed successfully
    }
    else
    {
        //Error occurred during transfer.
    }
	...
}
// Following code demonstrates TWIHS 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 TWIHS1_Callback(uintptr_t context)
{
    if(TWIHS1_ErrorGet() == TWIHS_ERROR_NONE)
    {
        //Transfer is completed successfully
    }
    else
    {
        //Error occurred during transfer.
    }
}

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

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

TWIHS Slave mode

This example uses the TWIHS peripheral library in slave mode and emulates an EEPROM of 512 bytes. There are two pages each of size 256 bytes. TWIHS slave expects two bytes of memory address from the TWIHS 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

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
};

void delay(uint32_t count)
{
    uint32_t i;
        
    for (i = 0; i < count; i++)
    {
        asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");
        asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");
        asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");
        asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");        
    }
}

bool APP_TWIHS_Callback ( TWIHS_SLAVE_TRANSFER_EVENT event, uintptr_t contextHandle )
{
    uint8_t rxByte;
    
    switch(event)
    {
        case TWIHS_SLAVE_TRANSFER_EVENT_ADDR_MATCH:
            if (eepromData.internalWriteInProgress == false)
            {                              
                /* Reset the indexes */
                eepromData.addrIndex = 0;
                eepromData.wrBufferIndex = 0;                
            }
            break;

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

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

        case TWIHS_SLAVE_TRANSFER_EVENT_TRANSMISSION_COMPLETE:
            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;
                
                /* Send NACK for next data packets from I2C master */
                TWIHS0_NACKDataPhase(true);
                
                eepromData.eepromCommand = EEPROM_CMD_WRITE;
            }
            break;
        default:
            break;
    }

    return true;
}

void EEPROM_StateMachine(void)
{
    switch(eepromData.eepromCommand)
    {
        case EEPROM_CMD_WRITE:
            memcpy(&EEPROM_EmulationBuffer[eepromData.wrAddr], &eepromData.wrBuffer[0], eepromData.nWrBytes);
            
            /* Simulate busy condition. NACK will be sent while application loops through the delay. */
            delay(10000);
            
            eepromData.internalWriteInProgress = false;
            eepromData.eepromCommand = EEPROM_CMD_IDLE;
            
            /* Internal write is not in progress. ACK the data packets. */
            TWIHS0_NACKDataPhase(false);
            
            break;
        case EEPROM_CMD_IDLE:
            /* Do nothing */
            break;
    }
}

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

    eepromData.eepromCommand = EEPROM_CMD_IDLE;

    TWIHS0_CallbackRegister(APP_TWIHS_Callback, 0);

    while ( true )
    {
        EEPROM_StateMachine();
    }

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

    return ( EXIT_FAILURE );
}

Library Interface

TWIHS peripheral library provides the following interfaces:

Functions

NameDescriptionMaster modeSlave mode (interrupt disabled)Slave mode (interrupt enabled)
TWIHSx_InitializeInitializes the instance of the TWIHS peripheral in either master or slave modeYesYesYes
TWIHSx_ReadReads data from the TWIHS slaveYesNoNo
TWIHSx_WriteWrites data to the TWIHS slaveYesNoNo
TWIHSx_WriteReadWrite and Read data from SlaveYesNoNo
TWIHSx_IsBusyReturns the peripheral busy statusYesNoYes
TWIHSx_ErrorGetReturns the TWIHS error that occurred on the busYesNoNo
TWIHSx_TransferSetupDynamic setup of TWIHS PeripheralYesNoNo
TWIHSx_CallbackRegisterSets the pointer to the function (and it's context) to be called when the given TWIHS's transfer events occurYesNoYes
TWIHSx_ReadByteRead the received TWIHS byteNoYesYes
TWIHSx_WriteByteWrite a data byte to TWIHS masterNoYesYes
TWIHSx_TransferDirGetReturns the TWIHS transfer directionNoYesYes
TWIHSx_LastByteAckStatusGetReturns the ACK status of the last byte written to the TWIHS masterNoYesYes
TWIHSx_NACKDataPhaseConfigures the hardware to send NAK for the next data phaseNoYesYes
TWIHSx_StatusGetReturns the TWIHS hardware status flagsNoYesNo
TWIHSx_BusScanScans and reports the target devices found on the busYesNoNo

Data types and constants

NameTypeDescriptionMaster modeSlave mode (interrupt disabled)Slave mode (interrupt enabled)
TWIHS_ERROREnumDefines the possible errors that the TWIHS peripheral can generate in TWIHS master modeYesNoNo
TWIHS_TRANSFER_SETUPStructTWIHS transfer setup data structureYesNoNo
TWIHS_CALLBACKTypedefDefines the data type and function signature for the TWIHS peripheral callback function in master modeYesNoNo
TWIHS_SLAVE_TRANSFER_DIREnumDefines the enum for TWIHS data transfer directionNoYesYes
TWIHS_SLAVE_ACK_STATUSEnumDefines the enum for the TWIHS acknowledgementNoYesYes
TWIHS_SLAVE_TRANSFER_EVENTEnumDefines the enum for the TWIHS slave transfer eventNoNoYes
TWIHS_SLAVE_CALLBACKTypedefDefines the data type and function signature for the TWIHS Slave callback functionNoNoYes
TWIHS_SLAVE_STATUS_FLAGEnumDefines the list of possible TWIHS slave eventsNoYesNo
Note: Not all APIs maybe implemented. See the specific device family section for available APIs.