1.35.18 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

Functions

Name Description Master mode Slave mode (interrupt disabled) Slave mode (interrupt enabled)
TWIHSx_Initialize Initializes the instance of the TWIHS peripheral in either master or slave mode Yes Yes Yes
TWIHSx_Read Reads data from the TWIHS slave Yes No No
TWIHSx_Write Writes data to the TWIHS slave Yes No No
TWIHSx_WriteRead Write and Read data from Slave Yes No No
TWIHSx_IsBusy Returns the peripheral busy status Yes No Yes
TWIHSx_ErrorGet Returns the TWIHS error that occurred on the bus Yes No No
TWIHSx_TransferSetup Dynamic setup of TWIHS Peripheral Yes No No
TWIHSx_CallbackRegister Sets the pointer to the function (and it's context) to be called when the given TWIHS's transfer events occur Yes No Yes
TWIHSx_ReadByte Read the received TWIHS byte No Yes Yes
TWIHSx_WriteByte Write a data byte to TWIHS master No Yes Yes
TWIHSx_TransferDirGet Returns the TWIHS transfer direction No Yes Yes
TWIHSx_LastByteAckStatusGet Returns the ACK status of the last byte written to the TWIHS master No Yes Yes
TWIHSx_NACKDataPhase Configures the hardware to send NAK for the next data phase No Yes Yes
TWIHSx_StatusGet Returns the TWIHS hardware status flags No Yes No

Data types and constants

Name Type Description Master mode Slave mode (interrupt disabled) Slave mode (interrupt enabled)
TWIHS_ERROR Enum Defines the possible errors that the TWIHS peripheral can generate in TWIHS master mode Yes No No
TWIHS_TRANSFER_SETUP Struct TWIHS transfer setup data structure Yes No No
TWIHS_CALLBACK Typedef Defines the data type and function signature for the TWIHS peripheral callback function in master mode Yes No No
TWIHS_SLAVE_TRANSFER_DIR Enum Defines the enum for TWIHS data transfer direction No Yes Yes
TWIHS_SLAVE_ACK_STATUS Enum Defines the enum for the TWIHS acknowledgement No Yes Yes
TWIHS_SLAVE_TRANSFER_EVENT Enum Defines the enum for the TWIHS slave transfer event No No Yes
TWIHS_SLAVE_CALLBACK Typedef Defines the data type and function signature for the TWIHS Slave callback function No No Yes
TWIHS_SLAVE_STATUS_FLAG Enum Defines the list of possible TWIHS slave events No Yes No