Exemple #1
0
class SPI:
    MSB = 0

    def __init__(self):
        from pyftdi.spi import SpiController
        self._spi = SpiController(cs_count=1)
        self._spi.configure('ftdi:///1')
        self._port = self._spi.get_port(0)
        self._port.set_frequency(100000)
        self._port._cpol = 0
        self._port._cpha = 0
        # Change GPIO controller to SPI
        Pin.ft232h_gpio = self._spi.get_gpio()

    def init(self, baudrate=100000, polarity=0, phase=0, bits=8,
                  firstbit=MSB, sck=None, mosi=None, miso=None):
        self._port.set_frequency(baudrate)
        # FTDI device can only support mode 0 and mode 2
        # due to the limitation of MPSSE engine.
        # This means CPHA must = 0
        self._port._cpol = polarity
        if phase != 0:
            raise ValueError("Only SPI phase 0 is supported by FT232H.")
        self._port._cpha = phase

    @property
    def frequency(self):
        return self._port.frequency

    def write(self, buf, start=0, end=None):
        end = end if end else len(buf)
        chunks, rest = divmod(end - start, self._spi.PAYLOAD_MAX_LENGTH)
        for i in range(chunks):
            chunk_start = start + i * self._spi.PAYLOAD_MAX_LENGTH
            chunk_end = chunk_start + self._spi.PAYLOAD_MAX_LENGTH
            self._port.write(buf[chunk_start:chunk_end])
        if rest:
            self._port.write(buf[-1*rest:])

    def readinto(self, buf, start=0, end=None, write_value=0):
        end = end if end else len(buf)
        result = self._port.read(end-start)
        for i, b in enumerate(result):
            buf[start+i] = b

    def write_readinto(self, buffer_out, buffer_in,  out_start=0, out_end=None, in_start=0, in_end=None):
        out_end = out_end if out_end else len(buffer_out)
        in_end = in_end if in_end else len(buffer_in)
        result = self._port.exchange(buffer_out[out_start:out_end],
                                     in_end-in_start, duplex=True)
        for i, b in enumerate(result):
            buffer_in[in_start+i] = b
Exemple #2
0
 def get_flash_device(url, cs=0, freq=None):
     """Obtain an instance of the detected flash device"""
     ctrl = SpiController(silent_clock=False)
     ctrl.configure(url)
     spi = ctrl.get_port(cs, freq)
     jedec = SerialFlashManager.read_jedec_id(spi)
     if not jedec:
         # it is likely that the latency setting is too low if this
         # condition is encountered
         raise SerialFlashUnknownJedec("Unable to read JEDEC Id")
     flash = SerialFlashManager._get_flash(spi, jedec)
     flash.set_spi_frequency(freq)
     return flash
Exemple #3
0
 def get_flash_device(url, cs=0, freq=None):
     """Obtain an instance of the detected flash device"""
     ctrl = SpiController(silent_clock=False)
     ctrl.configure(url)
     spi = ctrl.get_port(cs, freq)
     jedec = SerialFlashManager.read_jedec_id(spi)
     if not jedec:
         # it is likely that the latency setting is too low if this
         # condition is encountered
         raise SerialFlashUnknownJedec("Unable to read JEDEC Id")
     flash = SerialFlashManager._get_flash(spi, jedec)
     flash.set_spi_frequency(freq)
     return flash
def main(argv):
    """
    Entry point for bme280-monitor.py

    Arguments:
        argv: command line arguments
    """

    now = datetime.utcnow().strftime("%FT%TZ")
    args = process_arguments(argv)

    # Connect to the sensor.
    ctrl = SpiController()
    ctrl.configure(args.device)
    spi = ctrl.get_port(Port[args.cs].value)
    spi.set_frequency(args.frequency)
    try:
        bme280 = Bme280spi(spi)
    except RuntimeError as err:
        print(err)
        sys.exit(1)

    if "{}" in args.path:
        filename = args.path.format(now)
    else:
        filename = args.path

    # Write datafile header.
    with open(filename, "a") as datafile:
        datafile.write("# BME280 data.\n# Started monitoring at {}.\n".format(now))
        datafile.write("# Per line, the data items are:\n")
        datafile.write("# * UTC date and time in ISO8601 format\n")
        datafile.write("# * Temperature in °C\n")
        datafile.write("# * Pressure in Pa\n")
        datafile.write("# * Relative humidity in %.\n")

    # Read and write the data.
    try:
        # Throw the first read away; bogis pressure value.
        bme280.read()
        while True:
            now = datetime.utcnow().strftime("%FT%TZ")
            temperature, pressure, humidity = bme280.read()
            line = "{} {:.2f} {:.0f} {:.2f}\n".format(
                now, temperature, pressure, humidity
            )
            with open(filename, "a") as datafile:
                datafile.write(line)
            time.sleep(args.interval)
    except KeyboardInterrupt:
        sys.exit(1)
Exemple #5
0
def ftdi_spi(device='ftdi://::/1', bus_speed_hz=12000000, gpio_CS=3, gpio_DC=5, gpio_RST=6,
        reset_hold_time=0, reset_release_time=0):
    """
    Bridges an `SPI <https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus>`_
    (Serial Peripheral Interface) bus over an FTDI USB device to provide :py:func:`data` and
    :py:func:`command` methods.

    :param device: A URI describing the location of the FTDI device. If ``None`` is
        supplied (default), ``ftdi://::/1`` is used. See `pyftdi <https://pypi.org/project/pyftdi>`_
        for further details of the naming scheme used.
    :type device: string
    :param bus_speed_hz: SPI bus speed, defaults to 12MHz.
    :type bus_speed_hz: int
    :param gpio_CS: The ADx pin to connect chip select (CS) to (defaults to 3).
    :type gpio_CS: int
    :param gpio_DC: The ADx pin to connect data/command select (DC) to (defaults to 5).
    :type gpio_DC: int
    :param gpio_RST: The ADx pin to connect reset (RES / RST) to (defaults to 6).
    :type gpio_RST: int
        :param reset_hold_time: The number of seconds to hold reset active. Some devices may require
        a duration of 100ms or more to fully reset the display (default:0)
    :type reset_hold_time: float
    :param reset_release_time: The number of seconds to delay afer reset. Some devices may require
        a duration of 150ms or more after reset was triggered before the device can accept the
        initialization sequence (default:0)
    :type reset_release_time: float

    .. versionadded:: 1.9.0
    """
    from pyftdi.spi import SpiController

    controller = SpiController(cs_count=1)
    controller.configure(device)

    slave = controller.get_port(cs=gpio_CS - 3, freq=bus_speed_hz, mode=0)
    gpio = controller.get_gpio()

    # RESET and DC configured as outputs
    pins = _ftdi_pin(gpio_RST) | _ftdi_pin(gpio_DC)
    gpio.set_direction(pins, pins & 0xFF)

    serial = spi(
        __FTDI_WRAPPER_SPI(controller, slave),
        __FTDI_WRAPPER_GPIO(gpio),
        gpio_DC=gpio_DC,
        gpio_RST=gpio_RST,
        reset_hold_time=reset_hold_time,
        reset_release_time=reset_release_time)
    serial._managed = True
    return serial
Exemple #6
0
def setConfigure(ftdi_interface, ccp_header_file):
    spi = SpiController()
    spi.configure(ftdi_interface)
    global slave
    slave = spi.get_port(cs=0, freq=12E6, mode=0)

    global ccp_header
    ccp_header = cpp_header_parser.read_header(ccp_header_file)

    def makeup_data(keylist):
        return [ReadFromCppHeader(key) for key in keylist]

    blockWrite(ccp_header["gpo_data_15_to_0"], makeup_data(configDesignVals))
    blockWrite(ccp_header["port_cfg_00"], makeup_data(portConfigDesignVals))
    blockWrite(ccp_header["dac_data_port_00"], makeup_data(dacDesignVals))
Exemple #7
0
class SpiCsForceTestCase(unittest.TestCase):
    """Basic test for exercing direct /CS control.

       It requires a scope or a digital analyzer to validate the signal
       waveforms.
    """
    @classmethod
    def setUpClass(cls):
        cls.url = environ.get('FTDI_DEVICE', 'ftdi:///1')
        cls.debug = to_bool(environ.get('FTDI_DEBUG', 'off'))

    def setUp(self):
        self._spi = SpiController(cs_count=1)
        self._spi.configure(self.url, debug=self.debug)
        self._port = self._spi.get_port(0, freq=1E6, mode=0)

    def tearDown(self):
        """Close the SPI connection"""
        self._spi.terminate()

    def test_cs_default_pulse(self):
        for _ in range(5):
            self._port.force_select()

    def test_cs_long_pulse(self):
        for _ in range(5):
            self._port.force_select(cs_hold=200)

    def test_cs_manual_pulse(self):
        for _ in range(5):
            self._port.force_select(level=False)
            self._port.force_select(level=True)
            # beware that random USB bus access does not allow to create
            # precise delays. This is only the shorter bound, longer one is
            # not defined
            sleep(100e-6)

    def test_cs_pulse_write(self):
        self._port.force_select()
        self._port.write([0x00, 0x01, 0x02])

    def test_cs_default_pulse_rev_clock(self):
        if not self._spi.is_inverted_cpha_supported:
            self.skipTest('FTDI does not support mode 3')
        self._port.set_mode(3)
        for _ in range(5):
            self._port.force_select()
def main(argv):
    """
    Entry point for bmp280-monitor.py

    Arguments:
        argv: command line arguments
    """

    now = datetime.utcnow().strftime('%FT%TZ')
    args = process_arguments(argv)

    # Connect to the sensor.
    ctrl = SpiController()
    ctrl.configure(args.device)
    spi = ctrl.get_port(Port[args.cs].value)
    spi.set_frequency(args.frequency)
    try:
        bmp280 = Bmp280spi(spi)
    except RuntimeError as err:
        print(err)
        sys.exit(1)

    if '{}' in args.path:
        filename = args.path.format(now)
    else:
        filename = args.path

    # Write datafile header.
    with open(filename, 'a') as datafile:
        datafile.write(
            '# BMP280 data.\n# Started monitoring at {}.\n'.format(now))
        datafile.write('# Per line, the data items are:\n')
        datafile.write('# * UTC date and time in ISO8601 format\n')
        datafile.write('# * Temperature in °C\n')
        datafile.write('# * Pressure in Pa\n')

    # Read and write the data.
    try:
        while True:
            now = datetime.utcnow().strftime('%FT%TZ')
            temperature, pressure = bmp280.read()
            line = '{} {:.2f} {:.0f}\n'.format(now, temperature, pressure)
            with open(filename, 'a') as datafile:
                datafile.write(line)
            time.sleep(args.interval)
    except KeyboardInterrupt:
        sys.exit(1)
Exemple #9
0
def ftdi_spi(device='ftdi://::/1',
             bus_speed_hz=12000000,
             gpio_CS=3,
             gpio_DC=5,
             gpio_RST=6):
    """
    Bridges an `SPI <https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus>`_
    (Serial Peripheral Interface) bus over an FTDI USB device to provide :py:func:`data` and
    :py:func:`command` methods.

    :param device: A URI describing the location of the FTDI device. If ``None`` is
        supplied (default), ``ftdi://::/1`` is used. See `pyftdi <https://pypi.python.org/pypi/pyftdi>`_
        for further details of the naming scheme used.
    :type device: string
    :param bus_speed_hz: SPI bus speed, defaults to 12MHz.
    :type bus_speed_hz: int
    :param gpio_CS: The ADx pin to connect chip select (CS) to (defaults to 3).
    :type gpio_CS: int
    :param gpio_DC: The ADx pin to connect data/command select (DC) to (defaults to 5).
    :type gpio_DC: int
    :param gpio_RST: The ADx pin to connect reset (RES / RST) to (defaults to 6).
    :type gpio_RST: int

    .. versionadded:: 1.9.0
    """
    from pyftdi.spi import SpiController

    controller = SpiController(cs_count=1)
    controller.configure(device)

    slave = controller.get_port(cs=gpio_CS - 3, freq=bus_speed_hz, mode=0)
    gpio = controller.get_gpio()

    # RESET and DC configured as outputs
    pins = _ftdi_pin(gpio_RST) | _ftdi_pin(gpio_DC)
    gpio.set_direction(pins, pins & 0xFF)

    serial = spi(__FTDI_WRAPPER_SPI(controller, slave),
                 __FTDI_WRAPPER_GPIO(gpio),
                 gpio_DC=gpio_DC,
                 gpio_RST=gpio_RST)
    serial._managed = True
    return serial
Exemple #10
0
class PanelControl(object):

	def __init__(self, spi_frequency=5e6):
		# Params
		self.spi_frequency = spi_frequency

		# SPI link
		self.spi = SpiController(cs_count=3)
		self.spi.configure('ftdi://ftdi:2232h/1')
		self.slave = self.spi.get_port(cs=2, freq=self.spi_frequency, mode=0)

	def reg_w16(self, reg, v):
		self.slave.exchange([reg, v >> 8, v & 0xff])

	def reg_w8(self, reg, v):
		self.slave.exchange([reg, v])

	def read_status(self):
		rv = self.slave.exchange([0x00, 0x00], duplex=True)
		return rv[0] | rv[1]

	def send_data(self, data):
		self.slave.exchange([0x80] + data)

	def send_frame(self, frame, width=64, height=64, bits=16):
		# Size of a line
		ll = width * bits // 8

		# Scan all line
		for y in range(height):
			# Send write command to line buffer
			self.send_data(list(frame[y*ll:(y+1)*ll]))

			# Swap line buffer & Write it to line y of back frame buffer
			self.reg_w8(0x03, y)

		# Send frame swap command
		panel.reg_w8(0x04, 0x00)

		# Wait for the frame swap to occur
		while (panel.read_status() & 0x02 == 0):
			pass
Exemple #11
0
class SpiAccelTest(object):
    """Basic test for an ADXL345 device selected as CS1,
       SPI mode 3
    """
    def __init__(self):
        self._spi = SpiController()

    def open(self):
        """Open an I2c connection to a slave"""
        self._spi.configure('ftdi://ftdi:2232h/1')

    def read_device_id(self):
        port = self._spi.get_port(1, freq=6E6, mode=3)
        device_id = port.exchange([0x00], 1).tobytes()
        hex_device_id = hexlify(device_id).decode()
        print('DEVICE ID:', hex_device_id)
        return hex_device_id

    def close(self):
        """Close the I2C connection"""
        self._spi.terminate()
Exemple #12
0
class SpiDataFlashTest(object):
    """Basic test for a MX25L1606E data flash device selected as CS0,
       SPI mode 0
    """
    def __init__(self):
        self._spi = SpiController()

    def open(self):
        """Open an I2c connection to a slave"""
        self._spi.configure('ftdi://ftdi:2232h/1')

    def read_jedec_id(self):
        port = self._spi.get_port(0, freq=3E6, mode=0)
        jedec_id = port.exchange([0x9f], 3).tobytes()
        hex_jedec_id = hexlify(jedec_id).decode()
        print('JEDEC ID:', hex_jedec_id)
        return hex_jedec_id

    def close(self):
        """Close the I2C connection"""
        self._spi.terminate()
Exemple #13
0
class SpiRfda2125Test(object):
    """Basic test for a RFDA2125 Digital Controlled Variable Gain Amplifier
       selected as CS2,
       SPI mode 0
    """
    def __init__(self):
        self._spi = SpiController()

    def open(self):
        """Open an I2c connection to a slave"""
        self._spi.configure('ftdi://ftdi:2232h/1')
        self._port = self._spi.get_port(2, freq=1E6, mode=0)

    def change_attenuation(self, value):
        if not (0.0 <= value <= 31.5):
            print('Out-of-bound attenuation', file=stderr)
        intval = 63 - int(value * 2)
        self._port.write(bytes([intval]), 1)

    def close(self):
        """Close the I2C connection"""
        self._spi.terminate()
Exemple #14
0
class SpiAccelTest(object):
    """Basic test for an ADXL345 device selected as CS1,
       SPI mode 3
    """

    def __init__(self):
        self._spi = SpiController(cs_count=3)

    def open(self):
        """Open an SPI connection to a slave"""
        url = environ.get('FTDI_DEVICE', 'ftdi://ftdi:2232h/1')
        self._spi.configure(url)

    def read_device_id(self):
        port = self._spi.get_port(1, freq=6E6, mode=3)
        device_id = port.exchange([0x00], 1).tobytes()
        hex_device_id = hexlify(device_id).decode()
        print('DEVICE ID:', hex_device_id)
        return hex_device_id

    def close(self):
        """Close the SPI connection"""
        self._spi.terminate()
Exemple #15
0
class SpiDataFlashTest:
    """Basic test for a MX25L1606E data flash device selected as CS0,
       SPI mode 0
    """
    def __init__(self):
        self._spi = SpiController(cs_count=3)

    def open(self):
        """Open an SPI connection to a slave"""
        url = environ.get('FTDI_DEVICE', 'ftdi:///1')
        debug = to_bool(environ.get('FTDI_DEBUG', 'off'))
        self._spi.configure(url, debug=debug)

    def read_jedec_id(self):
        port = self._spi.get_port(0, freq=3E6, mode=0)
        jedec_id = port.exchange([0x9f], 3)
        hex_jedec_id = hexlify(jedec_id).decode()
        print('JEDEC ID:', hex_jedec_id)
        return hex_jedec_id

    def close(self):
        """Close the SPI connection"""
        self._spi.terminate()
Exemple #16
0
class SpiAccelTest:
    """Basic test for an ADXL345 device selected as CS1,
       SPI mode 3
    """
    def __init__(self):
        self._spi = SpiController(cs_count=3)

    def open(self):
        """Open an SPI connection to a slave"""
        url = environ.get('FTDI_DEVICE', 'ftdi:///1')
        debug = to_bool(environ.get('FTDI_DEBUG', 'off'))
        self._spi.configure(url, debug=debug)

    def read_device_id(self):
        port = self._spi.get_port(1, freq=6E6, mode=3)
        device_id = port.exchange([0x00], 1)
        hex_device_id = hexlify(device_id).decode()
        print('DEVICE ID:', hex_device_id)
        return hex_device_id

    def close(self):
        """Close the SPI connection"""
        self._spi.terminate()
Exemple #17
0
class SpiDataFlashTest(object):
    """Basic test for a MX25L1606E data flash device selected as CS0,
       SPI mode 0
    """

    def __init__(self):
        self._spi = SpiController(cs_count=3)

    def open(self):
        """Open an SPI connection to a slave"""
        url = environ.get('FTDI_DEVICE', 'ftdi://ftdi:2232h/1')
        self._spi.configure(url)

    def read_jedec_id(self):
        port = self._spi.get_port(0, freq=3E6, mode=0)
        jedec_id = port.exchange([0x9f], 3).tobytes()
        hex_jedec_id = hexlify(jedec_id).decode()
        print('JEDEC ID:', hex_jedec_id)
        return hex_jedec_id

    def close(self):
        """Close the SPI connection"""
        self._spi.terminate()
Exemple #18
0
class BoardControlBase(object):
    def __init__(self,
                 addr='ftdi://ftdi:2232h/1',
                 spi_frequency=30e6,
                 spi_cs=None):
        # SPI link
        self.spi_frequency = spi_frequency
        self.spi = SpiController(cs_count=3)
        self.spi.configure(addr)

        if spi_cs is not None:
            self.slave = self.spi.get_port(cs=spi_cs,
                                           freq=self.spi_frequency,
                                           mode=0)
        else:
            self.slave = self._spi_probe()

    def _spi_probe(self):
        for cs in [0, 2]:
            port = self.spi.get_port(cs=cs, freq=self.spi_frequency, mode=0)
            r = port.exchange(b'\x00', duplex=True)[0]
            if r != 0xff:
                return port
        raise RunttimeError('Automatic SPI CS probe failed')

    def reg_w16(self, reg, v):
        self.slave.exchange(struct.pack('>BH', reg, v))

    def reg_w8(self, reg, v):
        self.slave.exchange(struct.pack('>BB', reg, v))

    def reg_burst(self, reg, data):
        self.slave.exchange(bytearray([reg]) + data)

    def read_status(self):
        rv = self.slave.exchange(bytearray(2), duplex=True)
        return rv[0] | rv[1]
Exemple #19
0
class SpiRfda2125Test(object):
    """Basic test for a RFDA2125 Digital Controlled Variable Gain Amplifier
       selected as CS2,
       SPI mode 0
    """

    def __init__(self):
        self._spi = SpiController(cs_count=3)

    def open(self):
        """Open an SPI connection to a slave"""
        url = environ.get('FTDI_DEVICE', 'ftdi://ftdi:2232h/1')
        self._spi.configure(url)
        self._port = self._spi.get_port(2, freq=1E6, mode=0)

    def change_attenuation(self, value):
        if not (0.0 <= value <= 31.5):
            print('Out-of-bound attenuation', file=stderr)
        intval = 63-int(value*2)
        self._port.write(bytes([intval]), 1)

    def close(self):
        """Close the SPI connection"""
        self._spi.terminate()
Exemple #20
0
def lecture_rx():
    rx_len = read_one(0x13)  #REG_13_RX_NB_BYTES -> taille du packet recu
    cur_adr = read_one(0x10)  #REG_10_FIFO_RX_CURRENT_ADDR
    print("RX_LEN: %s - CUR_ADR: %s" % (str(rx_len), hex(cur_adr)))
    write_one(0x0d, cur_adr)  #REG_0D_FIFO_ADDR_PTR "FIFO SPI pointer"
    out = slave.exchange([0x00], rx_len)  #REG_00_FIFO = 0x00 "FIFO r/w access"
    if chr(
            out[0]
    ) == 's':  #protection par lecture du premier byte (pour ne pas Rx des msgs d'autres senders
        print(out)


#initialisation SPI
spi = SpiController()
spi.configure('ftdi://ftdi:2232h/1')
slave = spi.get_port(cs=0, freq=10E6, mode=0)

print("OP_MODE=", format(read_one(0x01), '#010b'))
write_one(
    0x01, 0x80
)  #0x01 = REG_01_OP_MODE -> 0b10000000 -> long range mode (LoRa) (p 108 )
#sleep(0.1)
write_one(0x01, 0x01)  #mode STDBY (p108)
#sleep(0.1)

#set frequency
frf = int((frf * 1000000.0) / FSTEP)
write_one(0x06, (frf >> 16) & 0xff)
write_one(0x07, (frf >> 8) & 0xff)
write_one(0x08, frf & 0xff)
Exemple #21
0
    return get_status(device) & SR_WIP


if len(sys.argv) < 2:
    print("Usage: raptor_flash.py <file>")
    sys.exit()

file_path = sys.argv[1]

if not os.path.isfile(file_path):
    print("File not found.")
    sys.exit()

spi = SpiController(cs_count=1, turbo=True)
# spi.configure(vendor=0x0403, product=0x6014, interface=1)
spi.configure('ftdi://::/1')
slave = spi.get_port(cs=0, freq=12E6,
                     mode=0)  # Chip select is 0 -- corresponds to D3

slave.write([CMD_RESET_CHIP])

jedec = slave.exchange([CMD_JEDEC_DATA], 3)
print("JEDEC = {}".format(binascii.hexlify(jedec)))

if jedec[0:1] != bytes.fromhex('ef'):
    print("Winbond SRAM not found")
    sys.exit()

report_status(jedec)

print("Erasing chip...")
Exemple #22
0
class SpiGpioTestCase(unittest.TestCase):
    """Basic test for GPIO access w/ SPI mode

       It expects the following I/O setup:

       AD4 connected t0 AC0
       AD5 connected t0 AC1
       AD6 connected t0 AC2
       AD7 connected t0 AC3
    """

    # AD0: SCLK, AD1: MOSI, AD2: MISO, AD3: /CS
    AD_OFFSET = 4
    AC_OFFSET = 8
    PIN_COUNT = 4

    def setUp(self):
        self._spi = SpiController(cs_count=1)
        url = environ.get('FTDI_DEVICE', 'ftdi://ftdi:2232h/1')
        self._spi.configure(url)
        self._port = self._spi.get_port(0, freq=1E6, mode=0)
        self._io = self._spi.get_gpio()

    def tearDown(self):
        """Close the SPI connection"""
        self._spi.terminate()

    def test_ac_to_ad(self):
        ad_pins = ((1 << self.PIN_COUNT) - 1) << self.AD_OFFSET  # input
        ac_pins = ((1 << self.PIN_COUNT) - 1) << self.AC_OFFSET  # output
        io_pins = ad_pins | ac_pins

        def ac_to_ad(ac_output):
            ac_output &= ac_pins
            ac_output >>= self.AC_OFFSET - self.AD_OFFSET
            return ac_output & ad_pins

        self._io.set_direction(io_pins, ac_pins)
        for ac in range(1 << self.PIN_COUNT):
            ac_out = ac << self.AC_OFFSET
            ad_in = ac_to_ad(ac_out)
            self._io.write(ac_out)
            # random SPI exchange to ensure SPI does not change GPIO
            self._port.exchange([0x00, 0xff], 2)
            rd = self._io.read()
            self.assertEqual(rd, ad_in)
        self.assertRaises(SpiIOError, self._io.write, ad_pins)

    def test_ad_to_ac(self):
        ad_pins = ((1 << self.PIN_COUNT) - 1) << self.AD_OFFSET  # output
        ac_pins = ((1 << self.PIN_COUNT) - 1) << self.AC_OFFSET  # input
        io_pins = ad_pins | ac_pins

        def ad_to_ac(ad_output):
            ad_output &= ad_pins
            ad_output <<= self.AC_OFFSET - self.AD_OFFSET
            return ad_output & ac_pins

        self._io.set_direction(io_pins, ad_pins)
        for ad in range(1 << self.PIN_COUNT):
            ad_out = ad << self.AD_OFFSET
            ac_in = ad_to_ac(ad_out)
            self._io.write(ad_out)
            # random SPI exchange to ensure SPI does not change GPIO
            self._port.exchange([0x00, 0xff], 2)
            rd = self._io.read()
            self.assertEqual(rd, ac_in)
        self.assertRaises(SpiIOError, self._io.write, ac_pins)
Exemple #23
0
import time
import sys
from pyftdi.spi import SpiController
from pyftdi.gpio import GpioSyncController
import FTDISPI


spiAdc = SpiController()
spiAdc.configure('ftdi:///1')
slaveAdc = spiAdc.get_port( \
    cs=0, \
    freq=1e6, \
    mode=0 \
)
adc = FTDISPI.Interface( \
    FTDISPI.MPSSE(slaveAdc), \
    defaultMap  = "ADC12DJ3200.json", \
    currentState = "ADC12DJ3200_current_state.json", \
    previousState = "ADC12DJ3200_previous_state.json",
)


# adc.writeCSV(sys.argv[1])
# print("*** ADC ***")
# adc.readState()

FTDISPI.uiLoop(adc)
Exemple #24
0
def main():
    done_stdin = False
    parser = argparse.ArgumentParser(
        prog="spitest",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        usage=USAGE,
        description=__doc__)
    parser.add_argument('--version',
                        action='store_true',
                        help='Show version and exit')
    parser.add_argument('-v',
                        '--verbose',
                        action='store_true',
                        help='Verbose output during processing')
    parser.add_argument(
        '-f',
        '--flippy',
        action='store_true',
        help='Flip the SPI/JTAG control GPIO 10 times and exit')
    parser.add_argument(
        '-l',
        '--length',
        type=int,
        action='store',
        help='Construct and send a message of specified length')
    parser.add_argument('-j',
                        '--jtag',
                        action='store_true',
                        help='Set SPI/JTAG control to JTAG and exit')
    parser.add_argument('message',
                        nargs='*',
                        metavar='input',
                        default='1234',
                        help='message to send in 4 byte chunks')
    args = parser.parse_args()

    if args.version:
        show_and_exit(__file__, ["pyftdi"])

    if (args.verbose):
        log.basicConfig(format="%(levelname)s: %(message)s", level=log.DEBUG)
    else:
        log.basicConfig(format="%(levelname)s: %(message)s")

    # Instanciate a SPI controller
    spi = SpiController(cs_count=1)

    # interfaces start from 1 here, so this is Channel A (called 0 in jtag)
    spi.configure('ftdi://ftdi:2232h/1')

    # Get a port to a SPI slave w/ /CS on A*BUS3 and SPI mode 0 @ 1MHz
    slave = spi.get_port(cs=0, freq=1E6, mode=0)

    # Get GPIO port to manage extra pins
    # BUS4 = JTAG TRST_N, BUS5 = JTAG SRST_N, BUS6 = JTAG_SPIN
    # Note: something makes FTDI default to BUS6 low, selected that for SPI
    # otherwise SRST being default low holds the chip in reset
    # pyftdi Set Direction also forces the output to zero
    # so initially make SRST an input w/pullup in FPGA in case SPI/JTAG was
    # initially JTAG
    gpio = spi.get_gpio()
    gpio.set_direction(0x40, 0x40)
    time.sleep(1)
    gpio.set_direction(0x70, 0x70)

    if args.jtag:
        gpio.write(0x70)
        return

    gpio.write(0x30)

    if args.flippy:
        for i in range(10):
            print("Select SPI")
            gpio.write(0x30)
            time.sleep(2)
            print("Select JTAG")
            gpio.write(0x70)
            time.sleep(2)
        return

    print("Select SPI")
    gpio.write(0x30)
    # Synchronous exchange with the remote SPI slave
    if args.length:
        s = ''
        for i in range(args.length):
            s += hex(i & 15)[-1]
    else:
        s = ''
        for m in args.message:
            s += m + ' '
            s = s[:-1]  # remove extra space put on end
        # pad to ensure multiple of 4 bytes
        filled = len(s) % 4
        if filled:
            s += '....'[filled:]

    while len(s):
        write_buf = bytes(s[:4], encoding='utf8')
        read_buf = slave.exchange(write_buf, duplex=True).tobytes()
        print("Got " + str(read_buf))
        s = s[4:]
Exemple #25
0
class SpiData93LC56BTest(object):
    """Basic class for a Microchip 93LC56B data flash device selected as CS0,
       SPI mode 0, Active High polarity for CS and Bi-directional data.

       Test setup: UM232H connected to the EEPROM on a FT4232H-56Q
       Mini Module. The FT4232H is forced into reset by connecting the
       RT# pin (CN2-8) to GND (CN2-6). Then make the following
       connections between the boards:

       UM232H       FT4232H-56Q
       ======       ===========
       GND        - GND
       D0 (CN2-1) - ECL (CN3-6)
       D1 (CN2-2) - EDA (CN3-7)
       D2 (CN2-3) - EDA (CN3-7)
       D3 (CN2-4) - ECS (CN3-5)

       NOTE: D1 & D2 are indeed both tied to the same EDA pin.
    """
    def __init__(self):
        self._spi = SpiController(cs_count=1, cs_pol=0)
        self._freq = 1E6
        self._mode = 0
        self._bidir = True

        # Maximum number of read cycles to wait while looking for the
        # Ready status after each write
        self._write_timeout_cnt = 25

        # According to the datasheet, the maximum write time is 6 ms
        self._Twc = 0.006

        # The opcodes are a full byte to make it easy to use with the
        # byte interface of SpiController. These opcodes also include
        # the start bit (SB), which is simply the left-most '1'
        # bit. The actual 2-bit opcode (OC) follows this start bit.
        #
        # The instructions ERAL, EWDS, EWEN and WRAL require a special
        # address byte to complete the opcode. So they are 2 element
        # lists whereas the others are single element lists.
        self._SBOC_erase = [0x07]
        self._SBOC_eral = [0x04, 0x80]  # requires EEPROM Vcc >= 4.5V
        self._SBOC_ewds = [0x04, 0x00]
        self._SBOC_ewen = [0x04, 0xc0]
        self._SBOC_read = [0x06]
        self._SBOC_write = [0x05]
        self._SBOC_wral = [0x04, 0x40]  # requires EEPROM Vcc >= 4.5V

    def open(self):
        """Open an SPI connection to a slave"""
        url = environ.get('FTDI_DEVICE', 'ftdi://ftdi:232h/1')
        self._spi.configure(url)

    def read_word(self, addr):
        # NOTE: Using SPI Mode 0. This really should have the FTDI
        # clock the read bits in on the rising edge, at least based on
        # my understanding of SPI. However, spi.py reads the bits on
        # the falling edge of the clock. For the 93LC56B, this is
        # exactly what we want. However, if spi.py ever gets changed,
        # will need to do writes and reads seperately with reads in
        # SPI Mode 1.
        port = self._spi.get_port(0,
                                  freq=self._freq,
                                  mode=self._mode,
                                  bidir=self._bidir)

        # byteswap() is to handle little endian data
        word = port.exchange(self._SBOC_read + [(addr & 0xFF)], 2)
        word = word.byteswap().tobytes()

        return word

    def read_all(self, readlen):
        # NOTE: Using SPI Mode 0. This really should have the FTDI
        # clock the read bits in on the rising edge, at least base don
        # my understanding of SPI. However, spi.py reads the bits on
        # the falling edge of the clock. For the 93LC56B, this is
        # exactly what we want. However, if spi.py ever gets changed,
        # will need to do writes and reads seperately with reads in
        # SPI Mode 1.
        port = self._spi.get_port(0,
                                  freq=self._freq,
                                  mode=self._mode,
                                  bidir=self._bidir)

        # readlen is byte len but extend it to the nearest 16-bit
        # boundary.
        readlen = ((readlen + 1) // 2) * 2
        data = port.exchange(self._SBOC_read + [0x00], readlen)

        # byte swap to handle data in little endian (from:
        # https://stackoverflow.com/questions/36096292/
        #         efficient-way-to-swap-bytes-in-python)
        data[0::2], data[1::2] = data[1::2], data[0::2]

        #print('DATA: ', data)
        #words = spack('H'*(len(data)//2), data)

        return data.tobytes()

    def write_word(self, addr, word):
        port = self._spi.get_port(0,
                                  freq=self._freq,
                                  mode=self._mode,
                                  bidir=self._bidir)

        # Must first enable Erase/Write
        port.exchange(self._SBOC_ewen)

        # Send the word, LSB first (little endian)
        port.exchange(self._SBOC_write +
                      [(addr & 0xFF), word & 0x0000ff, (word & 0x00ff00) >> 8])

        # Wait the write time
        sleep(self._Twc)

        # send a stop condition if sent at least 1 read with stop
        # False. Data is thrown away.
        status = port.read(1)
        print('Status: {}'.format(status))

        # Check the last bit of the last byte to make sure it is high
        # for Ready
        if ((status[-1] & 0x01) == 0x00):
            raise SpiIOError('ERROR: SPI Write never completed!')

        # Now disable Erase/Write since done with this write
        port.exchange(self._SBOC_ewds)

    # Write multiple bytes starting at byte address, addr. Length of
    # data must be a multiple of 2 since the EEPROM is 16-bits. So
    # extend data by 1 byte if this is not the case.
    def write(self, addr, data):

        if not isinstance(data, bytes):
            data = data.tobytes()

        # If addr is odd, raise an exception since it must be even
        if (addr & 0x01):
            err = "write addr must be even - the EEPROM is a 16-bit device"
            raise SpiIOError(err)

        wd_addr = (addr >> 1)  # convert to word address

        # if the byte data is an odd number of bytes, force it to be
        # on 16-bit divisions
        if (len(data) & 0x01):
            err = "data length must be even - the EEPROM is a 16-bit device"
            raise SpiIOError(err)

        port = self._spi.get_port(0,
                                  freq=self._freq,
                                  mode=self._mode,
                                  bidir=self._bidir)

        # Must first enable Erase/Write
        port.exchange(self._SBOC_ewen)

        for idx in range(0, len(data), 2):
            # Send the word, MSB first
            port.exchange(self._SBOC_write +
                          [(wd_addr & 0xFF), data[idx + 1], data[idx]])

            # Wait the write time
            sleep(self._Twc)

            # send a stop condition if sent at least 1 read with stop
            # False. Data is thrown away.
            status = port.read(1)

            # Check the last bit of the last byte to make sure it is
            # high for Ready
            if ((status[-1] & 0x01) == 0x00):
                print('ERROR: Last write never completed! Aborting!')
                break

            # increment to the next word address
            wd_addr += 1

        # Now disable Erase/Write since done with this write
        port.exchange(self._SBOC_ewds)

    def close(self):
        """Close the SPI connection"""
        self._spi.terminate()
Exemple #26
0
class SPI:
    MSB = 0

    baudrate = 100000
    mode = 0
    bits = 8

    def __init__(self):
        # change GPIO controller to SPI
        from pyftdi.spi import SpiController
        self._spi = SpiController(cs_count=1)
        self._spi.configure('ftdi:///1')
        Pin.ft232h_gpio = self._spi.get_gpio()

    def init(self,
             baudrate=100000,
             polarity=0,
             phase=0,
             bits=8,
             firstbit=MSB,
             sck=None,
             mosi=None,
             miso=None):
        self.cs = 0
        self.freq = baudrate
        if polarity == 0 and phase == 0:
            self.mode = 0
        elif polarity == 0 and phase == 1:
            self.mode = 1
        elif polarity == 1 and phase == 0:
            raise ValueError("SPI mode 2 is not supported.")
        elif polarity == 1 and phase == 1:
            self.mode = 3
        else:
            raise ValueError("Unknown SPI mode.")

    def write(self, buf, start=0, end=None):
        end = end if end else len(buf)
        port = self._spi.get_port(self.cs, self.freq, self.mode)
        port.write(buf[start:end])

    def readinto(self, buf, start=0, end=None, write_value=0):
        end = end if end else len(buf)
        port = self._spi.get_port(self.cs, self.freq, self.mode)
        result = port.read(end - start)
        for i, b in enumerate(result):
            buf[start + i] = b

    def write_readinto(self,
                       buffer_out,
                       buffer_in,
                       out_start=0,
                       out_end=None,
                       in_start=0,
                       in_end=None):
        out_end = out_end if out_end else len(buffer_out)
        in_end = in_end if in_end else len(buffer_in)
        port = self._spi.get_port(self.cs, self.freq, self.mode)
        result = port.exchange(buffer_out[out_start:out_end],
                               in_end - in_start)
        for i, b in enumerate(result):
            buffer_in[in_start + i] = b
Exemple #27
0
class SerialFlashManager(object):
    """Serial flash manager.

       Automatically detects and instanciate the proper flash device class
       based on the JEDEC identifier which is read out from the device itself.
    """

    CMD_JEDEC_ID = 0x9F

    def __init__(self, vendor, product, interface=1):
        self._ctrl = SpiController(silent_clock=False)
        self._ctrl.configure(vendor, product, interface)

    def get_flash_device(self, cs=0):
        """Obtain an instance of the detected flash device"""
        spi = self._ctrl.get_port(cs)
        jedec = SerialFlashManager.read_jedec_id(spi)
        if not jedec:
            # it is likely that the latency setting is too low if this
            # condition is encountered
            raise SerialFlashUnknownJedec("Unable to read JEDEC Id")
        return SerialFlashManager._get_flash(spi, jedec)

    @staticmethod
    def read_jedec_id(spi):
        """Read flash device JEDEC identifier (3 bytes)"""
        jedec_cmd = Array('B', [SerialFlashManager.CMD_JEDEC_ID])
        return spi.exchange(jedec_cmd, 3).tostring()

    @staticmethod
    def _get_flash(spi, jedec):
		contents = sys.modules[__name__].__dict__
		devices = []
		plugin_dir = os.path.dirname(os.path.realpath(__file__))
		plugin_files = [x[:-3] for x in os.listdir(plugin_dir) if (x.endswith(".py") and not x.startswith("__init__"))]
		sys.path.insert(0, plugin_dir)
		for p in plugin_files:
			mod = __import__(p)
#			print "mod: " + str(mod)

			sf = getattr(mod, "SerialFlash")

#			for sp in sf.__subclasses__():
#				print "subclass: " + str(sp)


#			print "plugin file: " + str(p)
#			print "sf: " + str(sf)

			for name in dir (mod):
				if name.startswith('_'):
					continue
				obj = getattr(mod, name)

				if obj not in sf.__subclasses__():
					continue

#				for p in SerialFlash.__subclasses__():
#					print "subclass: " + p

#				print "name: " + name
#				print "base classes: " + str(inspect.getmro(obj))


#				print "\tclass: %s is class %s" % (str(obj), str(SerialFlash))

#				if not isinstance (obj, SerialFlash):
#					continue


#				if ("SerialFlash" in str(inspect.getmro(obj))):
#					print "found subclass"
#
#				for bn in inspect.getmro(obj):
#					print "base name: " + str(bn)

#
#				print "type: " + str(type(obj))
#				print "sf type: " + str(type(SerialFlash))
#

#				if  isclass(obj) and issubclass(obj, SerialFlash) and obj is not SerialFLash :
#				if  isclass(obj) and "SerialFLash" not in str(obj) :
#				print "\t\tappend name: " + name
				devices.append(obj)


		for device in devices:
			if device.match(jedec):
				return device(spi, jedec)
		raise SerialFlashUnknownJedec(jedec)
Exemple #28
0
import sys
import time
from os import environ
from binascii import hexlify
from typing import Iterable, Optional, Tuple, Union
import numpy as np
from pyftdi.misc import pretty_size
from pyftdi.spi import SpiController, SpiPort

#  ftdi://ftdi:232h:2:11/1   (UPduino v3.0)
ftdi_url = environ.get('FTDI_DEVICE', 'ftdi://::/1')
print('Using FTDI device %s' % ftdi_url)
ctrl = SpiController(cs_count=2)
ctrl.configure(ftdi_url)
spi_freq = 1e6
spi1 = ctrl.get_port(cs=1, freq=spi_freq, mode=0)
spi0 = ctrl.get_port(cs=0, freq=spi_freq, mode=0)
#gpio = ctrl.get_gpio()
#gpio.set_direction(0x80, 0x80)

# Reset the FPGA and get the Flash ID
#gpio.write(0x00)
#time.sleep(0.1)
#spi1.exchange([0xAB], 1) # Wake up the flash
#jedec_id = spi1.exchange([0x9f,], 3)
#print(jedec_id)
#spi1.exchange([0xB9], 1) # Put the flash to sleep

# Release from reset
#gpio.write(0x80)
#gpio.set_direction(0x0, 0x0)
Exemple #29
0
class SpiUnalignedTestCase(unittest.TestCase):
    """Basic test for SPI with non 8-bit multiple transfer

       It expects the following I/O setup:

       MOSI (AD1) connected to MISO (AD2)
    """
    @classmethod
    def setUpClass(cls):
        cls.url = environ.get('FTDI_DEVICE', 'ftdi:///1')
        cls.debug = to_bool(environ.get('FTDI_DEBUG', 'off'))

    def setUp(self):
        self._spi = SpiController(cs_count=1)
        self._spi.configure(self.url, debug=self.debug)
        self._port = self._spi.get_port(0, freq=1E6, mode=0)

    def tearDown(self):
        """Close the SPI connection"""
        self._spi.terminate()

    def test_invalid_write(self):
        buf = b'\xff\xff'
        self.assertRaises(ValueError, self._port.write, buf, droptail=8)

    def test_bit_write(self):
        buf = b'\x0f'
        for loop in range(7):
            self._port.write(buf, droptail=loop + 1)

    def test_bytebit_write(self):
        buf = b'\xff\xff\x0f'
        for loop in range(7):
            self._port.write(buf, droptail=loop + 1)

    def test_invalid_read(self):
        self.assertRaises(ValueError, self._port.read, 1, droptail=8)
        self.assertRaises(ValueError, self._port.read, 2, droptail=8)

    def test_bit_read(self):
        # make MOSI stay to low level, so MISO samples 0
        self._port.write([0x00])
        for loop in range(7):
            data = self._port.read(1, droptail=loop + 1)
            self.assertEqual(len(data), 1)
        # make MOSI stay to high level, so MISO samples 1
        self._port.write([0x01])
        for loop in range(7):
            data = self._port.read(1, droptail=loop + 1)
            self.assertEqual(len(data), 1)

    def test_bytebit_read(self):
        self._port.write([0x00])
        for loop in range(7):
            data = self._port.read(3, droptail=loop + 1)
            self.assertEqual(len(data), 3)
            self.assertEqual(data[-1], 0)
        self._port.write([0x01])
        for loop in range(7):
            data = self._port.read(3, droptail=loop + 1)
            self.assertEqual(len(data), 3)

    def test_invalid_duplex(self):
        buf = b'\xff\xff'
        self.assertRaises(ValueError,
                          self._port.exchange,
                          buf,
                          duplex=False,
                          droptail=8)
        self.assertRaises(ValueError,
                          self._port.exchange,
                          buf,
                          duplex=False,
                          droptail=8)
        self.assertRaises(ValueError,
                          self._port.exchange,
                          buf,
                          duplex=True,
                          droptail=8)
        self.assertRaises(ValueError,
                          self._port.exchange,
                          buf,
                          duplex=True,
                          droptail=8)

    def test_bit_duplex(self):
        buf = b'\xcf'
        for loop in range(7):
            data = self._port.exchange(buf, duplex=True, droptail=loop + 1)
            self.assertEqual(len(data), 1)
            exp = buf[0] & ~((1 << (loop + 1)) - 1)
            # print(f'{data[0]:08b} {exp:08b}')
            self.assertEqual(data[0], exp)

    def test_bytebit_duplex(self):
        buf = b'\xff\xcf'
        for loop in range(7):
            data = self._port.exchange(buf, duplex=True, droptail=loop + 1)
            self.assertEqual(len(data), 2)
            exp = buf[-1] & ~((1 << (loop + 1)) - 1)
            # print(f'{data[-1]:08b} {exp:08b}')
            self.assertEqual(data[0], 0xFF)
            self.assertEqual(data[-1], exp)
Exemple #30
0
class SPI:
    """Custom SPI Class for FT232H"""

    MSB = 0

    def __init__(self):
        # pylint: disable=import-outside-toplevel
        from pyftdi.spi import SpiController

        # pylint: enable=import-outside-toplevel

        self._spi = SpiController(cs_count=1)
        self._spi.configure(get_ftdi_url())
        self._port = self._spi.get_port(0)
        self._port.set_frequency(100000)
        self._port._cpol = 0
        self._port._cpha = 0
        # Change GPIO controller to SPI
        Pin.ft232h_gpio = self._spi.get_gpio()

    # pylint: disable=too-many-arguments,unused-argument
    def init(
        self,
        baudrate=100000,
        polarity=0,
        phase=0,
        bits=8,
        firstbit=MSB,
        sck=None,
        mosi=None,
        miso=None,
    ):
        """Initialize the Port"""
        self._port.set_frequency(baudrate)
        # FTDI device can only support mode 0 and mode 2
        # due to the limitation of MPSSE engine.
        # This means CPHA must = 0
        self._port._cpol = polarity
        if phase != 0:
            raise ValueError("Only SPI phase 0 is supported by FT232H.")
        self._port._cpha = phase

    # pylint: enable=too-many-arguments

    @property
    def frequency(self):
        """Return the current frequency"""
        return self._port.frequency

    def write(self, buf, start=0, end=None):
        """Write data from the buffer to SPI"""
        end = end if end else len(buf)
        chunks, rest = divmod(end - start, self._spi.PAYLOAD_MAX_LENGTH)
        for i in range(chunks):
            chunk_start = start + i * self._spi.PAYLOAD_MAX_LENGTH
            chunk_end = chunk_start + self._spi.PAYLOAD_MAX_LENGTH
            self._port.write(buf[chunk_start:chunk_end])
        if rest:
            rest_start = start + chunks * self._spi.PAYLOAD_MAX_LENGTH
            self._port.write(buf[rest_start:end])

    # pylint: disable=unused-argument
    def readinto(self, buf, start=0, end=None, write_value=0):
        """Read data from SPI and into the buffer"""
        end = end if end else len(buf)
        buffer_out = [write_value] * (end - start)
        result = self._port.exchange(buffer_out, end - start, duplex=True)
        for i, b in enumerate(result):
            buf[start + i] = b

    # pylint: enable=unused-argument

    # pylint: disable=too-many-arguments
    def write_readinto(self,
                       buffer_out,
                       buffer_in,
                       out_start=0,
                       out_end=None,
                       in_start=0,
                       in_end=None):
        """Perform a half-duplex write from buffer_out and then
        read data into buffer_in
        """
        out_end = out_end if out_end else len(buffer_out)
        in_end = in_end if in_end else len(buffer_in)
        result = self._port.exchange(buffer_out[out_start:out_end],
                                     in_end - in_start,
                                     duplex=True)
        for i, b in enumerate(result):
            buffer_in[in_start + i] = b
Exemple #31
0
class FtdiDevice:
    """FTDI FT2232H SPI master to access FPGA Control/Status Registers (CSR)
    plus some GPIO control.

    SPI parameters:
      - FTDI channel B:
        * BDBUS0 - SCLK
        * BDBUS1 - MOSI
        * BDBUS2 - MISO
        * BDBUS3 - CSn
      - slave;
      - mode 0 only;
      - most significant bit transmitted first;
      - byte order from high to low;
      - SCK frequency must at least 8 lower than system frequency.

    There are 2 types of SPI transactions:
      - incremental burst -- address increments internally after every data (array)
      - fixed burst -- one adreess, multiple data (FIFO)
    Transaction is done with 8-bit address and 16 bit data words.
    Transaction format:
      - control word (3 bytes):
          * bit 23 -- write (1) or read (0)
          * bit 22 -- burst incremental (1) or fixed (0)
          * bit 21 .. 8 -- 14 bit length (0 - 1 data word, 1 - 2 data words, etc)
          * bits 7 .. 0 -- 8 bit address
      - data word (2 bytes) 1 .. N:
          * bits 15 .. 0 -- data to be written or readen

    GPIO parameters:
      - ADBUS7 - output - active low reset for FPGA configuration (ICE_RESET)
      - BDBUS7 - output - active high reset for FPGA logic (ICE_RESET_FT)
    """

    GPIO_RESET_LOGIC_POS = 7
    GPIO_RESET_CONFIG_POS = 7

    def __init__(self, ftdi_url, spi_freq=1E6):
        """Configure the FTDI interface.

        Keyword arguments:
         ftdi_url -- device url, which can be obtained by Ftdi.show_devices()
         freq -- SPI frequency up to 8E6 (for FPGA running on 64 MHz)
        """
        # Configure SPI master
        self._spi_ctrl = SpiController()
        self._spi_ctrl.configure(ftdi_url + '2')  # second port - channel B
        self._spi_port = self._spi_ctrl.get_port(cs=0, freq=spi_freq, mode=0)
        # Configure FPGA logic reset (ICE_RESET_FT)
        self._spi_gpio = self._spi_ctrl.get_gpio()
        self._spi_gpio.set_direction(1 << self.GPIO_RESET_LOGIC_POS,
                                     1 << self.GPIO_RESET_LOGIC_POS)
        self._spi_gpio.write(0)
        # Configure FPGA configuration reset (ICE_RESET)
        self._gpio_ctrl = GpioAsyncController()
        self._gpio_ctrl.configure(
            ftdi_url + '1',  # first port - channel A
            direction=(1 << self.GPIO_RESET_CONFIG_POS),
            frequency=1e6,
            initial=(1 << self.GPIO_RESET_CONFIG_POS))
        self._gpio_ctrl.write(1 << self.GPIO_RESET_CONFIG_POS)

    def _int_to_bytes(self, i, length=2):
        """Convert integer to bytes"""
        return int.to_bytes(i, length=length, byteorder='big', signed=False)

    def _words_to_bytes(self, words_list):
        """Convert list with 16 bit words to bytes"""
        bytes_str_list = [self._int_to_bytes(w, length=2) for w in words_list]
        return b''.join(bytes_str_list)  # concatenate all strings

    def _bytes_to_words(self, bytes_str):
        """Convert bytes string to list with 16 bit words"""
        return [
            int.from_bytes(bytes_str[b * 2:b * 2 + 2],
                           byteorder='big',
                           signed=False) for b in range(len(bytes_str) // 2)
        ]

    def _prepare_ctrl_word(self, addr, len, burst, wr):
        """Prepare control word for exchange.

           Keyword arguments:
             addr -- 8 bit address
             len -- number of 16 bit data words to write/read (2^14 max)
             burst -- 'fixed' address the same for every data, 'incr' - address + 1 for every next data word
             wr -- 1 for write operation, 0 - for read
        """
        ctrl_word = 0
        ctrl_word |= (wr << 23)
        ctrl_word |= ((burst == 'incr') << 22)
        ctrl_word |= (((len - 1) & 0x3FFF) << 8)
        ctrl_word |= ((addr & 0xFF) << 0)
        return ctrl_word

    def spi_read(self, addr, len=1, burst='fixed'):
        """Read data from address via SPI.

           Keyword arguments:
             addr -- 8 bit address
             len -- number of 16 bit data words to write/read (2^14 max)
             burst -- 'fixed' address the same for every data, 'incr' - address + 1 for every next data word
           Return:
             list of size 'len' with 16 bit data words
        """
        ctrl_word = self._prepare_ctrl_word(addr, len, burst, wr=0)
        rbytes = self._spi_port.exchange(self._int_to_bytes(ctrl_word, 3),
                                         len * 2)
        return self._bytes_to_words(rbytes)

    def spi_write(self, addr, data, burst='fixed'):
        """Write data to address via SPI.

           Keyword arguments:
             addr -- 8 bit address
             data -- list with 16 bit data words to write (list length 2^14 max)
             burst -- 'fixed' address the same for every data, 'incr' - address + 1 for every next data word
         """
        ctrl_word = self._prepare_ctrl_word(addr, len(data), burst, wr=1)
        wbytes = self._int_to_bytes(ctrl_word, 3) + self._words_to_bytes(data)
        self._spi_port.exchange(wbytes)

    def reset_logic_on(self):
        """Activate reset pin ICE_RESET_FT"""
        self._spi_gpio.write((1 << self.GPIO_RESET_LOGIC_POS)
                             | self._spi_gpio.read())

    def reset_logic_off(self):
        """Deactivate reset pin ICE_RESET_FT"""
        self._spi_gpio.write(~(1 << self.GPIO_RESET_LOGIC_POS)
                             & self._spi_gpio.read())

    def reset_config_on(self):
        """Activate reset pin ICE_RESET"""
        self._gpio_ctrl.write(~(1 << self.GPIO_RESET_CONFIG_POS)
                              & self._gpio_ctrl.read())

    def reset_config_off(self):
        """Deactivate reset pin ICE_RESET"""
        self._gpio_ctrl.write((1 << self.GPIO_RESET_LOGIC_POS)
                              | self._gpio_ctrl.read())

    def close_connection(self):
        """Close FTDI interface"""
        self._spi_ctrl.terminate()
        self._gpio_ctrl.close()
import time
import sys
from pyftdi.spi import SpiController
import FTDISPI
import JSONFile




spi = SpiController()
spi.configure('ftdi:///2')
slave = spi.get_port( \
    cs=0, \
    freq=1e6, \
    mode=0 \
)
dac = FTDISPI.Interface( \
    FTDISPI.MPSSE(slave), \
    defaultMap  = "DAC38RF8x.json", \
    currentState = "DAC_current_state.json", \
    previousState = "DAC_previous_state.json",
)





def VCO_OK(Tj, LFVOLT):
    if (Tj >= 108 and (LFVOLT == 5 or LFVOLT == 6)):
        return True
    elif (Tj >= 92 and (LFVOLT == 4 or LFVOLT == 5)):
Exemple #33
0
class KU10405:
    """This class controls the KU10405 chip via an FT232H SPI controller. Users should only concern
    themselves with the constructor and set_tap method.

    Example usage:
        from ku10405 import KU10405
        dut = KU10405()
        dut.set_tap(0, 100, 200)
    """

    # The apply pin both applies changes and indicates trim bits being set. When CS is high, a
    # rising edge of the apply pin indicates that settings should be applied. Trim bits are
    # programmed when the apply pin is high while CS is low during the rising edge of the first
    # clock cycle.
    APPLY_PIN = 7

    def __init__(self, readback=True, ftdi_url='ftdi://ftdi:232h/1'):
        """An FT232H chip must be connected to your computer for this constructor to succeed. It
        sets up the SPI/GPIO interface and configures readback.

        When readback is enabled, set_tap will throw an error if the readback of any write does not
        match what was programmed. Readback does have an impact on performance because it requires
        an extra SPI transaction for every call to set_tap, but for safety it should not be disabled
        unless speed is your top priority. Note that for readback to work, the appropriate switch on
        the board must be set.

        Args:
            readback (bool, optional): Set to False to disable readback error checking
        """
        self._readback = readback

        # Setup SPI interface
        self._spi_controller = SpiController()
        self._spi_controller.configure(ftdi_url)
        self._spi = self._spi_controller.get_port(cs=0, mode=0, freq=1e6)

        # Setup GPIO interface
        self._gpio = self._spi_controller.get_gpio()
        self._gpio.set_direction(1 << self.APPLY_PIN,
                                 1 << self.APPLY_PIN)  # make APLS an output
        self._set_apply(False)

        # We're always going to use address 0. This is here just in case that changes.
        self._addr = 0

    def set_tap(self, channel, mag, phase, enable=True, apply=True):
        """Sets the tap at the given channel to the given magnitude and phase. Magnitude and phase
        values control bits, not logical values. Disable the channel by setting enable to False.
        Changes are only applied if apply is set to True. The end result is the same if you always
        set apply to True or only set it to True on the last call of a sequence.

        Args:
            channel (int): Which channel to set (range: [0-3])
            mag (int): 14-bit attenuation (range: [0, 2^14))
            phase (int): 16-bit phase (range: [0, 2^16))
            enable (bool, optional): Set to False to disable this channel
            apply (bool, optional): Set to False if you don't want to apply these changes yet

        Raises:
            TypeError: raised if any arguments have the wrong type
            ValueError: raised if any arguments are out-of-range
        """
        if not all(isinstance(val, int) for val in (channel, mag, phase)):
            raise TypeError('Channel, magnitude, and phase must be integers')
        if not all(isinstance(val, bool) for val in (enable, apply)):
            raise TypeError('Enable and apply must be bools')
        if not 0 <= channel <= 3:
            raise ValueError('Address and channel must be in range [0, 3]')
        if not 0 <= mag <= 16383:
            raise ValueError('Magnitude must be in range [0, 16383]')
        if not 0 <= phase <= 65535:
            raise ValueError('Phase must be in range [0, 65535]')

        coarse_write, _ = \
            self._write(channel, 'coarse', mag >> 9, phase >> 11, enable)
        fine_write, coarse_read = \
            self._write(channel, 'fine', (mag >> 4) & 0x1F, (phase >> 5) & 0x3F)
        trim_write, fine_read = \
            self._write(channel, 'trim', mag & 0xF, phase & 0x1F)

        if self._readback:
            # Do a dummy write so we can get the trim readback. Note that this assumes we are not
            # using address 3!
            trim_read = self._spi.exchange((0xFFFF).to_bytes(2,
                                                             byteorder='big'),
                                           duplex=True)
            trim_read = (trim_read[0] << 8) | trim_read[1]

            if coarse_write != coarse_read or fine_write != fine_read or trim_write != trim_read:
                raise IOError(
                    'Readbacks do not match! Wrote coarse {}, fine {}, trim {}, but '
                    'read coarse {}, fine {}, trim {}'.format(
                        coarse_write, fine_write, trim_write, coarse_read,
                        fine_read, trim_read))

        if apply:
            self._set_apply(True)
            self._set_apply(False)

    def _write(self, channel, reg_type, mag, phase, enable=None):
        if reg_type not in ('coarse', 'fine', 'trim'):
            raise ValueError('Unrecognized register type {}'.format(reg_type))
        if reg_type == 'coarse' and enable is None:
            raise ValueError('Enable must be specified for coarse write')
        if reg_type in ('coarse', 'fine') and not 0 <= mag <= 31:
            raise ValueError('Coarse/fine magnitudes must be in range [0, 31]')
        if reg_type == 'trim' and not 0 <= mag <= 15:
            raise ValueError('Trim magnitude must be in range [0, 15]')
        if reg_type in ('coarse', 'trim') and not 0 <= phase <= 31:
            raise ValueError('Coarse/trim phases must be in range [0, 31]')
        if reg_type == 'fine' and not 0 <= phase <= 63:
            raise ValueError('Fine phase must be in range [0, 63]')

        wdata = (self._addr << 14) | (channel << 12)
        if reg_type == 'coarse':
            wdata |= (enable << 10) | (phase << 5) | mag
        elif reg_type == 'fine':
            wdata |= (1 << 11) | (phase << 5) | mag
        else:  # trim
            wdata |= (phase << 5) | mag
            self._set_apply(True)

        rdata = self._spi.exchange(wdata.to_bytes(2, byteorder='big'),
                                   duplex=True)
        rdata = (rdata[0] << 8) | rdata[1]

        if reg_type == 'trim':
            self._set_apply(False)

        return wdata, rdata

    def _set_apply(self, value):
        if not isinstance(value, bool):
            raise TypeError('GPIO value must be a bool.')
        self._gpio.write(value << self.APPLY_PIN)
Exemple #34
0
class SPIDriver:
    """
    Class that contains the driver for the FTDI SPI + GPIO.
    """
    def __init__(self):
        self.ctrl = None
        self.slave = None
        print('Starting driver ...')
        self.begin()

    def begin(self):
        try:
            self.ctrl = SpiController(cs_count=1)
            s = 'ftdi://0x0403:0x6011/1'
            self.ctrl.configure(s)

            self.slave = self.ctrl.get_port(cs=0, freq=6E6, mode=3)
            self.slave.set_frequency(8000000)

            self.gpio = self.ctrl.get_gpio()
            self.gpio.set_direction(
                0x10, 0x10)  # direction for the fet controller is OUTPUT (1)
            self.gpio.write(0x10)
            time.sleep(0.1)
            # to account for using separate ports for power and comms:
            self.backup_ctrl = SpiController(cs_count=1)
            self.backup_gpio = None
            if not s == 'ftdi://0x0403:0x6011/1':
                backup_s = 'ftdi://0x0403:0x6011/1'
                self.backup_ctrl.configure(backup_s)
                self.backup_gpio = self.backup_ctrl.get_gpio()
                self.backup_gpio.set_direction(0x10, 0x10)
                self.backup_gpio.write(0x10)
                time.sleep(1)
        except Exception as err:
            print('Error in initialising the FTDI driver ...:', err)

    def write_data_out(self, buffer):
        if not isinstance(buffer, bytes):
            raise Exception  # TODO define exception
        try:
            self.slave.write(buffer)
            return True
        except Exception as err:
            #TODO convert to Logging
            print('Error in writing data out to FTDI SPI...:', err)
            return False

    def set_power_on(self):
        self.gpio.write(0x10)
        if self.backup_gpio is not None:
            self.backup_gpio.write(0x10)

    def set_power_off(self):
        self.gpio.write(0x00)
        if self.backup_gpio is not None:
            self.backup_gpio.write(0x00)

    def terminate(self):
        self.ctrl.terminate()
        print('terminated')
Exemple #35
0
    return get_status(device) & SR_WIP


if len(sys.argv) < 2:
    print("Usage: raptor_flash.py <file>")
    sys.exit()

file_path = sys.argv[1]

if not os.path.isfile(file_path):
    print("File not found.")
    sys.exit()

spi = SpiController(cs_count=1, turbo=True)
# spi.configure(vendor=0x0403, product=0x6014, interface=1)
spi.configure('ftdi://ftdi:232h:0/1')
slave = spi.get_port(cs=0, freq=12E6,
                     mode=0)  # Chip select is 0 -- corresponds to D3

gpio = spi.get_gpio()
gpio.set_direction(0x0100, 0x0100)
gpio.write(0x0000)

# time.sleep(1.0)

slave.write([CMD_RESET_CHIP])

jedec = slave.exchange([CMD_JEDEC_DATA], 3)
print("JEDEC = {}".format(binascii.hexlify(jedec)))

if jedec[0] != int('ef', 16) and jedec[0] != int('01', 16) and jedec[0] != int(
Exemple #36
0
class SpiGpioTestCase(unittest.TestCase):
    """Basic test for GPIO access w/ SPI mode

       It expects the following I/O setup:

       AD4 connected t0 AC0
       AD5 connected t0 AC1
       AD6 connected t0 AC2
       AD7 connected t0 AC3
    """

    # AD0: SCLK, AD1: MOSI, AD2: MISO, AD3: /CS
    AD_OFFSET = 4
    AC_OFFSET = 8
    PIN_COUNT = 4

    def setUp(self):
        self._spi = SpiController(cs_count=1)
        url = environ.get('FTDI_DEVICE', 'ftdi://ftdi:2232h/1')
        self._spi.configure(url)
        self._port = self._spi.get_port(0, freq=1E6, mode=0)
        self._io = self._spi.get_gpio()

    def tearDown(self):
        """Close the SPI connection"""
        self._spi.terminate()

    def test_ac_to_ad(self):
        ad_pins = ((1 << self.PIN_COUNT) - 1) << self.AD_OFFSET  # input
        ac_pins = ((1 << self.PIN_COUNT) - 1) << self.AC_OFFSET  # output
        io_pins = ad_pins | ac_pins

        def ac_to_ad(ac_output):
            ac_output &= ac_pins
            ac_output >>= self.AC_OFFSET - self.AD_OFFSET
            return ac_output & ad_pins

        self._io.set_direction(io_pins, ac_pins)
        for ac in range(1 << self.PIN_COUNT):
            ac_out = ac << self.AC_OFFSET
            ad_in = ac_to_ad(ac_out)
            self._io.write(ac_out)
            # random SPI exchange to ensure SPI does not change GPIO
            self._port.exchange([0x00, 0xff], 2)
            rd = self._io.read()
            self.assertEqual(rd, ad_in)
        self.assertRaises(SpiIOError, self._io.write, ad_pins)

    def test_ad_to_ac(self):
        ad_pins = ((1 << self.PIN_COUNT) - 1) << self.AD_OFFSET  # output
        ac_pins = ((1 << self.PIN_COUNT) - 1) << self.AC_OFFSET  # input
        io_pins = ad_pins | ac_pins

        def ad_to_ac(ad_output):
            ad_output &= ad_pins
            ad_output <<= self.AC_OFFSET - self.AD_OFFSET
            return ad_output & ac_pins

        self._io.set_direction(io_pins, ad_pins)
        for ad in range(1 << self.PIN_COUNT):
            ad_out = ad << self.AD_OFFSET
            ac_in = ad_to_ac(ad_out)
            self._io.write(ad_out)
            # random SPI exchange to ensure SPI does not change GPIO
            self._port.exchange([0x00, 0xff], 2)
            rd = self._io.read()
            self.assertEqual(rd, ac_in)
        self.assertRaises(SpiIOError, self._io.write, ac_pins)