Full API reference
Device Initialization
- class Device(VID=1240, PID=221, devnum=0)
MCP2221(A) device
- Parameters
VID (int, optional) – Vendor Id (default to
0x04D8
)PID (int, optional) – Product Id (default to
0x00DD
)devnum (int, optional) – Device index if multiple device found with the same PID and VID.
- Raises
RuntimeError – if no device found with given VID and PID.
Example
>>> import EasyMCP2221 >>> mcp = EasyMCP2221.Device() >>> print(mcp) { "Chip settings": { "Power management options": "enabled", "USB PID": "0x00DD", "USB VID": "0x04D8", "USB requested number of mA": 100 }, "Factory Serial": "01234567", "GP settings": {}, "USB Manufacturer": "Microchip Technology Inc.", "USB Product": "MCP2221 USB-I2C/UART Combo", "USB Serial": "0000000000" }
Pin configuration
- set_pin_function(gp0=None, gp1=None, gp2=None, gp3=None, out0=False, out1=False, out2=False, out3=False)
Configure pin function and, optionally, output value.
You can set multiple pins at once.
Accepted functions depends on the pin.
- GP0 functions:
GPIO_IN (in) : Digital input
GPIO_OUT (out): Digital output
SSPND (out): Signals when the host has entered Suspend mode
LED_URX (out): UART Rx LED activity output (factory default)
- GP1 functions:
GPIO_IN (in) : Digital input
GPIO_OUT (out): Digital output
ADC (in) : ADC Channel 1
CLK_OUT (out): Clock Reference Output
IOC (in) : External Interrupt Edge Detector
LED_UTX (out): UART Tx LED activity output (factory default)
- GP2 functions:
GPIO_IN (in) : Digital input
GPIO_OUT (out): Digital output
ADC (in) : ADC Channel 2
DAC (out): DAC Output 1
USBCFG (out): USB device-configured status (factory default)
- GP3 functions:
GPIO_IN (in) : Digital input
GPIO_OUT (out): Digital output
ADC (in) : ADC Channel 3
DAC (out): DAC Output 2
LED_I2C (out): USB/I2C traffic indicator (factory default)
- Parameters
gp0 (str, optional) – Function for pin GP0. If None, don’t alter function.
gp1 (str, optional) – Function for pin GP1. If None, don’t alter function.
gp2 (str, optional) – Function for pin GP2. If None, don’t alter function.
gp3 (str, optional) – Function for pin GP3. If None, don’t alter function.
out0 (bool, optional) – Logic output for GP0 if configured as GPIO_OUT (default: False).
out1 (bool, optional) – Logic output for GP1 if configured as GPIO_OUT (default: False).
out2 (bool, optional) – Logic output for GP2 if configured as GPIO_OUT (default: False).
out3 (bool, optional) – Logic output for GP3 if configured as GPIO_OUT (default: False).
- Raises
ValueError – If invalid function for that pin is specified.
ValueError – If given out value for non GPIO_OUT pin.
Examples
Set all pins at once:
>>> mcp.set_pin_function( ... gp0 = "GPIO_IN", ... gp1 = "GPIO_OUT", ... gp2 = "ADC", ... gp3 = "LED_I2C") >>>
Change pin function at runtime:
>>> mcp.set_pin_function(gp1 = "GPIO_IN") >>>
It is not permitted to set the output of a non GPIO_OUT pin.
>>> mcp.set_pin_function( ... gp1 = "GPIO_OUT", out1 = True, ... gp2 = "ADC", out2 = True) Traceback (most recent call last): ... ValueError: Pin output value can only be set if pin function is GPIO_OUT. >>>
Only some functions are allowed for each pin.
>>> mcp.set_pin_function(gp0 = "ADC") Traceback (most recent call last): ... ValueError: Invalid function for GP0. Could be: GPIO_IN, GPIO_OUT, SSPND, LED_URX >>>
Hint
Pin assignments are active until reset or power cycle. Use
save_config()
to make this configuration the default at next start.
- save_config()
Write current status (pin assignments, GPIO output values, DAC reference and value, ADC reference, etc.) to flash memory.
You can save a new configuration as many times as you wish. That will be the default state at power up.
- Raises
RuntimeError – if command failed.
AssertionError – if an accidental flash protection attempt was prevented.
Example
Set all GPIO pins as digital inputs (high impedance state) at start-up to prevent short circuits while breadboarding.
>>> mcp.set_pin_function( ... gp0 = "GPIO_IN", ... gp1 = "GPIO_IN", ... gp2 = "GPIO_IN", ... gp3 = "GPIO_IN") >>> mcp.DAC_config(ref = "OFF") >>> mcp.ADC_config(ref = "VDD") >>> mcp.save_config()
GPIO
- GPIO_read()
Read all GPIO pins logic state.
Returned values can be True, False or None if the pin is not set for GPIO operation. For an output pin, the returned status is the actual value.
- Returns
4 logic values for the pins status gp0, gp1, gp2 and gp3.
- Return type
tuple of bool
Example
>>> mcp.GPIO_read() (None, 0, 1, None)
- GPIO_write(gp0=None, gp1=None, gp2=None, gp3=None)
Set pin output values.
If a pin is omitted, it will preserve the value.
To change the output state of a pin, it must be assigned to GPIO_IN or GPIO_OUT (see
set_pin_function()
).- Parameters
gp0 (bool, optional) – Set GP0 logic value.
gp1 (bool, optional) – Set GP1 logic value.
gp2 (bool, optional) – Set GP2 logic value.
gp3 (bool, optional) – Set GP3 logic value.
- Raises
RuntimeError – If given pin is not assigned to GPIO function.
Examples
Configure GP1 as output (defaults to False) and then set the value to logical True.
>>> mcp.set_pin_function(gp1 = "GPIO_OUT") >>> mcp.GPIO_write(gp1 = True)
If will fail if the pin is not assigned to GPIO:
>>> mcp.set_pin_function(gp2 = 'DAC') >>> mcp.GPIO_write(gp2 = False) Traceback (most recent call last): ... RuntimeError: Pin GP2 is not assigned to GPIO function.
ADC
- ADC_read()
Read all Analog to Digital Converter (ADC) channels.
Analog value is always available regardless of pin function (see
set_pin_function()
). If pin is configured as output (GPIO_OUT or LED_I2C), the read value is always the output state.ADC is 10 bits, so the minimum value is 0 and the maximum value is 1023.
- Returns
Value of 3 channels (gp1, gp2, gp3).
- Return type
tuple of int
Examples
All three pins configured as ADC inputs.
>>> mcp.ADC_config(ref = "VDD") >>> mcp.set_pin_function( ... gp1 = "ADC", ... gp2 = "ADC", ... gp3 = "ADC") >>> mcp.ADC_read() (185, 136, 198)
Reading the ADC value of a digital output gives the actual voltage in the pin. For a logic output
1
is equal toVdd
unless something is pulling that pin low (i.e. a LED).>>> mcp.set_pin_function( ... gp1 = "GPIO_OUT", out1 = True, ... gp2 = "GPIO_OUT", out2 = False) >>> mcp.ADC_read() (1023, 0, 198)
- ADC_config(ref='VDD')
Configure ADC reference voltage.
ref
values:“OFF”
“1.024V”
“2.048V”
“4.096V”
“VDD”
- Parameters
ref (str, optional) – ADC reference value. Default to supply voltage (Vdd).
- Raises
ValueError – if
ref
value is not valid.
Examples
>>> mcp.ADC_config()
>>> mcp.ADC_config("1.024V")
>>> mcp.ADC_config(ref = "5V") Traceback (most recent call last): ... ValueError: Accepted values for ref are 'OFF', '1.024V', '2.048V', '4.096V' and 'VDD'.
Hint
ADC configuration is saved when you call
save_config()
and reloaded at power-up. You only need to call this function if you want to change it.
DAC
- DAC_write(out)
Set the DAC output value.
Valid
out
values are 0 to 31.To use a GP pin as DAC, you must assign the function “DAC” (see
set_pin_function()
). MCP2221 only have 1 DAC. So if you assign to “DAC” GP2 and GP3 you will see the same output value in both.- Parameters
out (int) – Value to output (max. 32) referenced to DAC ref voltage.
Examples
>>> mcp.set_pin_function(gp2 = "DAC") >>> mcp.DAC_config(ref = "VDD") >>> mcp.DAC_write(31) >>>
>>> mcp.DAC_write(32) Traceback (most recent call last): ... ValueError: Accepted values for out are from 0 to 31.
- DAC_config(ref='VDD', out=None)
Configure Digital to Analog Converter (DAC) reference.
ref
values:“OFF”
“1.024V”
“2.048V”
“4.096V”
“VDD”
MCP2221’s DAC is 5 bits. So valid values for
out
are from 0 to 31.out
parameter is optional and defaults last value. UseDAC_write()
to set the DAC output value.- Parameters
ref (str, optional) – Reference voltage for DAC. Default to supply voltage (Vdd).
out (int, optional) – value to output. Default is last value.
- Raises
ValueError – if
ref
orout
values are not valid.
Examples
>>> mcp.set_pin_function(gp2 = "DAC") >>> mcp.DAC_config(ref = "4.096V")
>>> mcp.DAC_config(ref = 0) Traceback (most recent call last): ... ValueError: Accepted values for ref are 'OFF', '1.024V', '2.048V', '4.096V' and 'VDD'.
Hint
DAC configuration is saved when you call
save_config()
and reloaded at power-up. You only need to call this function if you want to change it.
I2C
- I2C_Slave(addr, force=False, speed=100000)
Create a new I2C_Slave object.
See
EasyMCP2221.I2C_Slave.I2C_Slave
for detailed information.- Parameters
addr (int) – Slave’s I2C bus address
- Returns
I2C_Slave object.
Example
>>> pcf = mcp.I2C_Slave(0x48) >>> eeprom = mcp.I2C_Slave(0x50) >>> eeprom EasyMCP2221's I2C slave device at bus address 0x50.
- I2C_write(addr, data, kind='regular', timeout_ms=20)
Write data to an address on I2C bus.
Valid values for
kind
are:- regular
It will send start, data, stop (this is the default)
- restart
It will send repeated start, data, stop
- nonstop
It will send start, data to write, (no stop). Please note that you must use ‘restart’ mode to read or write after a nonstop write.
- Parameters
addr (int) – I2C slave device base address.
data (bytes) – bytes to write. Maximum length is 65535 bytes, minimum is 1.
kind (str, optional) – kind of transfer (see description).
timeout_ms (int, optional) – maximum time to write data chunk in milliseconds (default 20 ms). Note this time applies for each 60 bytes chunk. The whole write operation may take much longer.
- Raises
ValueError – if any parameter is not valid.
NotAckError – if the I2C slave didn’t acknowledge.
TimeoutError – if the writing timeout is exceeded.
LowSDAError – See
I2C_cancel()
.LowSCLError – See
I2C_cancel()
.RuntimeError – if some other error occurs.
Examples
>>> mcp.I2C_write(0x50, b'This is data') >>>
Writing data to a non-existent device:
>>> mcp.I2C_write(0x60, b'This is data')) Traceback (most recent call last): ... EasyMCP2221.exceptions.NotAckError: Device did not ACK.
Note
MCP2221 writes data in 60-byte chunks.
The default timeout of 20 ms is twice the time required to send 60 bytes at the minimum supported rate (47 kHz).
MCP2221’s internal I2C engine has additional timeout controls.
- I2C_read(addr, size=1, kind='regular', timeout_ms=20)
Read data from I2C bus.
Valid values for
kind
are:- regular
It will send start, data, stop (this is the default)
- restart
It will send repeated start, data, stop
- Parameters
addr (int) – I2C slave device base address.
size (int, optional) – how many bytes to read. Maximum is 65535 bytes. Minimum is 1 byte.
kind (str, optional) – kind of transfer (see description).
timeout_ms (int, optional) – time to wait for the data in milliseconds (default 20 ms). Note this time applies for each 60 bytes chunk. The whole read operation may take much longer.
- Returns
data read
- Return type
bytes
- Raises
ValueError – if any parameter is not valid.
NotAckError – if the I2C slave didn’t acknowledge.
TimeoutError – if the writing timeout is exceeded.
LowSDAError – See
I2C_cancel()
.LowSCLError – See
I2C_cancel()
.RuntimeError – if some other error occurs.
Examples
>>> mcp.I2C_read(0x50, 12) b'This is data'
Write then Read without releasing the bus:
>>> mcp.I2C_write(0x50, position, 'nonstop') >>> mcp.I2C_read(0x50, length, 'restart') b'En un lugar de la Mancha...'
Hint
You can use
I2C_read()
with size 1 to check if there is any device listening with that address.There is a device in
0x50
(EEPROM):>>> mcp.I2C_read(0x50) b'1'
No device in
0x60
:>>> mcp.I2C_read(0x60) Traceback (most recent call last): ... EasyMCP2221.exceptions.NotAckError: Device did not ACK.
Note
MCP2221 reads data in 60-byte chunks.
The default timeout of 20 ms is twice the time required to receive 60 bytes at the minimum supported rate (47 kHz). If a timeout or other error occurs in the middle of character reading, the I2C may get locked. See
I2C_cancel()
.
- I2C_speed(speed=100000)
Set I2C bus speed.
Acceptable values for speed are between 50kHz and 400kHz.
- Parameters
speed (int) – Bus clock frequency in Hz. Default bus speed is 100kHz.
- Raises
ValueError – if speed parameter is out of range.
RuntimeError – if command failed (I2C engine is busy).”
Example
>>> mcp.I2C_speed(100000) >>>
- I2C_cancel()
Try to cancel an active I2C read or write command.
- Returns
True if device is now ready to go. False if the engine is not idle.
- Return type
bool
- Raises
LowSDAError – if I2C engine detects the SCL line does not go up (read exception description).
LowSCLError – if I2C engine detects the SDA line does not go up (read exception description).
Examples
Last transfer was cancel, and engine is ready for the next operation:
>>> mcp.I2C_cancel() True
Last transfer failed, and cancel failed too because I2C bus seems busy:
>>> mcp.I2C_cancel() Traceback (most recent call last): ... EasyMCP2221.exceptions.LowSCLError: SCL is low. I2C bus is busy or missing pull-up resistor.
Note
Do not call this function without issuing a
I2C_read()
orI2C_write()
first. It could render I2C engine inoperative until the next reset.>>> mcp.reset() >>> mcp.I2C_is_idle() True >>> mcp.I2C_cancel() False
Now the bus is busy until the next reset.
>>> mcp.I2C_speed(100000) Traceback (most recent call last): ... RuntimeError: I2C speed is not valid or bus is busy. >>> mcp.I2C_cancel() False >>> mcp.I2C_is_idle() False >>> mcp.I2C_cancel() False
After a reset, it will work again.
>>> mcp.reset() >>> mcp.I2C_is_idle() True
- I2C_is_idle()
Check if the I2C engine is idle.
- Returns
True if idle, False if engine is in the middle of a transfer (timeout detected).
- Return type
bool
Example
>>> mcp.I2C_is_idle() True >>>
Clock output
- clock_config(duty, freq)
Configure clock output frequency and Duty Cycle.
duty
values:0
25
50
75
freq
values:“375kHz”
“750kHz”
“1.5MHz”
“3MHz”
“6MHz”
“12MHz”
“24MHz”
To output clock signal, you also need to assign GP1 function to CLK_OUT (see
set_pin_function()
).- Parameters
duty (int) – Output duty cycle in percent.
freq (str) – Output frequency.
- Raises
ValueError – if any of the parameters is not valid.
Examples
>>> mcp.set_pin_function(gp1 = "CLK_OUT") >>> mcp.clock_config(50, "375kHz") >>>
>>> mcp.clock_config(100, "375kHz") Traceback (most recent call last): ... ValueError: Accepted values for duty are 0, 25, 50, 75.
>>> mcp.clock_config(25, "175kHz") Traceback (most recent call last): ... ValueError: Freq is one of 375kHz, 750kHz, 1.5MHz, 3MHz, 6MHz, 12MHz or 24MHz
USB wake-up
- enable_power_management(enable=False)
Enable or disable USB Power Management options for this device.
Set or clear Remote Wake-up Capability bit in flash configuration.
If enabled, Power Management Tab is available for this device in the Device Manager (Windows). So you can mark “Allow this device to wake the computer” option.
A device
reset()
(or power supply cycle) is needed in order for changes to take effect.- Parameters
enable (bool) – Enable or disable Power Management.
- Raises
RuntimeError – If write to flash command failed.
AssertionError – In rare cases, when some bug might have inadvertently activated Flash protection or permanent chip lock.
Example
>>> mcp.enable_power_management(True) >>> print(mcp) ... "Chip settings": { "Power management options": "enabled", ... >>> mcp.reset() >>>
- wake_up_config(edge='none')
Configure interruption edge.
- Valid values for
edge
: none: disable interrupt detection
raising: fire interruption in raising edge (i.e. when GP1 goes from Low to High).
falling: fire interruption in falling edge (i.e. when GP1 goes from High to Low).
both: fire interruption in both (i.e. when GP1 state changes).
In order to trigger, GP1 must be assigned to IOC function (see
set_pin_function()
).To wake-up the computer, Power Management options must be enabled (see
enable_power_management()
). And “Allow this device to wake the computer” option must be set in Device Manager.- Parameters
edge (str) – which edge triggers the interruption (see description).
- Raises
ValueError – if edge detection given.
Example
>>> mcp.wake_up_config("both") >>>
- Valid values for
Device reset
- reset()
Reset MCP2221.
Reboot the device and load stored configuration from flash.
This operation do not reset any I2C slave devices.
Low level and debug
- SRAM_config(clk_output=None, dac_ref=None, dac_value=None, adc_ref=None, int_conf=None, gp0=None, gp1=None, gp2=None, gp3=None)
Low level SRAM configuration.
Configure Runtime GPIO pins and parameters. All arguments are optional. Apply given settings, preserve the rest.
- Parameters
clk_output (int, optional) – settings
dac_ref (int, optional) – settings
dac_value (int, optional) – settings
adc_ref (int, optional) – settings
int_conf (int, optional) – settings
gp0 (int, optional) – settings
gp1 (int, optional) – settings
gp2 (int, optional) – settings
gp3 (int, optional) – settings
- Raises
RuntimeError – if command failed.
Examples
>>> from EasyMCP2221.Constants import * >>> mcp.SRAM_config(gp1 = GPIO_FUNC_GPIO | GPIO_DIR_IN)
>>> mcp.SRAM_config(dac_ref = ADC_REF_VRM | ADC_VRM_2048)
Note
Calling this function to change GPIO when DAC is active and DAC reference is not Vdd will create a 2ms gap in DAC output.
- send_cmd(buf)
Write a raw USB command to device and get the response.
Write 64 bytes to the HID interface, starting by
buf
bytes. Then read 64 bytes from HID and return them as a list. In case of failure (USB read/write or command error) it will retry. To prevent this, setcmd_retries
to zero.- Parameters
buf (list of bytes) – Full data to write, including command (64 bytes max).
- Returns
Full response data (64 bytes).
- Return type
list of bytes
Example
>>> from EasyMCP2221.Constants import * >>> r = mcp.send_cmd([CMD_GET_GPIO_VALUES]) [81, 0, 238, 239, 238, 239, 238, 239, 238, 239, 0, 0, 0, ... 0, 0]
See also
Class variables
cmd_retries
,debug_messages
andtrace_packets
.Hint
The response does not wait until the actual command execution is finished. Instead, it is generated right after the device receives the command. So an error response might indicate:
the most recent command is not valid
the previous command finished with an error condition (case of I2C write).
- Device.cmd_retries = 1
Times to retry a command if it fails.
- Type
int
- Device.debug_messages = False
Print debugging messages.
- Type
bool
- Device.trace_packets = False
Print all binary commands and responses.
- Type
bool
Exceptions
To capture EasyMCP2221.exceptions you must qualify them as EasyMCP2221.exceptions
:
try:
mcp.I2C_read(0x51, 1)
except EasyMCP2221.exceptions.NotAckError:
print("No device")
exit()
except EasyMCP2221.exceptions.LowSCLError:
print("SCL low")
or import them explicitly:
from EasyMCP2221.exceptions import *
...
try:
mcp.I2C_read(0x51, 1)
except NotAckError:
print("No device")
exit()
except LowSCLError:
print("SCL low")
- exception NotAckError
I2C slave device did not acknowledge last command or data. Possible causes are incorrect I2C address, device missing or busy.
- exception TimeoutError
I2C transaction timed out.
- Possible causes:
I2C bus noise
incorrect command, protocol or speed
slave device busy (e.g. EEPROM write cycle)
- exception LowSCLError
SCL remains low.
SCL should go up when I2C bus is idle.
- Possible causes:
Missing pull-up resistor or too high.
Signal integrity issues due to noise.
A slave device is using clock stretching to indicate it is busy.
Another device is using the bus.
- exception LowSDAError
SDA remains low.
SDA should go up when I2C bus is idle.
- Possible causes:
Missing pull-up resistor or too high.
Signal integrity issues due to noise.
An I2C read transfer timed out while slave was sending data, and now the I2C bus is locked-up. Read the Hint.
Hint
About the I2C bus locking-up.
Sometimes, due to a glitch or premature timeout, the master terminates the transfer. But the slave was in the middle of sending a byte. So it is expecting a few more clocks cycles to send the rest of the byte.
Since the master gave up, it will not clock the bus anymore, and so the slave won’t release SDA line. The master, seeing SDA line busy, refuses to initiate any new I2C transfer. If the slave does not implement any timeout (SMB slaves do have it, but I2C ones don’t), the I2C bus is locked-up forever.
MCP2221’s I2C engine cannot solve this problem. You can either manually clock the bus using any GPIO line, or cycle the power supply.