Compare commits

..

No commits in common. "master" and "pyrp3" have entirely different histories.

29 changed files with 682 additions and 1585 deletions

View File

@ -1,21 +0,0 @@
# Firmware for the Sinara 8462 Fast-Servo
## Building
### Reproducible build with Nix
1. Run `nix build .#packages.armv7l-linux.fast-servo-sd-image` to build the sd card image.
2. Run `nix develop` to build a dev shell to access the GUI.
### Flashing
1. Plug in your SD card to your computer and run `lsblk` to locate SD card
2. If there are any partitions on the SD card, run `umount <mount point>` all the related mount points.
3. Run `sudo dd if=<path to the SD Card Image> of=/dev/<SD Card Device Name in lsblk> bs=4M status=progress oflag=sync`
4. Eject the SD Card before removal
### Usage
1. Make sure the onboard DIP Switch is in the following condition.
- EN: OFF
- MODE: ON
2. Install the SD Card, power up the board via the power jack or PoE and plug in the RJ45 Ethernet cable.
3. Wait for all the front panel LEDs except the termination status LEDs to turn off. It can take a minutes or two for first boot. If it does not boot up, try to flash the SD Card again.
4. Run `ssh <fast servo ip address> -p 3030` to ssh into fast-servo and run `linien-server run` to start the linien server.
5. In the dev shell, run `linien` to launch the GUI. Add new device. Username is `root` and it does not take any password to log in. You leave the password field with any text.
6. Select the newly added device and click connect in the GUI to connect and start the GUI.

View File

@ -1,66 +0,0 @@
diff --git a/gateware/logic/autolock.py b/gateware/logic/autolock.py
index a6dc764..1a8407f 100644
--- a/gateware/logic/autolock.py
+++ b/gateware/logic/autolock.py
@@ -148,14 +148,17 @@ class RobustAutolock(Module, AutoCSR):
final_waited_for = Signal(bits_for(N_points))
# this is the signal that's used for detecting peaks
- sum_diff = Signal((len(self.sum_diff_calculator.output), True))
- abs_sum_diff = Signal.like(sum_diff)
+ self.sum_diff = Signal((len(self.sum_diff_calculator.output), True))
+ abs_sum_diff = Signal.like(self.sum_diff)
self.comb += [
self.sum_diff_calculator.writing_data_now.eq(self.writing_data_now),
self.sum_diff_calculator.restart.eq(self.at_start),
self.sum_diff_calculator.input.eq(self.input),
self.sum_diff_calculator.delay_value.eq(self.time_scale.storage),
- sum_diff.eq(self.sum_diff_calculator.output),
+ ]
+
+ self.sync += [
+ self.sum_diff.eq(self.sum_diff_calculator.output),
]
# has this signal at the moment the same sign as the peak we are looking for?
@@ -168,16 +171,17 @@ class RobustAutolock(Module, AutoCSR):
all_instructions_triggered = Signal()
self.comb += [
- sign_equal.eq((sum_diff > 0) == (current_peak_height > 0)),
- If(sum_diff >= 0, abs_sum_diff.eq(sum_diff)).Else(
- abs_sum_diff.eq(-1 * sum_diff)
+ sign_equal.eq((self.sum_diff > 0) == (current_peak_height > 0)),
+ If(self.sum_diff >= 0, abs_sum_diff.eq(self.sum_diff)).Else(
+ abs_sum_diff.eq(-1 * self.sum_diff)
),
If(
current_peak_height >= 0,
abs_current_peak_height.eq(current_peak_height),
).Else(abs_current_peak_height.eq(-1 * current_peak_height)),
over_threshold.eq(abs_sum_diff >= abs_current_peak_height),
- waited_long_enough.eq(waited_for > current_wait_for),
+ # HACK: To compensate the lock position output for the pipeline delay
+ waited_long_enough.eq((waited_for >= current_wait_for - 1) & (waited_for != 2 ** bits_for(N_points) - 1) & (current_wait_for - 1 != 2 ** bits_for(N_points) - 1)),
all_instructions_triggered.eq(
self.current_instruction_idx >= self.N_instructions.storage
),
@@ -190,7 +194,7 @@ class RobustAutolock(Module, AutoCSR):
self.sync += [
If(
self.at_start,
- waited_for.eq(0),
+ waited_for.eq(-1),
# fpga robust autolock algorithm registeres trigger events delayed.
# Therefore, we give it a head start for `final_waited_for`
final_waited_for.eq(ROBUST_AUTOLOCK_FPGA_DELAY),
@@ -213,7 +217,8 @@ class RobustAutolock(Module, AutoCSR):
self.current_instruction_idx.eq(
self.current_instruction_idx + 1
),
- waited_for.eq(0),
+ # HACK: To compensate the lock position output for the pipeline delay
+ waited_for.eq(-1),
).Else(waited_for.eq(waited_for + 1)),
),
If(

View File

@ -1,13 +0,0 @@
diff --git a/gateware/logic/iir.py b/gateware/logic/iir.py
index 2380dd7..60bfeb7 100644
--- a/gateware/logic/iir.py
+++ b/gateware/logic/iir.py
@@ -89,7 +89,7 @@ class Iir(Filter):
zr = Signal.like(z)
self.sync += zr.eq(z)
z = Signal.like(zr)
- self.comb += z.eq(zr + signal * c[coeff])
+ self.sync += z.eq(zr + signal * c[coeff])
self.comb += y_next.eq(z)
self.latency.value = Constant(order + 1)
self.interval.value = Constant(1)

View File

@ -1,31 +0,0 @@
diff --git a/linien-client/linien_client/deploy.py b/linien-client/linien_client/deploy.py
index df6683f..7355cc3 100644
--- a/linien-client/linien_client/deploy.py
+++ b/linien-client/linien_client/deploy.py
@@ -34,7 +34,7 @@ logger.setLevel(logging.DEBUG)
def read_remote_version(
- device: Device, ssh_port: int = 22, out_stream=sys.stdout
+ device: Device, ssh_port: int = 3030, out_stream=sys.stdout
) -> str:
"""Read the remote version of linien."""
@@ -62,7 +62,7 @@ def read_remote_version(
def start_remote_server(
- device: Device, ssh_port: int = 22, out_stream=sys.stdout
+ device: Device, ssh_port: int = 3030, out_stream=sys.stdout
) -> None:
"""Start the remote linien server."""
@@ -102,7 +102,7 @@ def start_remote_server(
def install_remote_server(
- device: Device, ssh_port: int = 22, out_stream=sys.stdout
+ device: Device, ssh_port: int = 3030, out_stream=sys.stdout
) -> None:
"""Install the remote linien server."""

View File

@ -1,15 +0,0 @@
diff --git a/linien-common/linien_common/common.py b/linien-common/linien_common/common.py
index 854d776..a310dbe 100644
--- a/linien-common/linien_common/common.py
+++ b/linien-common/linien_common/common.py
@@ -25,8 +25,8 @@ from typing import Dict, Iterable, List, Tuple, Union
import numpy as np
from scipy.signal import correlate, resample
-MHz = 0x10000000 / 8
-Vpp = ((1 << 14) - 1) / 4
+MHz = 0x10000000 / 8 * 125 / 100
+Vpp = (1 << 14) * 0.5 / 0.425 - 1
# conversion of bits to V
ANALOG_OUT_V = 1.8 / ((2**15) - 1)

View File

@ -0,0 +1,38 @@
# diff from elhep/Fast-Servo-Firmmware commit ID 7fae40c:
# https://github.com/elhep/Fast-Servo-Firmware/commit/7fae40c0f872a91218be378f8289b98b1e366729
# Fix for migen add_source deprecation and removed xilinx bootgen command
# .bin file is being generated by bit2bin.py from Linien repository
# https://github.com/linien-org/linien/blob/master/gateware/bit2bin.py
diff --git a/fast_servo/gateware/fast_servo_platform.py b/fast_servo/gateware/fast_servo_platform.py
index 13b4aa3..89a8103 100644
--- a/fast_servo/gateware/fast_servo_platform.py
+++ b/fast_servo/gateware/fast_servo_platform.py
@@ -324,7 +324,12 @@ class Platform(XilinxPlatform):
self.ps7_config = ps7_config
verilog_sources = os.listdir(verilog_dir)
- self.add_sources(verilog_dir, *verilog_sources)
+ self.add_source_dir(verilog_dir)
+
+ def build(self, *args, **kwargs):
+ build_dir = kwargs.get('build_dir', 'build')
+ self.copy_sources(build_dir)
+ super().build(*args, **kwargs)
def do_finalize(self, fragment):
try:
diff --git a/fast_servo/gateware/fast_servo_soc.py b/fast_servo/gateware/fast_servo_soc.py
index 02128f5..abfc583 100644
--- a/fast_servo/gateware/fast_servo_soc.py
+++ b/fast_servo/gateware/fast_servo_soc.py
@@ -282,9 +282,3 @@ if __name__ == "__main__":
os.chdir(os.path.join(root_path, build_dir))
with open(f"{build_name}.bif", "w") as f:
f.write(f"all:\n{{\n\t{build_name}.bit\n}}")
-
- cmd = f"bootgen -image {build_name}.bif -arch zynq -process_bitstream bin -w on".split(" ")
- subprocess.run(cmd)
-
-
-

View File

@ -1,42 +1,3 @@
# diff from elhep/Fast-Servo-Firmmware commit ID 7fae40c:
# https://github.com/elhep/Fast-Servo-Firmware/commit/7fae40c0f872a91218be378f8289b98b1e366729
# Fix for migen add_source deprecation and removed xilinx bootgen command
# .bin file is being generated by bit2bin.py from Linien repository
# https://github.com/linien-org/linien/blob/master/gateware/bit2bin.py
diff --git a/fast_servo/gateware/fast_servo_platform.py b/fast_servo/gateware/fast_servo_platform.py
index 13b4aa3..89a8103 100644
--- a/fast_servo/gateware/fast_servo_platform.py
+++ b/fast_servo/gateware/fast_servo_platform.py
@@ -324,7 +324,12 @@ class Platform(XilinxPlatform):
self.ps7_config = ps7_config
verilog_sources = os.listdir(verilog_dir)
- self.add_sources(verilog_dir, *verilog_sources)
+ self.add_source_dir(verilog_dir)
+
+ def build(self, *args, **kwargs):
+ build_dir = kwargs.get('build_dir', 'build')
+ self.copy_sources(build_dir)
+ super().build(*args, **kwargs)
def do_finalize(self, fragment):
try:
diff --git a/fast_servo/gateware/fast_servo_soc.py b/fast_servo/gateware/fast_servo_soc.py
index 02128f5..abfc583 100644
--- a/fast_servo/gateware/fast_servo_soc.py
+++ b/fast_servo/gateware/fast_servo_soc.py
@@ -282,9 +282,3 @@ if __name__ == "__main__":
os.chdir(os.path.join(root_path, build_dir))
with open(f"{build_name}.bif", "w") as f:
f.write(f"all:\n{{\n\t{build_name}.bit\n}}")
-
- cmd = f"bootgen -image {build_name}.bif -arch zynq -process_bitstream bin -w on".split(" ")
- subprocess.run(cmd)
-
-
-
# diff between linen-org/linien commit ID 93f1f50: # diff between linen-org/linien commit ID 93f1f50:
# https://github.com/linien-org/linien/commit/93f1f50ebd86fe3314cab5a549462d0fcbf6a658 # https://github.com/linien-org/linien/commit/93f1f50ebd86fe3314cab5a549462d0fcbf6a658
# and elhep/linien commit ID b73eea0: # and elhep/linien commit ID b73eea0:
@ -55,27 +16,41 @@ index b3f3683..98c6e51 100644
- repo: https://github.com/pycqa/isort - repo: https://github.com/pycqa/isort
rev: 5.12.0 rev: 5.12.0
diff --git a/gateware/build_fpga_image.sh b/gateware/build_fpga_image.sh
index f822402..be7401c 100644
--- a/gateware/build_fpga_image.sh
+++ b/gateware/build_fpga_image.sh
@@ -16,4 +16,9 @@ export PATH=$VIVADOPATH:$PATH
rm linien-server/linien_server/gateware.bin -f
# run with -m option to avoid errors related to relative imports without breaking pytest
-python3 -m gateware.fpga_image_helper
\ No newline at end of file
+
+if [ -z "$1" ]; then
+ python3 -m gateware.fpga_image_helper
+else
+ python3 -m gateware.fpga_image_helper -p $1
+fi
\ No newline at end of file
diff --git a/gateware/fpga_image_helper.py b/gateware/fpga_image_helper.py diff --git a/gateware/fpga_image_helper.py b/gateware/fpga_image_helper.py
index c3e20e7..ebead1d 100644 index 6c34429..a0b12d0 100644
--- a/gateware/fpga_image_helper.py --- a/gateware/fpga_image_helper.py
+++ b/gateware/fpga_image_helper.py +++ b/gateware/fpga_image_helper.py
@@ -1,6 +1,7 @@ @@ -1,5 +1,6 @@
# This file is part of Linien and based on redpid. # Copyright 2014-2015 Robert Jördens <jordens@gmail.com>
# # Copyright 2018-2022 Benjamin Wiegand <benjamin.wiegand@physik.hu-berlin.de>
# Copyright (C) 2016-2024 Linien Authors (https://github.com/linien-org/linien#license)
+# Copyright 2023 Jakub Matyas <jakubk.m@gmail.com> +# Copyright 2023 Jakub Matyas <jakubk.m@gmail.com>
# #
# Linien is free software: you can redistribute it and/or modify # This file is part of Linien and based on redpid.
# it under the terms of the GNU General Public License as published by #
@@ -20,16 +21,18 @@ @@ -23,14 +24,16 @@ from pathlib import Path
from pathlib import Path REPO_ROOT_DIR = Path(__file__).resolve().parents[1]
from .bit2bin import bit2bin from .bit2bin import bit2bin
-from .hw_platform import Platform -from .hw_platform import Platform
-from .linien_module import RootModule -from .linien_module import RootModule
REPO_ROOT_DIR = Path(__file__).resolve().parents[1]
def py_csrconstants(map, fil): def py_csrconstants(map, fil):
fil.write("csr_constants = {\n") fil.write("csr_constants = {\n")
@ -90,7 +65,7 @@ index c3e20e7..ebead1d 100644
fil.write("}\n\n") fil.write("}\n\n")
@@ -51,26 +54,51 @@ def get_csrmap(banks): @@ -52,26 +55,49 @@ def get_csrmap(banks):
def py_csrmap(it, fil): def py_csrmap(it, fil):
fil.write("csr = {\n") fil.write("csr = {\n")
for reg in it: for reg in it:
@ -109,7 +84,7 @@ index c3e20e7..ebead1d 100644
- platform = Platform() - platform = Platform()
- root = RootModule(platform) - root = RootModule(platform)
+ import argparse + import argparse
+
+ parser = argparse.ArgumentParser() + parser = argparse.ArgumentParser()
+ parser.add_argument("-p", "--platform", default=None) + parser.add_argument("-p", "--platform", default=None)
+ args = parser.parse_args() + args = parser.parse_args()
@ -128,11 +103,10 @@ index c3e20e7..ebead1d 100644
+ root = LinienFastServo(platform) + root = LinienFastServo(platform)
+ else: + else:
+ raise ValueError("Unknown platform") + raise ValueError("Unknown platform")
+ +
+ platform.add_source_dir(REPO_ROOT_DIR / "gateware" / "verilog") + platform.add_source_dir(REPO_ROOT_DIR / "gateware" / "verilog")
+ build_dir = REPO_ROOT_DIR / "gateware" / "build" + build_dir = REPO_ROOT_DIR / "gateware" / "build"
+ platform.build(root, build_name="top", build_dir=build_dir, run=True) + platform.build(root, build_name="top", build_dir=build_dir, run=True)
with open( with open(
REPO_ROOT_DIR / "linien-server" / "linien_server" / "csrmap.py", "w" REPO_ROOT_DIR / "linien-server" / "linien_server" / "csrmap.py", "w"
) as fil: ) as fil:
@ -143,7 +117,7 @@ index c3e20e7..ebead1d 100644
py_csrmap(csr, fil) py_csrmap(csr, fil)
fil.write("states = {}\n".format(repr(root.linien.state_names))) fil.write("states = {}\n".format(repr(root.linien.state_names)))
fil.write("signals = {}\n".format(repr(root.linien.signal_names))) fil.write("signals = {}\n".format(repr(root.linien.signal_names)))
-
- platform.add_source_dir(REPO_ROOT_DIR / "gateware" / "verilog") - platform.add_source_dir(REPO_ROOT_DIR / "gateware" / "verilog")
- build_dir = REPO_ROOT_DIR / "gateware" / "build" - build_dir = REPO_ROOT_DIR / "gateware" / "build"
- platform.build(root, build_name="top", build_dir=build_dir) - platform.build(root, build_name="top", build_dir=build_dir)
@ -154,14 +128,14 @@ diff --git a/gateware/linien_module.py b/gateware/linien_module.py
index 16ca186..6905ac0 100644 index 16ca186..6905ac0 100644
--- a/gateware/linien_module.py --- a/gateware/linien_module.py
+++ b/gateware/linien_module.py +++ b/gateware/linien_module.py
@@ -1,6 +1,7 @@ @@ -2,6 +2,7 @@
# This file is part of Linien and based on redpid. # Copyright 2018-2022 Benjamin Wiegand <benjamin.wiegand@physik.hu-berlin.de>
# # Copyright 2021-2023 Bastian Leykauf <leykauf@physik.hu-berlin.de>
# Copyright (C) 2016-2024 Linien Authors (https://github.com/linien-org/linien#license) # Copyright 2022 Christian Freier <christian.freier@nomadatomics.com>
+# Copyright 2023 Jakub Matyas <jakubk.m@gmail.com> +# Copyright 2023 Jakub Matyas <jakubk.m@gmail.com>
# #
# Linien is free software: you can redistribute it and/or modify # This file is part of Linien and based on redpid.
# it under the terms of the GNU General Public License as published by #
@@ -36,19 +37,13 @@ from misoc.interconnect.csr import AutoCSR, CSRStatus, CSRStorage @@ -36,19 +37,13 @@ from misoc.interconnect.csr import AutoCSR, CSRStatus, CSRStorage
from .logic.autolock import FPGAAutolock from .logic.autolock import FPGAAutolock
from .logic.chains import FastChain, SlowChain, cross_connect from .logic.chains import FastChain, SlowChain, cross_connect

View File

@ -20,15 +20,13 @@
from migen import * from migen import *
from migen.genlib.cdc import MultiReg from migen.genlib.cdc import MultiReg
from misoc.interconnect.csr import AutoCSR, CSRStatus, CSRStorage from misoc.interconnect.csr import AutoCSR, CSRStatus, CSRStorage
from misoc.interconnect.stream import AsyncFIFO
class CRG(Module): class _CRG(Module):
def __init__(self, platform, dco_clk, dco_freq=200e6): def __init__(self, platform, dco_clk, dco_freq=200e6):
self.clock_domains.cd_dco = ClockDomain() self.clock_domains.cd_dco = ClockDomain()
self.clock_domains.cd_dco2x = ClockDomain() self.clock_domains.cd_dco2x = ClockDomain()
self.clock_domains.cd_dco2d = ClockDomain() self.clock_domains.cd_dco2d = ClockDomain()
self.clock_domains.cd_dco2d_45_degree = ClockDomain()
dco_clk_p, dco_clk_n = dco_clk dco_clk_p, dco_clk_n = dco_clk
dco_clk_buf = Signal() dco_clk_buf = Signal()
@ -43,83 +41,59 @@ class CRG(Module):
clk_dco = Signal() clk_dco = Signal()
clk_dco2x = Signal() clk_dco2x = Signal()
clk_dco2d = Signal() clk_dco2d = Signal()
clk_dco2d_45_degree = Signal()
mmcm_ps_psdone = Signal()
self.locked = Signal() self.locked = Signal()
self.mmcm_rst = Signal()
self.ddr_clk_phase_shift_en = Signal()
self.ddr_clk_phase_incdec = Signal()
platform.add_period_constraint(dco_clk_p, 1e9 / dco_freq) platform.add_period_constraint(dco_clk_p, 1e9 / dco_freq)
self.specials += [ self.specials += [
Instance( Instance(
"MMCME2_ADV", "PLLE2_BASE",
p_BANDWIDTH="OPTIMIZED", p_BANDWIDTH="OPTIMIZED",
p_DIVCLK_DIVIDE=1, p_DIVCLK_DIVIDE=1,
p_CLKFBOUT_PHASE=0.0, p_CLKFBOUT_PHASE=0.0,
p_CLKFBOUT_MULT_F=4, # VCO @ 800 MHz p_CLKFBOUT_MULT=4, # VCO @ 800 MHz
p_CLKIN1_PERIOD=(1e9 / dco_freq), p_CLKIN1_PERIOD=(1e9 / dco_freq),
p_REF_JITTER1=0.01, p_REF_JITTER1=0.01,
p_STARTUP_WAIT="FALSE", p_STARTUP_WAIT="FALSE",
i_CLKIN1=dco_clk_buf, i_CLKIN1=dco_clk_buf,
i_PWRDWN=0, i_PWRDWN=0,
i_RST=ResetSignal("sys") | self.mmcm_rst, i_RST=ResetSignal("sys"),
i_CLKFBIN=clk_feedback_buf, i_CLKFBIN=clk_feedback_buf,
o_CLKFBOUT=clk_feedback, o_CLKFBOUT=clk_feedback,
p_CLKOUT0_DIVIDE=4,
p_CLKOUT0_USE_FINE_PS="TRUE", p_CLKOUT0_PHASE=0.0,
p_CLKOUT0_DIVIDE_F=8,
p_CLKOUT0_PHASE=45.0,
p_CLKOUT0_DUTY_CYCLE=0.5, p_CLKOUT0_DUTY_CYCLE=0.5,
o_CLKOUT0=clk_dco2d_45_degree, # 100 MHz <- dco_clk / 2 = 200 MHz / 2 o_CLKOUT0=clk_dco, # 200 MHz <- dco_clk
o_LOCKED=self.locked,
p_CLKOUT1_DIVIDE=2, p_CLKOUT1_DIVIDE=2,
p_CLKOUT1_PHASE=0.0, p_CLKOUT1_PHASE=0.0,
p_CLKOUT1_DUTY_CYCLE=0.5, p_CLKOUT1_DUTY_CYCLE=0.5,
o_CLKOUT1=clk_dco2x, # 400 MHZ <- 2 * dco_clk = 2*200 MHz o_CLKOUT1=clk_dco2x, # 400 MHZ <- 2 * dco_clk = 2*200 MHz
p_CLKOUT2_DIVIDE=8, p_CLKOUT2_DIVIDE=8,
p_CLKOUT2_PHASE=0.0, p_CLKOUT2_PHASE=0.0,
p_CLKOUT2_DUTY_CYCLE=0.5, p_CLKOUT2_DUTY_CYCLE=0.5,
o_CLKOUT2=clk_dco2d, # 100 MHz <- dco_clk / 2 = 200 MHz / 2 o_CLKOUT2=clk_dco2d, # 100 MHz <- dco_clk / 2 = 200 MHz / 2
o_LOCKED=self.locked,
p_CLKOUT3_DIVIDE=4,
p_CLKOUT3_PHASE=0.0,
p_CLKOUT3_DUTY_CYCLE=0.5,
o_CLKOUT3=clk_dco, # 200 MHz <- dco_clk
i_PSCLK=ClockSignal(),
i_PSEN=self.ddr_clk_phase_shift_en,
i_PSINCDEC=self.ddr_clk_phase_incdec,
o_PSDONE=mmcm_ps_psdone,
) )
] ]
self.specials += Instance("BUFG", i_I=clk_feedback, o_O=clk_feedback_buf) self.specials += Instance("BUFG", i_I=clk_feedback, o_O=clk_feedback_buf)
self.specials += Instance("BUFG", i_I=clk_dco, o_O=self.cd_dco.clk) self.specials += Instance("BUFG", i_I=clk_dco, o_O=self.cd_dco.clk)
self.specials += Instance("BUFG", i_I=clk_dco2d, o_O=self.cd_dco2d.clk) self.specials += Instance("BUFG", i_I=clk_dco2d, o_O=self.cd_dco2d.clk)
self.specials += Instance("BUFG", i_I=clk_dco2d_45_degree, o_O=self.cd_dco2d_45_degree.clk)
self.specials += Instance("BUFG", i_I=clk_dco2x, o_O=self.cd_dco2x.clk) self.specials += Instance("BUFG", i_I=clk_dco2x, o_O=self.cd_dco2x.clk)
# Ignore dco2d to mmcm dco_clk path created by SoC's rst.
platform.add_false_path_constraints(self.cd_dco2d.clk, dco_clk_buf)
self.specials += Instance("FD", p_INIT=1, i_D=~self.locked, i_C=self.cd_dco2d.clk, o_Q=self.cd_dco2d.rst)
class ADC(Module, AutoCSR): class ADC(Module, AutoCSR):
def __init__(self, platform, dco_freq=200e6): def __init__(self, platform, dco_freq=200e6):
adc_pads = platform.request("adc") adc_pads = platform.request("adc")
afe_pads = platform.request("adc_afe") afe_pads = platform.request("adc_afe")
self.frame_csr = CSRStatus(5) self.frame_csr = CSRStatus(4)
self.data_ch0 = CSRStatus(16) self.data_ch0 = CSRStatus(16)
self.data_ch1 = CSRStatus(16) self.data_ch1 = CSRStatus(16)
self.tap_delay = CSRStorage(5) self.tap_delay = CSRStorage(5)
self.bitslip_csr = CSRStorage(1) self.bitslip_csr = CSRStorage(1)
self.afe_ctrl = CSRStorage(7) self.afe_ctrl = CSRStorage(4)
tap_delay_val = Signal(5) tap_delay_val = Signal(5)
bitslip = Signal() bitslip = Signal()
@ -131,17 +105,7 @@ class ADC(Module, AutoCSR):
ch2_shdn = Signal() ch2_shdn = Signal()
self.data_out = [Signal(16, reset_less=True), Signal(16, reset_less=True)] self.data_out = [Signal(16, reset_less=True), Signal(16, reset_less=True)]
self.data_out_cdc = [Signal(16, reset_less=True), Signal(16, reset_less=True)]
self.s_frame = Signal(4) self.s_frame = Signal(4)
self.s_frame_cdc = Signal(4)
self.submodules.cdc_fifo = ClockDomainsRenamer({"write": "dco2d", "read": "sys"})(AsyncFIFO([("data", 36)], 4))
self.comb += [
self.cdc_fifo.sink.data.eq(Cat(self.data_out_cdc[0], self.data_out_cdc[1], self.s_frame_cdc)),
self.cdc_fifo.sink.stb.eq(~ResetSignal("dco2d")),
Cat(self.data_out[0], self.data_out[1], self.s_frame).eq(self.cdc_fifo.source.data),
self.cdc_fifo.source.ack.eq(~ResetSignal("sys")),
]
### ###
@ -153,14 +117,11 @@ class ADC(Module, AutoCSR):
# dco_clk.n.eq(adc_pads.dco_n), # dco_clk.n.eq(adc_pads.dco_n),
tap_delay_val.eq(self.tap_delay.storage), tap_delay_val.eq(self.tap_delay.storage),
Cat(ch1_gain_x10, ch2_gain_x10, ch1_shdn, ch2_shdn).eq( Cat(ch1_gain_x10, ch2_gain_x10, ch1_shdn, ch2_shdn).eq(
self.afe_ctrl.storage[0:4] self.afe_ctrl.storage
), ),
] ]
self.submodules.crg = CRG(platform, dco_clk, dco_freq) self.submodules._crg = _CRG(platform, dco_clk, dco_freq)
self.comb += self.afe_ctrl.storage[4].eq(self.crg.mmcm_rst)
self.comb += self.afe_ctrl.storage[5].eq(self.crg.ddr_clk_phase_shift_en)
self.comb += self.afe_ctrl.storage[6].eq(self.crg.ddr_clk_phase_incdec)
self.specials += MultiReg(self.bitslip_csr.re, bitslip_re_dco_2d, "dco2d") self.specials += MultiReg(self.bitslip_csr.re, bitslip_re_dco_2d, "dco2d")
self.sync.dco2d += [ self.sync.dco2d += [
@ -168,8 +129,7 @@ class ADC(Module, AutoCSR):
] ]
self.comb += [ self.comb += [
self.frame_csr.status[0:4].eq(self.s_frame[0:4]), self.frame_csr.status.eq(self.s_frame),
self.frame_csr.status[4].eq(self.crg.locked),
self.data_ch0.status.eq(self.data_out[0]), self.data_ch0.status.eq(self.data_out[0]),
self.data_ch1.status.eq(self.data_out[1]), self.data_ch1.status.eq(self.data_out[1]),
] ]
@ -186,7 +146,7 @@ class ADC(Module, AutoCSR):
self.specials += Instance( self.specials += Instance(
"LTC2195", "LTC2195",
i_rst_in=ResetSignal("dco2d"), i_rst_in=ResetSignal("sys"),
i_clk200=ClockSignal("idelay"), i_clk200=ClockSignal("idelay"),
i_DCO=ClockSignal("dco"), i_DCO=ClockSignal("dco"),
i_DCO_2D=ClockSignal("dco2d"), i_DCO_2D=ClockSignal("dco2d"),
@ -198,9 +158,9 @@ class ADC(Module, AutoCSR):
i_D1_in_n=adc_pads.data1_n, i_D1_in_n=adc_pads.data1_n,
i_bitslip=bitslip, i_bitslip=bitslip,
i_delay_val=tap_delay_val, i_delay_val=tap_delay_val,
o_ADC0_out=self.data_out_cdc[1], # LANES swapped on hardware o_ADC0_out=self.data_out[1], # LANES swapped on hardware
o_ADC1_out=self.data_out_cdc[0], o_ADC1_out=self.data_out[0],
o_FR_out=self.s_frame_cdc, o_FR_out=self.s_frame,
o_o_data_from_pins=dummy, o_o_data_from_pins=dummy,
o_idelay_rdy=dummy_idelay_rdy, o_idelay_rdy=dummy_idelay_rdy,
) )

View File

@ -20,7 +20,6 @@
from migen import * from migen import *
from misoc.interconnect.csr import AutoCSR, CSRStorage from misoc.interconnect.csr import AutoCSR, CSRStorage
from migen.genlib.io import DDROutput from migen.genlib.io import DDROutput
from misoc.interconnect.stream import AsyncFIFO
class DAC(Module, AutoCSR): class DAC(Module, AutoCSR):
@ -39,51 +38,37 @@ class DAC(Module, AutoCSR):
output_data_ch1 = Signal(14) output_data_ch1 = Signal(14)
self.data_in = [Signal(14, reset_less=True), Signal(14, reset_less=True)] self.data_in = [Signal(14, reset_less=True), Signal(14, reset_less=True)]
self.data_in_csr = [Signal(14, reset_less=True), Signal(14, reset_less=True)]
self.data_in_cdc = [Signal(14, reset_less=True), Signal(14, reset_less=True)]
self.data_in_csr_cdc = [Signal(14, reset_less=True), Signal(14, reset_less=True)]
platform.add_period_constraint(dac_pads.dclkio, 10.0) platform.add_period_constraint(dac_pads.dclkio, 10.0)
self.submodules.cdc_fifo = ClockDomainsRenamer({"write": "sys", "read": "dco2d"})(AsyncFIFO([("data", 56)], 4))
self.comb += [
self.data_in_csr[0].eq(self.output_value_ch0.storage),
self.data_in_csr[1].eq(self.output_value_ch1.storage),
self.cdc_fifo.sink.data.eq(Cat(self.data_in[0], self.data_in[1], self.data_in_csr[0], self.data_in_csr[1])),
self.cdc_fifo.sink.stb.eq(~ResetSignal("sys")),
Cat(self.data_in_cdc[0], self.data_in_cdc[1], self.data_in_csr_cdc[0], self.data_in_csr_cdc[1]).eq(self.cdc_fifo.source.data),
self.cdc_fifo.source.ack.eq(~ResetSignal("dco2d")),
]
self.comb += [ self.comb += [
Cat(manual_override, ch0_pd, ch1_pd).eq(self.dac_ctrl.storage), Cat(manual_override, ch0_pd, ch1_pd).eq(self.dac_ctrl.storage),
dac_pads.rst.eq(ResetSignal("dco2d")), dac_pads.rst.eq(ResetSignal("sys")),
dac_afe_pads.ch1_pd_n.eq(~ch0_pd), dac_afe_pads.ch1_pd_n.eq(~ch0_pd),
dac_afe_pads.ch2_pd_n.eq(~ch1_pd), dac_afe_pads.ch2_pd_n.eq(~ch1_pd),
output_data_ch0.eq( output_data_ch0.eq(
Mux(manual_override, self.data_in_csr_cdc[0], self.data_in_cdc[0]) Mux(manual_override, self.output_value_ch0.storage, self.data_in[0])
), ),
output_data_ch1.eq( output_data_ch1.eq(
Mux(manual_override, self.data_in_csr_cdc[1], self.data_in_cdc[1]) Mux(manual_override, self.output_value_ch1.storage, self.data_in[1])
), ),
] ]
self.specials += [ # data
Instance("ODDR", for lane in range(14):
i_C=ClockSignal("dco2d"), self.specials += DDROutput(
i_CE=~ResetSignal("dco2d"), i1 = output_data_ch0[lane],
i_D1=output_data_ch0[lane], # DDR CLK Rising Edge i2 = output_data_ch1[lane],
i_D2=output_data_ch1[lane], # DDR CLK Falling Edge o = dac_pads.data[lane],
o_Q=dac_pads.data[lane], clk = ClockSignal("dco2d")
p_DDR_CLK_EDGE="SAME_EDGE") )
for lane in range(14)]
self.specials += Instance("ODDR", # clock forwarding
i_C=ClockSignal("dco2d_45_degree"), self.specials += DDROutput(
i_CE=~ResetSignal("dco2d"), i1 = 0b0,
i_D1=0, i2 = 0b1,
i_D2=1, o = dac_pads.dclkio,
o_Q=dac_pads.dclkio, clk = ClockSignal("dco2d"),
p_DDR_CLK_EDGE="SAME_EDGE") )
class AUX_DAC_CTRL(Module, AutoCSR): class AUX_DAC_CTRL(Module, AutoCSR):

View File

@ -147,7 +147,6 @@ class BaseSoC(PS7, AutoCSR):
# self.add_main_adc(platform) # self.add_main_adc(platform)
self.submodules.adc = ADC(platform) self.submodules.adc = ADC(platform)
self.csr_devices.append("adc") self.csr_devices.append("adc")
platform.add_false_path_constraints(self.crg.cd_sys.clk, self.adc.crg.cd_dco2d.clk)
# self.add_main_dac(platform) # self.add_main_dac(platform)
self.submodules.dac = DAC(platform) self.submodules.dac = DAC(platform)

View File

@ -1,227 +0,0 @@
diff --git a/linien-gui/linien_gui/ui/general_panel.ui b/linien_gui/ui/general_panel.ui
index 7cf74a7..6c2bd45 100644
--- a/linien-gui/linien_gui/ui/general_panel.ui
+++ b/linien_gui/ui/general_panel.ui
@@ -128,11 +128,6 @@
<string>FAST OUT 2</string>
</property>
</item>
- <item>
- <property name="text">
- <string>ANALOG OUT 0</string>
- </property>
- </item>
</widget>
</item>
</layout>
@@ -213,11 +208,6 @@
<string>FAST OUT 2</string>
</property>
</item>
- <item>
- <property name="text">
- <string>ANALOG OUT 0</string>
- </property>
- </item>
<item>
<property name="text">
<string>disabled</string>
@@ -389,6 +379,9 @@
<property name="text">
<string>ANALOG OUT 0</string>
</property>
+ <property name="visible">
+ <bool>false</bool>
+ </property>
</widget>
</item>
<item>
@@ -399,6 +392,9 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
+ <property name="visible">
+ <bool>false</bool>
+ </property>
<item>
<property name="text">
<string>positive</string>
@@ -619,6 +615,9 @@
<property name="title">
<string>Slow Analog Outputs (0-1.8V)</string>
</property>
+ <property name="visible">
+ <bool>false</bool>
+ </property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label_20">
diff --git a/linien-gui/linien_gui/ui/main_window.ui b/linien_gui/ui/main_window.ui
index 3d8b8bf..72f6159 100644
--- a/linien-gui/linien_gui/ui/main_window.ui
+++ b/linien_gui/ui/main_window.ui
@@ -145,10 +145,10 @@ p, li { white-space: pre-wrap; }
<number>3</number>
</property>
<property name="minimum">
- <double>-1.000000000000000</double>
+ <double>-0.500000000000000</double>
</property>
<property name="maximum">
- <double>1.000000000000000</double>
+ <double>0.500000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
@@ -199,13 +199,13 @@ p, li { white-space: pre-wrap; }lin
<double>0.000000000000000</double>
</property>
<property name="maximum">
- <double>1.000000000000000</double>
+ <double>0.500000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
- <double>1.000000000000000</double>
+ <double>0.500000000000000</double>
</property>
</widget>
</item>
@@ -242,7 +242,6 @@ p, li { white-space: pre-wrap; }
<widget class="QLabel" name="label_4">
<property name="font">
<font>
- <weight>75</weight>
<bold>true</bold>
</font>
</property>
@@ -278,7 +277,6 @@ p, li { white-space: pre-wrap; }
<widget class="QLabel" name="label_5">
<property name="font">
<font>
- <weight>75</weight>
<bold>true</bold>
</font>
</property>
@@ -366,7 +364,6 @@ p, li { white-space: pre-wrap; }
<widget class="QLabel" name="label">
<property name="font">
<font>
- <weight>75</weight>
<bold>true</bold>
</font>
</property>
diff --git a/linien-gui/linien_gui/ui/modulation_sweep_panel.ui b/linien_gui/ui/modulation_sweep_panel.ui
index 6d8af14..29c8a63 100644
--- a/linien-gui/linien_gui/ui/modulation_sweep_panel.ui
+++ b/linien_gui/ui/modulation_sweep_panel.ui
@@ -68,7 +68,7 @@
<number>3</number>
</property>
<property name="maximum">
- <double>2.000000000000000</double>
+ <double>0.500000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
@@ -105,82 +105,82 @@
</property>
<item>
<property name="text">
- <string>3.8 kHz</string>
+ <string>3.04 kHz</string>
</property>
</item>
<item>
<property name="text">
- <string>1.9 kHz</string>
+ <string>1.52 kHz</string>
</property>
</item>
<item>
<property name="text">
- <string>954 Hz</string>
+ <string>763 Hz</string>
</property>
</item>
<item>
<property name="text">
- <string>477 Hz</string>
+ <string>382 Hz</string>
</property>
</item>
<item>
<property name="text">
- <string>238 Hz</string>
+ <string>190 Hz</string>
</property>
</item>
<item>
<property name="text">
- <string>119 Hz</string>
+ <string>95 Hz</string>
</property>
</item>
<item>
<property name="text">
- <string>59 Hz</string>
+ <string>47 Hz</string>
</property>
</item>
<item>
<property name="text">
- <string>30 Hz</string>
+ <string>24 Hz</string>
</property>
</item>
<item>
<property name="text">
- <string>15 Hz</string>
+ <string>12 Hz</string>
</property>
</item>
<item>
<property name="text">
- <string>7.5 Hz</string>
+ <string>6 Hz</string>
</property>
</item>
<item>
<property name="text">
- <string>3.7 Hz</string>
+ <string>2.96 Hz</string>
</property>
</item>
<item>
<property name="text">
- <string>1.9 Hz</string>
+ <string>1.52 Hz</string>
</property>
</item>
<item>
<property name="text">
- <string>0.93 Hz</string>
+ <string>0.74 Hz</string>
</property>
</item>
<item>
<property name="text">
- <string>0.47 Hz</string>
+ <string>0.38 Hz</string>
</property>
</item>
<item>
<property name="text">
- <string>0.23 Hz</string>
+ <string>0.18 Hz</string>
</property>
</item>
<item>
<property name="text">
- <string>0.12 Hz</string>
+ <string>0.10 Hz</string>
</property>
</item>
</widget>

View File

@ -1,43 +0,0 @@
diff --git a/linien_gui/ui/device_manager.py b/linien_gui/ui/device_manager.py
index e584825..16994ad 100644
--- a/linien_gui/ui/device_manager.py
+++ b/linien_gui/ui/device_manager.py
@@ -109,19 +109,13 @@ class DeviceManager(QtWidgets.QMainWindow):
) -> None:
loading_dialog.hide()
if not aborted:
- display_question = (
+ # Fast Servo does not support OTA Update
+ display_error = (
f"Server version ({remote_version}) does not match the client "
- f"({client_version}) version. Should the corresponding server "
- f"version be installed?"
+ f"({client_version}) version."
+ f"Please install a matching server and client version"
)
- if question_dialog(
- self, display_question, "Install corresponding version?"
- ):
- show_installation_progress_widget(
- parent=self,
- device=device,
- callback=lambda: self.connect_to_device(device),
- )
+ error_dialog(self, display_error)
def handle_authentication_exception():
loading_dialog.hide()
diff --git a/linien_gui/ui/main_window.py b/linien_gui/ui/main_window.py
index dad465e..8d6a0b4 100644
--- a/linien_gui/ui/main_window.py
+++ b/linien_gui/ui/main_window.py
@@ -202,7 +202,8 @@ class MainWindow(QtWidgets.QMainWindow):
super().closeEvent(*args, **kwargs)
def show_new_version_available(self):
- self.newVersionAvailableLabel.show()
+ # Fast Servo does not support OTA Update
+ pass
def handle_key_press(self, key):
logger.debug(f"key pressed {key}")

View File

@ -4,14 +4,14 @@
diff --git a/monitor/Makefile b/monitor/Makefile diff --git a/monitor/Makefile b/monitor/Makefile
new file mode 100644 new file mode 100644
index 0000000..0c9bb53 index 0000000..044d88e
--- /dev/null --- /dev/null
+++ b/monitor/Makefile +++ b/monitor/Makefile
@@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
+# Makefile for libmonitor +# Makefile for libmonitor
+ +
+OBJS = monitor.o +OBJS = monitor.o
+SRCS = $(subst .o,.c, $(OBJS))) +SRCS = $(subst .o,.c, $(OBJS))
+OSOBJS = monitor.os +OSOBJS = monitor.os
+TARGETLIB=libmonitor.so +TARGETLIB=libmonitor.so
+CFLAGS=-g -std=gnu99 -Wall -Werror +CFLAGS=-g -std=gnu99 -Wall -Werror
@ -59,16 +59,27 @@ index ce1b28e..233b82a 100644
libmonitor = cdll.LoadLibrary(libmonitor_file) libmonitor = cdll.LoadLibrary(libmonitor_file)
libmonitor.read_value.restype = c_uint32 libmonitor.read_value.restype = c_uint32
diff --git a/setup.py b/setup.py diff --git a/setup.py b/setup.py
index 9302177..2258ddc 100644 index 98bdaee..b0a8af4 100644
--- a/setup.py --- a/setup.py
+++ b/setup.py +++ b/setup.py
@@ -1,4 +1,28 @@ @@ -1,5 +1,10 @@
import re
-from distutils.core import Extension, setup -from distutils.core import Extension, setup
+import os +import os
+
+from distutils.core import setup +from distutils.core import setup
+from distutils.command.build import build +from distutils.command.build import build
+from distutils.command.install import install
+ +
from pathlib import Path
# from https://stackoverflow.com/a/7071358/2750945
@@ -11,9 +16,50 @@ if mo:
verstr = mo.group(1)
else:
raise RuntimeError("Unable to find version string in %s." % (VERSIONFILE,))
+ +
+# Patch from https://github.com/linien-org/pyrp3/blob/e6688acf8bd79d2dbe1d192d09c1a1baf1f6c67b/setup.py#L16-L55
+build_dir = "monitor/" +build_dir = "monitor/"
+ +
+def compile_libmonitor(): +def compile_libmonitor():
@ -80,16 +91,51 @@ index 9302177..2258ddc 100644
+ finally: + finally:
+ os.chdir(cwd) + os.chdir(cwd)
+ +
+
+def install_libmonitor(prefix=""):
+ cwd = os.getcwd() # get current directory
+ try:
+ os.chdir(build_dir)
+ os.system("make install INSTALL_DIR={prefix}".format(prefix=prefix))
+ finally:
+ os.chdir(cwd)
+
+
+class lib_build(build): +class lib_build(build):
+ def run(self): + def run(self):
+ compile_libmonitor() + compile_libmonitor()
+ build.run(self) + build.run(self)
+ +
+setup_args = dict( +
+ cmdclass={ +class lib_install(install):
+ "build": lib_build + def run(self):
+ } + compile_libmonitor()
+) + install_libmonitor(self.prefix)
+ # install.run(self)
+
+# Will use nix to install libmonitor
+cmdclass = {
+ "build": lib_build
+}
+
this_directory = Path(__file__).parent
long_description = (this_directory / "README.rst").read_text()
-setup_args = dict(ext_modules=[Extension("monitor", ["monitor/monitor.c"])]) +
setup(**setup_args) setup(
name="pyrp3",
version=verstr,
@@ -32,6 +78,7 @@ setup(
"cached_property>=1.5.2",
"numpy>=1.11.0",
],
+ cmdclass=cmdclass,
classifiers=[
"Intended Audience :: Developers",
"Intended Audience :: Education",
@@ -45,5 +92,4 @@ setup(
"Topic :: Software Development :: Libraries :: Python Modules",
],
keywords=["redpitaya", "FPGA", "zynq"],
- ext_modules=[Extension("monitor", ["monitor/monitor.c"])],
)

View File

@ -1,22 +0,0 @@
diff --git a/linien-server/linien_server/parameters.py b/linien-server/linien_server/parameters.py
index 12f16ed..287f304 100644
--- a/linien-server/linien_server/parameters.py
+++ b/linien-server/linien_server/parameters.py
@@ -311,7 +311,7 @@ class Parameters:
# ------------------- MODULATION PARAMETERS ------------------------------------
self.modulation_amplitude = Parameter(
- min_=0, max_=(1 << 14) - 1, start=1 * Vpp, restorable=True, loggable=True
+ min_=0, max_=(1 << 14) - 1, start=0.1 * Vpp, restorable=True, loggable=True
)
"""
The amplitude of the modulation in internal units. Use Vpp for conversion to
@@ -320,7 +320,7 @@ class Parameters:
"""
self.modulation_frequency = Parameter(
- min_=0, max_=0xFFFFFFFF, start=15 * MHz, restorable=True, loggable=True
+ min_=0, max_=0xFFFFFFFF, start=1 * MHz, restorable=True, loggable=True
)
"""
Frequency of the modulation in internal units. Use MHz for conversion to

View File

@ -1,26 +0,0 @@
diff --git a/linien-server/linien_server/cli.py b/linien-server/linien_server/cli.py
index 98539b2..7781c74 100644
--- a/linien-server/linien_server/cli.py
+++ b/linien-server/linien_server/cli.py
@@ -83,18 +83,9 @@ class LinienServerCLI:
else:
control = RedPitayaControlService(host=host)
- if fake or host:
- authenticator = no_authenticator
- else:
- authenticator = username_and_password_authenticator
-
- try:
- if not (fake or host): # only available on RP
- mdio_tool.disable_ethernet_blinking()
- run_threaded_server(control, authenticator=authenticator)
- finally:
- if not (fake or host): # only available on RP
- mdio_tool.enable_ethernet_blinking()
+ authenticator = no_authenticator
+
+ run_threaded_server(control, authenticator=authenticator)
def enable(self) -> None:
"""Enable the Linien server to start on boot."""

View File

@ -1,57 +0,0 @@
diff --git a/gateware/linien_module.py b/gateware/linien_module.py
index a958896..a64714c 100644
--- a/gateware/linien_module.py
+++ b/gateware/linien_module.py
@@ -233,23 +233,46 @@ class LinienModule(Module, AutoCSR):
self.fast_a.adc.eq(soc.analog.adc_a),
self.fast_b.adc.eq(soc.analog.adc_b),
]
-
+
# now, we combine the output of the two paths, with a variable factor each.
mixed = Signal(
(2 + ((signal_width + 1) + self.logic.chain_a_factor.size), True)
)
+
+ chain_a_factor_mult_fast_a_out_i = Signal(
+ (2 + ((signal_width + 1) + self.logic.chain_a_factor.size), True)
+ )
+
+ chain_b_factor_mult_fast_b_out_i = Signal(
+ (2 + ((signal_width + 1) + self.logic.chain_a_factor.size), True)
+ )
+ combined_offset_signed_left_shifted = Signal(
+ (2 + ((signal_width + 1) + self.logic.chain_a_factor.size), True)
+ )
+ fast_a_out_i_left_shifted = Signal(
+ (2 + ((signal_width + 1) + self.logic.chain_a_factor.size), True)
+ )
+
+ self.sync += [
+ chain_a_factor_mult_fast_a_out_i.eq(self.logic.chain_a_factor.storage * self.fast_a.out_i),
+ chain_b_factor_mult_fast_b_out_i.eq(self.logic.chain_b_factor.storage * self.fast_b.out_i),
+ combined_offset_signed_left_shifted.eq(self.logic.combined_offset_signed << (chain_factor_bits + s)),
+ fast_a_out_i_left_shifted.eq(self.fast_a.out_i << chain_factor_bits),
+ ]
+
+
self.comb += [
If(
self.logic.dual_channel.storage,
mixed.eq(
- (self.logic.chain_a_factor.storage * self.fast_a.out_i)
- + (self.logic.chain_b_factor.storage * self.fast_b.out_i)
- + (self.logic.combined_offset_signed << (chain_factor_bits + s))
+ chain_a_factor_mult_fast_a_out_i
+ + chain_b_factor_mult_fast_b_out_i
+ + combined_offset_signed_left_shifted
),
).Else(
mixed.eq(
- (self.fast_a.out_i << chain_factor_bits)
- + (self.logic.combined_offset_signed << (chain_factor_bits + s))
+ fast_a_out_i_left_shifted
+ + combined_offset_signed_left_shifted
)
)
]

View File

@ -1,19 +0,0 @@
diff --git a/gateware/logic/pid.py b/gateware/logic/pid.py
index e737577..f1a4096 100644
--- a/gateware/logic/pid.py
+++ b/gateware/logic/pid.py
@@ -43,10 +43,12 @@ class PID(Module, AutoCSR):
self.comb += [setpoint_signed.eq(self.setpoint.storage)]
self.error = Signal((self.width + 1, True))
+ error_reg = Signal((self.width + 1, True))
+ self.sync += self.error.eq(error_reg)
self.comb += [
- If(self.running, self.error.eq(self.input - self.setpoint.storage)).Else(
- self.error.eq(0)
+ If(self.running, error_reg.eq(self.input - self.setpoint.storage)).Else(
+ error_reg.eq(0)
)
]

View File

@ -1,64 +0,0 @@
diff --git a/gateware/logic/pid.py b/gateware/logic/pid.py
index 4320f94..e737577 100644
--- a/gateware/logic/pid.py
+++ b/gateware/logic/pid.py
@@ -56,10 +56,13 @@ class PID(Module, AutoCSR):
self.comb += [kp_signed.eq(self.kp.storage)]
kp_mult = Signal((self.width + self.coeff_width, True))
- self.comb += [kp_mult.eq(self.error * kp_signed)]
+ kp_mult_reg = Signal((self.width + self.coeff_width, True))
+ self.sync += kp_mult.eq(kp_mult_reg >> (self.coeff_width - 2))
+
+ self.comb += [kp_mult_reg.eq(self.error * kp_signed)]
self.output_p = Signal((self.width, True))
- self.comb += [self.output_p.eq(kp_mult >> (self.coeff_width - 2))]
+ self.comb += [self.output_p.eq(kp_mult)]
self.kp_mult = kp_mult
@@ -71,8 +74,10 @@ class PID(Module, AutoCSR):
self.comb += [ki_signed.eq(self.ki.storage)]
self.ki_mult = Signal((1 + self.width + self.coeff_width, True))
+ self.ki_mult_reg = Signal((1 + self.width + self.coeff_width, True))
+ self.sync += self.ki_mult.eq(self.ki_mult_reg)
+ self.comb += self.ki_mult_reg.eq((self.error * ki_signed) >> 4)
- self.comb += [self.ki_mult.eq((self.error * ki_signed) >> 4)]
int_reg_width = self.width + self.coeff_width + 4
extra_width = int_reg_width - self.width
@@ -110,15 +115,17 @@ class PID(Module, AutoCSR):
self.kd = CSRStorage(self.coeff_width)
kd_signed = Signal((self.coeff_width, True))
kd_mult = Signal((mult_width, True))
+ kd_mult_reg = Signal((mult_width, True))
+ self.sync += kd_mult.eq(kd_mult_reg)
- self.comb += [kd_signed.eq(self.kd.storage), kd_mult.eq(self.error * kd_signed)]
+ self.comb += [kd_signed.eq(self.kd.storage), kd_mult_reg.eq(self.error * kd_signed >> (self.coeff_width - self.d_shift))]
kd_reg = Signal((out_width, True))
kd_reg_r = Signal((out_width, True))
self.output_d = Signal((out_width, True))
self.sync += [
- kd_reg.eq(kd_mult >> (self.coeff_width - self.d_shift)),
+ kd_reg.eq(kd_mult),
kd_reg_r.eq(kd_reg),
self.output_d.eq(kd_reg - kd_reg_r),
]
@@ -143,4 +150,10 @@ class PID(Module, AutoCSR):
# sync is required here, otherwise we get artifacts when one of the
# signals changes sign
- self.sync += [self.pid_sum.eq(self.output_p + self.int_out + self.output_d)]
+ self.sync += [
+ If(
+ self.running,
+ self.pid_sum.eq(self.output_p + self.int_out + self.output_d),
+ )
+ .Else(self.pid_sum.eq(0))
+ ]

View File

@ -17,7 +17,9 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
import time import mmap
import os
import spidev import spidev
from pyfastservo.common import ( from pyfastservo.common import (
ADC_AFE_CTRL_ADDR, ADC_AFE_CTRL_ADDR,
@ -31,8 +33,6 @@ from pyfastservo.common import (
AUX_ADC_ADDR, AUX_ADC_ADDR,
MAP_MASK, MAP_MASK,
PAGESIZE, PAGESIZE,
write_to_memory,
read_from_memory
) )
# /dev/spidev1.0 <=> spidev<BUS>.<DEVICE> # /dev/spidev1.0 <=> spidev<BUS>.<DEVICE>
@ -44,181 +44,276 @@ AUX_ADC_PORT_A = 2
AUX_ADC_PORT_B = 3 AUX_ADC_PORT_B = 3
def spi_write(spi, address, value): def main_adc_config(test_pattern):
spi.xfer2([address, value])
def spi_read(spi, address):
rx_buffer = spi.xfer2([0x80 | address, 0x00])
return rx_buffer[1]
def main_adc_config(spi, test_pattern):
high_word = (test_pattern & 0xFF00) >> 8 high_word = (test_pattern & 0xFF00) >> 8
low_word = test_pattern & 0xFF low_word = test_pattern & 0xFF
spi_write(spi, 0x00, 0x80) # reset
spi_write(spi, 0x01, 0x20) # REGISTER A1: set to Two's complement Data Format
spi_write(spi, 0x02, 0x15) # REGISTER A2: set to LVDS output, set 4 data lanes and turn on test mode
spi_write(spi, 0x03, high_word) # REGISTER A3: test pattern high word
spi_write(spi, 0x04, low_word) # REGISTER A4: test pattern low word
def main_adc_test_mode(spi, enable):
reg_contents = 0x15 if enable else 0x11 # set to LVDS output, set 4 data lanes and turn on or off test mode
spi_write(spi, 0x02, reg_contents)
def verify_adc_registers(spi, reg_to_check):
for register, expected_value in reg_to_check.items():
value = spi_read(spi, register)
print(f"Spi readback register 0x{register:02x}: 0x{value:02x}")
if value != expected_value:
print(f"Different value read than sent in reg 0x{register:02x}")
def read_frame():
return read_from_memory(ADC_FRAME_ADDR, 1)[0]
def perform_bitslip():
for i in range(4):
current_frame = read_frame()
if current_frame & 0x0F != 0x0C:
print(f"Performing bitslip (iteration: {i}). Current frame: 0x{current_frame:02x}")
write_to_memory(ADC_BITSLIP_ADDR, 1)
else:
print(f"No bitslip required; Current frame: 0x{current_frame:02x}")
return
def mmcm_rst():
curr_cfg = read_from_memory(ADC_AFE_CTRL_ADDR, 1)[0] & 0x0F
write_to_memory(ADC_AFE_CTRL_ADDR, 0x10 | curr_cfg) # Reset MMCM
write_to_memory(ADC_AFE_CTRL_ADDR, 0x00 | curr_cfg) # Release MMCM Reset
while not(read_frame() & 0x10):
print(f"Waiting for MMCM to lock")
time.sleep(0.001)
def inc_ddr_clk_phase():
curr_cfg = read_from_memory(ADC_AFE_CTRL_ADDR, 1)[0] & 0x1F
write_to_memory(ADC_AFE_CTRL_ADDR, 0x40 | curr_cfg) # Set MMCM Phase Shift to be INC
write_to_memory(ADC_AFE_CTRL_ADDR, 0x60 | curr_cfg) # Assert MMCM Phase Shift EN High
write_to_memory(ADC_AFE_CTRL_ADDR, curr_cfg) # Deassert MMCM Phase Shift EN High
def dec_ddr_clk_phase():
curr_cfg = read_from_memory(ADC_AFE_CTRL_ADDR, 1)[0] & 0x1F
write_to_memory(ADC_AFE_CTRL_ADDR, 0x00 | curr_cfg) # Set MMCM Phase Shift to be DEC
write_to_memory(ADC_AFE_CTRL_ADDR, 0x20 | curr_cfg) # Assert MMCM Phase Shift EN High
write_to_memory(ADC_AFE_CTRL_ADDR, curr_cfg) # Deassert MMCM Phase Shift EN High
def find_edge():
prev_frame = read_frame()
for tap_delay in range(32):
write_to_memory(ADC_DELAY_ADDR, tap_delay)
current_frame = read_frame()
print(f"Tap delay: {tap_delay}, Current frame: 0x{current_frame:02x}")
print(f"prev_frame: 0x{prev_frame:02x}")
if current_frame != prev_frame:
final_delay = ((tap_delay+1) // 2) + 2
print(f"Edge detected; setting iDelay to: {final_delay}")
write_to_memory(ADC_DELAY_ADDR, final_delay)
return
prev_frame = current_frame
# If no edge detected
final_delay = 11
print(f"No edge detected; setting iDelay to: {final_delay}")
write_to_memory(ADC_DELAY_ADDR, final_delay)
def read_adc_channel(high_addr, low_addr):
return (read_from_memory(high_addr, 1)[0] << 8) | read_from_memory(low_addr, 1)[0]
def print_adc_channels():
adc_ch0 = read_adc_channel(ADC_CH0_HIGH_ADDR, ADC_CH0_LOW_ADDR)
adc_ch1 = read_adc_channel(ADC_CH1_HIGH_ADDR, ADC_CH1_LOW_ADDR)
print(f"Final ADC_CH0: 0x{adc_ch0:04x}")
print(f"Final ADC_CH1: 0x{adc_ch1:04x}")
def enable_adc_afe(ch1_x10=False, ch2_x10=False):
ctrl_value = (ch2_x10 << 1) | ch1_x10
write_to_memory(ADC_AFE_CTRL_ADDR, ctrl_value)
afe_ctrl = read_from_memory(ADC_AFE_CTRL_ADDR, 1)[0]
print(f"ADC_AFE_CTRL: 0x{afe_ctrl:02X}")
return afe_ctrl
def search_edge():
for tap_delay in range(32):
print(f"iDelay to: {tap_delay}")
write_to_memory(ADC_DELAY_ADDR, tap_delay)
time.sleep(1)
current_frame = read_frame()
print(f"Tap delay: {tap_delay}, Current frame: 0x{current_frame:02x}")
print_adc_channels()
def print_adc_channel(ch):
if ch == 0:
adc_ch0 = read_adc_channel(ADC_CH0_HIGH_ADDR, ADC_CH0_LOW_ADDR)
print(f"Final ADC_CH0: 0x{adc_ch0:04x}")
if ch == 1:
adc_ch1 = read_adc_channel(ADC_CH1_HIGH_ADDR, ADC_CH1_LOW_ADDR)
print(f"Final ADC_CH1: 0x{adc_ch1:04x}")
def find_min_max_ch(ch):
test = []
for i in range(100):
if ch == 0:
test.append(read_adc_channel(ADC_CH0_HIGH_ADDR, ADC_CH0_LOW_ADDR))
else:
test.append(read_adc_channel(ADC_CH1_HIGH_ADDR, ADC_CH1_LOW_ADDR))
print("ch", ch, hex(test[-1]))
print("Min:", hex(min(test)))
print("Max:", hex(max(test)))
print("Diff:", hex(max(test)-min(test)))
def configure_ltc2195():
spi = spidev.SpiDev() spi = spidev.SpiDev()
try: try:
spi.open(MAIN_ADC_BUS, MAIN_ADC_DEVICE) spi.open(MAIN_ADC_BUS, MAIN_ADC_DEVICE)
spi.max_speed_hz = 50000 spi.max_speed_hz = 50000
spi.mode = 0b00 # CPOL = 0 CPHA = 0 spi.mode = 0b00 # CPOL = 0 CPHA = 0
spi.cshigh = False spi.cshigh = True
# spi.read0 = False
test_pattern = 0x811F spi_buffer = [0x00, 0x80] # reset
main_adc_config(spi, test_pattern) rx_buffer = [0x00, 0x00]
verify_adc_registers(spi, { spi.xfer2(spi_buffer)
0x01: 0x20,
0x02: 0x15,
0x03: (test_pattern & 0xFF00) >> 8,
0x04: test_pattern & 0xFF
})
# ADC software reset put its PLL to sleep momentarily. Thus, MMCM needs to be reset as well. # REGISTER A1
mmcm_rst() spi_buffer = [0x01, 0x20] # set to Two's complement Data Format
spi.xfer2(spi_buffer)
# Performing Word Align
perform_bitslip()
find_edge()
# Printing it once is not enough to check whether the alignment is correct.
for i in range(100):
print_adc_channels()
main_adc_test_mode(spi, False) # read values back
verify_adc_registers(spi, {0x02: 0x11}) # Verify test mode is off spi_buffer = [0x81, 0x00]
rx_buffer = spi.xfer2(spi_buffer)
# FIXME: AFE Gain 1x is not functional on that batch of fast servo under development print(f"Spi readback register 0x01: 0x{rx_buffer[1]:02x}")
enable_adc_afe(ch1_x10=1, ch2_x10=1) if rx_buffer[1] != 0x20:
print("Different value read than sent in reg 0x02")
#find_min_max_ch(0) # REGISTER A2
#find_min_max_ch(1) spi_buffer = [
0x02,
0x15,
] # set to LVDS output, set 4 data lanes and turn on test mode
spi.xfer2(spi_buffer)
#for i in range(10): # read values back
# print_adc_channel(0) spi_buffer = [0x82, 0x00]
rx_buffer = spi.xfer2(spi_buffer)
print(f"Spi readback register 0x02: 0x{rx_buffer[1]:02x}")
if rx_buffer[1] != 0x15:
print("Different value read than sent in reg 0x02")
#for i in range(10): # REGISTER A3
# print_adc_channel(1) # test pattern high word
spi_buffer = [0x03, high_word]
spi.xfer2(spi_buffer)
# read balues back
spi_buffer = [0x83, 0x00]
rx_buffer = spi.xfer2(spi_buffer)
print(f"Spi readback register 0x03: 0x{rx_buffer[1]:02x}")
if rx_buffer[1] != high_word:
print("Different value read than sent in reg 0x03")
# REGISTER A4
# test pattern low word
spi_buffer = [0x04, low_word]
spi.xfer2(spi_buffer)
# read balues back
spi_buffer = [0x84, 0x00]
rx_buffer = spi.xfer2(spi_buffer)
print(f"Spi readback register 0x04: 0x{rx_buffer[1]:02x}")
if rx_buffer[1] != low_word:
print("Different value read than sent in reg 0x04")
finally:
spi.close()
def main_adc_test_mode(enable):
spi = spidev.SpiDev()
try:
spi.open(MAIN_ADC_BUS, MAIN_ADC_DEVICE)
spi.max_speed_hz = 50000
spi.mode = 0b00 # CPOL = 0 CPHA = 0
spi.cshigh = True
# spi.read0 = True
reg_contents = (
0x15 if enable else 0x11
) # set to LVDS output, set 4 data lanes and turn on or off test mode
spi_buffer = [0x02, reg_contents]
spi.xfer2(spi_buffer)
# read values back
spi_buffer = [0x82, 0x00]
rx_buffer = spi.xfer2(spi_buffer)
print(f"Spi readback register 0x02: 0x{rx_buffer[1]:02x}")
if rx_buffer[1] != reg_contents:
print("Different value read than sent in reg 0x02")
finally:
spi.close()
def read_from_memory(address, n_bytes):
assert n_bytes <= 4
addr = address
try:
f = os.open("/dev/mem", os.O_SYNC | os.O_RDWR)
with mmap.mmap(
f,
PAGESIZE,
mmap.MAP_SHARED,
mmap.PROT_READ | mmap.PROT_WRITE,
offset=addr & ~MAP_MASK,
) as mem:
start_addr = addr & MAP_MASK
stop_addr = start_addr + 4
# print(f"addr: 0x{addr:x}\tstart_addr: 0x{start_addr}\tstop_addr: 0x{stop_addr}")
contents = mem[start_addr:stop_addr]
read_value = list(contents)[:n_bytes]
# print("Read value: ", read_value)
finally:
os.close(f)
return read_value
def write_to_memory(address, value):
value_bytes = value.to_bytes(4, "little")
addr = address
try:
f = os.open("/dev/mem", os.O_SYNC | os.O_RDWR)
with mmap.mmap(
f,
PAGESIZE,
mmap.MAP_SHARED,
mmap.PROT_READ | mmap.PROT_WRITE,
offset=addr & ~MAP_MASK,
) as mem:
start_addr = addr & MAP_MASK
stop_addr = start_addr + 4
# print(f"addr: 0x{addr:x}\tstart_addr: 0x{start_addr}\tstop_addr: 0x{stop_addr}")
mem[start_addr:stop_addr] = value_bytes
contents = mem[start_addr:stop_addr]
# print("Read value: ", list(contents), " written value: ", list(value_bytes))
finally:
os.close(f)
def word_align():
value = 0
edge_detected = False
transition = False
tap_delay = 0
for i in range(4):
current_frame = read_from_memory(ADC_FRAME_ADDR, 1)[0]
if current_frame != 0x0C:
print(
f"Performing bitslip (bitslip iteration: {i}). Reason: current_frame is 0x{current_frame:02x} instead of 0x0C"
)
write_to_memory(ADC_BITSLIP_ADDR, 1)
else:
print(f"No bitslip required; Currernt frame = 0x{current_frame:02x}")
break
current_frame = read_from_memory(ADC_FRAME_ADDR, 1)[0]
prev_frame = current_frame
for i in range(32):
write_to_memory(ADC_DELAY_ADDR, tap_delay)
if edge_detected == 1:
break
current_frame = read_from_memory(ADC_FRAME_ADDR, 1)[0]
print(f"Tap delay: {tap_delay}")
print(f"Current frame: 0x{current_frame:02x}")
if current_frame == prev_frame:
tap_delay += 1
elif not transition:
tap_delay += 1
transition = True
elif transition:
tap_delay = i // 2
edge_detected = True
prev_frame = current_frame
if not edge_detected:
tap_delay = 11 # empirically tested to work best
write_to_memory(ADC_DELAY_ADDR, tap_delay)
print(f"No edge detected; setting iDelay to: {tap_delay}")
if edge_detected:
write_to_memory(ADC_DELAY_ADDR, tap_delay + 2)
print(f"Edge detected; setting iDelay to (tap_delay + 2): {tap_delay} + 2")
adc_ch0 = read_from_memory(ADC_CH0_HIGH_ADDR, 4)
print(f"ADC_CH0: 0x{adc_ch0}")
adc_ch0 = (read_from_memory(ADC_CH0_HIGH_ADDR, 1)[0] << 8) | read_from_memory(
ADC_CH0_LOW_ADDR, 1
)[0]
adc_ch1 = (read_from_memory(ADC_CH1_HIGH_ADDR, 1)[0] << 8) | read_from_memory(
ADC_CH1_LOW_ADDR, 1
)[0]
print(f"Final ADC_CH0: 0x{adc_ch0:04x}")
print(f"Final ADC_CH1: 0x{adc_ch1:04x}")
def modify_bit(original_value, position, bit_value):
mask = 1 << position
return (original_value & ~mask) | (bit_value << position)
def adc_aux_config():
# MSB to LSB
# | RANGE | ADDR [2:0] | DIFF |
# DIFF = 0 => configure as single ended (it is negated in gateware)
# RANGE = 0 => configure as 0-2.5 Vref
to_write = 0b00000
write_to_memory(AUX_ADC_ADDR, to_write)
def adc_aux_read(port, type, pin):
# port:
# 1 - port A
# 2 - port B
# type:
# 0 - single-ended
# 1 - differential
# pin:
# 0b000 - VA1/VB1
# 0b001 - VA2/VB2
# 0b010 - VA3/VB3
# 0b011 - VA4/VB4
assert type in (0, 1)
assert port in (1, 2)
write_buffer = [0, 0]
read_buffer = [0, 0]
aux_config_reg = read_from_memory(AUX_ADC_ADDR, 1)[0]
aux_config = (aux_config_reg & 0b10001) | pin << 1
write_to_memory(AUX_ADC_ADDR, aux_config)
spi = spidev.SpiDev()
try:
spi.open(1, 3) # AUX ADC 1?
spi.max_speed_hz = 5000
spi.mode = 0b00
spi.cshigh = True
read_buffer = spi.xfer2(write_buffer)
mu_voltage = read_buffer[0] << 8 | read_buffer[1] >> 2
print(f"MU_voltage: 0x{mu_voltage:04X}")
print(f"Read_buffer[0]: 0x{read_buffer[0]:02X}")
print(f"Read_buffer[1]: 0x{read_buffer[1]:02X}")
return mu_voltage * 2.5 / 4096
finally: finally:
spi.close() spi.close()
def main():
main_adc_config(0x811F)
word_align()
main_adc_test_mode(False)
write_to_memory(ADC_AFE_CTRL_ADDR, 0b1100) # {-, -, ch2_X10, ch1_X10}
print(read_from_memory(ADC_AFE_CTRL_ADDR, 1)[0])
if __name__ == "__main__": if __name__ == "__main__":
configure_ltc2195() main()

View File

@ -17,9 +17,6 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
import os
import mmap
CSR_SIZE = 0x800 CSR_SIZE = 0x800
MAP_SIZE = 0x1000 MAP_SIZE = 0x1000
MAP_MASK = 0xFFF MAP_MASK = 0xFFF
@ -74,47 +71,4 @@ CTRL_ADDR = DAC_BASE_ADDR + CTRL_OFFSET
CH0_HIGH_WORD_ADDR = DAC_BASE_ADDR + CH0_HIGH_WORD_OFFSET CH0_HIGH_WORD_ADDR = DAC_BASE_ADDR + CH0_HIGH_WORD_OFFSET
CH0_LOW_WORD_ADDR = DAC_BASE_ADDR + CH0_LOW_WORD_OFFSET CH0_LOW_WORD_ADDR = DAC_BASE_ADDR + CH0_LOW_WORD_OFFSET
CH1_HIGH_WORD_ADDR = DAC_BASE_ADDR + CH1_HIGH_WORD_OFFSET CH1_HIGH_WORD_ADDR = DAC_BASE_ADDR + CH1_HIGH_WORD_OFFSET
CH1_LOW_WORD_ADDR = DAC_BASE_ADDR + CH1_LOW_WORD_OFFSET CH1_LOW_WORD_ADDR = DAC_BASE_ADDR + CH1_LOW_WORD_OFFSET
def read_from_memory(address, n_bytes):
assert n_bytes <= 4
addr = address
try:
f = os.open("/dev/mem", os.O_SYNC | os.O_RDWR)
with mmap.mmap(
f,
PAGESIZE,
mmap.MAP_SHARED,
mmap.PROT_READ | mmap.PROT_WRITE,
offset=addr & ~MAP_MASK,
) as mem:
start_addr = addr & MAP_MASK
stop_addr = start_addr + 4
contents = mem[start_addr:stop_addr]
read_value = list(contents)[:n_bytes]
finally:
os.close(f)
return read_value
def write_to_memory(address, value):
value_bytes = value.to_bytes(4, "little")
addr = address
try:
f = os.open("/dev/mem", os.O_SYNC | os.O_RDWR)
with mmap.mmap(
f,
PAGESIZE,
mmap.MAP_SHARED,
mmap.PROT_READ | mmap.PROT_WRITE,
offset=addr & ~MAP_MASK,
) as mem:
start_addr = addr & MAP_MASK
stop_addr = start_addr + 4
mem[start_addr:stop_addr] = value_bytes
contents = mem[start_addr:stop_addr]
finally:
os.close(f)

View File

@ -17,7 +17,8 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
import time import mmap
import os
import spidev import spidev
from pyfastservo.common import ( from pyfastservo.common import (
@ -28,69 +29,117 @@ from pyfastservo.common import (
CTRL_ADDR, CTRL_ADDR,
MAP_MASK, MAP_MASK,
PAGESIZE, PAGESIZE,
write_to_memory,
read_from_memory
) )
# /dev/spidev2.0 <=> spidev<BUS>.<DEVICE> # /dev/spidev2.0 <=> spidev<BUS>.<DEVICE>
MAIN_DAC_BUS = 2 MAIN_DAC_BUS = 2
MAIN_DAC_DEVICE = 0 MAIN_DAC_DEVICE = 0
DAC_VERSION = 0x0A DAC_VERSION = 0x0A
def spi_write(spi, address, value): def main_dac_init():
spi.xfer2([address, value]) spi = spidev.SpiDev()
def spi_read(spi, address): try:
rx_buffer = spi.xfer2([0x80 | address, 0x00]) spi.open(MAIN_DAC_BUS, MAIN_DAC_DEVICE)
return rx_buffer[1] spi.max_speed_hz = 5000
spi.mode = 0b00 # CPOL = 0 CPHA = 0
spi.cshigh = True
def soft_reset(spi): spi_buffer = [0x00, 0x10] # software reset
spi_write(spi, 0x00, 0x10) # Software reset spi.xfer2(spi_buffer)
spi_write(spi, 0x00, 0x00) # Release software reset
spi_read(spi, 0x00) # Read reset address (necessary for reset to take effect)
def check_version(spi): spi_buffer = [0x00, 0x00] # release software reset
version = spi_read(spi, 0x1F) spi.xfer2(spi_buffer)
print(f"DAC version: 0x{version:02X}")
return version == DAC_VERSION
def configure_dac(spi): spi_buffer = [
power_down_reg = spi_read(spi, 0x01) 0x80,
spi_write(spi, 0x01, power_down_reg & ~(1 << 0)) # Clear EXTREF bit for internal reference 0x00,
spi_write(spi, 0x0D, 0x00) # Set RREF to 10 kΩ for 1.0V reference ] # for some reason it is needed to read the reset address for reset to actually reset
spi_write(spi, 0x04, 0xA0) # Enable on-chip IRSET (1.6 kΩ for 20mA output) rx_buffer = spi.xfer2(spi_buffer)
spi_write(spi, 0x07, 0xA0) # Enable on-chip QRSET (1.6 kΩ for 20mA output)
spi_write(spi, 0x05, 0x00) # Disable internal IRCML
spi_write(spi, 0x08, 0x00) # Disable internal QRCML
spi_write(spi, 0x02, 0xB4) # Enable 2's complement, IFirst: True, IRising: True, DCI_EN: Enabled
spi_write(spi, 0x14, 0x00)
spi_write(spi, 0x14, 0x08) # Trigger the retimer to reacquire the clock relationship
spi_write(spi, 0x14, 0x00)
def dac_self_calibration(spi): spi_buffer = [0x9F, 0x00] # hardware version
spi_write(spi, 0x12, 0x00) # Reset calibration status rx_buffer = spi.xfer2(spi_buffer)
spi_write(spi, 0x0E, 0x08) # Enable calibration clock, default divide ratio if rx_buffer[1] != DAC_VERSION:
spi_write(spi, 0x0E, 0x38) # CALSELI = 1, CALSELQ = 1, CALCLK = 1 print(f"Unrecognized device: 0x{rx_buffer[1]:02X}")
spi_write(spi, 0x12, 0x10) # Set CALEN bit
while True: print("=== Contents of spi buffer after DAC VERSION read back: ===")
status = spi_read(spi, 0x0F) print(f"0x{rx_buffer[0]:02X}{rx_buffer[1]:02X}")
if status & 0xC0 == 0xC0: # Both CALSTATI and CALSTATQ are 1
break spi_buffer = [0x82, 00]
time.sleep(0.01) rx_buffer = spi.xfer2(spi_buffer)
print(f"0x{rx_buffer[0]:02X}{rx_buffer[1]:02X}")
# set to 2's complement and I to be first of pair on data input pads
spi_buffer = [0x02, 0xB4]
rx_buffer = spi.xfer2(spi_buffer)
spi_buffer = [0x82, 00]
rx_buffer = spi.xfer2(spi_buffer)
print(f"0x{rx_buffer[0]:02X}{rx_buffer[1]:02X}")
for i in range(10):
spi_buffer = [0x94, 0x00]
rx_buffer = spi.xfer2(spi_buffer)
print(f"0x{rx_buffer[0]:02X}{rx_buffer[1]:02X}")
finally:
spi.close()
def read_from_memory(address, n_bytes):
assert n_bytes <= 4
addr = address
try:
f = os.open("/dev/mem", os.O_SYNC | os.O_RDWR)
with mmap.mmap(
f,
PAGESIZE,
mmap.MAP_SHARED,
mmap.PROT_READ | mmap.PROT_WRITE,
offset=addr & ~MAP_MASK,
) as mem:
start_addr = addr & MAP_MASK
stop_addr = start_addr + 4
# print(f"addr: 0x{addr:x}\tstart_addr: 0x{start_addr}\tstop_addr: 0x{stop_addr}")
contents = mem[start_addr:stop_addr]
read_value = list(contents)[:n_bytes]
finally:
os.close(f)
return read_value
def write_to_memory(address, value):
value_bytes = value.to_bytes(4, "little")
addr = address
try:
f = os.open("/dev/mem", os.O_SYNC | os.O_RDWR)
with mmap.mmap(
f,
PAGESIZE,
mmap.MAP_SHARED,
mmap.PROT_READ | mmap.PROT_WRITE,
offset=addr & ~MAP_MASK,
) as mem:
start_addr = addr & MAP_MASK
stop_addr = start_addr + 4
mem[start_addr:stop_addr] = value_bytes
contents = mem[start_addr:stop_addr]
finally:
os.close(f)
spi_write(spi, 0x12, 0x00) # Clear calibration bits
spi_write(spi, 0x0E, 0x30) # Keep CALSELI and CALSELQ set, clear CALCLK
print("DAC self-calibration completed")
def manual_override(enable=True): def manual_override(enable=True):
reg_contents = read_from_memory(CTRL_ADDR, 1)[0] reg_contents = read_from_memory(CTRL_ADDR, 1)[0]
print(f"REG contents: 0b{reg_contents:03b}")
to_write = reg_contents | 0b1 if enable else reg_contents & 0b110 to_write = reg_contents | 0b1 if enable else reg_contents & 0b110
write_to_memory(CTRL_ADDR, to_write) write_to_memory(CTRL_ADDR, to_write)
print(f"Set DAC Output Manual Override: {enable}")
def power_down_afe(channel, power_down=True):
def power_down(channel, power_down=True):
assert channel in (0, 1) assert channel in (0, 1)
bitmask = 1 << (channel + 1) & 0b111 bitmask = 1 << (channel + 1) & 0b111
@ -101,68 +150,33 @@ def power_down_afe(channel, power_down=True):
to_write = reg_contents | value to_write = reg_contents | value
write_to_memory(CTRL_ADDR, to_write) write_to_memory(CTRL_ADDR, to_write)
reg_contents = read_from_memory(CTRL_ADDR, 1)[0] reg_contents = read_from_memory(CTRL_ADDR, 1)[0]
print(f"Power Down DAC AFE Ch{channel}: {power_down}") print(f"REG contents: 0b{reg_contents:03b}")
def set_dac_output(value):
value = min(value, 0x3FFF)
low_word = value & 0xFF
high_word = (value >> 8) & 0x3F
# Note: DAC HIGH word and LOW word output are not updated def write_sample(channel, sample):
# at the same time. On scope, you will see more than one step assert channel in (0, 1)
# of value changed. if channel == 0:
write_to_memory(CH0_HIGH_WORD_ADDR, high_word) addresses = [CH0_HIGH_WORD_ADDR, CH0_LOW_WORD_ADDR]
write_to_memory(CH0_LOW_WORD_ADDR, low_word)
write_to_memory(CH1_HIGH_WORD_ADDR, high_word)
write_to_memory(CH1_LOW_WORD_ADDR, low_word)
print(f"DAC output set to: 0x{value:04X}")
def check_clk_relationship(spi):
clkmode_reg = spi_read(spi, 0x14)
print(f"CLKMODE reg: 0x{clkmode_reg:02X}")
if clkmode_reg & 0b00010000:
print("Clock relationship is not found")
return False
else: else:
print("Clock relationship is found") addresses = [CH1_HIGH_WORD_ADDR, CH1_LOW_WORD_ADDR]
return True
def configure_ad9117(): low_word_value = sample & 0xFF
spi = spidev.SpiDev() high_word_value = (sample >> 8) & 0x3F
spi.open(MAIN_DAC_BUS, MAIN_DAC_DEVICE) values = [high_word_value, low_word_value]
spi.max_speed_hz = 5000 for addr, value in zip(addresses, values):
spi.mode = 0b00 # CPOL = 0 CPHA = 0 write_to_memory(addr, value)
spi.cshigh = False
try:
soft_reset(spi)
if not check_version(spi):
print("Unrecognized DAC version")
return False
power_down_afe(0, True) def write_ramp():
power_down_afe(1, True) signal = [i for i in range(16384)]
configure_dac(spi) for value in signal:
check_clk_relationship(spi) write_sample(0, value)
dac_self_calibration(spi)
# Enable DAC outputs
spi_write(spi, 0x01, spi_read(spi, 0x01) & ~((1 << 4) | (1 << 3)))
power_down_afe(0, False)
power_down_afe(1, False)
manual_override(False)
print("AD9117 configuration completed successfully")
return True
except Exception as e:
print(f"Error configuring AD9117: {e}")
return False
finally:
spi.close()
def main():
main_dac_init()
power_down(0, False)
power_down(1, False)
if __name__ == "__main__": if __name__ == "__main__":
configure_ad9117() main()

View File

@ -21,8 +21,8 @@ from pyfastservo import adc, si5340, dac
def main(): def main():
si5340.configure_si5340() si5340.configure_si5340()
adc.configure_ltc2195() adc.main()
dac.configure_ad9117() dac.main()
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -17,264 +17,102 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
# Additional Reference:
# https://github.com/torvalds/linux/blob/master/drivers/clk/clk-si5341.c
import time
from smbus2 import SMBus from smbus2 import SMBus
BUS_NO = 0 BUS_NO = 0
IC_ADDR = 0x74 IC_ADDR = 0x74
DEVICE_READY = 0x00FE PAGE_ADDR = 0x1
PLL_M_DEN = 0x023B
STATUS = 0x000C
STATUS_STICKY = 0x0011
STATUS_LOSREF = 0x04 OUT0_MUX_SEL_ADDR = 0x15
STATUS_LOL = 0x08 OUT1_MUX_SEL_ADDR = 0x1A
OUT2_MUX_SEL_ADDR = 0x29
OUT3_MUX_SEL_ADDR = 0x2E
OUT2_AMPL_ADDR = 0x28
OUT3_PDN_ADDR = 0x2B
OUT3_FORMAT_ADDR = 0x2C
OUT3_AMPL_ADDR = 0x2D
def write_register(bus, address, value): N1_DIVIDER_UPDATE_ADDR = 0x17
page = address >> 8
register = address & 0xFF
bus.write_byte_data(IC_ADDR, 0x01, page)
try:
bus.write_byte_data(IC_ADDR, register, value)
except Exception as e:
raise Exception(f"Write failed 0x{value:02X} at 0x{address:04X}: {e}")
def write_preamble(bus): data_to_write = 0
preamble = [ clk_out_addr = [
(0x0B24, 0xC0), OUT0_MUX_SEL_ADDR,
(0x0B25, 0x00), OUT1_MUX_SEL_ADDR,
(0x0502, 0x01), OUT2_MUX_SEL_ADDR,
(0x0505, 0x03), OUT3_MUX_SEL_ADDR,
(0x0957, 0x17), ]
(0x0B4E, 0x1A),
]
for address, value in preamble:
write_register(bus, address, value)
def write_postamble(bus):
postamble = [
(0x001C, 0x01), # Soft reset
(0x0B24, 0xC3),
(0x0B25, 0x02),
]
for address, value in postamble:
write_register(bus, address, value)
def wait_device_ready(bus):
for _ in range(15):
if bus.read_byte_data(IC_ADDR, DEVICE_READY) == 0x0F:
return True
time.sleep(0.02)
return False
def wait_for_lock(bus):
for _ in range(10):
status = bus.read_byte_data(IC_ADDR, STATUS)
if not (status & (STATUS_LOSREF | STATUS_LOL)):
return True
time.sleep(0.01)
return False
def check_pll_status(bus):
pll_status = bus.read_byte_data(IC_ADDR, 0x0C)
pll_locked = not (pll_status & STATUS_LOL)
print(f"PLL {'locked' if pll_locked else 'unlocked'}")
return pll_locked
def check_los_status(bus):
los_status = bus.read_byte_data(IC_ADDR, 0x0D)
xaxb_los = (los_status & 0x10) != 0
print(f"XA/XB LOS {'asserted' if xaxb_los else 'deasserted'}")
return not xaxb_los
def configure_si5340(): def configure_si5340():
with SMBus(BUS_NO) as bus: with SMBus(BUS_NO) as bus:
if not wait_device_ready(bus):
print("Device not ready. Aborting.")
return
# Programming sequence from ClockBuilder Pro, default settings bus.write_byte_data(IC_ADDR, PAGE_ADDR, 0x0) # setting page to page 0
# to initialize system using XTAL input
main_config = [
(0x0006, 0x00), # TOOL_VERSION
(0x0007, 0x00), # Not in datasheet
(0x0008, 0x00), # Not in datasheet
(0x000B, 0x74), # I2C_ADDR
(0x0017, 0xD0), # INT mask (disable interrupts)
(0x0018, 0xFF), # INT mask
(0x0021, 0x0F), # Select XTAL as input
(0x0022, 0x00), # Not in datasheet
(0x002B, 0x02), # SPI config
(0x002C, 0x20), # LOS enable for XTAL
(0x002D, 0x00), # LOS timing
(0x002E, 0x00), # LOS trigger (thresholds)
(0x002F, 0x00),
(0x0030, 0x00),
(0x0031, 0x00),
(0x0032, 0x00),
(0x0033, 0x00),
(0x0034, 0x00),
(0x0035, 0x00), # LOS trigger (thresholds) end
(0x0036, 0x00), # LOS clear (thresholds)
(0x0037, 0x00),
(0x0038, 0x00),
(0x0039, 0x00),
(0x003A, 0x00),
(0x003B, 0x00),
(0x003C, 0x00),
(0x003D, 0x00), # LOS clear (thresholds) end
(0x0041, 0x00), # LOS0_DIV_SEL
(0x0042, 0x00), # LOS1_DIV_SEL
(0x0043, 0x00), # LOS2_DIV_SEL
(0x0044, 0x00), # LOS3_DIV_SEL
(0x009E, 0x00), # LOL_SET_THR
(0x0102, 0x01), # Enable outputs
(0x013F, 0x00), # OUTX_ALWAYS_ON
(0x0140, 0x00), # OUTX_ALWAYS_ON
(0x0141, 0x40), # OUT_DIS_LOL_MSK, OUT_DIS_MSK_LOS_PFD
(0x0202, 0x00), # XAXB_FREQ_OFFSET (=0)
# PLL Configuration # read device id
(0x0235, 0x00), # M_NUM low_word = bus.read_byte_data(IC_ADDR, 0x2)
(0x0236, 0x00), high_word = bus.read_byte_data(IC_ADDR, 0x3)
(0x0237, 0x00),
(0x0238, 0x80),
(0x0239, 0x89),
(0x023A, 0x00),
(0x023B, 0x00), # M_DEN
(0x023C, 0x00),
(0x023D, 0x00),
(0x023E, 0x80),
# Synthesizer configuration print(f"DEV ID: 0x{high_word:2x}{low_word:2x}")
(0x0302, 0x00), # N0_NUM
(0x0303, 0x00),
(0x0304, 0x00),
(0x0305, 0x00),
(0x0306, 0x21),
(0x0307, 0x00),
(0x0308, 0x00), # N0_DEN
(0x0309, 0x00),
(0x030A, 0x00),
(0x030B, 0x80),
(0x030C, 0x01), # N0_UPDATE
# N1 Configuration (1:1 ratio) data_to_write = 0x1
(0x030D, 0x00), # N1_NUM bus.write_byte_data(
(0x030E, 0x00), IC_ADDR, PAGE_ADDR, data_to_write
(0x030F, 0x00), ) # change to page 1 for output settings
(0x0310, 0x00),
(0x0311, 0x00),
(0x0312, 0x01),
(0x0313, 0x00), # N1_DEN
(0x0314, 0x00),
(0x0315, 0x00),
(0x0316, 0x01),
(0x0317, 0x01), # N1_UPDATE
# N2 Configuration (1:1 ratio) readback = bus.read_byte_data(IC_ADDR, PAGE_ADDR)
(0x0318, 0x00), # N2_NUM if data_to_write != readback:
(0x0319, 0x00), raise ValueError(f"Failed to set page.")
(0x031A, 0x00),
(0x031B, 0x00),
(0x031C, 0x00),
(0x031D, 0x01),
(0x031E, 0x00), # N2_DEN
(0x031F, 0x00),
(0x0320, 0x00),
(0x0321, 0x01),
(0x0322, 0x01), # N2_UPDATE
# N3 Configuration (1:1 ratio) for addr in clk_out_addr:
(0x0323, 0x00), # N3_NUM bus.write_byte_data(IC_ADDR, addr, 1) # set source to N1
(0x0324, 0x00),
(0x0325, 0x00),
(0x0326, 0x00),
(0x0327, 0x00),
(0x0328, 0x01),
(0x0329, 0x00), # N3_DEN
(0x032A, 0x00),
(0x032B, 0x00),
(0x032C, 0x01),
(0x032D, 0x01), # N3_UPDATE
# Output configuration bus.write_byte_data(IC_ADDR, OUT2_AMPL_ADDR, 13)
(0x0112, 0x06), # OUT0 config readback = bus.read_byte_data(IC_ADDR, OUT2_AMPL_ADDR)
(0x0113, 0x09), # OUT0 format # if data_to_write != readback:
(0x0114, 0x3B), # OUT0 CM/AMPL # raise ValueError(f"Problematic read: {readback}.")
(0x0115, 0x28), # OUT0 MUX_SEL
(0x0117, 0x06), # OUT1 config bus.write_byte_data(IC_ADDR, OUT2_AMPL_ADDR, 0x6B) # setting OUT2 to LVDS25
(0x0118, 0x09), # OUT1 format
(0x0119, 0x3B), # OUT1 CM/AMPL
(0x011A, 0x28), # OUT1 MUX_SEL
(0x0126, 0x06), # OUT2 config bus.write_byte_data(IC_ADDR, OUT3_FORMAT_ADDR, 0xCC) # SETTING out3 to LVCMOS 18
(0x0127, 0x09), # OUT2 format # bus.write_byte_data(IC_ADDR, 0x2E, 0x09) # SETTING out3 to LVCMOS 33
(0x0128, 0x3B), # OUT2 CM/AMPL
(0x0129, 0x28), # OUT2 MUX_SEL
(0x012B, 0x06), # OUT3 config readback = bus.read_byte_data(IC_ADDR, OUT3_PDN_ADDR)
(0x012C, 0xCC), # OUT3 format print(f"Si5340 OUTx_PDN CLK3: 0x{readback}")
(0x012D, 0x00), # OUT3 CM/AMPL
(0x012E, 0x58), # OUT3 MUX_SEL
# Miscellaneous configuration readback = bus.read_byte_data(IC_ADDR, OUT3_FORMAT_ADDR)
(0x090E, 0x02), # XAXB_EXTCLK_EN=0 XAXB_PDNB=1 (use XTAL) print(f"Si5340 OUTx_FORMAT CLK3: 0x{readback}")
(0x091C, 0x04), # ZDM_EN=4 (Normal mode)
(0x0943, 0x00), # IO_VDD_SEL
(0x0949, 0x00), # IN_EN (disable input clocks)
(0x094A, 0x00), # INx_TO_PFD_EN (disabled)
(0x094E, 0x49), # REFCLK_HYS_SEL (set by CBPro)
(0x094F, 0x02), # Not in datasheet
(0x095E, 0x00), # M_INTEGER (set by CBPro)
(0x0A02, 0x00), # N_ADD_0P5 (set by CBPro)
(0x0A03, 0x01), # N_CLK_TO_OUTX_EN
(0x0A04, 0x01), # N_PIBYP
(0x0A05, 0x01), # N_PDNB
(0x0A14, 0x00), # N0_HIGH_FREQ (set by CBPro)
(0x0A1A, 0x00), # N1_HIGH_FREQ (set by CBPro)
(0x0A20, 0x00), # N2_HIGH_FREQ (set by CBPro)
(0x0A26, 0x00), # N3_HIGH_FREQ (set by CBPro)
(0x0B44, 0x0F), # PDIV_ENB (set by CBPro)
(0x0B4A, 0x0E), # N_CLK_DIS
(0x0B57, 0x0E), # VCO_RESET_CALCODE (set by CBPro)
(0x0B58, 0x01), # VCO_RESET_CALCODE (set by CBPro)
]
write_preamble(bus) readback = bus.read_byte_data(IC_ADDR, OUT3_AMPL_ADDR)
print(f"Si5340 OUTx_AMPL CLK3: 0x{readback}")
time.sleep(0.3) readback = bus.read_byte_data(IC_ADDR, OUT3_MUX_SEL_ADDR)
print(f"Si5340 OUTx_CM CLK3: 0x{readback}")
print("Writing main configuration...") bus.write_byte_data(
for address, value in main_config: IC_ADDR, PAGE_ADDR, 0x3
write_register(bus, address, value) ) # setting page to 3 to change dividers values
print("Main configuration written")
write_postamble(bus) n1_numerator = [0x0, 0x0, 0x0, 0x60, 0x22, 0x0]
n1_numerator_10M = [0x0, 0x0, 0x0, 0xC0, 0x57, 0x1]
n1_num_addr = [0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12]
n1_denom_addr = [0x13, 0x14, 0x15, 0x16]
for addr, value in zip(n1_num_addr, n1_numerator):
bus.write_byte_data(IC_ADDR, addr, value)
if not wait_for_lock(bus): bus.write_byte_data(IC_ADDR, N1_DIVIDER_UPDATE_ADDR, 1)
print("Error waiting for input clock or PLL lock")
else:
print("Input clock present and PLL locked")
bus.write_byte_data(IC_ADDR, STATUS_STICKY, 0) for addr in n1_num_addr:
readback = bus.read_byte_data(IC_ADDR, addr)
print(f"Numerator buffer: 0x{readback:02x}")
# Final status check for addr in n1_denom_addr:
pll_locked = check_pll_status(bus) readback = bus.read_byte_data(IC_ADDR, addr)
xaxb_signal_present = check_los_status(bus) print(f"Denominator buffer: 0x{readback:02x}")
if not pll_locked: bus.write_byte_data(IC_ADDR, PAGE_ADDR, 0x0) # setting page to page 0
print("Error: PLL is not locked")
elif not xaxb_signal_present:
print("Error: XA/XB signal is lost")
else:
print("Si5340 configuration completed successfully")
if __name__ == "__main__": if __name__ == "__main__":
configure_si5340() configure_si5340()

22
flake.lock generated
View File

@ -18,16 +18,16 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1734323986, "lastModified": 1709237383,
"narHash": "sha256-m/lh6hYMIWDYHCAsn81CDAiXoT3gmxXI9J987W5tZrE=", "narHash": "sha256-cy6ArO4k5qTx+l5o+0mL9f5fa86tYUX3ozE1S+Txlds=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "394571358ce82dff7411395829aa6a3aad45b907", "rev": "1536926ef5621b09bba54035ae2bb6d806d72ac8",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"ref": "nixos-24.11", "ref": "nixos-unstable",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }
@ -64,11 +64,11 @@
"src-migen": { "src-migen": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1727677091, "lastModified": 1702942348,
"narHash": "sha256-Zg3SQnTwMM/VkOGKogbPyuCC2NhLy8HB2SPEUWWNgCU=", "narHash": "sha256-gKIfHZxsv+jcgDFRW9mPqmwqbZXuRvXefkZcSFjOGHw=",
"owner": "m-labs", "owner": "m-labs",
"repo": "migen", "repo": "migen",
"rev": "c19ae9f8ae162ffe2d310a92bfce53ac2a821bc8", "rev": "50934ad10a87ade47219b796535978b9bdf24023",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -80,11 +80,11 @@
"src-misoc": { "src-misoc": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1729234629, "lastModified": 1699352904,
"narHash": "sha256-TLsTCXV5AC2xh+bS7EhBVBKqdqIU3eKrnlWcFF9LtAM=", "narHash": "sha256-SglyTmXOPv8jJOjwAjJrj/WhAkItQfUbvKfUqrynwRg=",
"ref": "refs/heads/master", "ref": "refs/heads/master",
"rev": "6085a312bca26adeca6584e37d08c8ba2e1d6e38", "rev": "a53859f2167c31ab5225b6c09f30cf05527b94f4",
"revCount": 2460, "revCount": 2452,
"submodules": true, "submodules": true,
"type": "git", "type": "git",
"url": "https://github.com/m-labs/misoc.git" "url": "https://github.com/m-labs/misoc.git"

230
flake.nix
View File

@ -1,7 +1,7 @@
{ {
description = "Firmware for Sinara Fast-Servo based on Not-OS and Linien"; description = "Firmware for Sinara Fast-Servo based on Not-OS and Linien";
inputs.nixpkgs.url = github:NixOS/nixpkgs/nixos-24.11; inputs.nixpkgs.url = github:NixOS/nixpkgs/nixos-unstable;
inputs.not-os.url = github:cleverca22/not-os; inputs.not-os.url = github:cleverca22/not-os;
inputs.not-os.inputs.nixpkgs.follows = "nixpkgs"; inputs.not-os.inputs.nixpkgs.follows = "nixpkgs";
@ -14,34 +14,6 @@
pkgs-armv7l = pkgs.pkgsCross.zynq-armv7l-linux; pkgs-armv7l = pkgs.pkgsCross.zynq-armv7l-linux;
fsbl-support = ./fast-servo/fsbl-support; fsbl-support = ./fast-servo/fsbl-support;
version = "2.1.0";
linien-src = pkgs.applyPatches {
name = "linien-src";
src = pkgs.fetchFromGitHub {
owner = "linien-org";
repo = "linien";
rev = "v" + version;
sha256 = "sha256-j6oiP/usLfV5HZtKLcXQ5pHhhxRG05kP2FMwingiWm0=";
};
prePatch = ''
mkdir -p fast_servo/gateware
cp -r ${./fast-servo/linien-gateware}/. fast_servo/gateware
'';
patches = [
./fast-servo/linien-common-fast-servo-hardware-specific.patch
./fast-servo/linien-server-fast-servo-hardware-specific.patch
./fast-servo/linien-gui-fast-servo-hardware-specific.patch
./fast-servo/linien-client-ssh-port-change.patch
./fast-servo/linien-server-fast-servo.patch
./fast-servo/linien-gateware-fast-servo.patch
./fast-servo/autolock_pipeline.patch
./fast-servo/iir_pipeline.patch
./fast-servo/linien_module_pipeline.patch
./fast-servo/pid_pipeline.patch
./fast-servo/pid_err_sig_pipeline.patch
];
};
patched-not-os = pkgs.applyPatches { patched-not-os = pkgs.applyPatches {
name = "not-os-patched"; name = "not-os-patched";
src = not-os; src = not-os;
@ -52,7 +24,6 @@
./not-os-patches/pr-30.patch ./not-os-patches/pr-30.patch
./not-os-patches/pr-31.patch ./not-os-patches/pr-31.patch
./not-os-patches/pr-33.patch ./not-os-patches/pr-33.patch
./not-os-patches/iproute2.patch
]; ];
}; };
@ -125,44 +96,29 @@
freetype freetype
fontconfig fontconfig
]; ];
profile = "set -e; source /opt/Xilinx/Vivado/2024.2/settings64.sh"; profile = "set -e; source /opt/Xilinx/Vivado/2022.2/settings64.sh";
runScript = "vivado"; runScript = "vivado";
}; };
cma = pkgs-armv7l.python3Packages.buildPythonPackage rec {
pname = "cma";
version = "3.3.0";
src = pkgs.fetchFromGitHub {
owner = "CMA-ES";
repo = "pycma";
rev = "refs/tags/r${version}";
hash = "sha256-+UJI3hDVbDMfRF4bkwHED3eJCHzxS2hO4YPUzJqcoQI=";
};
propagatedBuildInputs = [ pkgs-armv7l.python3Packages.numpy ];
pythonImportsCheck = [ "cma" ];
checkPhase = ''
# At least one doctest fails, thus only limited amount of files is tested
python -m cma.test interfaces.py purecma.py logger.py optimization_tools.py transformations.py
'';
};
pyrp3 = pkgs-armv7l.python3Packages.buildPythonPackage rec { pyrp3 = pkgs-armv7l.python3Packages.buildPythonPackage rec {
pname = "pyrp3"; pname = "pyrp3";
version = "2.1.0"; version = "1.2.0";
format = "pyproject"; pyproject = true;
src = pkgs.fetchFromGitHub { src = pkgs.fetchFromGitHub {
owner = "linien-org"; owner = "linien-org";
repo = "pyrp3"; repo = "pyrp3";
rev = "v${version}"; rev = "v${version}";
hash = "sha256-ol1QGXyCOei94iIPIocuTRHBxa5jKSH5RzjzROfZaBI="; hash = "sha256-43TTlpJ5SMAjQM71bNVvrWQyciRXM3zpuA/Dw41AEgU=";
}; };
patches = ./fast-servo/linien-pyrp3-monitor.patch; patches = ./fast-servo/linien-pyrp3-monitor.patch;
nativeBuildInputs = [ nativeBuildInputs = with pkgs-armv7l.python3Packages; [
pkgs-armv7l.python3Packages.setuptools setuptools wheel setuptools-scm
pkgs-armv7l.gcc ] ++ (with pkgs-armv7l; [ gcc gnumake ]);
propagatedBuildInputs = with pkgs-armv7l.python3Packages; [
myhdl
rpyc4
cached-property
numpy
]; ];
postInstall = '' postInstall = ''
cp monitor/libmonitor.so $out/lib cp monitor/libmonitor.so $out/lib
@ -171,141 +127,13 @@
substituteInPlace $out/${pkgs.python3.sitePackages}/pyrp3/raw_memory.py \ substituteInPlace $out/${pkgs.python3.sitePackages}/pyrp3/raw_memory.py \
--replace "libmonitor.so" "$out/lib/libmonitor.so" --replace "libmonitor.so" "$out/lib/libmonitor.so"
''; '';
propagatedBuildInputs = with pkgs-armv7l.python3Packages; [
cached-property
numpy
rpyc
];
};
linien-common = pkgs.python3Packages.buildPythonPackage rec {
pname = "linien-common";
inherit version;
pyproject = true;
src = linien-src;
sourceRoot = "${src.name}/linien-common";
preBuild = ''
export HOME=$(mktemp -d)
'';
nativeBuildInputs = [ pkgs.python3Packages.setuptools ];
pythonRelaxDeps = [ "importlib-metadata" ];
propagatedBuildInputs = with pkgs.python3Packages; [
importlib-metadata
numpy
rpyc
scipy
appdirs
];
pythonImportsCheck = [ "linien_common" ];
};
linien-common-armv7l = pkgs-armv7l.python3Packages.buildPythonPackage rec {
pname = "linien-common-armv7l";
inherit version;
pyproject = true;
src = linien-src;
sourceRoot = "${src.name}/linien-common";
preBuild = ''
export HOME=$(mktemp -d)
'';
nativeBuildInputs = [ pkgs-armv7l.python3Packages.setuptools ];
pythonRelaxDeps = [ "importlib-metadata" ];
propagatedBuildInputs = with pkgs-armv7l.python3Packages; [
importlib-metadata
numpy
rpyc
scipy
appdirs
];
pythonImportsCheck = [ "linien_common" ];
};
linien-client = pkgs.python3Packages.buildPythonPackage rec {
pname = "linien-client";
inherit version;
src = linien-src;
pyproject = true;
sourceRoot = "${src.name}/linien-client";
preBuild = ''
export HOME=$(mktemp -d)
'';
nativeBuildInputs = [ pkgs.python3Packages.setuptools ];
doInstallCheck = false;
doCheck = false;
propagatedBuildInputs = with pkgs.python3Packages; [
fabric
typing-extensions
] ++ [ linien-common ];
pythonImportsCheck = [ "linien_client" ];
};
linien-gui = pkgs.python3Packages.buildPythonApplication rec {
pname = "linien-gui";
inherit version;
src = linien-src;
pyproject = true;
sourceRoot = "${src.name}/linien-gui";
nativeBuildInputs = with pkgs.python3Packages; [
setuptools
] ++ [
pkgs.qt5.wrapQtAppsHook
];
patches = [
./fast-servo/linien-gui-fast-servo-rm-ota-update.patch
];
# Makes qt-wayland appear in the qt paths injected by the wrapper - helps users
# with `QT_QPA_PLATFORM=wayland` in their environment.
buildInputs = [
pkgs.qt5.qtwayland
];
propagatedBuildInputs = with pkgs.python3Packages; [
click
pyqtgraph
pyqt5
requests
superqt
] ++ [ linien-client ];
dontWrapQtApps = true;
preFixup = ''
makeWrapperArgs+=("''${qtWrapperArgs[@]}")
'';
}; };
linien-server = pkgs-armv7l.python3Packages.buildPythonPackage rec { linien-server = pkgs-armv7l.python3Packages.buildPythonPackage rec {
pname = "linien-server"; pname = "linien-server";
inherit version;
src = linien-src;
pyproject = true; pyproject = true;
inherit (pkgs.python3Packages.linien-common) src version;
sourceRoot = "${src.name}/linien-server"; sourceRoot = "source/linien-server";
postPatch = '' postPatch = ''
cp ${fast-servo-gateware}/csrmap.py linien_server/csrmap.py cp ${fast-servo-gateware}/csrmap.py linien_server/csrmap.py
substituteInPlace linien_server/acquisition.py \ substituteInPlace linien_server/acquisition.py \
@ -315,19 +143,28 @@
''; '';
nativeBuildInputs = [ pkgs-armv7l.python3Packages.setuptools ]; nativeBuildInputs = [ pkgs-armv7l.python3Packages.setuptools ];
propagatedBuildInputs = with pkgs-armv7l.python3Packages; [ propagatedBuildInputs = with pkgs-armv7l.python3Packages; [
fire appdirs
influxdb-client certifi
pylpsd click
] ++ [
linien-common-armv7l
cma cma
pylpsd
pyrp3 pyrp3
requests
linien-common
]; ];
}; };
fast-servo-gateware = pkgs.stdenv.mkDerivation rec { fast-servo-gateware = pkgs.stdenv.mkDerivation rec {
name = "fast-servo-gateware"; name = "fast-servo-gateware";
src = linien-src; inherit (pkgs.python3Packages.linien-common) src;
prePatch = ''
mkdir -p fast_servo/gateware
cp -r ${./fast-servo/linien-gateware}/. fast_servo/gateware
'';
patches = [
fast-servo/linien-fast-servo-gateware.patch
fast-servo/linien-fast-servo-server.patch
];
nativeBuildInputs = [ nativeBuildInputs = [
(pkgs.python3.withPackages(ps: [ (pkgs.python3.withPackages(ps: [
migen misoc migen misoc
@ -639,13 +476,6 @@
"${board}-qemu" = not-os-qemu; "${board}-qemu" = not-os-qemu;
}; };
in rec { in rec {
devShell.x86_64-linux = pkgs.mkShell {
name = "nix-servo-dev_shell";
buildInputs = with pkgs.python3Packages; [
matplotlib
] ++ [ linien-common linien-client linien-gui ];
};
packages.x86_64-linux = { packages.x86_64-linux = {
inherit mkbootimage; inherit mkbootimage;
inherit migen misoc vivado; inherit migen misoc vivado;

View File

@ -1,13 +0,0 @@
diff --git a/system-path.nix b/system-path.nix
index 490197d..93e940a 100644
--- a/system-path.nix
+++ b/system-path.nix
@@ -6,7 +6,7 @@
with lib;
let
- requiredPackages = with pkgs; [ utillinux coreutils iproute iputils procps bashInteractive runit ];
+ requiredPackages = with pkgs; [ utillinux coreutils iproute2 iputils procps bashInteractive runit ];
in
{
options = {

View File

@ -1,5 +1,5 @@
diff --git a/configuration.nix b/configuration.nix diff --git a/configuration.nix b/configuration.nix
index 010c487..2d08009 100644 index 010c487..e1e85ba 100644
--- a/configuration.nix --- a/configuration.nix
+++ b/configuration.nix +++ b/configuration.nix
@@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
@ -8,7 +8,7 @@ index 010c487..2d08009 100644
{ {
imports = [ ./qemu.nix ]; imports = [ ./qemu.nix ];
@@ -7,10 +7,16 @@ @@ -7,10 +7,15 @@
environment.etc = { environment.etc = {
"ssh/authorized_keys.d/root" = { "ssh/authorized_keys.d/root" = {
text = '' text = ''
@ -18,7 +18,6 @@ index 010c487..2d08009 100644
+ ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBNdIiLvP2hmDUFyyE0oLOIXrjrMdWWpBV9/gPR5m4AiARx4JkufIDZzmptdYQ5FhJORJ4lluPqp7dAmahoSwg4lv9Di0iNQpHMJvNGZLHYKM1H1FWCCFIEDJ8bD4SVfrDg== root + ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBNdIiLvP2hmDUFyyE0oLOIXrjrMdWWpBV9/gPR5m4AiARx4JkufIDZzmptdYQ5FhJORJ4lluPqp7dAmahoSwg4lv9Di0iNQpHMJvNGZLHYKM1H1FWCCFIEDJ8bD4SVfrDg== root
+ ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBF/YybP+fQ0J+bNqM5Vgx5vDmVqVWsgUdF1moUxghv7d73GZAFaM6IFBdrXTAa33AwnWwDPMrTgP1V6SXBkb3ciJo/lD1urJGbydbSI5Ksq9d59wvOeANvyWYrQw6+eqTQ== sb + ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBF/YybP+fQ0J+bNqM5Vgx5vDmVqVWsgUdF1moUxghv7d73GZAFaM6IFBdrXTAa33AwnWwDPMrTgP1V6SXBkb3ciJo/lD1urJGbydbSI5Ksq9d59wvOeANvyWYrQw6+eqTQ== sb
+ ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBFkmOCQ3BQh3qUjLtfdqyeBsx8rkk/QYlzB0TMrnfn6waLN6yKfPC3WVFv4zN5kNKb/OayvqDa+zfkKe85e/oIPQQKflF7GrCHdssz33DCnW90cz532E6iqG1pjeZjID2A== flo + ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBFkmOCQ3BQh3qUjLtfdqyeBsx8rkk/QYlzB0TMrnfn6waLN6yKfPC3WVFv4zN5kNKb/OayvqDa+zfkKe85e/oIPQQKflF7GrCHdssz33DCnW90cz532E6iqG1pjeZjID2A== flo
+ ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICAranL376soiSJ0kxdYNrwElcaZPW1heLFjs8Y7n0jT linuswck
''; '';
mode = "0444"; mode = "0444";
}; };
@ -28,15 +27,11 @@ index 010c487..2d08009 100644
}; };
} }
diff --git a/runit.nix b/runit.nix diff --git a/runit.nix b/runit.nix
index d7b0bf3..14dd437 100644 index d7b0bf3..67cff43 100644
--- a/runit.nix --- a/runit.nix
+++ b/runit.nix +++ b/runit.nix
@@ -4,11 +4,11 @@ let @@ -7,8 +7,8 @@ let
sshd_config = pkgs.writeText "sshd_config" '' Port 22
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
- Port 22
+ Port 3030
PidFile /run/sshd.pid PidFile /run/sshd.pid
Protocol 2 Protocol 2
- PermitRootLogin yes - PermitRootLogin yes

View File

@ -1,5 +1,5 @@
diff --git a/base.nix b/base.nix diff --git a/base.nix b/base.nix
index 7eaee32..9aa338e 100644 index 7eaee32..3a2a0a9 100644
--- a/base.nix --- a/base.nix
+++ b/base.nix +++ b/base.nix
@@ -27,6 +27,11 @@ with lib; @@ -27,6 +27,11 @@ with lib;
@ -14,12 +14,9 @@ index 7eaee32..9aa338e 100644
not-os.simpleStaticIp = mkOption { not-os.simpleStaticIp = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
@@ -84,17 +89,25 @@ with lib; @@ -86,15 +91,25 @@ with lib;
};
environment.etc = {
"nix/nix.conf".source = pkgs.runCommand "nix.conf" {} '' "nix/nix.conf".source = pkgs.runCommand "nix.conf" {} ''
- extraPaths=$(for i in $(cat ${pkgs.writeReferencesToFile pkgs.runtimeShell}); do if test -d $i; then echo $i; fi; done) extraPaths=$(for i in $(cat ${pkgs.writeReferencesToFile pkgs.runtimeShell}); do if test -d $i; then echo $i; fi; done)
+ extraPaths=$(for i in $(cat ${pkgs.writeClosure [ pkgs.bash ]}); do if test -d $i; then echo $i; fi; done)
cat > $out << EOF cat > $out << EOF
- build-use-sandbox = true - build-use-sandbox = true
+ auto-optimise-store = true + auto-optimise-store = true
@ -31,6 +28,8 @@ index 7eaee32..9aa338e 100644
+ extra-sandbox-paths = /bin/sh=${pkgs.runtimeShell} $(echo $extraPaths) + extra-sandbox-paths = /bin/sh=${pkgs.runtimeShell} $(echo $extraPaths)
+ max-jobs = auto + max-jobs = auto
+ sandbox = true + sandbox = true
+ substituters = https://cache.armv7l.xyz
+ trusted-public-keys = cache.armv7l.xyz-1:kBY/eGnBAYiqYfg0fy0inWhshUo+pGFM3Pj7kIkmlBk=
+ trusted-users = root + trusted-users = root
EOF EOF
''; '';
@ -152,7 +151,7 @@ index c61f9d6..fbdf0fd 100644
}; };
} }
diff --git a/zynq_image.nix b/zynq_image.nix diff --git a/zynq_image.nix b/zynq_image.nix
index 3fa23ab..069fe89 100644 index 3fa23ab..9d1621e 100644
--- a/zynq_image.nix --- a/zynq_image.nix
+++ b/zynq_image.nix +++ b/zynq_image.nix
@@ -1,66 +1,89 @@ @@ -1,66 +1,89 @@
@ -164,7 +163,7 @@ index 3fa23ab..069fe89 100644
- # dont use overlays for the qemu, it causes a lot of wasted time on recompiles - # dont use overlays for the qemu, it causes a lot of wasted time on recompiles
- x86pkgs = import pkgs.path { system = "x86_64-linux"; }; - x86pkgs = import pkgs.path { system = "x86_64-linux"; };
- customKernel = pkgs.linux.override { - customKernel = pkgs.linux.override {
+ customKernel = (pkgs.linux_6_6.override { + customKernel = (pkgs.linux.override {
extraConfig = '' extraConfig = ''
OVERLAY_FS y OVERLAY_FS y
+ MEDIA_SUPPORT n + MEDIA_SUPPORT n
@ -250,7 +249,7 @@ index 3fa23ab..069fe89 100644
- environment.etc."service/getty/run".source = pkgs.writeShellScript "getty" '' - environment.etc."service/getty/run".source = pkgs.writeShellScript "getty" ''
- agetty ttyPS0 115200 - agetty ttyPS0 115200
+ environment = { + environment = {
+ systemPackages = with pkgs; [ inetutils wget gnugrep nano vim ]; + systemPackages = with pkgs; [ inetutils wget nano ];
+ etc = { + etc = {
+ "service/getty/run".source = pkgs.writeShellScript "getty" '' + "service/getty/run".source = pkgs.writeShellScript "getty" ''
+ hostname ${config.networking.hostName} + hostname ${config.networking.hostName}

View File

@ -394,10 +394,10 @@ index 0000000..53c5349
\ No newline at end of file \ No newline at end of file
diff --git a/xilinx-fpga-manager.patch b/xilinx-fpga-manager.patch diff --git a/xilinx-fpga-manager.patch b/xilinx-fpga-manager.patch
new file mode 100644 new file mode 100644
index 0000000..33daffe index 0000000..59aa585
--- /dev/null --- /dev/null
+++ b/xilinx-fpga-manager.patch +++ b/xilinx-fpga-manager.patch
@@ -0,0 +1,676 @@ @@ -0,0 +1,663 @@
+# Enable user-space interface for PL programming via Linux FPGA manager +# Enable user-space interface for PL programming via Linux FPGA manager
+# diff cherry-picked from Xilinx/linux-xilinx/tree/xlnx_rebase_v6.6_LTS +# diff cherry-picked from Xilinx/linux-xilinx/tree/xlnx_rebase_v6.6_LTS
+# commit IDs: e61c0a9, 0a38712, dc67651, 89a24e3, 8d224b1, 2a9c05f, 4e94580 +# commit IDs: e61c0a9, 0a38712, dc67651, 89a24e3, 8d224b1, 2a9c05f, 4e94580
@ -425,7 +425,7 @@ index 0000000..33daffe
+ tristate "Altera SOCFPGA FPGA Manager" + tristate "Altera SOCFPGA FPGA Manager"
+ depends on ARCH_INTEL_SOCFPGA || COMPILE_TEST + depends on ARCH_INTEL_SOCFPGA || COMPILE_TEST
+diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c +diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c
+index 0f4035b089a2..3aa9f5f041f6 100644 +index 06651389c592..6e8c45974f28 100644
+--- a/drivers/fpga/fpga-mgr.c +--- a/drivers/fpga/fpga-mgr.c
++++ b/drivers/fpga/fpga-mgr.c ++++ b/drivers/fpga/fpga-mgr.c
+@@ -8,6 +8,9 @@ +@@ -8,6 +8,9 @@
@ -673,7 +673,7 @@ index 0000000..33daffe
+ NULL, + NULL,
+ }; + };
+ ATTRIBUTE_GROUPS(fpga_mgr); + ATTRIBUTE_GROUPS(fpga_mgr);
+@@ -739,6 +871,106 @@ void fpga_mgr_put(struct fpga_manager *mgr) +@@ -732,6 +864,106 @@ void fpga_mgr_put(struct fpga_manager *mgr)
+ } + }
+ EXPORT_SYMBOL_GPL(fpga_mgr_put); + EXPORT_SYMBOL_GPL(fpga_mgr_put);
+ +
@ -780,8 +780,8 @@ index 0000000..33daffe
+ /** + /**
+ * fpga_mgr_lock - Lock FPGA manager for exclusive use + * fpga_mgr_lock - Lock FPGA manager for exclusive use
+ * @mgr: fpga manager + * @mgr: fpga manager
+@@ -788,6 +1020,9 @@ __fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info * +@@ -779,6 +1011,9 @@ struct fpga_manager *
+ struct module *owner) + fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info)
+ { + {
+ const struct fpga_manager_ops *mops = info->mops; + const struct fpga_manager_ops *mops = info->mops;
++#ifdef CONFIG_FPGA_MGR_DEBUG_FS ++#ifdef CONFIG_FPGA_MGR_DEBUG_FS
@ -790,7 +790,7 @@ index 0000000..33daffe
+ struct fpga_manager *mgr; + struct fpga_manager *mgr;
+ int id, ret; + int id, ret;
+ +
+@@ -826,10 +1061,28 @@ __fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info * +@@ -815,10 +1050,28 @@ fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *in
+ mgr->dev.of_node = parent->of_node; + mgr->dev.of_node = parent->of_node;
+ mgr->dev.id = id; + mgr->dev.id = id;
+ +
@ -819,7 +819,7 @@ index 0000000..33daffe
+ /* + /*
+ * Initialize framework state by requesting low level driver read state + * Initialize framework state by requesting low level driver read state
+ * from device. FPGA may be in reset mode or may have been programmed + * from device. FPGA may be in reset mode or may have been programmed
+@@ -843,6 +1096,28 @@ __fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info * +@@ -832,6 +1085,28 @@ fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *in
+ return ERR_PTR(ret); + return ERR_PTR(ret);
+ } + }
+ +
@ -848,7 +848,7 @@ index 0000000..33daffe
+ return mgr; + return mgr;
+ +
+ error_device: + error_device:
+@@ -894,6 +1169,10 @@ void fpga_mgr_unregister(struct fpga_manager *mgr) +@@ -882,6 +1157,10 @@ void fpga_mgr_unregister(struct fpga_manager *mgr)
+ { + {
+ dev_info(&mgr->dev, "%s %s\n", __func__, mgr->name); + dev_info(&mgr->dev, "%s %s\n", __func__, mgr->name);
+ +
@ -881,10 +881,10 @@ index 0000000..33daffe
+ &firmware_name)) { + &firmware_name)) {
+ info->firmware_name = devm_kstrdup(dev, firmware_name, + info->firmware_name = devm_kstrdup(dev, firmware_name,
+diff --git a/drivers/fpga/zynqmp-fpga.c b/drivers/fpga/zynqmp-fpga.c +diff --git a/drivers/fpga/zynqmp-fpga.c b/drivers/fpga/zynqmp-fpga.c
+index f3434e2c487b..d2434ed85eff 100644 +index f3434e2c487b..db923746cac5 100644
+--- a/drivers/fpga/zynqmp-fpga.c +--- a/drivers/fpga/zynqmp-fpga.c
++++ b/drivers/fpga/zynqmp-fpga.c ++++ b/drivers/fpga/zynqmp-fpga.c
+@@ -43,25 +43,47 @@ static int zynqmp_fpga_ops_write(struct fpga_manager *mgr, +@@ -43,25 +43,42 @@ static int zynqmp_fpga_ops_write(struct fpga_manager *mgr,
+ struct zynqmp_fpga_priv *priv; + struct zynqmp_fpga_priv *priv;
+ dma_addr_t dma_addr; + dma_addr_t dma_addr;
+ u32 eemi_flags = 0; + u32 eemi_flags = 0;
@ -915,11 +915,6 @@ index 0000000..33daffe
++ ++
+ wmb(); /* ensure all writes are done before initiate FW call */ + wmb(); /* ensure all writes are done before initiate FW call */
+ +
++ if (priv->flags & FPGA_MGR_DDR_MEM_AUTH_BITSTREAM)
++ eemi_flags |= XILINX_ZYNQMP_PM_FPGA_AUTHENTICATION_DDR;
++ else if (priv->flags & FPGA_MGR_SECURE_MEM_AUTH_BITSTREAM)
++ eemi_flags |= XILINX_ZYNQMP_PM_FPGA_AUTHENTICATION_OCM;
++
+ if (priv->flags & FPGA_MGR_PARTIAL_RECONFIG) + if (priv->flags & FPGA_MGR_PARTIAL_RECONFIG)
+ eemi_flags |= XILINX_ZYNQMP_PM_FPGA_PARTIAL; + eemi_flags |= XILINX_ZYNQMP_PM_FPGA_PARTIAL;
+ +
@ -936,22 +931,20 @@ index 0000000..33daffe
+ return ret; + return ret;
+ } + }
+diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h +diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h
+index e8b12ec8b060..ffd2dfdb6abd 100644 +index 9dda7d9898ff..edaf77160746 100644
+--- a/include/linux/firmware/xlnx-zynqmp.h +--- a/include/linux/firmware/xlnx-zynqmp.h
++++ b/include/linux/firmware/xlnx-zynqmp.h ++++ b/include/linux/firmware/xlnx-zynqmp.h
+@@ -83,6 +83,10 @@ +@@ -70,6 +70,8 @@
+ */ + */
+ #define XILINX_ZYNQMP_PM_FPGA_FULL 0x0U + #define XILINX_ZYNQMP_PM_FPGA_FULL 0x0U
+ #define XILINX_ZYNQMP_PM_FPGA_PARTIAL BIT(0) + #define XILINX_ZYNQMP_PM_FPGA_PARTIAL BIT(0)
++#define XILINX_ZYNQMP_PM_FPGA_AUTHENTICATION_DDR BIT(1)
++#define XILINX_ZYNQMP_PM_FPGA_AUTHENTICATION_OCM BIT(2)
++#define XILINX_ZYNQMP_PM_FPGA_ENCRYPTION_USERKEY BIT(3) ++#define XILINX_ZYNQMP_PM_FPGA_ENCRYPTION_USERKEY BIT(3)
++#define XILINX_ZYNQMP_PM_FPGA_ENCRYPTION_DEVKEY BIT(4) ++#define XILINX_ZYNQMP_PM_FPGA_ENCRYPTION_DEVKEY BIT(4)
+ +
+ /* FPGA Status Reg */ + /* FPGA Status Reg */
+ #define XILINX_ZYNQMP_PM_FPGA_CONFIG_STAT_OFFSET 7U + #define XILINX_ZYNQMP_PM_FPGA_CONFIG_STAT_OFFSET 7U
+diff --git a/include/linux/fpga/fpga-mgr.h b/include/linux/fpga/fpga-mgr.h +diff --git a/include/linux/fpga/fpga-mgr.h b/include/linux/fpga/fpga-mgr.h
+index 0d4fe068f3d8..f884d268c974 100644 +index 54f63459efd6..c96a4405f909 100644
+--- a/include/linux/fpga/fpga-mgr.h +--- a/include/linux/fpga/fpga-mgr.h
++++ b/include/linux/fpga/fpga-mgr.h ++++ b/include/linux/fpga/fpga-mgr.h
+@@ -9,8 +9,11 @@ +@@ -9,8 +9,11 @@
@ -966,7 +959,7 @@ index 0000000..33daffe
+ struct fpga_manager; + struct fpga_manager;
+ struct sg_table; + struct sg_table;
+ +
+@@ -66,17 +69,29 @@ enum fpga_mgr_states { +@@ -66,17 +69,25 @@ enum fpga_mgr_states {
+ * + *
+ * %FPGA_MGR_EXTERNAL_CONFIG: FPGA has been configured prior to Linux booting + * %FPGA_MGR_EXTERNAL_CONFIG: FPGA has been configured prior to Linux booting
+ * + *
@ -980,10 +973,6 @@ index 0000000..33daffe
++ * ++ *
++ * %FPGA_MGR_USERKEY_ENCRYPTED_BITSTREAM: indicates bitstream is encrypted with ++ * %FPGA_MGR_USERKEY_ENCRYPTED_BITSTREAM: indicates bitstream is encrypted with
++ * user key ++ * user key
++ * %FPGA_MGR_DDR_MEM_AUTH_BITSTREAM: do bitstream authentication using DDR
++ * memory if supported
++ * %FPGA_MGR_SECURE_MEM_AUTH_BITSTREAM: do bitstream authentication using secure
++ * memory if supported
+ */ + */
+ #define FPGA_MGR_PARTIAL_RECONFIG BIT(0) + #define FPGA_MGR_PARTIAL_RECONFIG BIT(0)
+ #define FPGA_MGR_EXTERNAL_CONFIG BIT(1) + #define FPGA_MGR_EXTERNAL_CONFIG BIT(1)
@ -997,7 +986,7 @@ index 0000000..33daffe
+ +
+ /** + /**
+ * struct fpga_image_info - information specific to an FPGA image + * struct fpga_image_info - information specific to an FPGA image
+@@ -86,6 +101,7 @@ enum fpga_mgr_states { +@@ -86,6 +97,7 @@ enum fpga_mgr_states {
+ * @config_complete_timeout_us: maximum time for FPGA to switch to operating + * @config_complete_timeout_us: maximum time for FPGA to switch to operating
+ * status in the write_complete op. + * status in the write_complete op.
+ * @firmware_name: name of FPGA image firmware file + * @firmware_name: name of FPGA image firmware file
@ -1005,7 +994,7 @@ index 0000000..33daffe
+ * @sgt: scatter/gather table containing FPGA image + * @sgt: scatter/gather table containing FPGA image
+ * @buf: contiguous buffer containing FPGA image + * @buf: contiguous buffer containing FPGA image
+ * @count: size of buf + * @count: size of buf
+@@ -102,6 +118,7 @@ struct fpga_image_info { +@@ -102,6 +114,7 @@ struct fpga_image_info {
+ u32 disable_timeout_us; + u32 disable_timeout_us;
+ u32 config_complete_timeout_us; + u32 config_complete_timeout_us;
+ char *firmware_name; + char *firmware_name;
@ -1013,7 +1002,7 @@ index 0000000..33daffe
+ struct sg_table *sgt; + struct sg_table *sgt;
+ const char *buf; + const char *buf;
+ size_t count; + size_t count;
+@@ -160,6 +177,7 @@ struct fpga_manager_info { +@@ -160,6 +173,7 @@ struct fpga_manager_info {
+ * @write: write count bytes of configuration data to the FPGA + * @write: write count bytes of configuration data to the FPGA
+ * @write_sg: write the scatter list of configuration data to the FPGA + * @write_sg: write the scatter list of configuration data to the FPGA
+ * @write_complete: set FPGA to operating state after writing is done + * @write_complete: set FPGA to operating state after writing is done
@ -1021,7 +1010,7 @@ index 0000000..33daffe
+ * @fpga_remove: optional: Set FPGA into a specific state during driver remove + * @fpga_remove: optional: Set FPGA into a specific state during driver remove
+ * @groups: optional attribute groups. + * @groups: optional attribute groups.
+ * + *
+@@ -182,6 +200,7 @@ struct fpga_manager_ops { +@@ -182,6 +196,7 @@ struct fpga_manager_ops {
+ int (*write_sg)(struct fpga_manager *mgr, struct sg_table *sgt); + int (*write_sg)(struct fpga_manager *mgr, struct sg_table *sgt);
+ int (*write_complete)(struct fpga_manager *mgr, + int (*write_complete)(struct fpga_manager *mgr,
+ struct fpga_image_info *info); + struct fpga_image_info *info);
@ -1029,7 +1018,7 @@ index 0000000..33daffe
+ void (*fpga_remove)(struct fpga_manager *mgr); + void (*fpga_remove)(struct fpga_manager *mgr);
+ const struct attribute_group **groups; + const struct attribute_group **groups;
+ }; + };
+@@ -196,23 +215,37 @@ struct fpga_manager_ops { +@@ -196,21 +211,35 @@ struct fpga_manager_ops {
+ /** + /**
+ * struct fpga_manager - fpga manager structure + * struct fpga_manager - fpga manager structure
+ * @name: name of low level fpga manager + * @name: name of low level fpga manager
@ -1042,7 +1031,6 @@ index 0000000..33daffe
+ * @state: state of fpga manager + * @state: state of fpga manager
+ * @compat_id: FPGA manager id for compatibility check. + * @compat_id: FPGA manager id for compatibility check.
+ * @mops: pointer to struct of fpga manager ops + * @mops: pointer to struct of fpga manager ops
+ * @mops_owner: module containing the mops
+ * @priv: low level driver private date + * @priv: low level driver private date
++ * @err: low level driver error code ++ * @err: low level driver error code
++ * @dir: debugfs image directory ++ * @dir: debugfs image directory
@ -1058,7 +1046,6 @@ index 0000000..33daffe
+ enum fpga_mgr_states state; + enum fpga_mgr_states state;
+ struct fpga_compat_id *compat_id; + struct fpga_compat_id *compat_id;
+ const struct fpga_manager_ops *mops; + const struct fpga_manager_ops *mops;
+ struct module *mops_owner;
+ void *priv; + void *priv;
++ int err; ++ int err;
++#ifdef CONFIG_FPGA_MGR_DEBUG_FS ++#ifdef CONFIG_FPGA_MGR_DEBUG_FS
@ -1067,21 +1054,21 @@ index 0000000..33daffe
+ }; + };
+ +
+ #define to_fpga_manager(d) container_of(d, struct fpga_manager, dev) + #define to_fpga_manager(d) container_of(d, struct fpga_manager, dev)
+@@ -258,4 +291,6 @@ __devm_fpga_mgr_register(struct device *parent, const char *name, +@@ -244,4 +273,6 @@ struct fpga_manager *
+ const struct fpga_manager_ops *mops, void *priv, + devm_fpga_mgr_register(struct device *parent, const char *name,
+ struct module *owner); + const struct fpga_manager_ops *mops, void *priv);
+ +
++#define FPGA_IOCTL_LOAD_DMA_BUFF _IOWR('R', 1, __u32) ++#define FPGA_IOCTL_LOAD_DMA_BUFF _IOWR('R', 1, __u32)
++ ++
+ #endif /*_LINUX_FPGA_MGR_H */ + #endif /*_LINUX_FPGA_MGR_H */
diff --git a/zynq_image.nix b/zynq_image.nix diff --git a/zynq_image.nix b/zynq_image.nix
index d5c5eda..7ede584 100644 index 9d1621e..012e50c 100644
--- a/zynq_image.nix --- a/zynq_image.nix
+++ b/zynq_image.nix +++ b/zynq_image.nix
@@ -3,6 +3,16 @@ @@ -3,6 +3,16 @@
with lib; with lib;
let let
customKernel = (pkgs.linux_6_6.override { customKernel = (pkgs.linux.override {
+ kernelPatches = [ + kernelPatches = [
+ ({ + ({
+ name = "xilinx-configfs-overlays"; + name = "xilinx-configfs-overlays";