Sunday, June 12, 2016

MCP2221 Tutorial - USB interfacing made easy

What is MCP2221?
MCP2221 is a USB to UART and I2C bridge IC from Microchip technologies, plus the bridge capability this chip has the following features:
4 GPIO pins, three of them can be configured to become a 10-bits Analog to Digital Converter (ADC) of a 1 KSps sampling rate, also two of these GPIO pins are multiplexed with a 5-bits Digital to Analog Converter (DAC).

Why MCP2221?
This MCP2221 is a simple and inexpensive computer/USB interface solution for computer control applications, with a very few component peripherals you can get it up and running, just a capacitor and pull-up resistor on the reset pin. It can be either bus-powered or self-powered, and it is available in PDIP package which makes it easy to prototype on a breadboard or prototyping PCB.

Development and application tools for the MCP2221:
The chip web page indicates that drivers for Windows OS, Linux, and Mac OS are available, plus a DLL library for C/C++ and .Net under Windows OS environment, other tools include Command Line Interface (CLI) and GUI-based Windows applications to control the MCP2221 I/O’s without the need to develop your own application, for more information check the IC datasheet on Microchip Technologies website here.

MCP2221 Driver:
The MCP2221 is a composite device, i.e. the device supports both HID and CDC classes, the CDC class supports the USB to UART bridge functionality and the HID class the support the USB to I2C bridge, GPIO, ADC and DAC features.  

Circuitry and connection:
VDD and VSS pins (1 and 14) are the IC power supply and ground pins respectively, pull-up (connect to VDD) the reset pin (pin 4) with a resistor (anything between 330 Ohm and 4.7 Kilo Ohms), and a 470 nF ceramic capacitor between VUSB pin (pin 11) and ground.

MCP2221 Circuit


Example applications:
DC and stepper motors control, simple monitoring applications, data input devices, interface to microcontrollers and other embedded processors, LED control.

Example code:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include <stdio.h>
#include <conio.h>
#include <Windows.h>
#include "mcp2221_dll_um.h"

#pragma comment(lib, "mcp2221_dll_um_x86.lib")  //Link MCP2221 library, applicable for visual studio only

//Global variables
void *handle;

void ExitFunc()
{
 printf("Closing\n");
 _sleep(10);
 //Mcp2221_Reset(handle);
 
 //Close all devices at exit
 Mcp2221_CloseAll();
}
int main()
{
 wchar_t LibVer[6];
 wchar_t MfrDescriptor[30];
 wchar_t ProdDescrip[30];
 int ver = 0; 
 int error = 0;
 int flag = 0;
 unsigned char pinFunc[4] = {MCP2221_GPFUNC_IO, MCP2221_GPFUNC_IO, MCP2221_GP_DAC, MCP2221_GPFUNC_IO};  //Set GP0, GP1, GP3 as digital IO and GP2 as DAC
 unsigned char pinDir[4] = {MCP2221_GPDIR_OUTPUT, MCP2221_GPDIR_OUTPUT, NO_CHANGE, MCP2221_GPDIR_OUTPUT};  //configure GP0, GP1, GP3 as digital output
 unsigned char OutValues[4] = {0, 0, NO_CHANGE, 0};   //set initial values to 0's
 unsigned char PowerAttrib;
 unsigned char DacVal = 31;
 unsigned char DacRefValue = 0;
 unsigned int ReqCurrent;
 unsigned int PID = 0xDD;
 unsigned int VID = 0x4D8;
 unsigned int NumOfDev = 0;

 atexit(ExitFunc); //Call exit function

 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 first MCP2221 device discovered by index
 handle = Mcp2221_OpenByIndex(VID, PID, NumOfDev-1); 
 error = Mcp2221_GetLastError();
 if(error == NULL)
  printf("Connection successful\n");
 else
  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 GPIO
 flag = Mcp2221_SetGpioSettings(handle, RUNTIME_SETTINGS, pinFunc, pinDir, OutValues);
 if(flag != 0)
 {
  printf("Error setting GPIO, error: %d\n", flag);
  system("pause");
 }
 Mcp2221_SetGpioValues(handle, OutValues); //reset all pins at initialization

 //Set DAC reference to VDD
 flag = Mcp2221_SetDacVref(handle, RUNTIME_SETTINGS, VREF_VDD);
 
 if(flag != 0)
 {
  printf("Error setting DAC reference, error: %d\n", flag);
  system("pause");
 }

 while(1)
 {
  //Set DAC value on GP2
  DacVal++;
  if(DacVal == 32)
   DacVal = 0;
  printf("DAC value is: %x\n", DacVal);
  flag = Mcp2221_SetDacValue(handle, RUNTIME_SETTINGS, DacVal);  //must use "RUNTIME_SETTINGS" to enable and output voltage to the DAC
  if(flag != 0)
  {
   printf("Error setting DAC, error: %d\n", flag);
   system("pause");
  }

  //Toggle GPIO pins: GP0, GP1, GP3 for 50mS
  OutValues[0] = MCP2221_GPVAL_HIGH;  //set GP0 (output high)
  OutValues[1] = MCP2221_GPVAL_LOW;   //reset GP1 (output low)
  OutValues[3] = MCP2221_GPVAL_LOW;   //reset GP3 (output low)
  Mcp2221_SetGpioValues(handle, OutValues);  //now set the DIO pins values
  _sleep(50);    //wait for 50mS
  OutValues[0] = MCP2221_GPVAL_LOW;    //reset GP0 (output low)
  OutValues[1] = MCP2221_GPVAL_HIGH;   //set GP1 (output high)
  OutValues[3] = MCP2221_GPVAL_HIGH;   //set GP3 (output high)
  Mcp2221_SetGpioValues(handle, OutValues);   //now set the DIO pins values
  _sleep(50);    //wait for 50mS
 }
 return 0;
}