示例#1
0
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()
示例#2
0
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
示例#3
0
class Dionysus(Olympus):
  """Dionysus

  Concrete Class that implements Dionysus specific communication functions
  """

  def __init__(self, idVendor=0x0403, idProduct=0x8530, debug = False):
    Olympus.__init__(self, debug)
    self.vendor = idVendor
    self.product = idProduct
    self.dev = Ftdi()
    self._open_dev()

    self.name = "Dionysus"

  def __del__(self):
    self.dev.close()

  def _open_dev(self):
    """_open_dev
    
    Open an FTDI communication channel

    Args:
      Nothing

    Returns:
      Nothing

    Raises:
      Exception
    """
    frequency = 30.0E6
#Latency can go down t 2 but when set there is a small chance that there is a crash
    latency = 4
    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')
    self.dev.purge_buffers()


  def read(self, device_id, address, length = 1, mem_device = False):
    """read

    read data from the Olympus image

    Args:
      device_id: Device identification number, found in the DRT
      address: Address of the register/memory to read
      mem_device: True if the device is on the memory bus
      length: Number of 32 bit words to read from the FPGA

    Returns:
      A byte array containing the raw data returned from Olympus

    Raises:
      OlympusCommError
    """
    read_data = Array('B')

    write_data = Array('B', [0xCD, 0x02]) 
    if mem_device:
      if self.debug:
        print "memory device"
      write_data = Array ('B', [0xCD, 0x12])
  
    fmt_string = "%06X" % (length) 
    write_data.fromstring(fmt_string.decode('hex'))
    offset_string = "00"
    if not mem_device:
      offset_string = "%02X" % device_id

    write_data.fromstring(offset_string.decode('hex'))

    addr_string = "%06X" % address
    write_data.fromstring(addr_string.decode('hex'))
    if self.debug:
      print "data read string: " + str(write_data)

    self.dev.purge_buffers()
    self.dev.write_data(write_data)

    timeout = time.time() + self.read_timeout
    rsp = Array('B')
    while time.time() < timeout:
      response = self.dev.read_data(1)
      if len(response) > 0:
        rsp = Array('B')
        rsp.fromstring(response)
        if rsp[0] == 0xDC:
          if self.debug:
            print "Got a response"  
          break

    if len(rsp) > 0:
      if rsp[0] != 0xDC:
        if self.debug:
          print "Response not found"  
        raise OlympusCommError("Did not find identification byte (0xDC): %s" % str(rsp))
    else:
      if self.debug:      
        print "No Response found"
      raise OlympusCommError("Timeout while waiting for a response")

    #I need to watch out for the modem status bytes
    read_count = 0
    response = Array('B')
    rsp = Array('B')
    timeout = time.time() + self.read_timeout

    while (time.time() < timeout) and (read_count < (length * 4 + 8)):
      response = self.dev.read_data((length * 4 + 8 ) - read_count)
      temp  = Array('B')
      temp.fromstring(response)
      #print "temp: %s", str(temp)
      if (len(temp) > 0):
        rsp += temp
        read_count = len(rsp)
    
    if self.debug:
      print "read length = %d, total length = %d" % (len(rsp), (length * 4 + 8))
      print "time left on timeout: %d" % (timeout - time.time())

    if self.debug:
      print "response length: " + str(length * 4 + 8)
      print "response status:\n\t" + str(rsp[:8])
      print "response data:\n" + str(rsp[8:])

    return rsp[8:]
    

  def write(self, device_id, address, data=None, mem_device = False):
    """write

    Write data to an Olympus image

    Args:
      device_id: Device identification number, found in the DRT
      address: Address of the register/memory to read
      mem_device: True if the device is on the memory bus
      data: Array of raw bytes to send to the device

    Returns:
      Nothing

    Raises:
      OlympusCommError
    """
    length = len(data) / 4

    # ID 01 NN NN NN OO AA AA AA DD DD DD DD
      # ID = ID BYTE (0xCD)
      # 01 = Write Command
      # NN = Size of write (3 bytes)
      # OO = Offset of device
      # AA = Address (4 bytes)
      # DD = Data (4 bytes)

    #create an array with the identification byte (0xCD)
    #and code for write (0x01)

    data_out = Array('B', [0xCD, 0x01]) 
    if mem_device:
      if self.debug:
        print "memory device"
      data_out = Array ('B', [0xCD, 0x11])
    
    """
    print "write command:\n\t" + str(data_out[:9])
    for i in range (0, len(data_out)):
      print str(hex(data_out[i])) + ", ",
    print " "
    """

 

    #append the length into the frist 32 bits
    fmt_string = "%06X" % (length) 
    data_out.fromstring(fmt_string.decode('hex'))
    offset_string = "00"
    if not mem_device:
      offset_string = "%02X" % device_id
    data_out.fromstring(offset_string.decode('hex'))
    addr_string = "%06X" % address
    data_out.fromstring(addr_string.decode('hex'))
    
    data_out.extend(data)

    """
    #if (self.debug):
    print "data write string:\n"
    print "write command:\n\t" + str(data_out[:9])
    for i in range (0, 9):
      print str(hex(data_out[i])) + ", ",
    print " "
    """


    #print "write data:\n" + str(data_out[9:])

    #avoid the akward stale bug
    self.dev.purge_buffers()

    self.dev.write_data(data_out)
    rsp = Array('B')

    timeout = time.time() + self.read_timeout
    while time.time() < timeout:
      response = self.dev.read_data(1)
      if len(response) > 0:
        rsp = Array('B')
        rsp.fromstring(response)
        if rsp[0] == 0xDC:
          if self.debug:
            print "Got a response"  
          break

    if (len(rsp) > 0):
      if rsp[0] != 0xDC:
        if self.debug:
          print "Response not found"  
        raise OlympusCommError("Did not find identification byte (0xDC): %s" % str(rsp))

    else:
      if self.debug:
        print "No Response"
      raise OlympusCommError("Timeout while waiting for a response")

    response = self.dev.read_data(8)
    rsp = Array('B')
    rsp.fromstring(response)

    if self.debug:
      print "Response: " + str(rsp)

  def ping(self):
    """ping

    Pings the Olympus image

    Args:
      Nothing

    Returns:
      Nothing

    Raises:
      OlympusCommError
    """
    data = Array('B')
    data.extend([0XCD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
    if self.debug:
      print "Sending ping...",
    self.dev.write_data(data)
    rsp = Array('B')
    temp = Array('B')

    timeout = time.time() + self.read_timeout

    while time.time() < timeout:
      response = self.dev.read_data(5)
      if self.debug:
        print ".",
      rsp = Array('B')
      rsp.fromstring(response)
      temp.extend(rsp)
      if 0xDC in rsp:
        if self.debug:
          print "Got a response"  
          print "Response: %s" % str(temp)
        break

    if not 0xDC in rsp:
      if self.debug:
        print "ID byte not found in response"  
        print "temp: " + str(temp)
      raise OlympusCommError("Ping response did not contain ID: %s" % str(temp))

    index  = rsp.index(0xDC) + 1

    read_data = Array('B')
    read_data.extend(rsp[index:])
    num = 3 - index
    read_data.fromstring(self.dev.read_data(num))
    if self.debug:
      print "Success!"
    return


  def reset(self):
    """reset

    Software reset the Olympus FPGA Master, this may not actually reset the
    entire FPGA image

    Args:
      Nothing

    Returns:
      Nothing

    Raises:
      OlympusCommError: A failure of communication is detected
    """
    data = Array('B')
    data.extend([0XCD, 0x03, 0x00, 0x00, 0x00]);
    if self.debug:
      print "Sending reset..."
    self.dev.purge_buffers()
    self.dev.write_data(data)

  def dump_core(self):
    """dump_core

    reads the state of the wishbone master prior to a reset, useful for
    debugging

    Args:
      Nothing

    Returns:
      Array of 32-bit values to be parsed by core_analyzer

    Raises:
      AssertionError: This function must be overriden by a board specific
      implementation
      OlympusCommError: A failure of communication is detected
    """

    data = Array('B')
    data.extend([0xCD, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
    print "Sending core dump request..."

    self.dev.purge_buffers()
    self.dev.write_data(data)

    core_dump = Array('L')
    wait_time = 5
    timeout = time.time() + wait_time

    temp = Array ('B')
    while time.time() < timeout:
      response = self.dev.read_data(1)
      rsp = Array('B')
      rsp.fromstring(response)
      temp.extend(rsp)
      if 0xDC in rsp:
        print "Got a response"  
        break

    if not 0xDC in rsp:
      print "Response not found"  
      raise OlympusCommError("Response Not Found")

    rsp = Array('B')
    read_total = 4
    read_count = len(rsp)

    #get the number of items from the address
    timeout = time.time() + wait_time
    while (time.time() < timeout) and (read_count < read_total):
      response = self.dev.read_data(read_total - read_count)
      temp  = Array('B')
      temp.fromstring(response)
      if (len(temp) > 0):
        rsp += temp
        read_count = len(rsp)

    print "Length of read: %d" % len(rsp)
    print "Data: %s" % str(rsp)
    count  = ( rsp[1] << 16 | rsp[2] << 8 | rsp[3]) * 4
    print "Number of core registers: %d" % (count / 4)

    #get the core dump data
    timeout = time.time() + wait_time
    read_total  = count
    read_count  = 0
    temp = Array ('B')
    rsp = Array('B')
    while (time.time() < timeout) and (read_count < read_total):
      response = self.dev.read_data(read_total - read_count)
      temp  = Array('B')
      temp.fromstring(response)
      if (len(temp) > 0):
        rsp += temp
        read_count = len(rsp)

    print "Length read: %d" % (len(rsp) / 4)
    print "Data: %s" % str(rsp)
    core_data = Array('L')
    for i in range (0, count, 4):
      print "count: %d" % i
      core_data.append(rsp[i] << 24 | rsp[i + 1] << 16 | rsp[i + 2] << 8 | rsp[i + 3])
    
    #if self.debug:
    print "core data: " + str(core_data)

    return core_data



 

  def wait_for_interrupts(self, wait_time = 1):
    """wait_for_interrupts
    
    listen for interrupts for the specified amount of time

    Args:
      wait_time: the amount of time in seconds to wait for an interrupt

    Returns:
      True: Interrupts were detected
      False: No interrupts detected

    Raises:
      Nothing
    """
    timeout = time.time() + wait_time

    temp = Array ('B')
    while time.time() < timeout:
      response = self.dev.read_data(1)
      rsp = Array('B')
      rsp.fromstring(response)
      temp.extend(rsp)
      if 0xDC in rsp:
        if self.debug:
          print "Got a response"  
        break

    if not 0xDC in rsp:
      if self.debug:
        print "Response not found"  
      return False

    read_total = 9
    read_count = len(rsp)

    #print "read_count: %s" % str(rsp)
    while (time.time() < timeout) and (read_count < read_total):
      response = self.dev.read_data(read_total - read_count)
      temp  = Array('B')
      temp.fromstring(response)
      #print "temp: %s", str(temp)
      if (len(temp) > 0):
        rsp += temp
        read_count = len(rsp)

    #print "read_count: %s" % str(rsp)
   

    index  = rsp.index(0xDC) + 1

    read_data = Array('B')
    read_data.extend(rsp[index:])
    #print "read_data: " + str(rsp)

    self.interrupts = read_data[-4] << 24 | read_data[-3] << 16 | read_data[-2] << 8 | read_data[-1]
    
    if self.debug:
      print "interrupts: " + str(self.interrupts)
    return True


  def comm_debug(self):
    """comm_debug

    A function that the end user will probably not interract with
    This is here to simply debug a communication medium

    Args:
      Nothing

    Returns:
      Nothing

    Raises:
      Nothing
    """
    #self.dev.set_dtr_rts(True, True)
    #self.dev.set_dtr(False)
    print "CTS: " + str(self.dev.get_cts())
#    print "DSR: " + str(self.dev.get_dsr())
    s1 = self.dev.modem_status()
    print "S1: " + str(s1)
示例#4
0
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()
示例#5
0
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