blob: f69004e7e4d40060001b6c869c0276f6c09b4dec [file] [log] [blame]
#!/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).tobytes()
print("Got " + str(read_buf))
s = s[4:]
if __name__ == '__main__':
main()