| #!/usr/bin/env python3 | 
 | # Copyright lowRISC contributors. | 
 | # Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
 | # SPDX-License-Identifier: Apache-2.0 | 
 | r"""Simple Tool for FPGA SPI experiments | 
 | """ | 
 |  | 
 | import argparse | 
 | import logging as log | 
 | import os | 
 | import subprocess | 
 | import sys | 
 | import time | 
 |  | 
 | import pkg_resources  # part of setuptools | 
 | from pyftdi.spi import SpiController | 
 |  | 
 |  | 
 | def show_and_exit(clitool, packages): | 
 |     util_path = os.path.dirname(os.path.realpath(clitool)) | 
 |     os.chdir(util_path) | 
 |     ver = subprocess.run( | 
 |         ["git", "describe", "--always", "--dirty", "--broken"], | 
 |         stdout=subprocess.PIPE).stdout.strip().decode('ascii') | 
 |     if (ver == ''): | 
 |         ver = 'not found (not in Git repository?)' | 
 |     sys.stderr.write(clitool + " Git version " + ver + '\n') | 
 |     for p in packages: | 
 |         sys.stderr.write(p + ' ' + pkg_resources.require(p)[0].version + '\n') | 
 |     exit(0) | 
 |  | 
 |  | 
 | USAGE = """ | 
 |   spitest [options] text [text ...] | 
 | """ | 
 |  | 
 |  | 
 | 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 device w/ /CS on A*BUS3 and SPI mode 0 @ 1MHz | 
 |     device = 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 device | 
 |     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 = device.exchange(write_buf, duplex=True) | 
 |         print("Got " + str(read_buf)) | 
 |         s = s[4:] | 
 |  | 
 |  | 
 | if __name__ == '__main__': | 
 |     main() |