I2C Drivers

The Embedded SDK includes an I2C driver for the microcontrollers that contain an I2C peripheral. The I2C drivers are provided with a common public API so they can be used across any of the supported platforms (microcontrollers). The I2C drivers do not preallocate any memory or other resources; therefore unused ports will not use any resources unless explicitly opened by the application.

Opening A Port

The code snippet below demonstrates how to initialize the driver and open an I2C port.

#include "mcu_i2c.h"
#include <assert.h>

static I2C i2c;                     /* Allocate an instance of the driver */

void APP_Function(void)
{
    STATUS status;


    status = I2C_Open(&i2c,         /* Open an I2C port */		 
                      0,            /* Port number (0 in this case) */
                      400000);      /* Clock frequency, in hertz */

    assert(status == SUCCESS);
}

Claiming The Bus

Each port contains an underlying mutex that can be used to synchronize access to the respective bus. Both the I2C_Write() and I2C_Read() requests automatically claim exclusive access to bus when they perform their transfer, but if it is needed to claim access across multiple requests, you can explicitly claim exclusive access to the bus using I2C_Claim() and I2C_Release().

The code snippet below shows how to acquire and later release exclusive access to the I2C bus.

#include "mcu_i2c.h"
#include <assert.h>

void APP_Function(void)
{
    STATUS status;


    status = I2C_Claim(&i2c,        /* Claim exclusive access to the bus */
                       INFINITE);   /* Max time to wait to acquire exclusive access to the bus */

    assert(status == SUCCESS);


    /* This thread has exclusive 
    access to the bus here */


    status = I2C_Release(&i2c);     /* Release the claim on the bus */	
    assert(status == SUCCESS);
}

Transferring Data

The provided drivers either use interrupts or DMA to actually perform the transfer. When a calling thread requests a transfer, the transfer is staged and the calling thread is blocked while the hardware completes the transfer. Once the transfer has completed, an interrupt will signal the calling thread and execution will resume.

A timeout interval can be specified to avoid a dead-lock condition if the hardware were to fail and never generate an interrupt, but care must be taken so that timeout conditions do not occur during normal operation. Ensure the specified timeout value is large enough to accommodate the transfer rate and the amount of data being transferred.

The code snippet below shows how to send and receive several data bytes using an open port.

#include "mcu_i2c.h"
#include <assert.h>

void APP_Function(void)
{
    STATUS status;
    BYTE data[3];
    BYTE buf[3];


    data[0] = 0;                    /* Initialize some arbitrary data */
    data[1] = 1;
    data[2] = 2;	

    status = I2C_Write(&i2c,        /* Perform a master write transfer */
                       0xA8,        /* The target device address */
                       data,        /* Pointer to the data to be written */
                       3,           /* Number of bytes to transferred */
                       1000);       /* Max time, in kernel ticks, to wait for completion */

    assert(status == SUCCESS);


    status = I2C_Read(&i2c,         /* Perform a master read transfer */
                      0xA8,         /* The target device address */
                      buf,          /* Pointer to the buffer to receive the data */
                      3,            /* Number of bytes to transferred */
                      1000);        /* Max time, in kernel ticks, to wait for completion */

    assert(status == SUCCESS);
}

I2C API

STATUS I2C_Open(I2C* port, BYTE number, UINT32 clk)
Opens an I2C port for communications.
PARAMETERS
port A pointer to a caller allocated I2C port to be opened.
number The port number for the port to be opened.
clk The clock frequency, in hertz, for the port.
RETURNS
SUCCESS The port has been opened.
ERR_NULLREFERENCE The argument 'port' was found to be NULL.
ERR_INVALIDCONTEXT The operation is not supported from the context of an interrupt service routine (ISR).
ERR_NOTSUPPORTED An unsupported port number was specified.
STATUS I2C_Close(I2C* port)
Closes an I2C port.
PARAMETERS
port A pointer to the port to be closed.
RETURNS
SUCCESS The port has been closed.
ERR_NULLREFERENCE The argument 'port' was found to be NULL.
ERR_INVALIDCONTEXT The operation is not supported from the context of an interrupt service routine (ISR).
ERR_NOTINITIALIZED The specified port has not been opened.
BOOLEAN I2C_IsOpen(I2C* port)
Returns an indication of whether an I2C port is currently open for communications.
PARAMETERS
port A pointer to the target I2C port.
RETURNS
TRUE if the I2C port is currently open; otherwise FALSE.
STATUS I2C_Read(I2C* port, BYTE address, void* buf, UINT32 nbytes, UINT32 timeout)
Reads and returns data received from an I2C port.
PARAMETERS
port A pointer to the port to receive the data.
address The target device address to be read.
buf A pointer to a caller allocated buffer used to receive the data.
nbytes The total number of bytes to be received.
timeout The maximum amount of time, in kernel ticks, to block and wait for the transfer to complete. Must not be zero and must be large enough to allow the transfer to complete; based upon clock rate and amount of data being transferred. Use INFINITE to wait indefinitely.
RETURNS
SUCCESS The data was been received.
ERR_NULLREFERENCE The argument 'port' or 'buf' was found to be NULL.
ERR_INVALIDCONTEXT The operation is not supported from the context of an interrupt service routine (ISR).
ERR_NOTINITIALIZED The specified port has not been opened.
ERR_DEVICENAK The target device returned a NAK.
ERR_INCOMPLETE An error occurred while transferring the data and the transfer did not complete.
ERR_TIMEOUT The specified timeout interval has elapsed prior to the transfer being completed.
STATUS I2C_Write(I2C* port, BYTE address, const void* data, UINT32 nbytes, UINT32 timeout)
Writes data to an I2C port.
PARAMETERS
port A pointer to the port to be written.
address The target device address to be written.
data A pointer to the data to be written.
nbytes The total number of bytes to be written.
timeout The maximum amount of time, in kernel ticks, to block and wait for the transfer to complete. Must not be zero and must be large enough to allow the transfer to complete; based upon clock rate and amount of data being transferred. Use INFINITE to wait indefinitely.
RETURNS
SUCCESS The data has been written.
ERR_NULLREFERENCE The argument 'port' or 'data' was found to be NULL.
ERR_INVALIDCONTEXT The operation is not supported from the context of an interrupt service routine (ISR).
ERR_NOTINITIALIZED The specified port has not been opened.
ERR_DEVICENAK The target device returned a NAK.
ERR_INCOMPLETE An error occurred while transferring the data and the transfer did not complete.
ERR_TIMEOUT The specified timeout interval has elapsed prior to the transfer being completed.
STATUS I2C_Claim(I2C* port, UINT32 timeout)
Claims exclusive access to an I2C port.
PARAMETERS
port A pointer to the port to be claimed.
timeout The maximum amount of time, in kernel ticks, to to block and wait to acquire a exclusive claim on the port. Use 0 to return immediately without waiting. Use INFINITE to wait indefinitely.
RETURNS
SUCCESS The port has been claimed.
ERR_NULLREFERENCE The argument 'port' was found to be NULL.
ERR_INVALIDCONTEXT The operation is not supported from the context of an interrupt service routine (ISR).
ERR_NOTINITIALIZED The specified port has not been opened.
ERR_TIMEOUT The specified amount of time has elapsed prior to acquiring the claim on the port.
STATUS I2C_Release(I2C* port)
Releases a previous claim on an I2C port.
PARAMETERS
port A pointer to the port to be released.
RETURNS
SUCCESS The claim on the port has been released.
ERR_NULLREFERENCE The argument 'port' was found to be NULL.
ERR_INVALIDCONTEXT The operation is not supported from the context of an interrupt service routine (ISR).
ERR_NOTINITIALIZED The specified port has not been opened.
ERR_NOTOWNER The caller is not the thread that claimed the port. Only the owner is allowed to release the port.