zero scan and documentation
This commit is contained in:
parent
2b698fc08a
commit
f30f6f1ad5
|
@ -110,11 +110,14 @@ buildroot-clean:
|
|||
-docker container stop upsilon-buildroot
|
||||
-docker container rm upsilon-buildroot
|
||||
|
||||
###### TFTP
|
||||
###### Execute
|
||||
|
||||
tftp:
|
||||
cd ../boot && py3tftp --host 192.168.1.100 -p 6969 -v
|
||||
|
||||
copy:
|
||||
scp ../boot/mmio.py ../linux/comm.py upsilon:~/
|
||||
|
||||
###### External projects
|
||||
|
||||
clone: f4pga buildroot litex opensbi
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
"""
|
||||
Copyright 2023 (C) Peter McGoron
|
||||
|
||||
This file is a part of Upsilon, a free and open source software project.
|
||||
For license terms, refer to the files in `doc/copying` in the Upsilon
|
||||
source distribution.
|
||||
"""
|
||||
|
||||
from pssh.clients import SSHClient
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import pandas as pd
|
||||
import sys
|
||||
|
||||
def sign_extend(value, bits):
|
||||
is_signed = (value >> (bits - 1)) & 1 == 1
|
||||
if not is_signed:
|
||||
return value
|
||||
return -((~value + 1) & ((1 << (bits - 1)) - 1))
|
||||
|
||||
client = SSHClient('192.168.1.50', user='root', pkey='~/.ssh/upsilon_key')
|
||||
client.scp_send('../linux/noise_test.py', '/root/noise_test.py')
|
||||
out = client.run_command('micropython noise_test.py')
|
||||
|
||||
current_dac = None
|
||||
current_adc = []
|
||||
x_ax = []
|
||||
y_ax = []
|
||||
for line in out.stdout:
|
||||
l = line.split(' ')
|
||||
if l[0] != current_dac:
|
||||
if current_dac is not None:
|
||||
m = np.mean(current_adc)
|
||||
sdev = np.std(current_adc)
|
||||
print(current_dac, m, sdev)
|
||||
x_ax.append(current_dac)
|
||||
y_ax.append(m)
|
||||
current_adc = [sign_extend(int(l[1]), 18)]
|
||||
current_dac = l[0]
|
||||
else:
|
||||
current_adc.append(sign_extend(int(l[1]),18))
|
||||
|
||||
df = pd.DataFrame({"x": x_ax, "y": y_ax})
|
||||
df.to_csv(f"{sys.argv[1]}.csv")
|
||||
plt.plot(df.x, df.y)
|
||||
plt.show()
|
|
@ -0,0 +1,46 @@
|
|||
Copyright 2023 (C) Peter McGoron.
|
||||
|
||||
This file is a part of Upsilon, a free and open source software project.
|
||||
For license terms, refer to the files in `doc/copying` in the Upsilon
|
||||
source distribution.
|
||||
|
||||
__________________________________________________________________________
|
||||
|
||||
This manual describes the controller software programming. This guide does not
|
||||
describe client programming (programs that run on the client and interface with
|
||||
the controller). It does not describe Verilog: see `verilog_manual.md` for
|
||||
that.
|
||||
|
||||
# Preqreuisites
|
||||
|
||||
You must know basic Linux shell (change directories, edit files with `vi`)
|
||||
and basic SSH usage (sftp, ssh).
|
||||
|
||||
Knowledge of Micropython (a subset of Python) is required for scripting.
|
||||
|
||||
I assume that you have the controller running and accessable. See `docker.md`
|
||||
for the easy quick-start guide.
|
||||
|
||||
# Programming in MicroPython
|
||||
|
||||
## Introduction to MicroPython
|
||||
|
||||
MicroPython is a programming language that is very similar to Python. It is
|
||||
stripped down and designed to run on very small devices. If you have written
|
||||
Python, you will be able to use MicroPython without issue. If you are not
|
||||
a hardcore Python programmer, you might not even notice a difference.
|
||||
|
||||
Everything you need to know is [here](https://docs.micropython.org).
|
||||
|
||||
## Standard Library
|
||||
|
||||
There are two modules of the standard library: `mmio` and `comm`.
|
||||
|
||||
`mmio` are wrappers that handle reads and writes from MMIO pins. This file
|
||||
is automatically generated by the build process. This file is generated in
|
||||
the `gateware` directory (if you use the Docker build system, the file is
|
||||
automatically copied to `boot/mmio.py`).
|
||||
|
||||
`comm` contains higher level wrappers for DAC and ADC pins. This module is
|
||||
documented well enough that you should be able to read it and understand
|
||||
how to use it.
|
|
@ -116,3 +116,9 @@ UART.
|
|||
Run `litex_term /dev/ttyUSB1`. You should get messages in the window with
|
||||
the TFTP server that the FPGA has connected to the server. Eventually you
|
||||
will get a login prompt: you have sucessfully loaded Upsilon onto your FPGA.
|
||||
|
||||
## Copy Library
|
||||
|
||||
Run `make copy` to copy the Micropython Upsilon library to the FPGA. After
|
||||
this the modules `comm` and `mmio` are available when running scripts in
|
||||
`/root`.
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
Copyright 2023 (C) Peter McGoron.
|
||||
|
||||
This file is a part of Upsilon, a free and open source software project.
|
||||
For license terms, refer to the files in `doc/copying` in the Upsilon
|
||||
source distribution.
|
||||
|
||||
__________________________________________________________________________
|
||||
|
||||
The User Manual is targeted towards non-programmers using Upsilon.
|
||||
|
||||
# Preqreuisites
|
||||
|
||||
You will need to know the basics of Git. Git is the system used to track
|
||||
changes and update Upsilon. you will need to know the wwhat a git repository is,
|
||||
how to pull changes from a repository, what commit hashes are and how to make
|
||||
branches.
|
||||
|
||||
You must know basic Linux shell (change directories, edit files with `vi`)
|
||||
and basic SSH usage (sftp, ssh).
|
||||
|
||||
Knowledge of Micropython (a subset of Python) is required for scripting.
|
||||
|
||||
|
||||
# Building and Booting
|
||||
|
||||
Follow `docs/docker.md` to setup the build environment, build Upsilon, and
|
||||
boot Upsilon.
|
|
@ -11,11 +11,43 @@
|
|||
#
|
||||
# TODO: Devicetree?
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
|
||||
class CSRGenerator:
|
||||
class MMIORegister:
|
||||
def __init__(self, name, read_only=False, number=1, exntype=None):
|
||||
"""
|
||||
Describes a MMIO register.
|
||||
:param name: The name of the MMIO register. This name must be the
|
||||
same as the pin name used in ``csr.json``, except for any
|
||||
numerical suffix.
|
||||
:param read_only: True if the register is read only. Defaults to
|
||||
``False``.
|
||||
:param number: The number of MMIO registers with the same name
|
||||
and number suffixes. The number suffixes must go from 0
|
||||
to ``number - 1`` with no gaps.
|
||||
"""
|
||||
self.name = name
|
||||
self.read_only = read_only
|
||||
self.number = number
|
||||
self.exntype = exntype
|
||||
|
||||
def mmio_factory(dac_num, exntype):
|
||||
def f(name, read_only=False):
|
||||
return MMIORegister(name, read_only, numer=dac_num, exntype=exntype)
|
||||
return f
|
||||
|
||||
|
||||
class MicroPythonCSRGenerator:
|
||||
def __init__(self, csrjson, bitwidthjson, registers, outf):
|
||||
"""
|
||||
This class generates a MicroPython wrapper for MMIO registers.
|
||||
|
||||
:param csrjson: Filename of a LiteX "csr.json" file.
|
||||
:param bitwidthjson: Filename of an Upsilon "bitwidthjson" file.
|
||||
:param registers: A list of
|
||||
"""
|
||||
self.registers = registers
|
||||
self.csrs = json.load(open(csrjson))
|
||||
self.bws = json.load(open(bitwidthjson))
|
||||
|
@ -70,13 +102,17 @@ class CSRGenerator:
|
|||
assert len(acc) == 2
|
||||
self.print(f'{indent}return {acc[0]} | ({acc[1]} << 32)\n')
|
||||
|
||||
def print_fun(self, optype, name, regnum, pfun):
|
||||
def print_fun(self, optype, reg, pfun):
|
||||
"""Print out a read/write function for an MMIO register.
|
||||
* {optype} is set to "read" or "write" (the string).
|
||||
* {name} is set to the name of the MMIO register, without number suffix.
|
||||
* {regnum} is set to the amount of that type oF MMIO register exists.
|
||||
* {pfun} is set to {self.print_write_register} or {self.print_read_register}
|
||||
|
||||
:param optype: is set to "read" or "write" (the string).
|
||||
:param reg: is the dictionary containing the register info.
|
||||
:param pfun: is set to {self.print_write_register} or {self.print_read_register}
|
||||
"""
|
||||
name = reg['name']
|
||||
regnum = reg['total']
|
||||
exntype = reg['exntype]'
|
||||
|
||||
self.print(f'def {optype}_{name}(')
|
||||
|
||||
printed_argument = False
|
||||
|
@ -101,26 +137,42 @@ class CSRGenerator:
|
|||
self.print(f'num == {i}:\n')
|
||||
pfun('\t\t', 'val', name, i)
|
||||
self.print(f'\telse:\n')
|
||||
self.print(f'\t\traise Exception("invalid {name}", regnum)\n')
|
||||
self.print(f'\t\traise {exntype}(regnum)\n')
|
||||
self.print('\n')
|
||||
|
||||
def print_file(self):
|
||||
self.print('import machine\n')
|
||||
self.print('class InvalidDACException(Exception):\n\tpass\n')
|
||||
self.print('class InvalidADCException(Exception):\n\tpass\n')
|
||||
for reg in self.registers:
|
||||
self.print_fun('read', reg['name'], reg['total'], self.print_read_register)
|
||||
self.print_fun('read', reg, self.print_read_register)
|
||||
if not reg['read_only']:
|
||||
self.print_fun('write', reg['name'], reg['total'], self.print_write_register)
|
||||
self.print_fun('write', reg, self.print_write_register)
|
||||
|
||||
if __name__ == "__main__":
|
||||
dac_num = 8
|
||||
adc_num = 8
|
||||
dac_reg = mmio_factory(dac_num, "InvalidDACException")
|
||||
adc_reg = mmio_factory(adc_num, "InvalidADCException")
|
||||
|
||||
registers = [
|
||||
{"read_only": False, "name": "dac_sel", "total": dac_num},
|
||||
{"read_only": True, "name": "dac_finished", "total": dac_num},
|
||||
{"read_only": False, "name": "dac_arm", "total": dac_num},
|
||||
{"read_only": True, "name": "dac_recv_buf", "total": dac_num},
|
||||
{"read_only": False, "name": "dac_send_buf", "total": dac_num},
|
||||
dac_reg("dac_sel"),
|
||||
dac_reg("dac_finished", read_only=True),
|
||||
dac_reg("dac_arm"),
|
||||
dac_reg("dac_recv_buf", read_only=True),
|
||||
dac_reg("dac_send_buf"),
|
||||
|
||||
adc_reg("adc_finished", read_only=True),
|
||||
adc_reg("adc_arm"),
|
||||
adc_reg("adc_recv_buf", read_only=True),
|
||||
adc_reg("adc_sel"),
|
||||
|
||||
MMIORegister("cl_in_loop", read_only=True),
|
||||
MMIORegister("cl_cmd"),
|
||||
MMIORegister("cl_word_in"),
|
||||
MMIORegister("cl_start_cmd"),
|
||||
MMIORegister("cl_finish_cmd", read_only=True),
|
||||
|
||||
# {"read_only": False, "name": "wf_arm", "total": dac_num},
|
||||
# {"read_only": False, "name": "wf_halt_on_finish", "total": dac_num},
|
||||
# {"read_only": True, "name": "wf_finished", "total": dac_num},
|
||||
|
@ -129,17 +181,5 @@ if __name__ == "__main__":
|
|||
# {"read_only": False, "name": "wf_refresh_start", "total": dac_num},
|
||||
# {"read_only": True, "name": "wf_refresh_finished", "total": dac_num},
|
||||
# {"read_only": False, "name": "wf_start_addr", "total": dac_num},
|
||||
|
||||
{"read_only": True, "name": "adc_finished", "total": adc_num},
|
||||
{"read_only": False, "name": "adc_arm", "total": adc_num},
|
||||
{"read_only": True, "name": "adc_recv_buf", "total": adc_num},
|
||||
{"read_only": False, "name": "adc_sel", "total": adc_num},
|
||||
|
||||
{"read_only": True, "name": "cl_in_loop", "total": 1},
|
||||
{"read_only": False, "name": "cl_cmd", "total": 1},
|
||||
{"read_only": False, "name": "cl_word_in", "total": 1},
|
||||
{"read_only": False, "name": "cl_word_out", "total": 1},
|
||||
{"read_only": False, "name": "cl_start_cmd", "total": 1},
|
||||
{"read_only": True, "name": "cl_finish_cmd", "total": 1},
|
||||
]
|
||||
CSRGenerator("csr.json", "csr_bitwidth.json", registers, sys.stdout).print_file()
|
||||
MicroPythonCSRGenerator("csr.json", "csr_bitwidth.json", registers, sys.stdout).print_file()
|
||||
|
|
|
@ -57,6 +57,9 @@ from litedram.frontend.dma import LiteDRAMDMAReader
|
|||
from liteeth.phy.mii import LiteEthPHYMII
|
||||
|
||||
"""
|
||||
Keep this diagram up to date! This is the wiring diagram from the ADC to
|
||||
the named Verilog pins.
|
||||
|
||||
Refer to `A7-constraints.xdc` for pin names.
|
||||
DAC: SS MOSI MISO SCK
|
||||
0: 1 2 3 4 (PMOD A top, right to left)
|
||||
|
|
|
@ -1,25 +1,48 @@
|
|||
# Copyright 2023 (C) Peter McGoron
|
||||
# This file is a part of Upsilon, a free and open source software project.
|
||||
# For license terms, refer to the files in `doc/copying` in the Upsilon
|
||||
# source distribution.
|
||||
#
|
||||
# Upsilon Micropython Standard Library.
|
||||
|
||||
from mmio import *
|
||||
|
||||
def dac_write_value(val, num):
|
||||
write_dac_send_buf(1 << 20 | val & 0xFFFFF, num) # 20 bit DAC
|
||||
# Write a 20 bit twos-complement value to a DAC.
|
||||
def dac_write_volt(val, num):
|
||||
"""
|
||||
Write a 20 bit twos-complement value to a DAC.
|
||||
|
||||
:param val: Two's complement 20 bit integer. The number is bitmasked
|
||||
to the appropriate length, so negative Python integers are also
|
||||
accepted. This DOES NOT check if the integer actually fits in 20
|
||||
bits.
|
||||
|
||||
:param num: DAC number.
|
||||
:raises Exception:
|
||||
"""
|
||||
write_dac_send_buf(1 << 20 | (val & 0xFFFFF), num)
|
||||
write_dac_arm(1, num)
|
||||
write_dac_arm(0, num)
|
||||
|
||||
def dac_read_value(val, num):
|
||||
# Read a register from a DAC.
|
||||
def dac_read_reg(val, num):
|
||||
write_dac_send_buf(1 << 23 | val, num)
|
||||
write_dac_arm(1, num)
|
||||
write_dac_arm(0, num)
|
||||
return read_dac_recv_buf(num)
|
||||
|
||||
# Initialize a DAC by setting it's output value to 0, and
|
||||
# removing the output restriction from the settings register.
|
||||
def dac_init(num):
|
||||
write_dac_sel(0,num)
|
||||
dac_write_value(0, num)
|
||||
write_dac_send_buf(1 << 22 | 1 << 2, num)
|
||||
dac_write_volt(0, num)
|
||||
write_dac_send_buf(1 << 21 | 1 << 1, num)
|
||||
write_dac_arm(1, num)
|
||||
write_dac_arm(0, num)
|
||||
return dac_read_value(1 << 22, num)
|
||||
return dac_read_reg(1 << 21, num)
|
||||
|
||||
def adc_read_value(num):
|
||||
# Read a value from an ADC.
|
||||
def adc_read(num):
|
||||
write_adc_arm(1, num)
|
||||
write_adc_arm(0, num)
|
||||
return read_from_adc(num)
|
||||
return read_adc_recv_buf(num)
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
from comm import *
|
||||
from time import sleep_ms
|
||||
|
||||
for i in range(-300,300):
|
||||
dac_write_volt(i, 0)
|
||||
for j in range(0,20):
|
||||
print(i, adc_read(0))
|
||||
|
Loading…
Reference in New Issue