Source code for PyExpLabSys.drivers.microchip_tech_mcp3428

""" Driver for Microchip Technology MCP3428 Analog Input device
Calibrated to PR33-13 from ncd.io other products will use different
voltage references."""
# pylint: disable=no-self-use
import time
import io
import fcntl


[docs]class I2C: """File based i2c. Code adapted from: https://www.raspberrypi.org/forums/viewtopic.php?t=134997"""
[docs] def __init__(self, device, bus): self.file_read = io.open("/dev/i2c-" + str(bus), "rb", buffering=0) self.file_write = io.open("/dev/i2c-" + str(bus), "wb", buffering=0) i2c_slave = 0x0703 # set device address fcntl.ioctl(self.file_read, i2c_slave, device) fcntl.ioctl(self.file_write, i2c_slave, device)
[docs] def write(self, values): """ Write a value to i2c port """ self.file_write.write(bytearray(values))
[docs] def read(self, number_of_bytes): """ Read value from i2c port""" value_bytes = self.file_read.read(number_of_bytes) return list(value_bytes)
[docs] def close(self): """ Close the device """ self.file_write.close() self.file_read.close()
[docs]class MCP3428(object): """Class for reading voltage from MCP3428 For some reason this chip works only partly with smbus, hence the use of file based i2c. """
[docs] def __init__(self, address_index=0, voltage_ref=2.048): self.voltage_ref = voltage_ref # On ncd.io devices, this is approx ~11.1745V self.device_address = 0x68 + address_index self.bus = I2C(self.device_address, 1)
def __del__(self): self.bus.close()
[docs] def read_sample( self, channel: int = 1, gain: int = 1, resolution: int = 12 ) -> float: """ Read a single sample """ command_byte = ( self.resolution(resolution) | 0x00 | self.gain(gain) # One shot measuremet, use 0x10 for continous mode | self.channel(channel) ) command_byte = command_byte | 0x80 # start conversion self.bus.write([command_byte]) # t = time.time() while True: time.sleep(0.001) data = self.bus.read(3) if (data[2] & 0x80) == 0: break # meas_time = time.time() - t # print('High: {}, Low: {}'.format( # bin(data[0])[2:].zfill(8), bin(data[1])[2:].zfill(8))) # print('Execution time: {:.2f}ms'.format(meas_time * 1000)) raw_value = data[0] * 256 + data[1] if raw_value > (2 ** (resolution - 1) - 1): raw_value = raw_value - 2 ** resolution # print('Raw sensor value: {}'.format(raw_value)) bit_size = self.voltage_ref / (2 ** (resolution - 1) * gain) voltage = raw_value * bit_size return voltage
[docs] def gain(self, gain: int = 1) -> int: """ Return the command code to set gain """ gain_val = 0x00 if gain == 1: gain_val = 0x00 if gain == 2: gain_val = 0x01 if gain == 4: gain_val = 0x02 if gain == 8: gain_val = 0x03 return gain_val
[docs] def resolution(self, resolution: int = 12) -> int: """ Return the command code to set resolution """ resolution_val = 0x00 if resolution == 12: resolution_val = 0x00 if resolution == 14: resolution_val = 0x04 if resolution == 16: resolution_val = 0x08 return resolution_val
[docs] def channel(self, channel: int = 1) -> int: """ Return the command code to set channel """ channel_val = 0x00 if channel == 1: channel_val = 0x00 if channel == 2: channel_val = 0x20 if channel == 3: channel_val = 0x40 if channel == 4: channel_val = 0x60 # print('Channel val: {}, bin: {}'.format(channel_val, bin(channel_val))) return channel_val
if __name__ == '__main__': MCP = MCP3428(address_index=4) print(MCP.read_sample(channel=1, gain=1, resolution=16) * (3.3 + 2.2) / 2.2) print(MCP.read_sample(channel=2, gain=1, resolution=16) * (3.3 + 2.2) / 2.2) print(MCP.read_sample(channel=3, gain=1, resolution=16) * (3.3 + 2.2) / 2.2) print(MCP.read_sample(channel=4, gain=1, resolution=16) * (3.3 + 2.2) / 2.2) print() # for adc_index in range(0, 8): # adc = MCP3428(adc_index) # values = [] # for channel in range(0, 4): # values.append(adc.read_sample(channel=channel, gain=1, resolution=16)) # print('ADC: {}: {}'.format(adc_index, values))