Monday, June 11, 2018

MCP2221 Tutorial - I2C Interfacing made easy

What is MCP2221?
MCP2221 is a USB to UART & I2C bridge integrated circuit from Microchip Technologies; I would highly recommend reading this tutorial first for further information on it.

How can the MCP2221 be beneficial to me?
Well, if you want to build a computer control and/or data acquisition unit via USB to an I2C slave device without the hustle of using a microcontroller or an Arduino, and less expensive than both of them, the MCP2221 is a good option, it acts as a master I2C device, and it can be programmed easily using its DLL from Microchip on Windows OS, or by configuring it as a USB-I2C dongle on Linux. Another advantage for the MCP2221 that it comes in a PDIP package, which makes it convenient for breadboard prototyping and testing.

What is I2C?
In brief, it is a low speed, master-slave serial communication protocol that uses two lines: data line, named SDA, and clock, named SCL. It is mainly used for sensors interfacing, low speed ADC/DAC or any similar integrated circuits. According to the I2C standard, the maximum speed is 3.2 Mbits/sec between a master and slave but the MCP2221 supports only up to 400 KHz bit rate.
For more C examples for the MCP2221, please visit this GitHub repository. 



Example Code:


#include <stdio.h>
#include "mcp2221_dll_um.h"

//Linking the MCP2221 library, only valid for Visual Studio
#pragma comment(lib, "mcp2221_dll_um_x86.lib")

#define I2cAddr7bit 1
#define I2cAddr8bit 0

//Global variables
void *handle;
wchar_t SerNum = 0x0000075428;
wchar_t LibVer[6];
wchar_t MfrDescriptor[30];
wchar_t ProdDescrip[30];
int ver = 0;
int error = 0;
int flag = 0;
unsigned int PID = 0xDD;
unsigned int VID = 0x4D8;
unsigned int NumOfDev = 0;
unsigned char PowerAttrib;
unsigned char DacVal = 31;
unsigned char SlaveAddress = 0x63;
unsigned char TxBuffer[8];
unsigned char RxBuffer[8];

//Functions prototypes
void ExitFunc();
void Mcp2221_config();

void ExitFunc()
{
    Mcp2221_CloseAll();
 Mcp2221_Reset(handle);
}

void Mcp2221_config()
{
    ver = Mcp2221_GetLibraryVersion(LibVer);  //Get DLL version
    if(ver == 0)
    {
        printf("Library (DLL) version: %ls\n", LibVer);
    }
    else
    {
        error = Mcp2221_GetLastError();
        printf("Version can't be found, version: %d, error: %d\n", ver, error);
    }

    //Get number of connected devices with this VID & PID
    Mcp2221_GetConnectedDevices(VID, PID, &NumOfDev);
    if(NumOfDev == 0)
    {
        printf("No MCP2221 devices connected\n");
        //exit(0);
    }
    else
    {
        printf("Number of devices found: %d\n", NumOfDev);
    }

    //open device by S/N
    //handle = Mcp2221_OpenBySN(VID, PID, &SerNum);

    //Open device by index
    handle = Mcp2221_OpenByIndex(VID, PID, NumOfDev-1);
    if(error == NULL)
    {
        printf("Connection successful\n");       
    }
    else
    {
        error = Mcp2221_GetLastError();
        printf("Error message is %s\n", error);
    }

    //Get manufacturer descriptor
    flag = Mcp2221_GetManufacturerDescriptor(handle, MfrDescriptor);
    if(flag == 0)
    {
        printf("Manufacturer descriptor: %ls\n", MfrDescriptor);

    }
    else
    {
        printf("Error getting descriptor: %d\n", flag);
    }

    //Get product descriptor
    flag = Mcp2221_GetProductDescriptor(handle, ProdDescrip);
    if(flag == 0)
    {
        printf("Product descriptor: %ls\n", ProdDescrip);        
    }
    else
    {
        printf("Error getting product descriptor: %d\n", flag);        
    }

    //Get power attributes
    flag = Mcp2221_GetUsbPowerAttributes(handle, &PowerAttrib, &ReqCurrent);
    if(flag == 0)
    {
        printf("Power Attributes, %x\nRequested current units = %d\nRequested current(mA) = %d\n", PowerAttrib, ReqCurrent, ReqCurrent*2);
    }
    else
    {
        printf("Error getting power attributes: %d\n", flag);      
    }

    //Set I2C bus
    flag = Mcp2221_SetSpeed(handle, 500000);    //set I2C speed to 400 KHz
    if(flag == 0)
    {
        printf("I2C is configured\n");        
    }
    else
    {
        printf("Error setting I2C bus: %d\n", flag);        
    }

    //Set I2C advanced parameters
    flag = Mcp2221_SetAdvancedCommParams(handle, 10, 1000);  //10ms timeout, try 1000 times
    if(flag == 0)
    {
        printf("I2C advanced settings set\n");
    }
    else
    {
        printf("Error setting I2C advanced settings: %d\n", flag);      
    }
}

void main(int argc, char *argv[])
{
    atexit(ExitFunc); //Call exit function

    //Configure any connected MCP2221
    Mcp2221_config();
 
    while(1)
    {
  
  //Write all contents of TxBuffer to I2C slave device 0x63
  flag = Mcp2221_I2cWrite(handle, sizeof(TxBuffer), SlaveAddress, I2cAddr7bit, TxBuffer);    //issue start condition then address
  if(flag == 0)
  {
   printf("Writing to device %x successful\n", SlaveAddress);
  }
  else
  {
   printf("Error writing to I2C device: %x, Error: %d\n", SlaveAddress1, flag);
   Mcp2221_I2cCancelCurrentTransfer(handle);
  }
  
  //Read 8 bytes from I2C slave device 0x63
  flag = Mcp2221_I2cRead(handle, 8, SlaveAddress, I2cAddr7bit, RxBuffer);
  if(flag == 0)
  {
   printf("Data received is %x\n", RxBuffer);
  }
  else 
  {
   printf("Error receiving ack: %d\n", flag);
  } 
    }
}