Compare commits

...

33 Commits

Author SHA1 Message Date
67e7bf4af2 Add instructions for firmware development 2024-12-20 17:40:08 +08:00
b87fad5ed4 Add hardware specific patch to linien
- Correct MHz and Voltage Scaling
- Hide Analog Out related GUI Elements
- Change default amplitude and frequency values
2024-12-20 16:29:17 +08:00
372aac6a44 Reorganize flake.nix
- No functional change
2024-12-20 16:29:04 +08:00
e05f31b70c Disable OTA Update on client and gui 2024-12-20 16:28:53 +08:00
67cba47a3f Change ssh port from 22 to 3030 2024-12-18 14:02:36 +08:00
a87a0a224f Upgrade linien from v1.0.0 to v2.1.0
- Add linien GUI dev shell for fast servo platform
2024-12-18 12:43:12 +08:00
eb0d01d339 nixos 24.11 2024-12-17 16:41:29 +08:00
b631c1fa4a pid: add pipeline on error signal computation 2024-12-11 15:24:27 +08:00
bc5d24a69a Fix malformed pid_pipeline patch 2024-12-11 12:36:02 +08:00
0f15e0ef70 Add patches to fix timing errors in gateware 2024-12-11 11:01:15 +08:00
5816c070ef flake: update dependencies 2024-12-04 23:02:47 +08:00
322d61d436 iproute -> iproute2 2024-12-04 23:02:39 +08:00
3be72cd2dc update vivado 2024-12-04 22:14:08 +08:00
77643909ef pyfastservo: add note for dac output override 2024-11-15 15:42:25 +08:00
a5dc232be4 gateware: add cdc fifo for dac output value override csr 2024-11-15 15:42:25 +08:00
87059eef2b gateware: async fifo with depth of 2 is broken
- Changing depth to 4 has resolved cdc issue
2024-11-15 15:42:25 +08:00
8a40bb4f21 gateware: Add cdc fifo for adc and dac
- dco2d and sys clk use two different clock sources
2024-11-13 15:43:35 +08:00
bbe09de52c pyfastservo adc: Add helper fn for phase shifting the dac ddr clock 2024-11-08 16:37:29 +08:00
9f2e609b6e pyfastservo dac: Change debug MSG 2024-11-08 16:37:16 +08:00
6705b182d5 pyfastservo dac: power_down -> power_down_afe 2024-11-08 16:35:52 +08:00
51c8b755d2 pyfastservo dac: hard_reset -> soft_reset 2024-11-08 16:35:52 +08:00
5d55ab4c9c pyfastservo dac: reacquire clk relationship at init 2024-11-08 16:35:52 +08:00
560b28508c pyfastservo dac: turn off manual override by default 2024-11-08 16:35:52 +08:00
b1a9fa0ad4 pyfastservo adc: Set default afe gain to 10x 2024-11-08 16:35:52 +08:00
5343b3d45a pyfastservo adc: print 100 times to check test pattern 2024-11-08 16:35:52 +08:00
4940ee52cc pyfastservo adc: Add mmcm rst after ADC is rst 2024-11-08 16:35:52 +08:00
382e8467d9 pyfastservo adc: Fix find edge bug
- Fix: if frame changed at 31 tap delay, edge would not get detected
2024-11-08 16:35:52 +08:00
6cef418756 gateware: Add CSR Ctrl to PL's MMCM
- Generate 45 Degree Phase Shifted DDR Clock
- PLLE2_Base -> MMCM_ADV for ddr clock dynamic phase shift
- Add mmcm_rst, ddr_clk_ps, mmcm_locked status to CSR
- Generate dco2d rst signal from mmcm and connect to the related logic
2024-11-08 16:33:17 +08:00
e708696b5d add grep and vim 2024-10-31 19:06:59 +08:00
3cf9a721cf add linuswck ssh key 2024-10-31 14:54:14 +08:00
8b20379427 remove nixos armv7l unofficial binary cache 2024-08-22 14:14:51 +08:00
15a66c01fa dac: fix initialization order 2024-08-20 16:35:49 +08:00
2d75b4112e flake: update dependencies 2024-08-19 22:03:51 +08:00
25 changed files with 1112 additions and 241 deletions

21
README.md Normal file
View File

@ -0,0 +1,21 @@
# 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

@ -0,0 +1,66 @@
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

@ -0,0 +1,13 @@
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

@ -0,0 +1,31 @@
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

@ -0,0 +1,15 @@
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

@ -1,38 +0,0 @@
# 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,3 +1,42 @@
# 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:
@ -16,41 +55,27 @@ 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 6c34429..a0b12d0 100644 index c3e20e7..ebead1d 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,5 +1,6 @@ @@ -1,6 +1,7 @@
# Copyright 2014-2015 Robert Jördens <jordens@gmail.com>
# Copyright 2018-2022 Benjamin Wiegand <benjamin.wiegand@physik.hu-berlin.de>
+# Copyright 2023 Jakub Matyas <jakubk.m@gmail.com>
#
# This file is part of Linien and based on redpid. # This file is part of Linien and based on redpid.
# #
@@ -23,14 +24,16 @@ from pathlib import Path # Copyright (C) 2016-2024 Linien Authors (https://github.com/linien-org/linien#license)
REPO_ROOT_DIR = Path(__file__).resolve().parents[1] +# Copyright 2023 Jakub Matyas <jakubk.m@gmail.com>
#
# Linien is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -20,16 +21,18 @@
from pathlib import Path
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")
@ -65,7 +90,7 @@ index 6c34429..a0b12d0 100644
fil.write("}\n\n") fil.write("}\n\n")
@@ -52,26 +55,49 @@ def get_csrmap(banks): @@ -51,26 +54,51 @@ 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:
@ -84,7 +109,7 @@ index 6c34429..a0b12d0 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()
@ -107,6 +132,7 @@ index 6c34429..a0b12d0 100644
+ 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:
@ -117,7 +143,7 @@ index 6c34429..a0b12d0 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)
@ -128,14 +154,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
@@ -2,6 +2,7 @@ @@ -1,6 +1,7 @@
# Copyright 2018-2022 Benjamin Wiegand <benjamin.wiegand@physik.hu-berlin.de>
# Copyright 2021-2023 Bastian Leykauf <leykauf@physik.hu-berlin.de>
# Copyright 2022 Christian Freier <christian.freier@nomadatomics.com>
+# Copyright 2023 Jakub Matyas <jakubk.m@gmail.com>
#
# This file is part of Linien and based on redpid. # This file is part of Linien and based on redpid.
# #
# Copyright (C) 2016-2024 Linien Authors (https://github.com/linien-org/linien#license)
+# Copyright 2023 Jakub Matyas <jakubk.m@gmail.com>
#
# Linien is free software: you can redistribute it and/or modify
# 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,13 +20,15 @@
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()
@ -41,59 +43,83 @@ 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(
"PLLE2_BASE", "MMCME2_ADV",
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=4, # VCO @ 800 MHz p_CLKFBOUT_MULT_F=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"), i_RST=ResetSignal("sys") | self.mmcm_rst,
i_CLKFBIN=clk_feedback_buf, i_CLKFBIN=clk_feedback_buf,
o_CLKFBOUT=clk_feedback, o_CLKFBOUT=clk_feedback,
p_CLKOUT0_DIVIDE=4,
p_CLKOUT0_PHASE=0.0, p_CLKOUT0_USE_FINE_PS="TRUE",
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_dco, # 200 MHz <- dco_clk o_CLKOUT0=clk_dco2d_45_degree, # 100 MHz <- dco_clk / 2 = 200 MHz / 2
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(4) self.frame_csr = CSRStatus(5)
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(4) self.afe_ctrl = CSRStorage(7)
tap_delay_val = Signal(5) tap_delay_val = Signal(5)
bitslip = Signal() bitslip = Signal()
@ -105,7 +131,17 @@ 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")),
]
### ###
@ -117,11 +153,14 @@ 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 self.afe_ctrl.storage[0:4]
), ),
] ]
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 += [
@ -129,7 +168,8 @@ class ADC(Module, AutoCSR):
] ]
self.comb += [ self.comb += [
self.frame_csr.status.eq(self.s_frame), self.frame_csr.status[0:4].eq(self.s_frame[0:4]),
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]),
] ]
@ -146,7 +186,7 @@ class ADC(Module, AutoCSR):
self.specials += Instance( self.specials += Instance(
"LTC2195", "LTC2195",
i_rst_in=ResetSignal("sys"), i_rst_in=ResetSignal("dco2d"),
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"),
@ -158,9 +198,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[1], # LANES swapped on hardware o_ADC0_out=self.data_out_cdc[1], # LANES swapped on hardware
o_ADC1_out=self.data_out[0], o_ADC1_out=self.data_out_cdc[0],
o_FR_out=self.s_frame, o_FR_out=self.s_frame_cdc,
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,6 +20,7 @@
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):
@ -38,37 +39,51 @@ 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("sys")), dac_pads.rst.eq(ResetSignal("dco2d")),
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.output_value_ch0.storage, self.data_in[0]) Mux(manual_override, self.data_in_csr_cdc[0], self.data_in_cdc[0])
), ),
output_data_ch1.eq( output_data_ch1.eq(
Mux(manual_override, self.output_value_ch1.storage, self.data_in[1]) Mux(manual_override, self.data_in_csr_cdc[1], self.data_in_cdc[1])
), ),
] ]
# data self.specials += [
for lane in range(14): Instance("ODDR",
self.specials += DDROutput( i_C=ClockSignal("dco2d"),
i1 = output_data_ch0[lane], i_CE=~ResetSignal("dco2d"),
i2 = output_data_ch1[lane], i_D1=output_data_ch0[lane], # DDR CLK Rising Edge
o = dac_pads.data[lane], i_D2=output_data_ch1[lane], # DDR CLK Falling Edge
clk = ClockSignal("dco2d") o_Q=dac_pads.data[lane],
) p_DDR_CLK_EDGE="SAME_EDGE")
for lane in range(14)]
# clock forwarding self.specials += Instance("ODDR",
self.specials += DDROutput( i_C=ClockSignal("dco2d_45_degree"),
i1 = 0b0, i_CE=~ResetSignal("dco2d"),
i2 = 0b1, i_D1=0,
o = dac_pads.dclkio, i_D2=1,
clk = ClockSignal("dco2d"), o_Q=dac_pads.dclkio,
) p_DDR_CLK_EDGE="SAME_EDGE")
class AUX_DAC_CTRL(Module, AutoCSR): class AUX_DAC_CTRL(Module, AutoCSR):

View File

@ -147,6 +147,7 @@ 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

@ -0,0 +1,227 @@
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

@ -0,0 +1,43 @@
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..044d88e index 0000000..0c9bb53
--- /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,27 +59,16 @@ 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 98bdaee..b0a8af4 100644 index 9302177..2258ddc 100644
--- a/setup.py --- a/setup.py
+++ b/setup.py +++ b/setup.py
@@ -1,5 +1,10 @@ @@ -1,4 +1,28 @@
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():
@ -91,51 +80,16 @@ index 98bdaee..b0a8af4 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(
+class lib_install(install):
+ def run(self):
+ compile_libmonitor()
+ install_libmonitor(self.prefix)
+ # install.run(self)
+
+# Will use nix to install libmonitor
+ cmdclass={ + cmdclass={
+ "build": lib_build + "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(**setup_args)
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

@ -0,0 +1,22 @@
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

@ -0,0 +1,26 @@
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

@ -0,0 +1,57 @@
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

@ -0,0 +1,19 @@
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

@ -0,0 +1,64 @@
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,7 @@
# 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 spidev import spidev
from pyfastservo.common import ( from pyfastservo.common import (
ADC_AFE_CTRL_ADDR, ADC_AFE_CTRL_ADDR,
@ -78,27 +78,44 @@ def read_frame():
def perform_bitslip(): def perform_bitslip():
for i in range(4): for i in range(4):
current_frame = read_frame() current_frame = read_frame()
if current_frame != 0x0C: if current_frame & 0x0F != 0x0C:
print(f"Performing bitslip (iteration: {i}). Current frame: 0x{current_frame:02x}") print(f"Performing bitslip (iteration: {i}). Current frame: 0x{current_frame:02x}")
write_to_memory(ADC_BITSLIP_ADDR, 1) write_to_memory(ADC_BITSLIP_ADDR, 1)
else: else:
print(f"No bitslip required; Current frame: 0x{current_frame:02x}") print(f"No bitslip required; Current frame: 0x{current_frame:02x}")
return 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(): def find_edge():
prev_frame = read_frame() prev_frame = read_frame()
transition = False
for tap_delay in range(32): for tap_delay in range(32):
write_to_memory(ADC_DELAY_ADDR, tap_delay) write_to_memory(ADC_DELAY_ADDR, tap_delay)
current_frame = read_frame() current_frame = read_frame()
print(f"Tap delay: {tap_delay}, Current frame: 0x{current_frame:02x}") 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: if current_frame != prev_frame:
if not transition: final_delay = ((tap_delay+1) // 2) + 2
transition = True
else:
final_delay = (tap_delay // 2) + 2
print(f"Edge detected; setting iDelay to: {final_delay}") print(f"Edge detected; setting iDelay to: {final_delay}")
write_to_memory(ADC_DELAY_ADDR, final_delay) write_to_memory(ADC_DELAY_ADDR, final_delay)
return return
@ -126,6 +143,36 @@ def enable_adc_afe(ch1_x10=False, ch2_x10=False):
print(f"ADC_AFE_CTRL: 0x{afe_ctrl:02X}") print(f"ADC_AFE_CTRL: 0x{afe_ctrl:02X}")
return afe_ctrl 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(): def configure_ltc2195():
spi = spidev.SpiDev() spi = spidev.SpiDev()
try: try:
@ -144,15 +191,31 @@ def configure_ltc2195():
0x04: test_pattern & 0xFF 0x04: test_pattern & 0xFF
}) })
# ADC software reset put its PLL to sleep momentarily. Thus, MMCM needs to be reset as well.
mmcm_rst()
# Performing Word Align # Performing Word Align
perform_bitslip() perform_bitslip()
find_edge() find_edge()
# Printing it once is not enough to check whether the alignment is correct.
for i in range(100):
print_adc_channels() print_adc_channels()
main_adc_test_mode(spi, False) main_adc_test_mode(spi, False)
verify_adc_registers(spi, {0x02: 0x11}) # Verify test mode is off verify_adc_registers(spi, {0x02: 0x11}) # Verify test mode is off
enable_adc_afe() # FIXME: AFE Gain 1x is not functional on that batch of fast servo under development
enable_adc_afe(ch1_x10=1, ch2_x10=1)
#find_min_max_ch(0)
#find_min_max_ch(1)
#for i in range(10):
# print_adc_channel(0)
#for i in range(10):
# print_adc_channel(1)
finally: finally:
spi.close() spi.close()

View File

@ -45,7 +45,7 @@ def spi_read(spi, address):
rx_buffer = spi.xfer2([0x80 | address, 0x00]) rx_buffer = spi.xfer2([0x80 | address, 0x00])
return rx_buffer[1] return rx_buffer[1]
def hard_reset(spi): def soft_reset(spi):
spi_write(spi, 0x00, 0x10) # Software reset spi_write(spi, 0x00, 0x10) # Software reset
spi_write(spi, 0x00, 0x00) # Release software reset spi_write(spi, 0x00, 0x00) # Release software reset
spi_read(spi, 0x00) # Read reset address (necessary for reset to take effect) spi_read(spi, 0x00) # Read reset address (necessary for reset to take effect)
@ -63,7 +63,10 @@ def configure_dac(spi):
spi_write(spi, 0x07, 0xA0) # Enable on-chip QRSET (1.6 kΩ for 20mA output) 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, 0x05, 0x00) # Disable internal IRCML
spi_write(spi, 0x08, 0x00) # Disable internal QRCML spi_write(spi, 0x08, 0x00) # Disable internal QRCML
spi_write(spi, 0x02, 0xB4) # Enable 2's complement, LVDS interface, 4 LVDS lanes 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): def dac_self_calibration(spi):
spi_write(spi, 0x12, 0x00) # Reset calibration status spi_write(spi, 0x12, 0x00) # Reset calibration status
@ -83,11 +86,11 @@ def dac_self_calibration(spi):
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(channel, power_down=True): def power_down_afe(channel, power_down=True):
assert channel in (0, 1) assert channel in (0, 1)
bitmask = 1 << (channel + 1) & 0b111 bitmask = 1 << (channel + 1) & 0b111
@ -98,19 +101,32 @@ def power_down(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"REG contents: 0b{reg_contents:03b}") print(f"Power Down DAC AFE Ch{channel}: {power_down}")
def set_dac_output(value): def set_dac_output(value):
value = min(value, 0x3FFF) value = min(value, 0x3FFF)
low_word = value & 0xFF low_word = value & 0xFF
high_word = (value >> 8) & 0x3F high_word = (value >> 8) & 0x3F
# Note: DAC HIGH word and LOW word output are not updated
# at the same time. On scope, you will see more than one step
# of value changed.
write_to_memory(CH0_HIGH_WORD_ADDR, high_word) write_to_memory(CH0_HIGH_WORD_ADDR, high_word)
write_to_memory(CH0_LOW_WORD_ADDR, low_word) write_to_memory(CH0_LOW_WORD_ADDR, low_word)
write_to_memory(CH1_HIGH_WORD_ADDR, high_word) write_to_memory(CH1_HIGH_WORD_ADDR, high_word)
write_to_memory(CH1_LOW_WORD_ADDR, low_word) write_to_memory(CH1_LOW_WORD_ADDR, low_word)
print(f"DAC output set to: 0x{value:04X}") 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:
print("Clock relationship is found")
return True
def configure_ad9117(): def configure_ad9117():
spi = spidev.SpiDev() spi = spidev.SpiDev()
spi.open(MAIN_DAC_BUS, MAIN_DAC_DEVICE) spi.open(MAIN_DAC_BUS, MAIN_DAC_DEVICE)
@ -119,21 +135,25 @@ def configure_ad9117():
spi.cshigh = False spi.cshigh = False
try: try:
hard_reset(spi) soft_reset(spi)
if not check_version(spi): if not check_version(spi):
print("Unrecognized DAC version") print("Unrecognized DAC version")
return False return False
configure_dac(spi) power_down_afe(0, True)
dac_self_calibration(spi) power_down_afe(1, True)
power_down(0, False) configure_dac(spi)
power_down(1, False) check_clk_relationship(spi)
manual_override(True) dac_self_calibration(spi)
# Enable DAC outputs # Enable DAC outputs
spi_write(spi, 0x01, spi_read(spi, 0x01) & ~((1 << 4) | (1 << 3))) 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") print("AD9117 configuration completed successfully")
return True return True

22
flake.lock generated
View File

@ -18,16 +18,16 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1719838683, "lastModified": 1734323986,
"narHash": "sha256-Zw9rQjHz1ilNIimEXFeVa1ERNRBF8DoXDhLAZq5B4pE=", "narHash": "sha256-m/lh6hYMIWDYHCAsn81CDAiXoT3gmxXI9J987W5tZrE=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "d032c1a6dfad4eedec7e35e91986becc699d7d69", "rev": "394571358ce82dff7411395829aa6a3aad45b907",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"ref": "nixos-24.05", "ref": "nixos-24.11",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }
@ -64,11 +64,11 @@
"src-migen": { "src-migen": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1715484909, "lastModified": 1727677091,
"narHash": "sha256-4DCHBUBfc/VA+7NW2Hr0+JP4NnKPru2uVJyZjCCk0Ws=", "narHash": "sha256-Zg3SQnTwMM/VkOGKogbPyuCC2NhLy8HB2SPEUWWNgCU=",
"owner": "m-labs", "owner": "m-labs",
"repo": "migen", "repo": "migen",
"rev": "4790bb577681a8c3a8d226bc196a4e5deb39e4df", "rev": "c19ae9f8ae162ffe2d310a92bfce53ac2a821bc8",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -80,11 +80,11 @@
"src-misoc": { "src-misoc": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1715647536, "lastModified": 1729234629,
"narHash": "sha256-q+USDcaKHABwW56Jzq8u94iGPWlyLXMyVt0j/Gyg+IE=", "narHash": "sha256-TLsTCXV5AC2xh+bS7EhBVBKqdqIU3eKrnlWcFF9LtAM=",
"ref": "refs/heads/master", "ref": "refs/heads/master",
"rev": "fea9de558c730bc394a5936094ae95bb9d6fa726", "rev": "6085a312bca26adeca6584e37d08c8ba2e1d6e38",
"revCount": 2455, "revCount": 2460,
"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.05; inputs.nixpkgs.url = github:NixOS/nixpkgs/nixos-24.11;
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,6 +14,34 @@
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;
@ -24,6 +52,7 @@
./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
]; ];
}; };
@ -96,29 +125,44 @@
freetype freetype
fontconfig fontconfig
]; ];
profile = "set -e; source /opt/Xilinx/Vivado/2022.2/settings64.sh"; profile = "set -e; source /opt/Xilinx/Vivado/2024.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 = "1.2.0"; version = "2.1.0";
pyproject = true; format = "pyproject";
src = pkgs.fetchFromGitHub { src = pkgs.fetchFromGitHub {
owner = "linien-org"; owner = "linien-org";
repo = "pyrp3"; repo = "pyrp3";
rev = "v${version}"; rev = "v${version}";
hash = "sha256-43TTlpJ5SMAjQM71bNVvrWQyciRXM3zpuA/Dw41AEgU="; hash = "sha256-ol1QGXyCOei94iIPIocuTRHBxa5jKSH5RzjzROfZaBI=";
}; };
patches = ./fast-servo/linien-pyrp3-monitor.patch; patches = ./fast-servo/linien-pyrp3-monitor.patch;
nativeBuildInputs = with pkgs-armv7l.python3Packages; [ nativeBuildInputs = [
setuptools wheel setuptools-scm pkgs-armv7l.python3Packages.setuptools
] ++ (with pkgs-armv7l; [ gcc gnumake ]); pkgs-armv7l.gcc
propagatedBuildInputs = with pkgs-armv7l.python3Packages; [
myhdl
rpyc4
cached-property
numpy
]; ];
postInstall = '' postInstall = ''
cp monitor/libmonitor.so $out/lib cp monitor/libmonitor.so $out/lib
@ -127,13 +171,141 @@
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 = "source/linien-server"; sourceRoot = "${src.name}/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 \
@ -143,28 +315,19 @@
''; '';
nativeBuildInputs = [ pkgs-armv7l.python3Packages.setuptools ]; nativeBuildInputs = [ pkgs-armv7l.python3Packages.setuptools ];
propagatedBuildInputs = with pkgs-armv7l.python3Packages; [ propagatedBuildInputs = with pkgs-armv7l.python3Packages; [
appdirs fire
certifi influxdb-client
click
cma
pylpsd pylpsd
] ++ [
linien-common-armv7l
cma
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";
inherit (pkgs.python3Packages.linien-common) src; src = linien-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
@ -476,6 +639,13 @@
"${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

@ -0,0 +1,13 @@
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..e1e85ba 100644 index 010c487..2d08009 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..e1e85ba 100644
{ {
imports = [ ./qemu.nix ]; imports = [ ./qemu.nix ];
@@ -7,10 +7,15 @@ @@ -7,10 +7,16 @@
environment.etc = { environment.etc = {
"ssh/authorized_keys.d/root" = { "ssh/authorized_keys.d/root" = {
text = '' text = ''
@ -18,6 +18,7 @@ index 010c487..e1e85ba 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";
}; };
@ -27,11 +28,15 @@ index 010c487..e1e85ba 100644
}; };
} }
diff --git a/runit.nix b/runit.nix diff --git a/runit.nix b/runit.nix
index d7b0bf3..67cff43 100644 index d7b0bf3..14dd437 100644
--- a/runit.nix --- a/runit.nix
+++ b/runit.nix +++ b/runit.nix
@@ -7,8 +7,8 @@ let @@ -4,11 +4,11 @@ let
Port 22 sshd_config = pkgs.writeText "sshd_config" ''
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..3ade454 100644 index 7eaee32..9aa338e 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,7 +14,7 @@ index 7eaee32..3ade454 100644
not-os.simpleStaticIp = mkOption { not-os.simpleStaticIp = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
@@ -84,17 +89,27 @@ with lib; @@ -84,17 +89,25 @@ with lib;
}; };
environment.etc = { environment.etc = {
"nix/nix.conf".source = pkgs.runCommand "nix.conf" {} '' "nix/nix.conf".source = pkgs.runCommand "nix.conf" {} ''
@ -31,8 +31,6 @@ index 7eaee32..3ade454 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
''; '';
@ -154,7 +152,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..d5c5eda 100644 index 3fa23ab..069fe89 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 @@
@ -252,7 +250,7 @@ index 3fa23ab..d5c5eda 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 nano ]; + systemPackages = with pkgs; [ inetutils wget gnugrep nano vim ];
+ etc = { + etc = {
+ "service/getty/run".source = pkgs.writeShellScript "getty" '' + "service/getty/run".source = pkgs.writeShellScript "getty" ''
+ hostname ${config.networking.hostName} + hostname ${config.networking.hostName}