class Newport: direction = 0xff # gpio direction byte def __init__(self, address='ftdi://ftdi:232/1'): self.gpio = GpioController() self.state = None self.address = address def __del__(self): self.disconnect() def connect(self): self.gpio.open_from_url(self.address, direction=self.direction) self.state = self.gpio.read() def disconnect(self): self.gpio.close() def on(self): self.gpio.write(0x00) self.state = self.gpio.read() def off(self): self.gpio.write(0xff) self.state = self.gpio.read()
class LEDTest(): """Test for LED on FT232H board""" def __init__(self): self._gpio = GpioController() self._state = 0 # SW cache of the GPIO output lines def pins(self): print(self._gpio.direction) def open(self, out_pins): """Open a GPIO connection, defining which pins are configured as output and input""" out_pins &= 0xFF url = environ.get('FTDI_DEVICE', 'ftdi://ftdi:232h/1') self._gpio.open_from_url(url, direction=out_pins) def close(self): """Close the GPIO connection""" self._gpio.close() def get_gpio(self, line): """Retrieve the level of a GPIO input pin :param line: specify which GPIO to read out. :return: True for high-level, False for low-level """ value = self._gpio.read_port() print(value) return bool(value & (1 << line)) def set_gpio(self, line, on): """Set the level of a GPIO ouput pin. :param line: specify which GPIO to madify. :param on: a boolean value, True for high-level, False for low-level """ if on: state = self._state | (1 << line) else: state = self._state & ~(1 << line) self._commit_state(state) def _commit_state(self, state): """Update GPIO outputs """ self._gpio.write_port(state) # do not update cache on error self._state = state
class GpioTest(object): """ """ def __init__(self): self._gpio = GpioController() self._state = 0 # SW cache of the GPIO output lines def open(self, out_pins): """Open a GPIO connection, defining which pins are configured as output and input""" out_pins &= 0xFF url = environ.get('FTDI_DEVICE', 'ftdi://ftdi:2232h/1') self._gpio.open_from_url(url, direction=out_pins) def close(self): """Close the GPIO connection""" self._gpio.close() def set_gpio(self, line, on): """Set the level of a GPIO ouput pin. :param line: specify which GPIO to madify. :param on: a boolean value, True for high-level, False for low-level """ if on: state = self._state | (1 << line) else: state = self._state & ~(1 << line) self._commit_state(state) def get_gpio(self, line): """Retrieve the level of a GPIO input pin :param line: specify which GPIO to read out. :return: True for high-level, False for low-level """ value = self._gpio.read_port() return bool(value & (1 << line)) def _commit_state(self, state): """Update GPIO outputs """ self._gpio.write_port(state) # do not update cache on error self._state = state
#!/usr/bin/env python3 # deps can be satisfied on Linux with `sudo pip3 install pyftdi` from pyftdi.gpio import GpioController, GpioException from time import sleep import sys import serial import bitstring bitstring.bytealigned = True # change the default behaviour bitbang = GpioController() bitbang.open_from_url('ftdi:///1') ser = serial.Serial('/dev/ttyUSB0', 115200, timeout=None) DELAY = 0.0000005 #strict worst-case delay is 0.54ms -- we can relax that due to lots of delays in the many layers of software between us. #on my machine this results in a minimum CLK pulse width of 0.58 ms on my machine HARD_DELAY = 0.00054 # for cases where strict delay adherence is necessary (e.g. when begining shift-out) state = 0 def pin_output(line): bitbang.set_direction(1 << line, 1 << line) return def pin_input(line): bitbang.set_direction(1 << line, 0)
class Executor(multiprocessing.Process): ''' Provides an executor - responsible for banging data onto and off of the wire - which is intended to be run in a separate process. This also handles timing and has been built to use queues to try and reduce clock jitter. This was lifted from whatabanger with slight modifications. ''' def __init__(self, req, res, clk=0x01, mosi=0x02, miso=0x04, cs=0x08): ''' Ensure a logger is setup, and access to the GPIO is possible. ''' super(Executor, self).__init__() self.log = logging.getLogger(__name__) # The initial state is everything pulled HIGH. self.state = 0xFF # Ensure the work queue is accessible - this is used for the parent # to push request to bang onto the wire. self._in = req self._out = res # Defaults are: # Pin D0 - 0x01 - OUT (CLOCK) # Pin D1 - 0x02 - OUT (MOSI) # Pin D2 - 0x04 - IN (MISO) # Pin D3 - 0x08 - OUT (CHIP SELECT) self.clk = clk self.miso = miso self.mosi = mosi self.cs = cs # Setup the clock interval. This isn't the cycle time, but half the # target cycle time. self.clock_interval = 0.0 # Setup the interface, ensuring that MISO is set to GPIO IN. self.gpio = GpioController() direction = xor(0xFF, self.miso) self.log.debug("Setting up FT2232 for GPIO (%s)", "{0:08b}".format(direction)) self.gpio.open_from_url( url='ftdi://0x0403:0x6010/1', direction=direction, ) # Set the initial GPIO state. self.gpio.write_port(self.state) self.log.debug("Set the initial GPIO state to %s", self.state) def _write_bits(self, bits): ''' Write bits onto the wire (Master to Target) communication. ''' self.log.debug("Starting banging bits (%s)", bits) for bit in bits: # Pull the clock HIGH, and drive CS low. self.state |= self.clk self.state &= ~self.cs self.gpio.write_port(self.state) time.sleep(self.clock_interval) # Check whether we need to write a HIGH or LOW for the bit to be # transmitted (where HIGH is 1). if bit == 1: self.state |= self.mosi else: self.state &= ~self.mosi # Send data via MOSI on the FALLING-edge of the clock. self.state &= ~self.clk self.gpio.write_port(self.state) time.sleep(self.clock_interval) # If there's not a Logic Analyser connected, determining when all # data has been sent is a pain. Thus, this. self.log.debug("Finished banging bits") def _read_bits(self, count): ''' Reads N bits from the wire. ''' self.log.debug("Reading %s bits", count) # This should already be the case, but ensure MISO isn't drive by # the master (us). self.gpio.set_direction(self.miso, 0x0) result = [] for _ in range(count): # Data will be banged onto the wire by the target device on the # RISING edge. self.state |= self.clk self.gpio.write_port(self.state) # Finally, read the state of MISO to determine the value sent by # the target. if (self.gpio.read() & self.miso) == self.miso: result.append(1) else: result.append(0) # Sleep and then drive the clock LOW to complete the cycle. time.sleep(self.clock_interval) self.state &= ~self.clk self.gpio.write_port(self.state) time.sleep(self.clock_interval) self.log.debug("Read %s", result) return result def _write_clock(self): ''' 'Write' a clock cycle without sending any data. ''' # Pull the clock HIGH. self.state |= self.clk self.gpio.write_port(self.state) time.sleep(self.clock_interval) # Pull the clock LOW. self.state &= ~self.clk self.gpio.write_port(self.state) time.sleep(self.clock_interval) def run(self): ''' Run the clock, and bang bits as required. ''' self.log.info("Bit banger clock and monitor started") while True: # If there's anything in the queue, bang away. if self._in.qsize() > 0: request = self._in.get() self._write_bits(request['bits']) r = 0 while r <= request['size']: result = self._read_bits(8) r += 8 self._out.put(result) else: # If no data is pending send, make sure we still drive the # clock. self._write_clock()
self.i2c_end() return v def i2c_read_from_reg(self, reg): """Reads a single byte from specified register. :param reg: Register to be read. :return: Byte that was read. """ v = self.i2c_write_address(0, self.address) v &= self.i2c_write_byte(reg) self.i2c_end() v &= self.i2c_write_address(1, self.address) byte = self.i2c_read_byte() if not v: print("Error") self.i2c_end() return byte if __name__ == '__main__': mask = 0x13 # in, in,in Out, In, In, out, out gpio = GpioController() gpio.open_from_url('ftdi://ftdi:4232h/1', mask) port = I2CPort(gpio) switch2 = I2CDevice(port, 0x71) switch2.i2c_write_byte_to(0x04) i = switch2.i2c_read_byte_from() print("%x" % i) gpio.close()
class PapilioOne(PyFTDIGPIOAdapter): """ A JTAG adapter for Papilio One devices ported to use PyFTDI python library instead of libftdi. """ #VID/PID constants. VENDOR_ID = 0x0403 PRODUCT_ID = 0x6010 #Port-number constants. TCK_PORT = 0 TDI_PORT = 1 TDO_PORT = 2 TMS_PORT = 3 DEFAULT_FREQ = int(1e6) FTDI_URL = 'ftdi://0x{:04x}:0x{:04x}/1'.format(VENDOR_ID, PRODUCT_ID) def __init__(self, serial_number=None, debug=False): """ Create a new instance of the Papilio One. serial_number -- The serial number of the board to connect to, or None to use the first available bitbangable FTDI. Use caution with this one! NOTE: This is IGNORED. """ # Instead of using BitBangDevice(), use GpioController() from PyFTDI self._gpio = GpioController() # If FTDI_DEVICE environment variable, use it instead of self.FTDI_URL url = environ.get('FTDI_DEVICE', self.FTDI_URL) # Open the PyFTDI URL with outputs set as per set_up_jtag_port() self._gpio.open_from_url(url, direction=self.set_up_jtag_port()) atexit.register(self.cleanup) #Initiatialize the core JTAG subsystem. super().__init__(self._gpio) def cleanup(self): print("Running PyFTDI GPIO cleanup...") self._gpio.close() def set_tck_period(self, period): """ Handle the settck virtual cable command which requests a certain TCK period. Return the actual period. """ #@@@# Modify to actually change frequency using PyFTDI functions. ## Actual Period depends on many factors since this tries to simply go as fast as it can. So nothing to set. Respond that it goes at 100 Hz or 10e6 ns return int(1e9 // self.DEFAULT_FREQ) def set_up_jtag_port(self): direction = 0 direction |= (1 << self.TCK_PORT) direction |= (1 << self.TDI_PORT) direction |= (1 << self.TMS_PORT) direction &= ~(1 << self.TDO_PORT) return direction def set_tms(self, value, commit=True): """ Specifies the value of the TMS port. Used by the parent class. """ self._set_bit(self.TMS_PORT, value, commit) def set_tdi(self, value, commit=True): """ Specifies the value of the TDI port. Used by the parent class. """ self._set_bit(self.TDI_PORT, value, commit) def set_tck(self, value, commit=True): """ Specifies the value of the TCK port. Used by the parent class. """ self._set_bit(self.TCK_PORT, value, commit) def get_tdo(self): """ Reads the current value of the TDO port. Used by the parent class. """ return self._get_bit(self.TDO_PORT)