Compare commits

...

43 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
ed816517cf si5340: implement paged register writes
Signed-off-by: Florian Agbuya <fa@m-labs.ph>
2024-07-31 16:44:39 +08:00
f5729d3bdb pyfastservo: update initialize script 2024-07-10 16:11:17 +08:00
e3b1525125 pyfastservo: fix adc init script and cleanup 2024-07-10 16:11:17 +08:00
b92d401f2b pyfastservo: fix dac init script and cleanup 2024-07-10 16:11:17 +08:00
eed43e3fe3 pyfastservo: transfer common functions to common 2024-07-10 16:11:17 +08:00
b2dedd77ad rebased from linux 6.6 LTS 2024-07-02 14:42:39 +08:00
693e301ccf fix pkgs.writeReferencesToFile deprecation and pin linux version 2024-07-02 14:26:07 +08:00
6fca060256 flake: update to nixpkgs 24.05 2024-07-02 14:23:54 +08:00
85af23e547 use recommended init sequence for si5340
Signed-off-by: Florian Agbuya <fa@m-labs.ph>
2024-06-25 10:19:58 +08:00
c9d34348bc fix adc and dac initialization 2024-06-10 10:02:29 +08:00
29 changed files with 1571 additions and 668 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): + cmdclass={
+ def run(self): + "build": lib_build
+ 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(**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,9 +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 mmap import time
import os
import spidev import spidev
from pyfastservo.common import ( from pyfastservo.common import (
ADC_AFE_CTRL_ADDR, ADC_AFE_CTRL_ADDR,
@ -33,6 +31,8 @@ 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,276 +44,181 @@ AUX_ADC_PORT_A = 2
AUX_ADC_PORT_B = 3 AUX_ADC_PORT_B = 3
def main_adc_config(test_pattern): def spi_write(spi, address, value):
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 = spidev.SpiDev() 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
try: def main_adc_test_mode(spi, enable):
spi.open(MAIN_ADC_BUS, MAIN_ADC_DEVICE) reg_contents = 0x15 if enable else 0x11 # set to LVDS output, set 4 data lanes and turn on or off test mode
spi.max_speed_hz = 50000 spi_write(spi, 0x02, reg_contents)
spi.mode = 0b00 # CPOL = 0 CPHA = 0
spi.cshigh = True
# spi.read0 = False
spi_buffer = [0x00, 0x80] # reset def verify_adc_registers(spi, reg_to_check):
rx_buffer = [0x00, 0x00] 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}")
spi.xfer2(spi_buffer) def read_frame():
return read_from_memory(ADC_FRAME_ADDR, 1)[0]
# REGISTER A1
spi_buffer = [0x01, 0x20] # set to Two's complement Data Format
spi.xfer2(spi_buffer)
# read values back
spi_buffer = [0x81, 0x00]
rx_buffer = spi.xfer2(spi_buffer)
print(f"Spi readback register 0x01: 0x{rx_buffer[1]:02x}")
if rx_buffer[1] != 0x20:
print("Different value read than sent in reg 0x02")
# REGISTER A2
spi_buffer = [
0x02,
0x15,
] # set to LVDS output, set 4 data lanes and turn on test mode
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] != 0x15:
print("Different value read than sent in reg 0x02")
# REGISTER A3
# 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
def perform_bitslip():
for i in range(4): for i in range(4):
current_frame = read_from_memory(ADC_FRAME_ADDR, 1)[0] current_frame = read_frame()
if current_frame != 0x0C: if current_frame & 0x0F != 0x0C:
print( print(f"Performing bitslip (iteration: {i}). Current frame: 0x{current_frame:02x}")
f"Performing bitslip (bitslip iteration: {i}). Reason: current_frame is 0x{current_frame:02x} instead of 0x0C"
)
write_to_memory(ADC_BITSLIP_ADDR, 1) write_to_memory(ADC_BITSLIP_ADDR, 1)
else: else:
print(f"No bitslip required; Currernt frame = 0x{current_frame:02x}") print(f"No bitslip required; Current frame: 0x{current_frame:02x}")
break return
current_frame = read_from_memory(ADC_FRAME_ADDR, 1)[0] def mmcm_rst():
prev_frame = current_frame 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)
for i in range(32): 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) write_to_memory(ADC_DELAY_ADDR, tap_delay)
if edge_detected == 1: current_frame = read_frame()
break
current_frame = read_from_memory(ADC_FRAME_ADDR, 1)[0]
print(f"Tap delay: {tap_delay}") print(f"Tap delay: {tap_delay}, Current frame: 0x{current_frame:02x}")
print(f"Current frame: 0x{current_frame:02x}") print(f"prev_frame: 0x{prev_frame:02x}")
if current_frame == prev_frame: if current_frame != prev_frame:
tap_delay += 1 final_delay = ((tap_delay+1) // 2) + 2
elif not transition: print(f"Edge detected; setting iDelay to: {final_delay}")
tap_delay += 1 write_to_memory(ADC_DELAY_ADDR, final_delay)
transition = True return
elif transition:
tap_delay = i // 2
edge_detected = True
prev_frame = current_frame prev_frame = current_frame
if not edge_detected: # If no edge detected
tap_delay = 11 # empirically tested to work best final_delay = 11
write_to_memory(ADC_DELAY_ADDR, tap_delay) print(f"No edge detected; setting iDelay to: {final_delay}")
print(f"No edge detected; setting iDelay to: {tap_delay}") write_to_memory(ADC_DELAY_ADDR, final_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) def read_adc_channel(high_addr, low_addr):
print(f"ADC_CH0: 0x{adc_ch0}") return (read_from_memory(high_addr, 1)[0] << 8) | read_from_memory(low_addr, 1)[0]
adc_ch0 = (read_from_memory(ADC_CH0_HIGH_ADDR, 1)[0] << 8) | read_from_memory( def print_adc_channels():
ADC_CH0_LOW_ADDR, 1 adc_ch0 = read_adc_channel(ADC_CH0_HIGH_ADDR, ADC_CH0_LOW_ADDR)
)[0] adc_ch1 = read_adc_channel(ADC_CH1_HIGH_ADDR, ADC_CH1_LOW_ADDR)
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_CH0: 0x{adc_ch0:04x}")
print(f"Final ADC_CH1: 0x{adc_ch1: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 modify_bit(original_value, position, bit_value): def search_edge():
mask = 1 << position for tap_delay in range(32):
return (original_value & ~mask) | (bit_value << position) 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 adc_aux_config(): def configure_ltc2195():
# 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() spi = spidev.SpiDev()
try: try:
spi.open(1, 3) # AUX ADC 1? spi.open(MAIN_ADC_BUS, MAIN_ADC_DEVICE)
spi.max_speed_hz = 5000 spi.max_speed_hz = 50000
spi.mode = 0b00 spi.mode = 0b00 # CPOL = 0 CPHA = 0
spi.cshigh = True spi.cshigh = False
read_buffer = spi.xfer2(write_buffer) test_pattern = 0x811F
mu_voltage = read_buffer[0] << 8 | read_buffer[1] >> 2 main_adc_config(spi, test_pattern)
print(f"MU_voltage: 0x{mu_voltage:04X}")
print(f"Read_buffer[0]: 0x{read_buffer[0]:02X}") verify_adc_registers(spi, {
print(f"Read_buffer[1]: 0x{read_buffer[1]:02X}") 0x01: 0x20,
return mu_voltage * 2.5 / 4096 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.
mmcm_rst()
# 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)
verify_adc_registers(spi, {0x02: 0x11}) # Verify test mode is off
# 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()
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__":
main() configure_ltc2195()

View File

@ -17,6 +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 os
import mmap
CSR_SIZE = 0x800 CSR_SIZE = 0x800
MAP_SIZE = 0x1000 MAP_SIZE = 0x1000
MAP_MASK = 0xFFF MAP_MASK = 0xFFF
@ -72,3 +75,46 @@ 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,8 +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 mmap import time
import os
import spidev import spidev
from pyfastservo.common import ( from pyfastservo.common import (
@ -29,117 +28,69 @@ 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 main_dac_init(): def spi_write(spi, address, value):
spi = spidev.SpiDev() spi.xfer2([address, value])
try: def spi_read(spi, address):
spi.open(MAIN_DAC_BUS, MAIN_DAC_DEVICE) rx_buffer = spi.xfer2([0x80 | address, 0x00])
spi.max_speed_hz = 5000 return rx_buffer[1]
spi.mode = 0b00 # CPOL = 0 CPHA = 0
spi.cshigh = True
spi_buffer = [0x00, 0x10] # software reset def soft_reset(spi):
spi.xfer2(spi_buffer) spi_write(spi, 0x00, 0x10) # Software reset
spi_write(spi, 0x00, 0x00) # Release software reset
spi_read(spi, 0x00) # Read reset address (necessary for reset to take effect)
spi_buffer = [0x00, 0x00] # release software reset def check_version(spi):
spi.xfer2(spi_buffer) version = spi_read(spi, 0x1F)
print(f"DAC version: 0x{version:02X}")
return version == DAC_VERSION
spi_buffer = [ def configure_dac(spi):
0x80, power_down_reg = spi_read(spi, 0x01)
0x00, spi_write(spi, 0x01, power_down_reg & ~(1 << 0)) # Clear EXTREF bit for internal reference
] # for some reason it is needed to read the reset address for reset to actually reset spi_write(spi, 0x0D, 0x00) # Set RREF to 10 kΩ for 1.0V reference
rx_buffer = spi.xfer2(spi_buffer) spi_write(spi, 0x04, 0xA0) # Enable on-chip IRSET (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, 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)
spi_buffer = [0x9F, 0x00] # hardware version def dac_self_calibration(spi):
rx_buffer = spi.xfer2(spi_buffer) spi_write(spi, 0x12, 0x00) # Reset calibration status
if rx_buffer[1] != DAC_VERSION: spi_write(spi, 0x0E, 0x08) # Enable calibration clock, default divide ratio
print(f"Unrecognized device: 0x{rx_buffer[1]:02X}") spi_write(spi, 0x0E, 0x38) # CALSELI = 1, CALSELQ = 1, CALCLK = 1
spi_write(spi, 0x12, 0x10) # Set CALEN bit
print("=== Contents of spi buffer after DAC VERSION read back: ===") while True:
print(f"0x{rx_buffer[0]:02X}{rx_buffer[1]:02X}") status = spi_read(spi, 0x0F)
if status & 0xC0 == 0xC0: # Both CALSTATI and CALSTATQ are 1
spi_buffer = [0x82, 00] break
rx_buffer = spi.xfer2(spi_buffer) time.sleep(0.01)
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
@ -150,33 +101,68 @@ 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):
value = min(value, 0x3FFF)
low_word = value & 0xFF
high_word = (value >> 8) & 0x3F
def write_sample(channel, sample): # Note: DAC HIGH word and LOW word output are not updated
assert channel in (0, 1) # at the same time. On scope, you will see more than one step
if channel == 0: # of value changed.
addresses = [CH0_HIGH_WORD_ADDR, CH0_LOW_WORD_ADDR] write_to_memory(CH0_HIGH_WORD_ADDR, high_word)
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:
addresses = [CH1_HIGH_WORD_ADDR, CH1_LOW_WORD_ADDR] print("Clock relationship is found")
return True
low_word_value = sample & 0xFF def configure_ad9117():
high_word_value = (sample >> 8) & 0x3F spi = spidev.SpiDev()
values = [high_word_value, low_word_value] spi.open(MAIN_DAC_BUS, MAIN_DAC_DEVICE)
for addr, value in zip(addresses, values): spi.max_speed_hz = 5000
write_to_memory(addr, value) spi.mode = 0b00 # CPOL = 0 CPHA = 0
spi.cshigh = False
try:
soft_reset(spi)
if not check_version(spi):
print("Unrecognized DAC version")
return False
def write_ramp(): power_down_afe(0, True)
signal = [i for i in range(16384)] power_down_afe(1, True)
for value in signal: configure_dac(spi)
write_sample(0, value) check_clk_relationship(spi)
dac_self_calibration(spi)
def main(): # Enable DAC outputs
main_dac_init() spi_write(spi, 0x01, spi_read(spi, 0x01) & ~((1 << 4) | (1 << 3)))
power_down(0, False)
power_down(1, False) 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()
if __name__ == "__main__": if __name__ == "__main__":
main() configure_ad9117()

View File

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

View File

@ -17,102 +17,264 @@
# 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
PAGE_ADDR = 0x1 DEVICE_READY = 0x00FE
PLL_M_DEN = 0x023B
STATUS = 0x000C
STATUS_STICKY = 0x0011
OUT0_MUX_SEL_ADDR = 0x15 STATUS_LOSREF = 0x04
OUT1_MUX_SEL_ADDR = 0x1A STATUS_LOL = 0x08
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
N1_DIVIDER_UPDATE_ADDR = 0x17 def write_register(bus, address, value):
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}")
data_to_write = 0 def write_preamble(bus):
clk_out_addr = [ preamble = [
OUT0_MUX_SEL_ADDR, (0x0B24, 0xC0),
OUT1_MUX_SEL_ADDR, (0x0B25, 0x00),
OUT2_MUX_SEL_ADDR, (0x0502, 0x01),
OUT3_MUX_SEL_ADDR, (0x0505, 0x03),
] (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
bus.write_byte_data(IC_ADDR, PAGE_ADDR, 0x0) # setting page to page 0 # Programming sequence from ClockBuilder Pro, default settings
# 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)
# read device id # PLL Configuration
low_word = bus.read_byte_data(IC_ADDR, 0x2) (0x0235, 0x00), # M_NUM
high_word = bus.read_byte_data(IC_ADDR, 0x3) (0x0236, 0x00),
(0x0237, 0x00),
(0x0238, 0x80),
(0x0239, 0x89),
(0x023A, 0x00),
(0x023B, 0x00), # M_DEN
(0x023C, 0x00),
(0x023D, 0x00),
(0x023E, 0x80),
print(f"DEV ID: 0x{high_word:2x}{low_word:2x}") # Synthesizer configuration
(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
data_to_write = 0x1 # N1 Configuration (1:1 ratio)
bus.write_byte_data( (0x030D, 0x00), # N1_NUM
IC_ADDR, PAGE_ADDR, data_to_write (0x030E, 0x00),
) # change to page 1 for output settings (0x030F, 0x00),
(0x0310, 0x00),
(0x0311, 0x00),
(0x0312, 0x01),
(0x0313, 0x00), # N1_DEN
(0x0314, 0x00),
(0x0315, 0x00),
(0x0316, 0x01),
(0x0317, 0x01), # N1_UPDATE
readback = bus.read_byte_data(IC_ADDR, PAGE_ADDR) # N2 Configuration (1:1 ratio)
if data_to_write != readback: (0x0318, 0x00), # N2_NUM
raise ValueError(f"Failed to set page.") (0x0319, 0x00),
(0x031A, 0x00),
(0x031B, 0x00),
(0x031C, 0x00),
(0x031D, 0x01),
(0x031E, 0x00), # N2_DEN
(0x031F, 0x00),
(0x0320, 0x00),
(0x0321, 0x01),
(0x0322, 0x01), # N2_UPDATE
for addr in clk_out_addr: # N3 Configuration (1:1 ratio)
bus.write_byte_data(IC_ADDR, addr, 1) # set source to N1 (0x0323, 0x00), # N3_NUM
(0x0324, 0x00),
(0x0325, 0x00),
(0x0326, 0x00),
(0x0327, 0x00),
(0x0328, 0x01),
(0x0329, 0x00), # N3_DEN
(0x032A, 0x00),
(0x032B, 0x00),
(0x032C, 0x01),
(0x032D, 0x01), # N3_UPDATE
bus.write_byte_data(IC_ADDR, OUT2_AMPL_ADDR, 13) # Output configuration
readback = bus.read_byte_data(IC_ADDR, OUT2_AMPL_ADDR) (0x0112, 0x06), # OUT0 config
# if data_to_write != readback: (0x0113, 0x09), # OUT0 format
# raise ValueError(f"Problematic read: {readback}.") (0x0114, 0x3B), # OUT0 CM/AMPL
(0x0115, 0x28), # OUT0 MUX_SEL
bus.write_byte_data(IC_ADDR, OUT2_AMPL_ADDR, 0x6B) # setting OUT2 to LVDS25 (0x0117, 0x06), # OUT1 config
(0x0118, 0x09), # OUT1 format
(0x0119, 0x3B), # OUT1 CM/AMPL
(0x011A, 0x28), # OUT1 MUX_SEL
bus.write_byte_data(IC_ADDR, OUT3_FORMAT_ADDR, 0xCC) # SETTING out3 to LVCMOS 18 (0x0126, 0x06), # OUT2 config
# bus.write_byte_data(IC_ADDR, 0x2E, 0x09) # SETTING out3 to LVCMOS 33 (0x0127, 0x09), # OUT2 format
(0x0128, 0x3B), # OUT2 CM/AMPL
(0x0129, 0x28), # OUT2 MUX_SEL
readback = bus.read_byte_data(IC_ADDR, OUT3_PDN_ADDR) (0x012B, 0x06), # OUT3 config
print(f"Si5340 OUTx_PDN CLK3: 0x{readback}") (0x012C, 0xCC), # OUT3 format
(0x012D, 0x00), # OUT3 CM/AMPL
(0x012E, 0x58), # OUT3 MUX_SEL
readback = bus.read_byte_data(IC_ADDR, OUT3_FORMAT_ADDR) # Miscellaneous configuration
print(f"Si5340 OUTx_FORMAT CLK3: 0x{readback}") (0x090E, 0x02), # XAXB_EXTCLK_EN=0 XAXB_PDNB=1 (use XTAL)
(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)
]
readback = bus.read_byte_data(IC_ADDR, OUT3_AMPL_ADDR) write_preamble(bus)
print(f"Si5340 OUTx_AMPL CLK3: 0x{readback}")
readback = bus.read_byte_data(IC_ADDR, OUT3_MUX_SEL_ADDR) time.sleep(0.3)
print(f"Si5340 OUTx_CM CLK3: 0x{readback}")
bus.write_byte_data( print("Writing main configuration...")
IC_ADDR, PAGE_ADDR, 0x3 for address, value in main_config:
) # setting page to 3 to change dividers values write_register(bus, address, value)
print("Main configuration written")
n1_numerator = [0x0, 0x0, 0x0, 0x60, 0x22, 0x0] write_postamble(bus)
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)
bus.write_byte_data(IC_ADDR, N1_DIVIDER_UPDATE_ADDR, 1) if not wait_for_lock(bus):
print("Error waiting for input clock or PLL lock")
else:
print("Input clock present and PLL locked")
for addr in n1_num_addr: bus.write_byte_data(IC_ADDR, STATUS_STICKY, 0)
readback = bus.read_byte_data(IC_ADDR, addr)
print(f"Numerator buffer: 0x{readback:02x}")
for addr in n1_denom_addr: # Final status check
readback = bus.read_byte_data(IC_ADDR, addr) pll_locked = check_pll_status(bus)
print(f"Denominator buffer: 0x{readback:02x}") xaxb_signal_present = check_los_status(bus)
bus.write_byte_data(IC_ADDR, PAGE_ADDR, 0x0) # setting page to page 0 if not pll_locked:
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": 1709237383, "lastModified": 1734323986,
"narHash": "sha256-cy6ArO4k5qTx+l5o+0mL9f5fa86tYUX3ozE1S+Txlds=", "narHash": "sha256-m/lh6hYMIWDYHCAsn81CDAiXoT3gmxXI9J987W5tZrE=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "1536926ef5621b09bba54035ae2bb6d806d72ac8", "rev": "394571358ce82dff7411395829aa6a3aad45b907",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"ref": "nixos-unstable", "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": 1702942348, "lastModified": 1727677091,
"narHash": "sha256-gKIfHZxsv+jcgDFRW9mPqmwqbZXuRvXefkZcSFjOGHw=", "narHash": "sha256-Zg3SQnTwMM/VkOGKogbPyuCC2NhLy8HB2SPEUWWNgCU=",
"owner": "m-labs", "owner": "m-labs",
"repo": "migen", "repo": "migen",
"rev": "50934ad10a87ade47219b796535978b9bdf24023", "rev": "c19ae9f8ae162ffe2d310a92bfce53ac2a821bc8",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -80,11 +80,11 @@
"src-misoc": { "src-misoc": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1699352904, "lastModified": 1729234629,
"narHash": "sha256-SglyTmXOPv8jJOjwAjJrj/WhAkItQfUbvKfUqrynwRg=", "narHash": "sha256-TLsTCXV5AC2xh+bS7EhBVBKqdqIU3eKrnlWcFF9LtAM=",
"ref": "refs/heads/master", "ref": "refs/heads/master",
"rev": "a53859f2167c31ab5225b6c09f30cf05527b94f4", "rev": "6085a312bca26adeca6584e37d08c8ba2e1d6e38",
"revCount": 2452, "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-unstable; 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..3a2a0a9 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,9 +14,12 @@ index 7eaee32..3a2a0a9 100644
not-os.simpleStaticIp = mkOption { not-os.simpleStaticIp = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
@@ -86,15 +91,25 @@ with lib; @@ -84,17 +89,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
@ -28,8 +31,6 @@ index 7eaee32..3a2a0a9 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
''; '';
@ -151,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..9d1621e 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 @@
@ -163,7 +164,7 @@ index 3fa23ab..9d1621e 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.override { + customKernel = (pkgs.linux_6_6.override {
extraConfig = '' extraConfig = ''
OVERLAY_FS y OVERLAY_FS y
+ MEDIA_SUPPORT n + MEDIA_SUPPORT n
@ -249,7 +250,7 @@ index 3fa23ab..9d1621e 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}

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..59aa585 index 0000000..33daffe
--- /dev/null --- /dev/null
+++ b/xilinx-fpga-manager.patch +++ b/xilinx-fpga-manager.patch
@@ -0,0 +1,663 @@ @@ -0,0 +1,676 @@
+# 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..59aa585
+ 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 06651389c592..6e8c45974f28 100644 +index 0f4035b089a2..3aa9f5f041f6 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..59aa585
+ NULL, + NULL,
+ }; + };
+ ATTRIBUTE_GROUPS(fpga_mgr); + ATTRIBUTE_GROUPS(fpga_mgr);
+@@ -732,6 +864,106 @@ void fpga_mgr_put(struct fpga_manager *mgr) +@@ -739,6 +871,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..59aa585
+ /** + /**
+ * fpga_mgr_lock - Lock FPGA manager for exclusive use + * fpga_mgr_lock - Lock FPGA manager for exclusive use
+ * @mgr: fpga manager + * @mgr: fpga manager
+@@ -779,6 +1011,9 @@ struct fpga_manager * +@@ -788,6 +1020,9 @@ __fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *
+ fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info) + struct module *owner)
+ { + {
+ 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..59aa585
+ struct fpga_manager *mgr; + struct fpga_manager *mgr;
+ int id, ret; + int id, ret;
+ +
+@@ -815,10 +1050,28 @@ fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *in +@@ -826,10 +1061,28 @@ __fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *
+ 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..59aa585
+ /* + /*
+ * 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
+@@ -832,6 +1085,28 @@ fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *in +@@ -843,6 +1096,28 @@ __fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *
+ return ERR_PTR(ret); + return ERR_PTR(ret);
+ } + }
+ +
@ -848,7 +848,7 @@ index 0000000..59aa585
+ return mgr; + return mgr;
+ +
+ error_device: + error_device:
+@@ -882,6 +1157,10 @@ void fpga_mgr_unregister(struct fpga_manager *mgr) +@@ -894,6 +1169,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..59aa585
+ &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..db923746cac5 100644 +index f3434e2c487b..d2434ed85eff 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,42 @@ static int zynqmp_fpga_ops_write(struct fpga_manager *mgr, +@@ -43,25 +43,47 @@ 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,6 +915,11 @@ index 0000000..59aa585
++ ++
+ 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;
+ +
@ -931,20 +936,22 @@ index 0000000..59aa585
+ 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 9dda7d9898ff..edaf77160746 100644 +index e8b12ec8b060..ffd2dfdb6abd 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
+@@ -70,6 +70,8 @@ +@@ -83,6 +83,10 @@
+ */ + */
+ #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 54f63459efd6..c96a4405f909 100644 +index 0d4fe068f3d8..f884d268c974 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 @@
@ -959,7 +966,7 @@ index 0000000..59aa585
+ struct fpga_manager; + struct fpga_manager;
+ struct sg_table; + struct sg_table;
+ +
+@@ -66,17 +69,25 @@ enum fpga_mgr_states { +@@ -66,17 +69,29 @@ 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
+ * + *
@ -973,6 +980,10 @@ index 0000000..59aa585
++ * ++ *
++ * %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)
@ -986,7 +997,7 @@ index 0000000..59aa585
+ +
+ /** + /**
+ * struct fpga_image_info - information specific to an FPGA image + * struct fpga_image_info - information specific to an FPGA image
+@@ -86,6 +97,7 @@ enum fpga_mgr_states { +@@ -86,6 +101,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
@ -994,7 +1005,7 @@ index 0000000..59aa585
+ * @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 +114,7 @@ struct fpga_image_info { +@@ -102,6 +118,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;
@ -1002,7 +1013,7 @@ index 0000000..59aa585
+ struct sg_table *sgt; + struct sg_table *sgt;
+ const char *buf; + const char *buf;
+ size_t count; + size_t count;
+@@ -160,6 +173,7 @@ struct fpga_manager_info { +@@ -160,6 +177,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
@ -1010,7 +1021,7 @@ index 0000000..59aa585
+ * @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 +196,7 @@ struct fpga_manager_ops { +@@ -182,6 +200,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);
@ -1018,7 +1029,7 @@ index 0000000..59aa585
+ 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,21 +211,35 @@ struct fpga_manager_ops { +@@ -196,23 +215,37 @@ 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
@ -1031,6 +1042,7 @@ index 0000000..59aa585
+ * @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
@ -1046,6 +1058,7 @@ index 0000000..59aa585
+ 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
@ -1054,21 +1067,21 @@ index 0000000..59aa585
+ }; + };
+ +
+ #define to_fpga_manager(d) container_of(d, struct fpga_manager, dev) + #define to_fpga_manager(d) container_of(d, struct fpga_manager, dev)
+@@ -244,4 +273,6 @@ struct fpga_manager * +@@ -258,4 +291,6 @@ __devm_fpga_mgr_register(struct device *parent, const char *name,
+ devm_fpga_mgr_register(struct device *parent, const char *name, + const struct fpga_manager_ops *mops, void *priv,
+ const struct fpga_manager_ops *mops, void *priv); + struct module *owner);
+ +
++#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 9d1621e..012e50c 100644 index d5c5eda..7ede584 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.override { customKernel = (pkgs.linux_6_6.override {
+ kernelPatches = [ + kernelPatches = [
+ ({ + ({
+ name = "xilinx-configfs-overlays"; + name = "xilinx-configfs-overlays";