class Interface(object): def __init__(self): self.baud_rate = 250000 self.data_bits = 8 self.stop_bits = 2 self.parity = 'N' self.flow_ctrl = '' self.rts_state = 0 self._is_open = False self._init_dmx() def _init_dmx(self): self.ftdi = Ftdi() try: self.ftdi.open(VENDOR, PRODUCT, 0) self.ftdi.set_baudrate(self.baud_rate) self.ftdi.set_line_property(self.data_bits, self.stop_bits, self.parity, break_=Ftdi.BREAK_OFF) self.ftdi.set_flowctrl(self.flow_ctrl) self.ftdi.purge_buffers() self.ftdi.set_rts(self.rts_state) self._is_open = True except USBError, e: print e self._is_open = False
class SDWire(StorageBase): def __init__(self, serial=None): self.serial = serial self.ftdi = Ftdi() self.vendor_id = 0x04e8 self.product_id = 0x6001 def _open(self): self.ftdi.open(vendor=self.vendor_id, product=self.product_id, serial=self.serial) def _close(self): self.ftdi.close() def to_host(self): self._open() self.ftdi.set_bitmode(mode=Ftdi.BitMode(0x20), bitmask=0xf1) self._close() def to_board(self): self._open() self.ftdi.set_bitmode(mode=Ftdi.BitMode(0x20), bitmask=0xf0) self._close()
class Sycamore (object): SYNC_FIFO_INTERFACE = 0 SYNC_FIFO_INDEX = 0 def __init__(self, idVendor, idProduct): self.vendor = idVendor self.product = idProduct self.dev = Ftdi() self.open_dev() def __del__(self): self.dev.close() def ping(self): data = Array('B', '0000'.decode('hex')) print "writing" for a in data: print "Data: %02X" % (a) self.dev.write_data(data) print "reading" time.sleep(.1) response = self.dev.read_data(4) rsp = Array('B') rsp.fromstring(response) print "rsp: " + str(rsp) # for a in rsp: # print "Data: %02X" % (a) def open_dev(self): frequency = 30.0E6 latency = 2 self.dev.open(self.vendor, self.product, 0) # Drain input buffer self.dev.purge_buffers() # Reset # Enable MPSSE mode self.dev.set_bitmode(0x00, Ftdi.BITMODE_SYNCFF) # Configure clock frequency = self.dev._set_frequency(frequency) # Set latency timer self.dev.set_latency_timer(latency) # Set chunk size self.dev.write_data_set_chunksize(0x10000) self.dev.read_data_set_chunksize(0x10000) self.dev.set_flowctrl('hw') # Configure I/O # self.write_data(Array('B', [Ftdi.SET_BITS_LOW, 0x00, 0x00])) # Disable loopback # self.write_data(Array('B', [Ftdi.LOOPBACK_END])) # self.validate_mpsse() # Drain input buffer self.dev.purge_buffers()
def test_multiple_interface(self): # the following calls used to create issues (several interfaces from # the same device). The test expects an FTDI 2232H here ftdi1 = Ftdi() ftdi1.open(vendor=0x403, product=0x6010, interface=1) ftdi2 = Ftdi() ftdi2.open(vendor=0x403, product=0x6010, interface=2) for _ in range(5): print("If#1: ", hex(ftdi1.poll_modem_status())) print("If#2: ", ftdi2.modem_status()) sleep(0.500) ftdi1.close() ftdi2.close()
def test_multiple_interface(self): # the following calls used to create issues (several interfaces from # the same device) ftdi1 = Ftdi() ftdi1.open(interface=1) ftdi2 = Ftdi() ftdi2.open(interface=2) import time for x in range(5): print "If#1: ", hex(ftdi1.poll_modem_status()) print "If#2: ", ftdi2.modem_status() time.sleep(0.500) ftdi1.close() ftdi2.close()
def test_multiple_interface(self): # the following calls used to create issues (several interfaces from # the same device). The test expect an FTDI 2232H here ftdi1 = Ftdi() ftdi1.open(vendor=0x403, product=0x6014, interface=1) # ftdi2 = Ftdi() # ftdi2.open(vendor=0x403, product=0x6014, interface=2) import time for x in range(5): print "poll_modem_status: ", hex(ftdi1.poll_modem_status()) # print "modem_status: ", ftdi1.modem_status() # print "If#2: ", ftdi2.modem_status() time.sleep(0.500) ftdi1.close()
def open_uart(): ################################################################################ global uart # set up the device uart = Ftdi() try: uart.open(0x403, 0x6001) except Exception as e: uart = None print("error={}".format(e)) return uart.set_baudrate(10400) uart.set_line_property(8, 1, 'N')
class FTDI_DAQ(Instrument): _ports = [] _port = None _last_byte = chr(0) _aliases = {} def __init__(self, name, serial=None, port='A', baudrate=115200): ''' discover and initialize Tunnel_DAC hardware Input: serial - serial number of the FTDI converter channel - 2 character channel id the DAC is connected to; the first byte identifies the channel (A..D for current devices) the second byte identifies the bit within that channel (0..7) numdacs - number of DACs daisy-chained on that line delay - communications delay assumed between PC and the USB converter ''' logging.info(__name__ + ': Initializing instrument Tunnel_DAC') Instrument.__init__(self, name, tags=['physical']) self._conn = Ftdi() # VIDs and PIDs of converters used vps = [ (0x0403, 0x6011), # FTDI UM4232H 4ch (0x0403, 0x6014) # FTDI UM232H 1ch ] # explicitly clear device cache of UsbTools #UsbTools.USBDEVICES = [] # find all devices and obtain serial numbers devs = self._conn.find_all(vps) # filter list by serial number if provided if (serial != None): devs = [dev for dev in devs if dev[2] == serial] if (len(devs) == 0): logging.error(__name__ + ': failed to find matching FTDI devices.') elif (len(devs) > 1): logging.error( __name__ + ': more than one converter found and no serial number given.') logging.info(__name__ + ': available devices are: %s.' % str([dev[2] for dev in devs])) vid, pid, self._serial, ports, description = devs[0] self._ports = [chr(ord('A') + i) for i in range(ports)] # open device (self._port, bit) = self._parse_channel_string(port) self._conn.open(vid, pid, interface=ord(self._port) - ord('A') + 1, serial=self._serial) logging.info(__name__ + ': using converter with serial #%s' % self._serial) self._conn.set_bitmode(0xFF, Ftdi.BITMODE_BITBANG) self._set_baudrate(baudrate) # provide user interface self.add_parameter('port', type=str, flags=Instrument.FLAG_GET) #self.add_parameter('aliases', type=types.DictType, flags=Instrument.FLAG_GETSET) self.add_function('digital_out') self.add_function('digital_stream') self.add_function('set_aliases') self.add_function('get_aliases') def do_get_port(self): return self._port def set_aliases(self, aliases): ''' define channel aliases accepts a dictionary that resolves alias names to internal channel names ''' self._aliases = aliases def get_aliases(self): ''' retrieve channel aliases ''' return self._aliases def digital_out(self, channel, status): ''' set a bit/byte on a FTDI channel ''' (port, bit) = self._parse_channel_string(channel) if (bit != None): if (status): byte = chr(ord(self._last_byte) | (1 << bit)) else: byte = chr(ord(self._last_byte) & ~(1 << bit)) else: byte = chr(0xff) if status else chr(0) self._conn.write_data(byte) self._last_byte = byte def digital_stream(self, channel, samples, rate): ''' write a serial bit/byte stream to the device rate max 6 MHz for ft4232h chip ''' (port, bit) = self._parse_channel_string(channel) # convert bit stream into byte stream if (bit != None): byte = 1 << bit samples = [(chr(ord(self._last_byte) | byte) if x else (chr(ord(self._last_byte) & ~byte))) for x in BitArray(samples)] # output data on the device self._set_baudrate(rate) self._conn.write_data(''.join(samples)) self._last_byte = samples[-1] def _parse_channel_string(self, channel): ''' parses a channel string into a (port, bit) tuple ''' # translate aliases if (self._aliases.has_key(channel)): channel = self._aliases[channel] # parse & mangle channel string m = re.match('(?P<port>[A-Z]+[0-9]*)(?P<bit>:[0-9]+)?', channel).groupdict() if (m == None): raise ValueError('channel identifier %s not understood.' % channel) port = m['port'] if (m['bit'] != None): bit = int(m['bit'].lstrip(':')) else: bit = None # check if the channel exists on this device if (not (port in self._ports)): raise ValueError('prot %s not supported by this device.' % port) if ((self._port != None) and (port != self._port)): raise ValueError( 'this implementation can not change the port identifier outside __init__.' ) if ((bit != None) and ((bit < 0) or (bit > 7))): raise ValueError('bit number must be between 0 and 7, not %d.' % bit) return (port, bit) def _set_baudrate(self, baudrate): ''' change baud rate of the FTDIs serial engine ''' # 80k generates bit durations of 12.5us, 80 is magic :( # magic?: 4 from incorrect BITBANG handling of pyftdi, 2.5 from 120MHz instead of 48MHz clock of H devices self._baudrate = baudrate self._conn.set_baudrate(baudrate / 80)
class Blaster: def __init__(self, debug=False): self.blaster = Ftdi() self.virtual = True self.blaster.LATENCY_MIN = 1 self.blaster.open(0x09FB, 0x6001) self.blaster.write_data_set_chunksize(1) self._last = None # Last deferred TDO bit self.debug = debug def readwritebit(self, tms, tdi): val = ENA + tms * TMS + tdi * TDI self.blaster._write(bytes([val])) val = ENA + tms * TMS + tdi * TDI + TCK + TDO self.blaster._write(bytes([val])) rd = self.blaster.read_data_bytes(1, attempt=3) tdo = ord(rd) & 1 return tdo def writebit(self, tms, tdi): val = ENA + tms * TMS + tdi * TDI self.blaster._write(bytes([val])) val = ENA + tms * TMS + tdi * TDI + TCK self.blaster._write(bytes([val])) def shiftinoutval(self, length, val): outval = 0 if (self.debug): print(">>Out{2:d}:0x{0:x}={0:0{1}b}".format(val, length, length)) nbytes = length >> 3 if nbytes > 63: raise Exception("length > 63 bytes") self.blaster._write(bytes([ENA])) valcmd = bytearray([BYTESHIFT | DORDWR | (nbytes & 0x3F)]) txlen = (nbytes & 0x3F) << 3 valbytes = (val & ((1 << txlen) - 1)).to_bytes(nbytes & 0x3F, 'little') valcmd.extend(valbytes) self.blaster._write(valcmd) rd = self.blaster.read_data_bytes(nbytes & 0x3F, attempt=3) rxlen = len(rd) outval += int.from_bytes(rd, 'little') val >>= txlen if (self.debug): print(">>Inbytes{2:d}:0x{0:x}={0:0{1}b}".format( outval, rxlen * 8, rxlen)) length -= txlen for i in range(length): bit = val & 1 tdo = self.readwritebit(0, bit) val >>= 1 outval += (tdo << (i + rxlen * 8)) if (self.debug): print(">>In{2:d}:0x{0:x}={0:0{1}b}".format(outval, (length + nbytes * 8), length)) return outval def shiftinval(self, length, val): if (self.debug): print(">>Out{2:d}:0x{0:x}={0:0{1}b}".format(val, length, length)) nbytes = length >> 3 while nbytes > 0: self.blaster._write(bytes([ENA])) valcmd = bytearray([BYTESHIFT | (nbytes & 0x3F)]) len = (nbytes & 0x3F) << 3 valbytes = (val & ((1 << len) - 1)).to_bytes( nbytes & 0x3F, 'little') valcmd.extend(valbytes) self.blaster._write(valcmd) val >>= len nbytes -= nbytes & 0x3F length -= len for i in range(length): bit = val & 1 tdo = self.writebit(0, bit) val >>= 1 def write_tms(self, tms, should_read=False): """Change the TAP controller state""" if not isinstance(tms, BitSequence): raise JtagError('Expect a BitSequence') tdo = 0 for val in tms: if (self._last is not None): if (should_read): if (self.debug): print(">>Tmsout:" + bin(self._last)) tdo = self.readwritebit(val, int(self._last)) if (self.debug): print(">>Tmsin:" + bin(tdo)) else: if (self.debug): print(">>Tmsout:" + bin(self._last)) self.writebit(val, int(self._last)) else: self.writebit(val, 0) should_read = False self._last = None return BitSequence(tdo, 1) def reset(self): """Reset the attached TAP controller. sync sends the command immediately (no caching) """ # we can either send a TRST HW signal or perform 5 cycles with TMS=1 # to move the remote TAP controller back to 'test_logic_reset'state # TAP reset (even with HW reset, could be removed though) self.write_tms(BitSequence('11111')) def write(self, out, use_last=True): if not isinstance(out, BitSequence): return JtagError('Expect a BitSequence') if use_last: (out, self._last) = (out[:-1], bool(out[-1])) length = len(out) self.shiftinval(length, int(out)) def writeread(self, out, use_last=True): if not isinstance(out, BitSequence): return JtagError('Expect a BitSequence') if use_last: (out, self._last) = (out[:-1], bool(out[-1])) length = len(out) bs = BitSequence(value=self.shiftinoutval(length, int(out)), length=length) return bs def read(self, length): """Read out a sequence of bits from TDO""" bs = BitSequence(value=self.shiftinoutval(length, 0), length=length) return bs def close(self): self.blaster.close()
import codecs import sys import time from random import randint VID = 0x0403 PID = 0x6010 #BAUDRATE = 9600 BAUDRATE = 921600 if __name__ == '__main__': ft = Ftdi() dev_list = ft.find_all([(VID, PID)], True) if (len(dev_list) > 0): print("Device found:\n\t", dev_list) ft.open(vendor=VID, product=PID, interface=2) print("Opened device!") # if you don't do this, first byte sent never arrives to the other side # if you happen to know why, let us know :) # dummy = self.ft.read_data(1) #empty buffer else: print("Device not connected!") exit() ft.set_baudrate(BAUDRATE) print("Baudrate set to {}".format(BAUDRATE)) #ft.read_data_bytes(1) N = 2 i = 0 fifo_rd = []
from pyftdi.ftdi import Ftdi from time import sleep ftdi1 = Ftdi() ftdi1.open(vendor=0x403, product=0x6015, interface=1) vps = [(0x0403, 0x6015)] for x in range(5): print("If#1: ", hex(ftdi1.poll_modem_status())) print("Read Pins:", bin(ftdi1.read_pins())) print("Devices:", bin(ftdi1.find_all(vps))) sleep(0.500) ftdi1.close()
# #>>> DRIVERS # It's necessary to manually unload these drivers: # sudo rmmod ftdi_sio # sudo rmmod usbserial # # from pyftdi.ftdi import Ftdi import codecs import sys import time if __name__ == '__main__': ft = Ftdi() ft.open(vendor=0x0403, product=0x6010, interface=2) i = 0 rd = 0 while True: #i = (i*2)%256 time.sleep(0.2) i = (i + 1) % 256 if (i == 0): i = 1 print("write: " + str(ft.write_data(bytes([i]))), i) time.sleep(0.3) rd = ft.read_data(10) #num = int(rd.encode('hex'), 16) #num = struct.unpack(">L", rd)[0] for j in range(len(rd)): num = int(rd[j]) print("read: " + repr(num) + "\t" + str(rd))
class PyFtdiBootloader(JennicProtocol): AUTO_PROG_MODE = True VENDOR_ID = 0x0403 PRODICT_ID = 0x6001 def __init__(self, pid=0x6001, devno=1, flag=None, baud_fast=True, ftdi_obj=None): self.DEFAULT_TIMEOUT = 1 # 100 for debug self.MAX_TIMEOUT = 3 # 100 fpr debug self.MAX_TIMEOUT_ERASEFULL = 8 self.MAX_TIMEOUT_ERASESECT = 2 self.BAUD_DEFAULT = 38400 self.b_ftdi_obj = False self.devno = 1 self.pid = pid self.isopen = False self.baud_fast = baud_fast if ftdi_obj is not None: self.ser = ftdi_obj self.b_ftdi_obj = True self.isopen = True else: if pid == None: pid = self.PRODICT_ID self.devno = None if devno.__class__ == int: self.devno = devno elif devno.__class__ == str: pass #self.devno = find_devno_by_serial(self.VENDOR_ID, pid, devno) else: self.devno = 1 self.pid = pid self.isopen = False self.baud_fast = baud_fast self.ser = Ftdi() self.open(baud=self.BAUD_DEFAULT) self.dev_prog() self.baud_default_to_fast() JennicProtocol.__init__(self) def open(self, baud=None): if self.b_ftdi_obj: if baud is not None: self.ser.set_baudrate(baud) return self.isopen if self.ser is not None: if self.isopen: self.close() if self.ser is None: self.ser = Ftdi() self.isopen = False try: self.ser.open(vendor=self.VENDOR_ID, product=self.pid, interface=self.devno) self.isopen = True except: pass if baud is None: baud = self.self.BAUD_DEFAULT self.ser.set_baudrate(baud) return self.isopen def close(self, destruct=False): if self.b_ftdi_obj: pass else: try: if self.ser is not None: self.ser.close() except: pass if destruct: try: if self.ser is not None: del self.ser except: pass self.ser = None self.isopen = False def baud_set(self, baud, reopen=False): if reopen: self.close() self.open(baud) else: self.ser.set_baudrate(baud) def baud_default(self): self.bause_set(self.BAUD_DEFAULT) def baud_default_to_fast(self): if self.baud_fast: self.change_baud(1000000) def __del__(self): self.close() """ TWE をリセットする """ def dev_reset(self): # RESET self.ser.set_bitmode(0xFB, self.ser.BitMode.CBUS) sleep(0.05) self.ser.set_bitmode(0xFF, self.ser.BitMode.CBUS) """ TWE をプログラムモードに設定する """ def dev_prog(self): # FIRMWARE PROGRAM'.', self.ser.set_bitmode(0xF3, self.ser.BitMode.CBUS) sleep(0.05) self.ser.set_bitmode(0xF7, self.ser.BitMode.CBUS) sleep(0.2) self.ser.set_bitmode(0xFF, self.ser.BitMode.CBUS) sleep(0.05) """ シリアルポートに書き出す data: byte列を入力 """ def write(self, data): self.ser.write_data(data) """ シリアルポートから読み出す timeout: タイムアウト秒 (float) raise_error: タイムアウト時に例外を発生させる 例外: TypeError タイムアウト """ def read(self, size, timeout=None, raise_error=True): d = b'' ts = time.monotonic() if timeout is None: timeout = self.DEFAULT_TIMEOUT while True: d += self.ser.read_data(size - len(d)) if len(d) >= size: break else: # timeout check if time.monotonic() - ts > timeout: if raise_error: raise TypeError() break else: sleep(.01) return d """ serial ポートから \n が来るまで読み出す。 戻り値:str (iso-8859-1) """ def readline(self, timeout=None): d = b'' ts = time.monotonic() if timeout is None: timeout = 1 while True: c = self.ser.read_data(1) d += c if c == b'\n': break elif c == b'': sleep(0.01) # timeout check if time.monotonic() - ts > timeout: break else: pass return d.decode('iso-8859-1') """ JN51XX のシリアルプロトコル """ def talk(self, typ, anstype, addr=None, mlen=None, data=None, max_tim=None): length = 3 if addr != None: length += 4 if mlen != None: length += 2 if data != None: length += len(data) msg = pack('<BB', length - 1, typ) if addr != None: msg += pack('<I', addr) if mlen != None: msg += pack('<H', mlen) if data != None: if data.__class__ == str: msg += data.encode() else: # msg += pack('<%is' % len(data), "".join(map(chr, data))) msg += bytes(data) msg += pack('<B', self.crc(msg, len(msg))) if anstype == None: self.write(msg) return [] try: #self.ser.timeout = self.DEFAULT_TIMEOUT self.write(msg) n = self.read(1) ans = b'' if (len(n) == 1): n = n[0] else: raise TypeError() while len(ans) < n: # TODO: problematic ans += self.read(n) except TypeError: # thrown when self.ser.read() gets nothing timeout = self.MAX_TIMEOUT if max_tim != None: timeout = max_tim n = self.read(1, timeout) ans = b'' if (len(n) == 1): n = n[0] else: raise TypeError() while len(ans) < n: # TODO: problematic ans += self.read(n) return ans[1:-1]
class FifoController (object): SYNC_FIFO_INTERFACE = 1 SYNC_FIFO_INDEX = 0 def __init__(self, idVendor, idProduct): self.vendor = idVendor self.product = idProduct self.f = Ftdi() def set_sync_fifo(self, frequency=30.0E6, latency=2): """Configure the interface for synchronous FIFO mode""" # Open an FTDI interface # self.f.open(self.vendor, self.product, self.SYNC_FIFO_INTERFACE, self.SYNC_FIFO_INDEX, None, None) self.f.open(self.vendor, self.product, 0) # Drain input buffer self.f.purge_buffers() # Reset # Enable MPSSE mode self.f.set_bitmode(0x00, Ftdi.BITMODE_SYNCFF) # Configure clock frequency = self.f._set_frequency(frequency) # Set latency timer self.f.set_latency_timer(latency) # Set chunk size self.f.write_data_set_chunksize(0x10000) self.f.read_data_set_chunksize(0x10000) self.f.set_flowctrl('hw') # Configure I/O # self.write_data(Array('B', [Ftdi.SET_BITS_LOW, 0x00, 0x00])) # Disable loopback # self.write_data(Array('B', [Ftdi.LOOPBACK_END])) # self.validate_mpsse() # Drain input buffer self.f.purge_buffers() # Return the actual frequency return frequency def set_async_fifo(self, frequency=6.0E6, latency=2): """Configure the interface for synchronous FIFO mode""" # Open an FTDI interface self.f.open(self.vendor, self.product, self.SYNC_FIFO_INTERFACE, self.SYNC_FIFO_INDEX, None, None) # Set latency timer self.f.set_latency_timer(latency) # Set chunk size self.f.write_data_set_chunksize(512) self.f.read_data_set_chunksize(512) # Drain input buffer self.f.purge_buffers() # Enable MPSSE mode self.f.set_bitmode(0x00, Ftdi.BITMODE_BITBANG) # Configure clock frequency = self.f._set_frequency(frequency) # Configure I/O # self.write_data(Array('B', [Ftdi.SET_BITS_LOW, 0x00, 0x00])) # Disable loopback # self.write_data(Array('B', [Ftdi.LOOPBACK_END])) # self.validate_mpsse() # Drain input buffer self.f.purge_buffers() # Return the actual frequency return frequency
def load_eeprom(vid, pid, sn): ftdi = Ftdi() eeprom = FtdiEeprom() ftdi.open(vid, pid, serial=sn) eeprom.connect(ftdi) return eeprom
class FTDI_DAQ(Instrument): _ports = [] _port = None _last_byte = chr(0) _aliases = {} def __init__(self, name, serial = None, port = 'A', baudrate = 115200): ''' discover and initialize Tunnel_DAC hardware Input: serial - serial number of the FTDI converter channel - 2 character channel id the DAC is connected to; the first byte identifies the channel (A..D for current devices) the second byte identifies the bit within that channel (0..7) numdacs - number of DACs daisy-chained on that line delay - communications delay assumed between PC and the USB converter ''' logging.info(__name__+ ': Initializing instrument Tunnel_DAC') Instrument.__init__(self, name, tags=['physical']) self._conn = Ftdi() # VIDs and PIDs of converters used vps = [ (0x0403, 0x6011), # FTDI UM4232H 4ch (0x0403, 0x6014) # FTDI UM232H 1ch ] # explicitly clear device cache of UsbTools #UsbTools.USBDEVICES = [] # find all devices and obtain serial numbers devs = self._conn.find_all(vps) # filter list by serial number if provided if(serial != None): devs = [dev for dev in devs if dev[2] == serial] if(len(devs) == 0): logging.error(__name__ + ': failed to find matching FTDI devices.') elif(len(devs) > 1): logging.error(__name__ + ': more than one converter found and no serial number given.') logging.info(__name__ + ': available devices are: %s.'%str([dev[2] for dev in devs])) vid, pid, self._serial, ports, description = devs[0] self._ports = [chr(ord('A') + i) for i in range(ports)] # open device (self._port, bit) = self._parse_channel_string(port) self._conn.open(vid, pid, interface = ord(self._port) - ord('A') + 1, serial = self._serial) logging.info(__name__ + ': using converter with serial #%s'%self._serial) self._conn.set_bitmode(0xFF, Ftdi.BITMODE_BITBANG) self._set_baudrate(baudrate) # provide user interface self.add_parameter('port', type=types.StringType, flags=Instrument.FLAG_GET) #self.add_parameter('aliases', type=types.DictType, flags=Instrument.FLAG_GETSET) self.add_function('digital_out') self.add_function('digital_stream') self.add_function('set_aliases') self.add_function('get_aliases') def do_get_port(self): return self._port def set_aliases(self, aliases): ''' define channel aliases accepts a dictionary that resolves alias names to internal channel names ''' self._aliases = aliases def get_aliases(self): ''' retrieve channel aliases ''' return self._aliases def digital_out(self, channel, status): ''' set a bit/byte on a FTDI channel ''' (port, bit) = self._parse_channel_string(channel) if(bit != None): if(status): byte = chr(ord(self._last_byte) | (1<<bit)) else: byte = chr(ord(self._last_byte) & ~(1<<bit)) else: byte = chr(0xff) if status else chr(0) self._conn.write_data(byte) self._last_byte = byte def digital_stream(self, channel, samples, rate): ''' write a serial bit/byte stream to the device ''' (port, bit) = self._parse_channel_string(channel) # convert bit stream into byte stream if(bit != None): byte = 1<<bit samples = [(chr(ord(self._lastbyte) | byte) if x else (chr(ord(self._lastbyte) & ~byte))) for x in BitArray(samples)] # output data on the device self._set_baudrate(rate) self._conn.write_data(samples) self._last_byte = samples[-1] def _parse_channel_string(self, channel): ''' parses a channel string into a (port, bit) tuple ''' # translate aliases if(self._aliases.has_key(channel)): channel = self._aliases[channel] # parse & mangle channel string m = re.match('(?P<port>[A-Z]+[0-9]*)(?P<bit>:[0-9]+)?', channel).groupdict() if(m == None): raise ValueError('channel identifier %s not understood.'%channel) port = m['port'] if(m['bit'] != None): bit = int(m['bit'].lstrip(':')) else: bit = None # check if the channel exists on this device if(not (port in self._ports)): raise ValueError('prot %s not supported by this device.'%port) if((self._port != None) and (port != self._port)): raise ValueError('this implementation can not change the port identifier outside __init__.') if((bit != None) and ((bit < 0) or (bit > 7))): raise ValueError('bit number must be between 0 and 7, not %d.'%bit) return (port, bit) def _set_baudrate(self, baudrate): ''' change baud rate of the FTDIs serial engine ''' # 80k generates bit durations of 12.5us, 80 is magic :( # magic?: 4 from incorrect BITBANG handling of pyftdi, 2.5 from 120MHz instead of 48MHz clock of H devices self._baudrate = baudrate self._conn.set_baudrate(baudrate/80)
# Pygame init pygame.init() size = width, height = 752, 480 black = 0, 0, 0 screen = pygame.display.set_mode(size) ls = [(0x0403, 0x6014)] datasize = 16 + 752 * 480 + 752 + 16 ret = Ftdi() print(ret.find_all(ls)) ret.open(1027, 24596) ret.set_bitmode(0xff, 0) time.sleep(1) ret.set_bitmode(0xff, 0x40) ret.set_latency_timer(2) ret.read_data_set_chunksize(65536) ret.write_data_set_chunksize(65536) ret.set_flowctrl('hw') try: ret.write_data(b'S') except ValueError: print('Cannot write') stop = False while not stop:
class Tunnel_DAC(Instrument): def __init__(self, name, serial = None, channel = 'A0', numdacs=3, delay = 1e-3): ''' discover and initialize Tunnel_DAC hardware Input: serial - serial number of the FTDI converter channel - 2 character channel id the DAC is connected to; the first byte identifies the channel (A..D for current devices) the second byte identifies the bit within that channel (0..7) numdacs - number of DACs daisy-chained on that line delay - communications delay assumed between PC and the USB converter ''' logging.info(__name__+ ': Initializing instrument Tunnel_DAC') Instrument.__init__(self, name, tags=['physical']) self._conn = Ftdi() # VIDs and PIDs of converters used vps = [ (0x0403, 0x6011), # FTDI UM4232H 4ch (0x0403, 0x6014) # FTDI UM232H 1ch ] # explicitly clear device cache of UsbTools #UsbTools.USBDEVICES = [] # find all devices and obtain serial numbers devs = self._conn.find_all(vps) # filter list by serial number if provided if(serial != None): devs = [dev for dev in devs if dev[2] == serial] if(len(devs) == 0): logging.error(__name__ + ': failed to find matching FTDI devices.') elif(len(devs) > 1): logging.error(__name__ + ': more than one converter found and no serial number given.') logging.info(__name__ + ': available devices are: %s.'%str([dev[2] for dev in devs])) vid, pid, self._serial, channels, description = devs[0] # parse channel string if(len(channel) != 2): logging.error(__name__ + ': channel identifier must be a string of length 2. ex. A0, D5.') self._channel = 1 + ord(channel[0]) - ord('A') self._bit = ord(channel[1]) - ord('0') if((self._channel < 1) or (self._channel > channels)): logging.error(__name__ + ': channel %c is not supported by this device.'%(chr(ord('A')+self._channel-1))) if((self._bit < 0) or (self._bit > 7)): logging.error(__name__ + ': subchannel must be between 0 and 7, not %d.'%self._bit) # open device self._conn.open(vid, pid, interface = self._channel, serial = self._serial) logging.info(__name__ + ': using converter with serial #%s'%self._serial) self._conn.set_bitmode(0xFF, Ftdi.BITMODE_BITBANG) # 80k generates bit durations of 12.5us, 80 is magic :( # magic?: 4 from incorrect BITBANG handling of pyftdi, 2.5 from 120MHz instead of 48MHz clock of H devices # original matlab code uses 19kS/s self._conn.set_baudrate(19000/80) # house keeping self._numdacs = numdacs self._sleeptime = (10. + 16.*self._numdacs)*12.5e-6 + delay # 1st term from hardware parameters, 2nd term from USB self._minval = -5000. self._maxval = 5000. self._resolution = 16 # DAC resolution in bits self._voltages = [0.]*numdacs self.add_parameter('voltage', type=types.FloatType, flags=Instrument.FLAG_SET, channels=(1, self._numdacs), minval = self._minval, maxval = self._maxval, units='mV', format = '%.02f') # tags=['sweep'] self.add_function('set_voltages') self.add_function('commit') def _encode(self, data, channel = 0, bits_per_item = 16, big_endian = True): ''' convert binary data into line symbols the tunnel electronic DAC logic box triggers on rising signal edges and samples data after 18us. we use a line code with three bits of duration 12us, where a logical 1 is encoded as B"110" and a logical 0 is encoded as B"100". the line data is returned as a byte string with three bytes/symbol. Input: data - a vector of data entities (usually a string or list of integers) channel - a number in [0, 7] specifying the output bit on the USB-to-UART chip bits_per_item - number of bits to extract from each element of the data vector ''' # build line code for the requested channel line_1 = chr(1<<channel) line_0 = chr(0) line_code = [''.join([line_0, line_1, line_1]), ''.join([line_0, line_1, line_0])] # do actual encoding result = [] result.append(10*line_0) for item in data: for bit in (range(bits_per_item-1, -1, -1) if big_endian else range(0, bits_per_item)): result.append(line_code[1 if(item & (1<<bit)) else 0]) result.append(10*line_0) return ''.join(result) def commit(self): ''' send updated parameter values to the physical DACs via USB ''' # normalize, scale, clip voltages voltages = [-1+2*(x-self._minval)/(self._maxval-self._minval) for x in self._voltages] voltages = [max(-2**(self._resolution-1), min(2**(self._resolution-1)-1, int(2**(self._resolution-1)*x))) for x in voltages] # encode and send data = self._encode(reversed(voltages), self._bit, self._resolution) self._conn.write_data(data) # wait for the FTDI fifo to clock the data to the DACs sleep(self._sleeptime) def do_set_voltage(self, value, channel): ''' immediately update voltage on channel ch parameter checking is done by qtlab ''' self._voltages[channel-1] = value self.commit() def set_voltages(self, valuedict): ''' update voltages on several channels simultaneously todo: update instrument panel display ''' for channel, value in valuedict.iteritems(): # bounds checking & clipping if((channel < 1) or (channel > self._numdacs)): logging.error(__name__ + ': channel %d out of range.'%channel) continue value = float(value) if((value < self._minval) or (value >= self._maxval)): logging.error(__name__ + ': value %f out of range. clipping.'%value) value = max(self._minval, min(self._maxval, value)) # does not handle maxval correctly self._voltages[channel-1] = value self.commit()