Compare commits

...

72 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
db88e5db59 use libmonitor compiled by gnumake 2024-05-22 15:32:23 +08:00
7d5fbdd281 use fast-servo csrmap 2024-05-21 16:07:48 +08:00
fc71fe0ab3 fix incorrect terminology 2024-04-25 10:36:28 +08:00
1ee382564e add pyfastservo package and initialize at boot 2024-04-24 18:03:17 +08:00
7c6320f66d configure loading of bitstream at boot time 2024-04-24 18:03:17 +08:00
3d98549fd1 rename board specific packages 2024-04-23 14:19:19 +08:00
0ff299aa55 increase qemu image size 2024-04-04 13:43:19 +08:00
c2d38540c0 integrate linien-server to not-os 2024-04-04 13:06:01 +08:00
d9a2d60b50 configure arm linux toolchain 2024-03-26 17:53:25 +08:00
26dd210eb6 rebase from 251f65f 2024-03-26 17:51:46 +08:00
251f65f217 cross-compilation transferred to crossSystem 2024-03-26 17:50:40 +08:00
0d3f87c5bc use nix gnu toolchain format for baremetal apps 2024-03-25 15:14:15 +08:00
208d56adb2 fix linien-server red pitaya dependencies 2024-03-20 13:40:09 +08:00
628582a981 add spidev on device tree 2024-03-15 11:46:51 +08:00
bc09e60a15 add fpga programming support 2024-03-14 13:03:09 +08:00
88b3197c0c add provenance information 2024-03-08 14:35:59 +08:00
0cda432bf9 add fast-servo python init scripts 2024-03-08 14:35:59 +08:00
1244c84f67 fix typo 2024-03-06 17:53:13 +08:00
3618a1f17d add linien-server package 2024-03-06 11:48:08 +08:00
22992e2e82 update nixpkgs and use upstream qemu 2024-03-05 09:50:55 +08:00
d6ac3944fb linux: add fpga support 2024-03-04 17:40:33 +08:00
c61597ea4f fix qemu build errors 2024-03-01 18:09:53 +08:00
efe58d8106 move not-os patches to dedicated folder 2024-03-01 17:14:09 +08:00
007ca18cab fix homeless-shelter error 2024-03-01 16:39:56 +08:00
506bbcc0db add fast-servo linien gateware 2024-03-01 16:39:56 +08:00
e12b672cdc add __pycache__ 2024-03-01 16:39:56 +08:00
cd9590503c add fast-servo gateware support files 2024-03-01 16:39:56 +08:00
e4dcc0e84a configure shutdown instructions in runit stage 3 2024-02-22 09:58:29 +08:00
1f3591a693 add nix substituters and update nix.conf 2024-02-20 14:02:51 +08:00
47 changed files with 6253 additions and 193 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
__pycache__
result result

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

@ -1,7 +1,7 @@
# 0 "my_dts/system-top.dts" # 0 "system-top.dts"
# 0 "<built-in>" # 0 "<built-in>"
# 0 "<command-line>" # 0 "<command-line>"
# 1 "my_dts/system-top.dts" # 1 "system-top.dts"
@ -10,8 +10,8 @@
/dts-v1/; /dts-v1/;
# 1 "my_dts/zynq-7000.dtsi" 1 # 1 "zynq-7000.dtsi" 1
# 15 "my_dts/zynq-7000.dtsi" # 15 "zynq-7000.dtsi"
/ { / {
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
@ -564,8 +564,8 @@
}; };
}; };
}; };
# 10 "my_dts/system-top.dts" 2 # 10 "system-top.dts" 2
# 1 "my_dts/pcw.dtsi" 1 # 1 "pcw.dtsi" 1
@ -641,7 +641,48 @@
fclk-enable = <0x0>; fclk-enable = <0x0>;
ps-clk-frequency = <33333333>; ps-clk-frequency = <33333333>;
}; };
# 11 "my_dts/system-top.dts" 2 # 11 "system-top.dts" 2
# 1 "system-user.dtsi" 1
&spi0 {
is-decoded-cs = <1>;
num-cs = <4>;
spidev@1 {
compatible = "rohm,dh2228fv";
spi-max-frequency = <50000000>;
reg = <1>;
};
spidev@2 {
compatible = "rohm,dh2228fv";
spi-max-frequency = <50000000>;
reg = <2>;
};
spidev@3 {
compatible = "rohm,dh2228fv";
spi-max-frequency = <50000000>;
reg = <3>;
};
spidev@4 {
compatible = "rohm,dh2228fv";
spi-max-frequency = <50000000>;
reg = <4>;
};
};
&spi1 {
spidev@0 {
compatible = "rohm,dh2228fv";
spi-max-frequency = <50000000>;
reg = <0>;
};
};
# 12 "system-top.dts" 2
/ { / {
model = "Sinara Fast Servo board"; model = "Sinara Fast Servo board";
chosen { chosen {

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

@ -0,0 +1,629 @@
# 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:
# https://github.com/linien-org/linien/commit/93f1f50ebd86fe3314cab5a549462d0fcbf6a658
# and elhep/linien commit ID b73eea0:
# https://github.com/elhep/linien/commit/b73eea07889dda8b55f0cf4c2afde96cf4c3efd1
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index b3f3683..98c6e51 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -3,7 +3,7 @@ repos:
rev: 23.11.0
hooks:
- id: black
- exclude: ^(gateware/logic/|gateware/lowlevel/|gateware/linien_module.py|linien-server/linien_server/csrmap.py)
+ exclude: ^(gateware/logic/|gateware/lowlevel/|gateware/linien_module.py|linien-server/linien_server/csrmap.py|gateware/targets)
- repo: https://github.com/pycqa/isort
rev: 5.12.0
diff --git a/gateware/fpga_image_helper.py b/gateware/fpga_image_helper.py
index c3e20e7..ebead1d 100644
--- a/gateware/fpga_image_helper.py
+++ b/gateware/fpga_image_helper.py
@@ -1,6 +1,7 @@
# 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
@@ -20,16 +21,18 @@
from pathlib import Path
from .bit2bin import bit2bin
-from .hw_platform import Platform
-from .linien_module import RootModule
REPO_ROOT_DIR = Path(__file__).resolve().parents[1]
def py_csrconstants(map, fil):
fil.write("csr_constants = {\n")
- for k, v in root.linien.csrbanks.constants:
- fil.write(" '{}_{}': {},\n".format(k, v.name, v.value.value))
+ for k, v in root.csrbanks.constants:
+ if k == "linien":
+ # compaitbility layer
+ fil.write(" '{}': {},\n".format(v.name, v.value.value))
+ else:
+ fil.write(" '{}_{}': {},\n".format(k, v.name, v.value.value))
fil.write("}\n\n")
@@ -51,26 +54,51 @@ def get_csrmap(banks):
def py_csrmap(it, fil):
fil.write("csr = {\n")
for reg in it:
- fil.write(" '{}_{}': ({}, 0x{:03x}, {}, {}),\n".format(*reg))
+ main_name = reg[0]
+ secondary_name = reg[1]
+ # compaitbility layer
+ if main_name == "linien" or secondary_name.startswith(main_name):
+ fil.write(" '{}': ({}, 0x{:03x}, {}, {}),\n".format(*reg[1:]))
+ else:
+ fil.write(" '{}_{}': ({}, 0x{:03x}, {}, {}),\n".format(*reg))
fil.write("}\n")
if __name__ == "__main__":
- platform = Platform()
- root = RootModule(platform)
+ import argparse
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument("-p", "--platform", default=None)
+ args = parser.parse_args()
+ if args.platform is None or args.platform.lower() == "redpitaya":
+ from gateware.hw_platform import Platform
+ from gateware.targets.red_pitaya import PitayaSoC
+
+ platform = Platform()
+ root = PitayaSoC(platform)
+ elif args.platform.lower() == "fastservo":
+ from fast_servo.gateware.fast_servo_platform import Platform
+
+ from gateware.targets.fast_servo import LinienFastServo
+
+ platform = Platform()
+ root = LinienFastServo(platform)
+ else:
+ raise ValueError("Unknown platform")
+
+ platform.add_source_dir(REPO_ROOT_DIR / "gateware" / "verilog")
+ build_dir = REPO_ROOT_DIR / "gateware" / "build"
+ platform.build(root, build_name="top", build_dir=build_dir, run=True)
with open(
REPO_ROOT_DIR / "linien-server" / "linien_server" / "csrmap.py", "w"
) as fil:
- py_csrconstants(root.linien.csrbanks.constants, fil)
- csr = get_csrmap(root.linien.csrbanks.banks)
+ py_csrconstants(root.csrbanks.constants, fil)
+ csr = get_csrmap([*root.csrbanks.banks, *root.linien.csrbanks.banks])
py_csrmap(csr, fil)
fil.write("states = {}\n".format(repr(root.linien.state_names)))
fil.write("signals = {}\n".format(repr(root.linien.signal_names)))
- platform.add_source_dir(REPO_ROOT_DIR / "gateware" / "verilog")
- build_dir = REPO_ROOT_DIR / "gateware" / "build"
- platform.build(root, build_name="top", build_dir=build_dir)
bit2bin(
build_dir / "top.bit",
REPO_ROOT_DIR / "linien-server" / "linien_server" / "gateware.bin",
diff --git a/gateware/linien_module.py b/gateware/linien_module.py
index 16ca186..6905ac0 100644
--- a/gateware/linien_module.py
+++ b/gateware/linien_module.py
@@ -1,6 +1,7 @@
# 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
from .logic.autolock import FPGAAutolock
from .logic.chains import FastChain, SlowChain, cross_connect
from .logic.decimation import Decimate
-from .logic.delta_sigma import DeltaSigma
from .logic.iir import Iir
from .logic.limit import LimitCSR
from .logic.modulate import Modulate
from .logic.pid import PID
from .logic.sweep import SweepCSR
-from .lowlevel.analog import PitayaAnalog
-from .lowlevel.crg import CRG
-from .lowlevel.dna import DNA
-from .lowlevel.gpio import Gpio
-from .lowlevel.pitaya_ps import PitayaPS, Sys2CSR, SysCDC, SysInterconnect
+from .lowlevel.pitaya_ps import Sys2CSR
from .lowlevel.scopegen import ScopeGen
-from .lowlevel.xadc import XADC
class LinienLogic(Module, AutoCSR):
@@ -156,45 +151,24 @@ class LinienLogic(Module, AutoCSR):
class LinienModule(Module, AutoCSR):
- def __init__(self, platform):
+ def __init__(self, soc):
width = 14
signal_width = 25
coeff_width = 25
chain_factor_bits = 8
self.init_submodules(
- width, signal_width, coeff_width, chain_factor_bits, platform
+ width, signal_width, coeff_width, chain_factor_bits, soc
)
- self.connect_everything(width, signal_width, coeff_width, chain_factor_bits)
+ self.connect_everything(width, signal_width, coeff_width, chain_factor_bits, soc)
def init_submodules(
- self, width, signal_width, coeff_width, chain_factor_bits, platform
+ self, width, signal_width, coeff_width, chain_factor_bits, soc
):
- sys_double = ClockDomainsRenamer("sys_double")
self.submodules.logic = LinienLogic(
coeff_width=coeff_width, chain_factor_width=chain_factor_bits
)
- self.submodules.analog = PitayaAnalog(
- platform.request("adc"), platform.request("dac")
- )
- self.submodules.xadc = XADC(platform.request("xadc"))
-
- for i in range(4):
- pwm = platform.request("pwm", i)
- ds = sys_double(DeltaSigma(width=15))
- self.comb += pwm.eq(ds.out)
- setattr(self.submodules, f"ds{i}", ds)
-
- exp = platform.request("exp")
- self.submodules.gpio_n = Gpio(exp.n)
- self.submodules.gpio_p = Gpio(exp.p)
-
- leds = Cat(*(platform.request("user_led", i) for i in range(8)))
- self.comb += leds.eq(self.gpio_n.o)
-
- self.submodules.dna = DNA(version=2)
-
self.submodules.fast_a = FastChain(
width,
signal_width,
@@ -210,18 +184,22 @@ class LinienModule(Module, AutoCSR):
offset_signal=self.logic.chain_b_offset_signed,
)
+ # FIXME: does it do anything?!
_ = ClockDomainsRenamer("sys_slow")
sys_double = ClockDomainsRenamer("sys_double")
max_decimation = 16
self.submodules.decimate = sys_double(Decimate(max_decimation))
self.clock_domains.cd_decimated_clock = ClockDomain()
decimated_clock = ClockDomainsRenamer("decimated_clock")
+ # TODO: No support for slow Analog Out on Fast Servo
self.submodules.slow_chain = decimated_clock(SlowChain())
-
self.submodules.scopegen = ScopeGen(signal_width)
+ soc.add_interconnect_slave(self.scopegen.scope_sys)
+ soc.add_interconnect_slave(self.scopegen.asg_sys)
+
self.state_names, self.signal_names = cross_connect(
- self.gpio_n,
+ soc.gpio_n,
[
("fast_a", self.fast_a),
("fast_b", self.fast_b),
@@ -233,10 +211,6 @@ class LinienModule(Module, AutoCSR):
)
csr_map = {
- "dna": 28,
- "xadc": 29,
- "gpio_n": 30,
- "gpio_p": 31,
"fast_a": 0,
"fast_b": 1,
"slow_chain": 2,
@@ -251,19 +225,13 @@ class LinienModule(Module, AutoCSR):
name if mem is None else name + "_" + mem.name_override
],
)
- self.submodules.sys2csr = Sys2CSR()
- self.submodules.csrcon = csr_bus.Interconnect(
- self.sys2csr.csr, self.csrbanks.get_buses()
- )
- self.submodules.syscdc = SysCDC()
- self.comb += self.syscdc.target.connect(self.sys2csr.sys)
- def connect_everything(self, width, signal_width, coeff_width, chain_factor_bits):
+ def connect_everything(self, width, signal_width, coeff_width, chain_factor_bits, soc):
s = signal_width - width
self.comb += [
- self.fast_a.adc.eq(self.analog.adc_a),
- self.fast_b.adc.eq(self.analog.adc_b),
+ 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.
@@ -297,7 +265,7 @@ class LinienModule(Module, AutoCSR):
self.comb += [
If(
self.logic.pid_only_mode.storage,
- self.logic.pid.input.eq(self.analog.adc_a << s),
+ self.logic.pid.input.eq(soc.analog.adc_a << s),
).Else(
self.logic.pid.input.eq(mixed_limited),
),
@@ -347,40 +315,42 @@ class LinienModule(Module, AutoCSR):
# ANALOG OUTPUTS ---------------------------------------------------------------
# ANALOG OUT 0 gets a special treatment because it may contain signal of slow
# pid or sweep
- analog_out = Signal((width + 3, True))
- self.comb += [
- analog_out.eq(
- Mux(
- self.logic.sweep_channel.storage == OutputChannel.ANALOG_OUT0,
- self.logic.sweep.y,
- 0,
- )
- + Mux(
- self.logic.sweep_channel.storage == OutputChannel.ANALOG_OUT0,
- self.logic.out_offset_signed,
- 0,
- )
- + Mux(
- self.logic.slow_control_channel.storage
+
+ if soc.soc_name == "RedPitaya":
+ analog_out = Signal((width + 3, True))
+ self.comb += [
+ analog_out.eq(
+ Mux(
+ self.logic.sweep_channel.storage == OutputChannel.ANALOG_OUT0,
+ self.logic.sweep.y,
+ 0,
+ )
+ + Mux(
+ self.logic.sweep_channel.storage == OutputChannel.ANALOG_OUT0,
+ self.logic.out_offset_signed,
+ 0,
+ )
+ + Mux(
+ self.logic.slow_control_channel.storage
== OutputChannel.ANALOG_OUT0,
self.slow_chain.output,
- 0,
- )
- ),
- ]
- # NOTE: not sure why limit is used
- self.comb += self.slow_chain.limit.x.eq(analog_out)
- # ds0 apparently has 16 bit, but only allowing positive values --> "15 bit"?
- slow_out_shifted = Signal(15)
- self.sync += slow_out_shifted.eq((self.slow_chain.limit.y << 1) + (1 << 14))
- self.comb += self.ds0.data.eq(slow_out_shifted)
-
- # connect other analog outputs
- self.comb += [
- self.ds1.data.eq(self.logic.analog_out_1.storage),
- self.ds2.data.eq(self.logic.analog_out_2.storage),
- self.ds3.data.eq(self.logic.analog_out_3.storage),
- ]
+ 0,
+ )
+ ),
+ ]
+ # NOTE: not sure why limit is used
+ self.comb += self.slow_chain.limit.x.eq(analog_out)
+ # ds0 apparently has 16 bit, but only allowing positive values --> "15 bit"?
+ slow_out_shifted = Signal(15)
+ self.sync += slow_out_shifted.eq((self.slow_chain.limit.y << 1) + (1 << 14))
+ self.comb += soc.ds0.data.eq(slow_out_shifted)
+
+ # connect other analog outputs
+ self.comb += [
+ soc.ds1.data.eq(self.logic.analog_out_1.storage),
+ soc.ds2.data.eq(self.logic.analog_out_2.storage),
+ soc.ds3.data.eq(self.logic.analog_out_3.storage),
+ ]
# ------------------------------------------------------------------------------
@@ -395,7 +365,7 @@ class LinienModule(Module, AutoCSR):
self.comb += [
self.logic.autolock.robust.at_start.eq(self.logic.sweep.sweep.trigger),
- self.scopegen.gpio_trigger.eq(self.gpio_p.i[0]),
+ self.scopegen.gpio_trigger.eq(soc.gpio_p.i[0]),
self.scopegen.sweep_trigger.eq(self.logic.sweep.sweep.trigger),
self.scopegen.automatically_rearm.eq(
self.logic.autolock.request_lock.storage
@@ -404,8 +374,8 @@ class LinienModule(Module, AutoCSR):
self.scopegen.automatically_trigger.eq(
self.logic.autolock.lock_running.status
),
- self.analog.dac_a.eq(self.logic.limit_fast1.y),
- self.analog.dac_b.eq(self.logic.limit_fast2.y),
+ soc.analog.dac_a.eq(self.logic.limit_fast1.y),
+ soc.analog.dac_b.eq(self.logic.limit_fast2.y),
]
# Having this in a comb statement caused errors. See PR #251.
@@ -428,23 +398,4 @@ class DummyHK(Module, AutoCSR):
self.submodules.csrcon = csr_bus.Interconnect(
self.sys2csr.csr, self.csrbanks.get_buses()
)
- self.sys = self.sys2csr.sys
-
-
-class RootModule(Module):
- def __init__(self, platform):
- self.submodules.ps = PitayaPS(platform.request("cpu"))
- self.submodules.crg = CRG(
- platform.request("clk125"), self.ps.fclk[0], ~self.ps.frstn[0]
- )
- self.submodules.linien = LinienModule(platform)
-
- self.submodules.hk = ClockDomainsRenamer("sys_ps")(DummyHK())
-
- self.submodules.ic = SysInterconnect(
- self.ps.axi.sys,
- self.hk.sys,
- self.linien.scopegen.scope_sys,
- self.linien.scopegen.asg_sys,
- self.linien.syscdc.source,
- )
+ self.sys = self.sys2csr.sys
\ No newline at end of file
diff --git a/gateware/targets/__init__.py b/gateware/targets/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/gateware/targets/fast_servo.py b/gateware/targets/fast_servo.py
new file mode 100644
index 0000000..da5bf3b
--- /dev/null
+++ b/gateware/targets/fast_servo.py
@@ -0,0 +1,85 @@
+# Copyright 2023 Jakub Matyas <jakubk.m@gmail.com>
+# Warsaw University of Technology
+#
+# This file is part of Linien and provides support for Linien on
+# Fast Servo platform.
+#
+# Linien is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Linien is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Linien. If not, see <http://www.gnu.org/licenses/>.
+
+from fast_servo.gateware.fast_servo_soc import BaseSoC
+from migen import *
+from misoc.interconnect import csr_bus
+
+from gateware.linien_module import DummyHK, LinienModule
+from gateware.lowlevel.dna import DNA
+from gateware.lowlevel.gpio import Gpio
+from gateware.lowlevel.pitaya_ps import SysInterconnect
+
+
+class FastServoAnalog(Module):
+ def __init__(self, adc, dac):
+ size = 14 # length of DAC
+
+ self.adc_a = Signal(size)
+ self.adc_b = Signal(size)
+ self.dac_a = Signal(size)
+ self.dac_b = Signal(size)
+
+ self.comb += [
+ self.adc_a.eq(adc.data_out[0][2:]),
+ self.adc_b.eq(adc.data_out[1][2:]),
+ ]
+
+ self.sync += [
+ dac.data_in[0].eq(self.dac_a),
+ dac.data_in[1].eq(self.dac_b),
+ ]
+
+
+class LinienFastServo(BaseSoC):
+ def __init__(self, platform):
+ super().__init__(platform)
+
+ self.submodules.dna = DNA(version=2)
+
+ self.submodules.analog = FastServoAnalog(self.adc, self.dac)
+ gpios = platform.request("gpio")
+ self.submodules.gpio_n = Gpio(gpios.n)
+ # self.csr_devices.append("gpio_n")
+ self.submodules.gpio_p = Gpio(gpios.p)
+ # self.csr_devices.append("gpio_p")
+ self.csr_map.update({
+ "dna": 28,
+ "gpio_n": 30,
+ "gpio_p": 31,
+ })
+
+ # ---------------------------------------------
+ #
+ # FIXME - passing self to LinienModule
+ self.submodules.linien = LinienModule(self)
+
+ def soc_finalize(self):
+ self.add_interconnect_slave(self.syscdc.source)
+ self.submodules.csrbanks = csr_bus.CSRBankArray(self,
+ self.get_csr_dev_address)
+ self.submodules.csrcon = csr_bus.Interconnect(
+ self.sys2csr.csr, [*self.csrbanks.get_buses(), *self.linien.csrbanks.get_buses()]
+ )
+ self.submodules.hk = DummyHK()
+ self.submodules.interconnect = SysInterconnect(
+ self.axi2sys.sys,
+ self.hk.sys,
+ *self.interconnect_slaves
+ )
\ No newline at end of file
diff --git a/gateware/targets/red_pitaya.py b/gateware/targets/red_pitaya.py
new file mode 100644
index 0000000..c029e81
--- /dev/null
+++ b/gateware/targets/red_pitaya.py
@@ -0,0 +1,103 @@
+# Copyright 2014-2015 Robert Jördens <jordens@gmail.com>
+# 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.
+#
+# Linien is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Linien is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Linien. If not, see <http://www.gnu.org/licenses/>.
+
+from migen import *
+from misoc.interconnect import csr_bus
+from misoc.interconnect.csr import AutoCSR
+
+from gateware.linien_module import DummyHK, LinienModule
+from gateware.logic.delta_sigma import DeltaSigma
+from gateware.lowlevel.analog import PitayaAnalog
+from gateware.lowlevel.crg import CRG
+from gateware.lowlevel.dna import DNA
+from gateware.lowlevel.gpio import Gpio
+from gateware.lowlevel.pitaya_ps import PitayaPS, Sys2CSR, SysCDC, SysInterconnect
+from gateware.lowlevel.xadc import XADC
+
+
+class PitayaSoC(Module, AutoCSR):
+ def __init__(self, platform):
+ self.csr_map = {
+ "gpio_n": 30,
+ "gpio_p": 31,
+ "dna": 28,
+ "xadc": 29,
+ }
+ self.soc_name = "RedPitaya"
+ self.interconnect_slaves = []
+
+ self.submodules.ps = PitayaPS(platform.request("cpu"))
+ self.submodules.crg = CRG(
+ platform.request("clk125"), self.ps.fclk[0], ~self.ps.frstn[0]
+ )
+ self.submodules.sys2csr = Sys2CSR()
+ self.submodules.syscdc = SysCDC()
+ self.comb += self.syscdc.target.connect(self.sys2csr.sys)
+
+ self.submodules.xadc = XADC(platform.request("xadc"))
+ self.submodules.analog = PitayaAnalog(platform.request("adc"), platform.request("dac"))
+
+ for i in range(4):
+ pwm = platform.request("pwm", i)
+ ds = ClockDomainsRenamer("sys_double")(DeltaSigma(width=15))
+ self.comb += pwm.eq(ds.out)
+ setattr(self.submodules, f"ds{i}", ds)
+
+ exp = platform.request("exp")
+ self.submodules.gpio_n = Gpio(exp.n)
+ self.submodules.gpio_p = Gpio(exp.p)
+
+ leds = Cat(*(platform.request("user_led", i) for i in range(8)))
+ self.comb += leds.eq(self.gpio_n.o)
+
+ self.submodules.dna = DNA(version=2)
+
+ # ---------------------------------------------
+ #
+ # FIXME - passing self to LinienModule
+ self.submodules.linien = LinienModule(self)
+ self.add_interconnect_slave(self.syscdc.source)
+ self.run_finalize()
+
+
+ def add_interconnect_slave(self, slave):
+ self.interconnect_slaves.append(slave)
+
+ def get_csr_dev_address(self, name, memory):
+ if memory is not None:
+ name = name + "_" + memory.name_override
+ try:
+ return self.csr_map[name]
+ except KeyError:
+ return None
+
+ def run_finalize(self):
+ self.submodules.csrbanks = csr_bus.CSRBankArray(self,
+ self.get_csr_dev_address)
+ self.submodules.csrcon = csr_bus.Interconnect(
+ self.sys2csr.csr, [*self.csrbanks.get_buses(), *self.linien.csrbanks.get_buses()]
+ )
+ self.submodules.hk = DummyHK()
+ self.submodules.interconnect = SysInterconnect(
+ self.ps.axi.sys,
+ self.hk.sys,
+ *self.interconnect_slaves
+ )
\ No newline at end of file

View File

@ -0,0 +1,5 @@
## Source Repository
Files in this directory were copied from [elhep/Fast-Servo-Firmware](https://github.com/elhep/Fast-Servo-Firmware/tree/master/fast_servo/gateware).
## Commit ID
The files were copied from commit ID [7fae40c](https://github.com/elhep/Fast-Servo-Firmware/commit/7fae40c0f872a91218be378f8289b98b1e366729).

View File

@ -0,0 +1,3 @@
import os
verilog_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), "verilog")

View File

@ -0,0 +1,219 @@
# This file is part of Fast Servo Software Package.
#
# Copyright (C) 2023 Jakub Matyas
# Warsaw University of Technology <jakubk.m@gmail.com>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from migen import *
from migen.genlib.cdc import MultiReg
from misoc.interconnect.csr import AutoCSR, CSRStatus, CSRStorage
from misoc.interconnect.stream import AsyncFIFO
class CRG(Module):
def __init__(self, platform, dco_clk, dco_freq=200e6):
self.clock_domains.cd_dco = ClockDomain()
self.clock_domains.cd_dco2x = 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_buf = Signal()
self.specials += Instance(
"IBUFGDS", i_I=dco_clk_p, i_IB=dco_clk_n, o_O=dco_clk_buf
)
# # #
clk_feedback = Signal()
clk_feedback_buf = Signal()
clk_dco = Signal()
clk_dco2x = Signal()
clk_dco2d = Signal()
clk_dco2d_45_degree = Signal()
mmcm_ps_psdone = 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)
self.specials += [
Instance(
"MMCME2_ADV",
p_BANDWIDTH="OPTIMIZED",
p_DIVCLK_DIVIDE=1,
p_CLKFBOUT_PHASE=0.0,
p_CLKFBOUT_MULT_F=4, # VCO @ 800 MHz
p_CLKIN1_PERIOD=(1e9 / dco_freq),
p_REF_JITTER1=0.01,
p_STARTUP_WAIT="FALSE",
i_CLKIN1=dco_clk_buf,
i_PWRDWN=0,
i_RST=ResetSignal("sys") | self.mmcm_rst,
i_CLKFBIN=clk_feedback_buf,
o_CLKFBOUT=clk_feedback,
p_CLKOUT0_USE_FINE_PS="TRUE",
p_CLKOUT0_DIVIDE_F=8,
p_CLKOUT0_PHASE=45.0,
p_CLKOUT0_DUTY_CYCLE=0.5,
o_CLKOUT0=clk_dco2d_45_degree, # 100 MHz <- dco_clk / 2 = 200 MHz / 2
o_LOCKED=self.locked,
p_CLKOUT1_DIVIDE=2,
p_CLKOUT1_PHASE=0.0,
p_CLKOUT1_DUTY_CYCLE=0.5,
o_CLKOUT1=clk_dco2x, # 400 MHZ <- 2 * dco_clk = 2*200 MHz
p_CLKOUT2_DIVIDE=8,
p_CLKOUT2_PHASE=0.0,
p_CLKOUT2_DUTY_CYCLE=0.5,
o_CLKOUT2=clk_dco2d, # 100 MHz <- dco_clk / 2 = 200 MHz / 2
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_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_45_degree, o_O=self.cd_dco2d_45_degree.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):
def __init__(self, platform, dco_freq=200e6):
adc_pads = platform.request("adc")
afe_pads = platform.request("adc_afe")
self.frame_csr = CSRStatus(5)
self.data_ch0 = CSRStatus(16)
self.data_ch1 = CSRStatus(16)
self.tap_delay = CSRStorage(5)
self.bitslip_csr = CSRStorage(1)
self.afe_ctrl = CSRStorage(7)
tap_delay_val = Signal(5)
bitslip = Signal()
bitslip_re_dco_2d = Signal()
ch1_gain_x10 = Signal()
ch2_gain_x10 = Signal()
ch1_shdn = Signal()
ch2_shdn = Signal()
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_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")),
]
###
# DCO clock coming from LTC2195
# dco_clk = Record([("p", 1), ("n", 1)])
dco_clk =(adc_pads.dco_p, adc_pads.dco_n)
self.comb += [
# dco_clk.p.eq(adc_pads.dco_p),
# dco_clk.n.eq(adc_pads.dco_n),
tap_delay_val.eq(self.tap_delay.storage),
Cat(ch1_gain_x10, ch2_gain_x10, ch1_shdn, ch2_shdn).eq(
self.afe_ctrl.storage[0:4]
),
]
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.sync.dco2d += [
bitslip.eq(Mux(bitslip_re_dco_2d, self.bitslip_csr.storage, 0))
]
self.comb += [
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_ch1.status.eq(self.data_out[1]),
]
self.comb += [
afe_pads.ch1_gain.eq(ch1_gain_x10),
afe_pads.ch2_gain.eq(ch2_gain_x10),
afe_pads.nshdn_ch1.eq(~ch1_shdn),
afe_pads.nshdn_ch2.eq(~ch2_shdn),
]
dummy = Signal(8)
dummy_idelay_rdy = Signal()
self.specials += Instance(
"LTC2195",
i_rst_in=ResetSignal("dco2d"),
i_clk200=ClockSignal("idelay"),
i_DCO=ClockSignal("dco"),
i_DCO_2D=ClockSignal("dco2d"),
i_FR_in_p=adc_pads.frame_p,
i_FR_in_n=adc_pads.frame_n,
i_D0_in_p=adc_pads.data0_p,
i_D0_in_n=adc_pads.data0_n,
i_D1_in_p=adc_pads.data1_p,
i_D1_in_n=adc_pads.data1_n,
i_bitslip=bitslip,
i_delay_val=tap_delay_val,
o_ADC0_out=self.data_out_cdc[1], # LANES swapped on hardware
o_ADC1_out=self.data_out_cdc[0],
o_FR_out=self.s_frame_cdc,
o_o_data_from_pins=dummy,
o_idelay_rdy=dummy_idelay_rdy,
)
class AUX_ADC_CTRL(Module, AutoCSR):
def __init__(self, platform):
adc_aux_pads = platform.request("aux_adc")
self.adc_aux_ctrl = CSRStorage(5)
self.comb += [
adc_aux_pads.diff_n.eq(~self.adc_aux_ctrl.storage[0]),
adc_aux_pads.a.eq(self.adc_aux_ctrl.storage[1:4]),
adc_aux_pads.range.eq(self.adc_aux_ctrl.storage[4]),
]

View File

@ -0,0 +1,99 @@
# This file is part of Fast Servo Software Package.
#
# Copyright (C) 2023 Jakub Matyas
# Warsaw University of Technology <jakubk.m@gmail.com>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from migen import *
from misoc.interconnect.csr import AutoCSR, CSRStorage
from migen.genlib.io import DDROutput
from misoc.interconnect.stream import AsyncFIFO
class DAC(Module, AutoCSR):
def __init__(self, platform):
dac_pads = platform.request("dac")
dac_afe_pads = platform.request("dac_afe")
self.dac_ctrl = CSRStorage(3)
self.output_value_ch0 = CSRStorage(14)
self.output_value_ch1 = CSRStorage(14)
manual_override = Signal()
ch0_pd = Signal()
ch1_pd = Signal()
output_data_ch0 = Signal(14)
output_data_ch1 = Signal(14)
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)
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 += [
Cat(manual_override, ch0_pd, ch1_pd).eq(self.dac_ctrl.storage),
dac_pads.rst.eq(ResetSignal("dco2d")),
dac_afe_pads.ch1_pd_n.eq(~ch0_pd),
dac_afe_pads.ch2_pd_n.eq(~ch1_pd),
output_data_ch0.eq(
Mux(manual_override, self.data_in_csr_cdc[0], self.data_in_cdc[0])
),
output_data_ch1.eq(
Mux(manual_override, self.data_in_csr_cdc[1], self.data_in_cdc[1])
),
]
self.specials += [
Instance("ODDR",
i_C=ClockSignal("dco2d"),
i_CE=~ResetSignal("dco2d"),
i_D1=output_data_ch0[lane], # DDR CLK Rising Edge
i_D2=output_data_ch1[lane], # DDR CLK Falling Edge
o_Q=dac_pads.data[lane],
p_DDR_CLK_EDGE="SAME_EDGE")
for lane in range(14)]
self.specials += Instance("ODDR",
i_C=ClockSignal("dco2d_45_degree"),
i_CE=~ResetSignal("dco2d"),
i_D1=0,
i_D2=1,
o_Q=dac_pads.dclkio,
p_DDR_CLK_EDGE="SAME_EDGE")
class AUX_DAC_CTRL(Module, AutoCSR):
def __init__(self, platform):
dac_aux_pads = platform.request("aux_dac")
self.dac_aux_ctrl = CSRStorage(3)
self.comb += [
dac_aux_pads.nclr.eq(~self.dac_aux_ctrl.storage[0]),
dac_aux_pads.bin.eq(self.dac_aux_ctrl.storage[1]),
dac_aux_pads.nldac.eq(~self.dac_aux_ctrl.storage[2]),
]

View File

@ -0,0 +1,385 @@
# Copyright 2014-2015 Robert Jördens <jordens@gmail.com>
# Copyright 2018-2022 Benjamin Wiegand <benjamin.wiegand@physik.hu-berlin.de>
# Copyright 2021-2022 Bastian Leykauf <leykauf@physik.hu-berlin.de>
# Copyright 2023 Jakub Matyas
# Warsaw University of Technology <jakubk.m@gmail.com>
#
# This file is part of Fast Servo Software Package and is based on Linien.
#
# Linien is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Linien is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Linien. If not, see <http://www.gnu.org/licenses/>.
from functools import reduce
from operator import or_
from migen import (
DIR_M_TO_S,
DIR_S_TO_M,
Cat,
ClockSignal,
If,
Instance,
Module,
Record,
Replicate,
ResetSignal,
Signal,
)
from misoc.interconnect import csr_bus, wishbone
sys_layout = [
("rstn", 1, DIR_M_TO_S),
("clk", 1, DIR_M_TO_S),
("addr", 32, DIR_M_TO_S),
("wdata", 32, DIR_M_TO_S),
("sel", 4, DIR_M_TO_S),
("wen", 1, DIR_M_TO_S),
("ren", 1, DIR_M_TO_S),
("rdata", 32, DIR_S_TO_M),
("err", 1, DIR_S_TO_M),
("ack", 1, DIR_S_TO_M),
]
axi_layout = [
("arvalid", 1),
("awvalid", 1),
("bready", 1),
("rready", 1),
("wlast", 1),
("wvalid", 1),
("arid", 12),
("awid", 12),
("wid", 12),
("arburst", 2),
("arlock", 2),
("arsize", 3),
("awburst", 2),
("awlock", 2),
("awsize", 3),
("arprot", 3),
("awprot", 3),
("araddr", 32),
("awaddr", 32),
("wdata", 32),
("arcache", 4),
("arlen", 4),
("arqos", 4),
("awcache", 4),
("awlen", 4),
("awqos", 4),
("wstrb", 4),
("aclk", 1),
("arready", 1),
("awready", 1),
("bvalid", 1),
("rlast", 1),
("rvalid", 1),
("wready", 1),
("bid", 12),
("rid", 12),
("bresp", 2),
("rresp", 2),
("rdata", 32),
("arstn", 1),
]
class PitayaPS(Module):
def __init__(self, cpu):
self.fclk = Signal(4)
self.frstn = Signal(4)
###
self.submodules.axi = Axi2Sys()
axi = self.axi.axi
self.comb += [
axi.aclk.eq(self.fclk[0]),
axi.arstn.eq(self.frstn[0]),
]
self.specials += Instance(
"system_processing_system7_0_0",
io_MIO=cpu.mio,
io_PS_CLK=cpu.ps_clk,
io_PS_PORB=cpu.ps_porb,
io_PS_SRSTB=cpu.ps_srstb,
io_DDR_Addr=cpu.DDR_addr,
io_DDR_BankAddr=cpu.DDR_ba,
io_DDR_CAS_n=cpu.DDR_cas_n,
io_DDR_Clk_n=cpu.DDR_ck_n,
io_DDR_Clk=cpu.DDR_ck_p,
io_DDR_CKE=cpu.DDR_cke,
io_DDR_CS_n=cpu.DDR_cs_n,
io_DDR_DM=cpu.DDR_dm,
io_DDR_DQ=cpu.DDR_dq,
io_DDR_DQS_n=cpu.DDR_dqs_n,
io_DDR_DQS=cpu.DDR_dqs_p,
io_DDR_ODT=cpu.DDR_odt,
io_DDR_RAS_n=cpu.DDR_ras_n,
io_DDR_DRSTB=cpu.DDR_reset_n,
io_DDR_WEB=cpu.DDR_we_n,
io_DDR_VRN=cpu.ddr_vrn,
io_DDR_VRP=cpu.ddr_vrp,
o_FCLK_CLK0=self.fclk[0],
o_FCLK_CLK1=self.fclk[1],
o_FCLK_CLK2=self.fclk[2],
o_FCLK_CLK3=self.fclk[3],
o_FCLK_RESET0_N=self.frstn[0],
o_FCLK_RESET1_N=self.frstn[1],
o_FCLK_RESET2_N=self.frstn[2],
o_FCLK_RESET3_N=self.frstn[3],
i_M_AXI_GP0_ACLK=axi.aclk,
o_M_AXI_GP0_ARVALID=axi.arvalid,
o_M_AXI_GP0_AWVALID=axi.awvalid,
o_M_AXI_GP0_BREADY=axi.bready,
o_M_AXI_GP0_RREADY=axi.rready,
o_M_AXI_GP0_WLAST=axi.wlast,
o_M_AXI_GP0_WVALID=axi.wvalid,
o_M_AXI_GP0_ARID=axi.arid,
o_M_AXI_GP0_AWID=axi.awid,
o_M_AXI_GP0_WID=axi.wid,
o_M_AXI_GP0_ARBURST=axi.arburst,
o_M_AXI_GP0_ARLOCK=axi.arlock,
o_M_AXI_GP0_ARSIZE=axi.arsize,
o_M_AXI_GP0_AWBURST=axi.awburst,
o_M_AXI_GP0_AWLOCK=axi.awlock,
o_M_AXI_GP0_AWSIZE=axi.awsize,
o_M_AXI_GP0_ARPROT=axi.arprot,
o_M_AXI_GP0_AWPROT=axi.awprot,
o_M_AXI_GP0_ARADDR=axi.araddr,
o_M_AXI_GP0_AWADDR=axi.awaddr,
o_M_AXI_GP0_WDATA=axi.wdata,
o_M_AXI_GP0_ARCACHE=axi.arcache,
o_M_AXI_GP0_ARLEN=axi.arlen,
o_M_AXI_GP0_ARQOS=axi.arqos,
o_M_AXI_GP0_AWCACHE=axi.awcache,
o_M_AXI_GP0_AWLEN=axi.awlen,
o_M_AXI_GP0_AWQOS=axi.awqos,
o_M_AXI_GP0_WSTRB=axi.wstrb,
i_M_AXI_GP0_ARREADY=axi.arready,
i_M_AXI_GP0_AWREADY=axi.awready,
i_M_AXI_GP0_BVALID=axi.bvalid,
i_M_AXI_GP0_RLAST=axi.rlast,
i_M_AXI_GP0_RVALID=axi.rvalid,
i_M_AXI_GP0_WREADY=axi.wready,
i_M_AXI_GP0_BID=axi.bid,
i_M_AXI_GP0_RID=axi.rid,
i_M_AXI_GP0_BRESP=axi.bresp,
i_M_AXI_GP0_RRESP=axi.rresp,
i_M_AXI_GP0_RDATA=axi.rdata,
i_SPI0_SS_I=0,
# i_SPI0_SS_I=spi.ss_i,
# o_SPI0_SS_O=spi.ss_o,
# o_SPI0_SS_T=spi.ss_t,
# o_SPI0_SS1_O=spi.ss1_o,
# o_SPI0_SS2_O=spi.ss2_o,
i_SPI0_SCLK_I=0,
# i_SPI0_SCLK_I=spi.sclk_i,
# o_SPI0_SCLK_O=spi.sclk_o,
# o_SPI0_SCLK_T=spi.sclk_t,
i_SPI0_MOSI_I=0,
# i_SPI0_MOSI_I=spi.mosi_i,
# o_SPI0_MOSI_O=spi.mosi_o,
# o_SPI0_MOSI_T=spi.mosi_t,
i_SPI0_MISO_I=0,
# i_SPI0_MISO_I=spi.miso_i,
# o_SPI0_MISO_O=spi.miso_o,
# o_SPI0_MISO_T=spi.miso_t,
i_USB0_VBUS_PWRFAULT=0,
)
class Axi2Sys(Module):
def __init__(self):
self.sys = Record(sys_layout)
self.axi = Record(axi_layout)
###
self.comb += [self.sys.clk.eq(self.axi.aclk), self.sys.rstn.eq(self.axi.arstn)]
self.specials += Instance(
"axi_slave",
p_AXI_DW=32,
p_AXI_AW=32,
p_AXI_IW=12,
i_axi_clk_i=self.axi.aclk,
i_axi_rstn_i=self.axi.arstn,
i_axi_awid_i=self.axi.awid,
i_axi_awaddr_i=self.axi.awaddr,
i_axi_awlen_i=self.axi.awlen,
i_axi_awsize_i=self.axi.awsize,
i_axi_awburst_i=self.axi.awburst,
i_axi_awlock_i=self.axi.awlock,
i_axi_awcache_i=self.axi.awcache,
i_axi_awprot_i=self.axi.awprot,
i_axi_awvalid_i=self.axi.awvalid,
o_axi_awready_o=self.axi.awready,
i_axi_wid_i=self.axi.wid,
i_axi_wdata_i=self.axi.wdata,
i_axi_wstrb_i=self.axi.wstrb,
i_axi_wlast_i=self.axi.wlast,
i_axi_wvalid_i=self.axi.wvalid,
o_axi_wready_o=self.axi.wready,
o_axi_bid_o=self.axi.bid,
o_axi_bresp_o=self.axi.bresp,
o_axi_bvalid_o=self.axi.bvalid,
i_axi_bready_i=self.axi.bready,
i_axi_arid_i=self.axi.arid,
i_axi_araddr_i=self.axi.araddr,
i_axi_arlen_i=self.axi.arlen,
i_axi_arsize_i=self.axi.arsize,
i_axi_arburst_i=self.axi.arburst,
i_axi_arlock_i=self.axi.arlock,
i_axi_arcache_i=self.axi.arcache,
i_axi_arprot_i=self.axi.arprot,
i_axi_arvalid_i=self.axi.arvalid,
o_axi_arready_o=self.axi.arready,
o_axi_rid_o=self.axi.rid,
o_axi_rdata_o=self.axi.rdata,
o_axi_rresp_o=self.axi.rresp,
o_axi_rlast_o=self.axi.rlast,
o_axi_rvalid_o=self.axi.rvalid,
i_axi_rready_i=self.axi.rready,
o_sys_addr_o=self.sys.addr,
o_sys_wdata_o=self.sys.wdata,
o_sys_sel_o=self.sys.sel,
o_sys_wen_o=self.sys.wen,
o_sys_ren_o=self.sys.ren,
i_sys_rdata_i=self.sys.rdata,
i_sys_err_i=self.sys.err,
i_sys_ack_i=self.sys.ack,
)
class SysInterconnect(Module):
def __init__(self, master, *slaves):
cs = Signal(max=len(slaves)) if len(slaves) != 1 else Signal()
self.comb += cs.eq(master.addr[20:23])
rets = []
for i, s in enumerate(slaves):
sel = Signal()
self.comb += [
sel.eq(cs == i),
s.clk.eq(master.clk),
s.rstn.eq(master.rstn),
s.addr.eq(master.addr),
s.wdata.eq(master.wdata),
s.sel.eq(master.sel),
s.wen.eq(sel & master.wen),
s.ren.eq(sel & master.ren),
]
ret = Cat(s.err, s.ack, s.rdata)
rets.append(Replicate(sel, len(ret)) & ret)
self.comb += Cat(master.err, master.ack, master.rdata).eq(reduce(or_, rets))
class Sys2Wishbone(Module):
def __init__(self):
self.wishbone = wb = wishbone.Interface()
self.sys = sys = Record(sys_layout)
###
sys2 = Record(sys_layout)
self.specials += Instance(
"bus_clk_bridge",
i_sys_clk_i=sys.clk,
i_sys_rstn_i=sys.rstn,
i_sys_addr_i=sys.addr,
i_sys_wdata_i=sys.wdata,
i_sys_sel_i=sys.sel,
i_sys_wen_i=sys.wen,
i_sys_ren_i=sys.ren,
o_sys_rdata_o=sys.rdata,
o_sys_err_o=sys.err,
o_sys_ack_o=sys.ack,
i_clk_i=ClockSignal(),
i_rstn_i=~ResetSignal(),
o_addr_o=sys2.addr,
o_wen_o=sys2.wen,
o_ren_o=sys2.ren,
o_wdata_o=sys2.wdata,
i_rdata_i=sys2.rdata,
i_err_i=sys2.err,
i_ack_i=sys2.ack,
)
self.sync += [
If(
sys2.ren | sys2.wen,
wb.cyc.eq(1),
wb.adr.eq(sys2.addr[2:]),
wb.we.eq(sys2.wen),
wb.dat_w.eq(sys2.wdata),
).Elif(wb.ack, wb.cyc.eq(0))
]
self.comb += [
wb.stb.eq(wb.cyc),
sys2.rdata.eq(wb.dat_r),
sys2.ack.eq(wb.ack),
sys2.err.eq(wb.err),
]
class SysCDC(Module):
def __init__(self, cd_target="sys"):
self.source = Record(sys_layout)
self.target = Record(sys_layout)
self.specials += Instance(
"bus_clk_bridge",
i_sys_clk_i=self.source.clk,
i_sys_rstn_i=self.source.rstn,
i_sys_addr_i=self.source.addr,
i_sys_wdata_i=self.source.wdata,
i_sys_sel_i=self.source.sel,
i_sys_wen_i=self.source.wen,
i_sys_ren_i=self.source.ren,
o_sys_rdata_o=self.source.rdata,
o_sys_err_o=self.source.err,
o_sys_ack_o=self.source.ack,
i_clk_i=self.target.clk,
i_rstn_i=self.target.rstn,
o_addr_o=self.target.addr,
o_wdata_o=self.target.wdata,
o_wen_o=self.target.wen,
o_ren_o=self.target.ren,
i_rdata_i=self.target.rdata,
i_err_i=self.target.err,
i_ack_i=self.target.ack,
)
self.comb += [
self.target.clk.eq(ClockSignal(cd_target)),
self.target.rstn.eq(~ResetSignal(cd_target)),
]
class Sys2CSR(Module):
def __init__(self):
self.csr = csr_bus.Interface()
self.sys = Record(sys_layout)
###
stb = Signal()
self.sync += [
stb.eq(self.sys.wen | self.sys.ren),
self.csr.adr.eq(self.sys.addr[2:]),
self.csr.we.eq(self.sys.wen),
self.csr.dat_w.eq(self.sys.wdata),
self.sys.ack.eq(stb),
self.sys.rdata.eq(self.csr.dat_r),
]

View File

@ -0,0 +1,193 @@
# This file is part of Fast Servo Software Package.
#
# Copyright (C) 2023 Jakub Matyas
# Warsaw University of Technology <jakubk.m@gmail.com>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from migen import *
class PS7(Module):
def __init__(self, platform, ps7_name=None):
self.frstn = Signal()
self.ps7_tcl = []
self.platform = platform
self.ps7_name = "Zynq" if ps7_name is None else ps7_name
ps7_clk = platform.request("ps7_clk")
ps7_porb = platform.request("ps7_porb")
ps7_srstb = platform.request("ps7_srstb")
ps7_mio = platform.request("ps7_mio")
ps7_ddram = platform.request("ps7_ddram")
self.cpu_params = dict(
# Clk / Rst.
io_PS_CLK = ps7_clk,
io_PS_PORB = ps7_porb,
io_PS_SRSTB = ps7_srstb,
# MIO.
io_MIO = ps7_mio,
# DDRAM.
io_DDR_Addr = ps7_ddram.addr,
io_DDR_BankAddr = ps7_ddram.ba,
io_DDR_CAS_n = ps7_ddram.cas_n,
io_DDR_Clk_n = ps7_ddram.ck_n,
io_DDR_Clk = ps7_ddram.ck_p,
io_DDR_CKE = ps7_ddram.cke,
io_DDR_CS_n = ps7_ddram.cs_n,
io_DDR_DM = ps7_ddram.dm,
io_DDR_DQ = ps7_ddram.dq,
io_DDR_DQS_n = ps7_ddram.dqs_n,
io_DDR_DQS = ps7_ddram.dqs_p,
io_DDR_ODT = ps7_ddram.odt,
io_DDR_RAS_n = ps7_ddram.ras_n,
io_DDR_DRSTB = ps7_ddram.reset_n,
io_DDR_WEB = ps7_ddram.we_n,
io_DDR_VRN = ps7_ddram.vrn,
io_DDR_VRP = ps7_ddram.vrp,
# USB0.
# i_USB0_VBUS_PWRFAULT = 0,
# Fabric Clk / Rst.
# o_FCLK_CLK0 = ClockSignal("ps7"),
o_FCLK_RESET0_N = self.frstn
)
self.set_ps7(name=self.ps7_name,
config={
**self.platform.ps7_config
})
def add_ps7_config(self, config):
# Config must be provided as a config, value dict.
assert isinstance(config, dict)
# Add configs to PS7.
self.ps7_tcl.append("set_property -dict [list \\")
for config, value in config.items():
self.ps7_tcl.append("CONFIG.{} {} \\".format(config, '{{' + str(value) + '}}'))
self.ps7_tcl.append(f"] [get_ips {self.ps7_name}]")
def set_ps7(self, name=None, config=None, preset=None):
self.ps7_name = name
self.ps7_tcl.append(f"set ps7 [create_ip -vendor xilinx.com -name processing_system7 -module_name {self.ps7_name}]")
self.add_ps7_config(config)
def add_axi_gp_master(self, interface):
# assert type(interface) is Axi2Sys
axi_interface = interface
self.cpu_params.update({
# AXI GP clk.
f"i_M_AXI_GP0_ACLK" : axi_interface.aclk,
# AXI GP aw.
f"o_M_AXI_GP0_AWVALID" : axi_interface.awvalid,
f"i_M_AXI_GP0_AWREADY" : axi_interface.awready,
f"o_M_AXI_GP0_AWADDR" : axi_interface.awaddr,
f"o_M_AXI_GP0_AWBURST" : axi_interface.awburst,
f"o_M_AXI_GP0_AWLEN" : axi_interface.awlen,
f"o_M_AXI_GP0_AWSIZE" : axi_interface.awsize,
f"o_M_AXI_GP0_AWID" : axi_interface.awid,
f"o_M_AXI_GP0_AWLOCK" : axi_interface.awlock,
f"o_M_AXI_GP0_AWPROT" : axi_interface.awprot,
f"o_M_AXI_GP0_AWCACHE" : axi_interface.awcache,
f"o_M_AXI_GP0_AWQOS" : axi_interface.awqos,
# AXI GP w.
f"o_M_AXI_GP0_WVALID" : axi_interface.wvalid,
f"o_M_AXI_GP0_WLAST" : axi_interface.wlast,
f"i_M_AXI_GP0_WREADY" : axi_interface.wready,
f"o_M_AXI_GP0_WID" : axi_interface.wid,
f"o_M_AXI_GP0_WDATA" : axi_interface.wdata,
f"o_M_AXI_GP0_WSTRB" : axi_interface.wstrb,
# AXI GP b.
f"i_M_AXI_GP0_BVALID" : axi_interface.bvalid,
f"o_M_AXI_GP0_BREADY" : axi_interface.bready,
f"i_M_AXI_GP0_BID" : axi_interface.bid,
f"i_M_AXI_GP0_BRESP" : axi_interface.bresp,
# AXI GP ar.
f"o_M_AXI_GP0_ARVALID" : axi_interface.arvalid,
f"i_M_AXI_GP0_ARREADY" : axi_interface.arready,
f"o_M_AXI_GP0_ARADDR" : axi_interface.araddr,
f"o_M_AXI_GP0_ARBURST" : axi_interface.arburst,
f"o_M_AXI_GP0_ARLEN" : axi_interface.arlen,
f"o_M_AXI_GP0_ARID" : axi_interface.arid,
f"o_M_AXI_GP0_ARLOCK" : axi_interface.arlock,
f"o_M_AXI_GP0_ARSIZE" : axi_interface.arsize,
f"o_M_AXI_GP0_ARPROT" : axi_interface.arprot,
f"o_M_AXI_GP0_ARCACHE" : axi_interface.arcache,
f"o_M_AXI_GP0_ARQOS" : axi_interface.arqos,
# AXI GP r.
f"i_M_AXI_GP0_RVALID" : axi_interface.rvalid,
f"o_M_AXI_GP0_RREADY" : axi_interface.rready,
f"i_M_AXI_GP0_RLAST" : axi_interface.rlast,
f"i_M_AXI_GP0_RID" : axi_interface.rid,
f"i_M_AXI_GP0_RRESP" : axi_interface.rresp,
f"i_M_AXI_GP0_RDATA" : axi_interface.rdata,
})
def add_i2c_emio(self, platform, i2c_name, i2c_number):
ps7_i2c_pads = platform.request(i2c_name, i2c_number) #, loose=True)
if ps7_i2c_pads is not None:
o_i2c_scl = Signal()
i_i2c_scl = Signal()
t_i2c_scl = Signal()
o_i2c_sda = Signal()
i_i2c_sda = Signal()
t_i2c_sda = Signal()
self.specials += Instance("IOBUF",
i_T = t_i2c_sda,
i_I = o_i2c_sda,
io_IO = ps7_i2c_pads.sda,
o_O = i_i2c_sda,
)
self.specials += Instance("IOBUF",
i_T = t_i2c_scl,
i_I = o_i2c_scl,
io_IO = ps7_i2c_pads.scl,
o_O = i_i2c_scl,
)
self.cpu_params.update({
f"i_I2C{i2c_number}_SCL_I" : i_i2c_scl,
f"o_I2C{i2c_number}_SCL_T" : t_i2c_scl,
f"o_I2C{i2c_number}_SCL_O" : o_i2c_scl,
f"i_I2C{i2c_number}_SDA_I" : i_i2c_sda,
f"o_I2C{i2c_number}_SDA_T" : t_i2c_sda,
f"o_I2C{i2c_number}_SDA_O" : o_i2c_sda,
})
def do_finalize(self):
if len(self.ps7_tcl):
self.ps7_tcl += [
f"upgrade_ip [get_ips {self.ps7_name}]",
f"generate_target all [get_ips {self.ps7_name}]",
f"synth_ip [get_ips {self.ps7_name}]"
]
self.platform.toolchain.pre_synthesis_commands += self.ps7_tcl
self.specials += Instance(self.ps7_name, **self.cpu_params)

View File

@ -0,0 +1,141 @@
# This file is part of Fast Servo Software Package.
#
# Copyright (C) 2023 Jakub Matyas
# Warsaw University of Technology <jakubk.m@gmail.com>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from enum import Enum
from migen import *
class SpiInterface(Enum):
ADC = 0
DAC = 1
class SpiPhy(Module):
def __init__(self, spi_type, ps7_spi_pads):
assert isinstance(spi_type, SpiInterface)
self.ps_ss = Signal(3, reset_less=True)
self.ps_miso_o = Signal()
self.ps_miso_t = Signal()
self.ps_mosi_o = Signal()
self.ps_mosi_t = Signal()
self.ps_sclk_o = Signal()
self.ps_sclk_t = Signal()
self.ps_sclk_i = Signal()
self.ps_mosi_i = Signal()
self.ps_miso_i = Signal()
self.ps_ss_i = Signal()
self.ps_ss_t = Signal()
if spi_type.name == "ADC":
cs_translated = Signal(4, reset_less=True)
main_adc_miso = Signal(reset_less=True)
aux_adc_miso_a = Signal(reset_less=True)
aux_adc_miso_b = Signal(reset_less=True)
aux_dac_miso = Signal(reset_less=True)
miso_signals = [main_adc_miso, aux_adc_miso_a, aux_adc_miso_b, aux_dac_miso]
# MAIN ADC
self.specials += Instance("OBUFT", i_I=self.ps_sclk_o, i_T=self.ps_sclk_t, o_O=ps7_spi_pads.sclk)
self.specials += Instance("OBUFT", i_I=self.ps_mosi_o, i_T=self.ps_mosi_t, o_O=ps7_spi_pads.mosi)
self.specials += Instance("IBUF", i_I=ps7_spi_pads.miso, o_O=main_adc_miso)
# AUX ADC
self.specials += Instance("OBUFT", i_I=self.ps_sclk_o, i_T=self.ps_sclk_t, o_O=ps7_spi_pads.aux_adc_sclk)
self.specials += Instance("IBUF", i_I=ps7_spi_pads.aux_adc_miso_a, o_O=aux_adc_miso_a)
self.specials += Instance("IBUF", i_I=ps7_spi_pads.aux_adc_miso_b, o_O=aux_adc_miso_b)
# AUX DAC
self.specials += Instance("OBUFT", i_I=self.ps_sclk_o, i_T=self.ps_sclk_t, o_O=ps7_spi_pads.aux_dac_sclk)
self.specials += Instance("OBUFT", i_I=self.ps_mosi_o, i_T=self.ps_mosi_t, o_O=ps7_spi_pads.aux_dac_mosi)
self.specials += Instance("IBUF", i_I=ps7_spi_pads.aux_dac_miso, o_O=aux_dac_miso)
cases = {}
# for i in range(4):
# case_mask = ~(1 << i) & 0xF
# print(f"Case mask: 0b{case_mask:04b}")
# cases[i + 1] = [
# cs_translated.eq(case_mask),
# self.ps_miso_i.eq(miso_signals[i])
# ]
cases[0b001] = [
cs_translated.eq(0b1110),
self.ps_miso_i.eq(main_adc_miso),
]
cases[0b010] = [
cs_translated.eq(0b1101),
self.ps_miso_i.eq(aux_adc_miso_a),
]
cases[0b011] = [
cs_translated.eq(0b1011),
self.ps_miso_i.eq(aux_adc_miso_b),
]
cases[0b100] = [
cs_translated.eq(0b0111),
self.ps_miso_i.eq(aux_dac_miso),
]
cases["default"] = [
cs_translated.eq(0b1111),
self.ps_miso_i.eq(0b1),
]
self.comb += [
self.ps_ss_i.eq(1),
Case(self.ps_ss, cases),
ps7_spi_pads.cs.eq(cs_translated[0]),
# only one CS line physically available to AUX ADC
ps7_spi_pads.aux_adc_cs.eq(cs_translated[1] & cs_translated[2]),
ps7_spi_pads.aux_dac_miso.eq(cs_translated[3]),
]
else:
self.specials += Instance(
"spi2threewire",
o_ps_sclk_i = self.ps_sclk_i,
i_ps_sclk_o = self.ps_sclk_o,
i_ps_sclk_t = self.ps_sclk_t,
o_ps_mosi_i = self.ps_mosi_i,
i_ps_mosi_o = self.ps_mosi_o,
i_ps_mosi_t = self.ps_mosi_t,
o_ps_miso_i = self.ps_miso_i,
i_ps_miso_o = self.ps_miso_o,
i_ps_miso_t = self.ps_miso_t,
o_ps_ss_i = self.ps_ss_i,
i_ps_ss = self.ps_ss,
i_ps_ss_t = self.ps_ss_t,
o_o_ss = ps7_spi_pads.cs,
o_o_sclk = ps7_spi_pads.sclk,
io_sdio = ps7_spi_pads.sdio,
)

View File

@ -0,0 +1,336 @@
# This file is part of Fast Servo Software Package.
#
# Copyright (C) 2022-2023 Jakub Matyas
# Warsaw University of Technology <jakubk.m@gmail.com>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from migen.build.generic_platform import *
from migen.build.xilinx import XilinxPlatform
import os
from fast_servo.gateware import verilog_dir
# IOs ----------------------------------------------------------------------------------------------
_io = [
# Front panel LEDs
("fp_led", 0, Pins("G7"), IOStandard("LVCMOS25")),
("fp_led", 1, Pins("G8"), IOStandard("LVCMOS25")),
("fp_led", 2, Pins("G2"), IOStandard("LVCMOS25")),
("fp_led", 3, Pins("G3"), IOStandard("LVCMOS25")),
# LEDs
("user_led", 0, Pins("AB16"), IOStandard("LVCMOS33")),
("user_led", 1, Pins("AA14"), IOStandard("LVCMOS33")),
("user_led", 2, Pins("AA15"), IOStandard("LVCMOS33")),
# ETH LEDs
("eth_led", 0, Pins("V11"), IOStandard("LVCMOS33")),
("eth_led", 1, Pins("U13"), IOStandard("LVCMOS33")),
("from_eth_phy", 0, Pins("J3"), IOStandard("LVCMOS18")),
("from_eth_phy", 1, Pins("K8"), IOStandard("LVCMOS18")),
# CLK 100 MHz from oscillator
("clk100", 0, Pins("Y14"), IOStandard("LVCMOS33")),
# MGT clk from on-board Si5338A
("mgt_clk1", 0,
Subsignal("p", Pins("U5")),
Subsignal("n", Pins("V5")),
IOStandard("LVDS_25"),
),
# FCLK125 from on-board Si5338A
("fclk125", 0, Pins("K2"), IOStandard("LVCMOS18")),
# # ADC CLK
# ("fpga_clk", 0,
# Subsignal("p", Pins("C6")),
# Subsignal("n", Pins("C5")),
# IOStandard("LVDS_25"),
# ),
# DAC CLK
("fpga_clk", 1,
Subsignal("p", Pins("J7")),
Subsignal("n", Pins("J6")),
IOStandard("LVDS_25"),
),
# MAIN ADC LT2195
("adc", 0,
Subsignal("data0_p", Pins("F7 B7 E4 D1"), IOStandard("LVDS_25")),
Subsignal("data0_n", Pins("E7 B6 E3 C1"), IOStandard("LVDS_25")),
Subsignal("data1_p", Pins("A2 D5 F2 D7"), IOStandard("LVDS_25")),
Subsignal("data1_n", Pins("A1 C4 F1 D6"), IOStandard("LVDS_25")),
Subsignal("dco_p", Pins("B4"), IOStandard("LVDS_25")),
Subsignal("dco_n", Pins("B3"), IOStandard("LVDS_25")),
Subsignal("frame_p", Pins("B2"), IOStandard("LVDS_25")),
Subsignal("frame_n", Pins("B1"), IOStandard("LVDS_25"))
),
# ADC AFE
("adc_afe", 0,
Subsignal("ch1_gain", Pins("AA12"), IOStandard("LVCMOS33")),
Subsignal("ch2_gain", Pins("AB11"), IOStandard("LVCMOS33")),
Subsignal("nshdn_ch1", Pins("G4"), IOStandard("LVCMOS25")),
Subsignal("nshdn_ch2", Pins("F4"), IOStandard("LVCMOS25")),
),
# P5 R5 N1 N4 L2 P6 N3 R4 P1 L1 M3 M4 U2 T2
# MAIN DAC AD9117
("dac", 0,
Subsignal("data",
Pins("T2 U2 M4 M3 L1 P1 R4 N3 P6 L2 N4 N1 R5 P5"),
IOStandard("LVCMOS18")),
Subsignal("dclkio", Pins("U1"), IOStandard("LVCMOS18")),
Subsignal("rst", Pins("T1"), IOStandard("LVCMOS18")),
),
# DAC AFE
("dac_afe", 0,
Subsignal("ch1_pd_n", Pins("L5")),
Subsignal("ch2_pd_n", Pins("L4")),
IOStandard("LVCMOS18"),
),
# AUXILIARY ADC
("aux_adc", 0,
Subsignal("diff_n", Pins("W18")),
Subsignal("a", Pins("AB18 AB19 W17")),
Subsignal("range", Pins("U19")),
IOStandard("LVCMOS33")
),
# AUXILIARY DAC
("aux_dac", 0,
Subsignal("nclr", Pins("V19")),
Subsignal("bin", Pins("AA19")),
Subsignal("nldac", Pins("AB21")),
IOStandard("LVCMOS33")
),
# ADC SPI
("spi", 0,
Subsignal("sclk", Pins("J1"), IOStandard("LVCMOS18")),
Subsignal("mosi", Pins("J5"), IOStandard("LVCMOS18")),
Subsignal("miso", Pins("K5"), IOStandard("LVCMOS18")),
Subsignal("cs", Pins("J2"), IOStandard("LVCMOS18")),
Subsignal("aux_adc_sclk", Pins("AB22"), IOStandard("LVCMOS33")),
Subsignal("aux_adc_miso_a", Pins("Y18"), IOStandard("LVCMOS33")),
Subsignal("aux_adc_miso_b", Pins("AA16"), IOStandard("LVCMOS33")),
Subsignal("aux_adc_cs", Pins("Y19"), IOStandard("LVCMOS33")),
Subsignal("aux_dac_sclk", Pins("V18"), IOStandard("LVCMOS33")),
Subsignal("aux_dac_mosi", Pins("U17"), IOStandard("LVCMOS33")),
Subsignal("aux_dac_miso", Pins("U18"), IOStandard("LVCMOS33")),
Subsignal("aux_dac_cs", Pins("AA20"), IOStandard("LVCMOS33")),
),
# DAC SPI
("spi", 1,
Subsignal("sclk", Pins("K3"), IOStandard("LVCMOS18")),
Subsignal("sdio", Pins("R2"), IOStandard("LVCMOS18")),
Subsignal("cs", Pins("R3"), IOStandard("LVCMOS18")),
# Subsignal("sclk_aux", Pins("V18"), IOStandard("LVCMOS33")),
# Subsignal("mosi_aux", Pins("U17"), IOStandard("LVCMOS33")),
# Subsignal("miso_aux", Pins("U18"), IOStandard("LVCMOS33")),
# Subsignal("cs_aux", Pins("AA20"), IOStandard("LVCMOS33")),
),
#Pins("Y15 AB14 AB13 V13 V14 V15 U12 W13 W12 R17 W15 AB17 Y12 Y13 V16 W16 AA17 Y17"),
("gpio", 0,
Subsignal("n", Pins("Y15 AB14 AB13 V13 V14 V15 U12 W13"), IOStandard("LVCMOS33")),
Subsignal("p", Pins("W12 R17 W15 AB17 Y12 Y13 V16 W16"), IOStandard("LVCMOS33")),
),
# PS7
("ps7_clk", 0, Pins("_" * 1)),
("ps7_porb", 0, Pins("_" * 1)),
("ps7_srstb", 0, Pins("_" * 1)),
("ps7_mio", 0, Pins("_" * 54)),
("ps7_ddram", 0,
Subsignal("addr", Pins("_" * 15)),
Subsignal("ba", Pins("_" * 3)),
Subsignal("cas_n", Pins("_" * 1)),
Subsignal("ck_n", Pins("_" * 1)),
Subsignal("ck_p", Pins("_" * 1)),
Subsignal("cke", Pins("_" * 1)),
Subsignal("cs_n", Pins("_" * 1)),
Subsignal("dm", Pins("_" * 4)),
Subsignal("dq", Pins("_" * 32)),
Subsignal("dqs_n", Pins("_" * 4)),
Subsignal("dqs_p", Pins("_" * 4)),
Subsignal("odt", Pins("_" * 1)),
Subsignal("ras_n", Pins("_" * 1)),
Subsignal("reset_n", Pins("_" * 1)),
Subsignal("we_n", Pins("_" * 1)),
Subsignal("vrn", Pins("_" * 1)),
Subsignal("vrp", Pins("_" * 1)),
),
# I2C0 to Si5340 on Fast Servo
("ps7_i2c", 0,
Subsignal("sda", Pins("M2")),
Subsignal("scl", Pins("M1")),
IOStandard("LVCMOS18")
),
# Si540 nRST
("nrst", 0, Pins("M7"), IOStandard("LVCMOS18")),
]
_connector_eem = [
("eem", {
"d0_cc_n": "C3",
"d0_cc_p": "D3",
"d1_n": "A4",
"d1_p": "A5",
"d2_n": "F6",
"d2_p": "G6",
"d3_n": "A6",
"d3_p": "A7",
"d4_n": "E5",
"d4_p": "F5",
"d5_n": "H3",
"d5_p": "H4",
"d6_n": "B8",
"d6_p": "C8",
"d7_n": "D8",
"d7_p": "E8",
}),
]
_connector_gpio = [
("gpio", {
"qspi_io3": "Y15",
"qspi_io2": "AB14",
"qspi_io1": "AB13",
"qspi_io0": "V13",
"qspi_clk": "V14",
"qspi_ncs": "V15",
"hrtim_che1": "U12",
"hrtim_che2": "W13",
"hrtim_cha1": "W12",
"hrtim_cha2": "R17",
"lptim2_out": "W15",
"uart4_tx": "AB17",
"spi1_mosi": "Y12",
"spi1_miso": "Y13",
"spi1_nss": "V16",
"spi1_sck": "W16",
"i2c1_sda": "AA17",
"i2c1_scl": "Y17",
})
]
# PS7 config ---------------------------------------------------------------------------------------
ps7_config_board_preset = {
"PCW_PRESET_BANK0_VOLTAGE" : "LVCMOS 3.3V",
"PCW_PRESET_BANK1_VOLTAGE" : "LVCMOS 1.8V",
"PCW_CRYSTAL_PERIPHERAL_FREQMHZ" : "33.333333",
"PCW_QSPI_PERIPHERAL_ENABLE" : "1",
"PCW_QSPI_GRP_SINGLE_SS_ENABLE" : "1",
"PCW_SINGLE_QSPI_DATA_MODE" : "x4",
"PCW_QSPI_QSPI_IO" : "MIO 1 .. 6",
"PCW_QSPI_GRP_FBCLK_ENABLE" : "1",
# SD Card
"PCW_SD0_PERIPHERAL_ENABLE" : "1",
"PCW_SD0_SD0_IO" : "MIO 40 .. 45",
"PCW_MIO_40_PULLUP" : "disabled",
"PCW_MIO_41_PULLUP" : "disabled",
"PCW_MIO_42_PULLUP" : "disabled",
"PCW_MIO_43_PULLUP" : "disabled",
"PCW_MIO_44_PULLUP" : "disabled",
"PCW_MIO_45_PULLUP" : "disabled",
# UART
"PCW_UART0_PERIPHERAL_ENABLE" : "1",
"PCW_UART0_UART0_IO" : "MIO 10 .. 11",
# ETHERNET
"PCW_ACT_ENET0_PERIPHERAL_FREQMHZ" : "125",
"PCW_ENET0_PERIPHERAL_CLKSRC" : "ARM PLL",
"PCW_ENET0_PERIPHERAL_ENABLE" : "1",
"PCW_ENET0_ENET0_IO" : "MIO 16 .. 27",
"PCW_ENET0_GRP_MDIO_ENABLE" : "1",
"PCW_ENET0_GRP_MDIO_IO" : "MIO 52 .. 53",
"PCW_ENET_RESET_ENABLE" : "1",
"PCW_ENET0_RESET_ENABLE" : "1",
"PCW_ENET0_RESET_IO" : "MIO 50",
# USB
"PCW_USB0_PERIPHERAL_ENABLE" : "1",
"PCW_USB0_USB0_IO" : "MIO 28 .. 39",
"PCW_USB_RESET_ENABLE" : "1",
"PCW_USB0_RESET_ENABLE" : "1",
"PCW_USB0_RESET_IO" : "MIO 51",
"PCW_WDT_PERIPHERAL_ENABLE" : "1",
"PCW_TTC0_PERIPHERAL_ENABLE" : "1", # TTC0 required for Linux
# I2C
"PCW_I2C_RESET_ENABLE" : "0",
"PCW_I2C_RESET_POLARITY" : "Active Low",
# I2C0
"PCW_I2C0_I2C0_IO" : "EMIO",
"PCW_I2C0_PERIPHERAL_ENABLE" : "1",
"PCW_I2C0_GRP_INT_ENABLE" : "1",
"PCW_I2C0_GRP_INT_IO" : "EMIO",
# I2C1
"PCW_I2C1_PERIPHERAL_ENABLE" : "1",
"PCW_I2C1_I2C1_IO" : "MIO 48 .. 49",
"PCW_I2C1_I2C1_IO" : "MIO 12 .. 13",
"PCW_I2C1_PERIPHERAL_ENABLE" : "1",
"PCW_UIPARAM_DDR_MEMORY_TYPE" : "DDR 3 (Low Voltage)",
"PCW_UIPARAM_DDR_PARTNO" : "MT41J256M16 RE-125",
"PCW_GPIO_MIO_GPIO_ENABLE" : "1",
"PCW_FPGA0_PERIPHERAL_FREQMHZ" : "100",
"PCW_EN_CLK0_PORT" : "0", # dont use FCLK0
}
class Platform(XilinxPlatform):
default_clk_name = "clk100"
default_clk_period = 10.0
def __init__(self):
XilinxPlatform.__init__(self, "xc7z015-clg485-1", _io, _connector_gpio + _connector_eem, toolchain="vivado")
ps7_config = ps7_config_board_preset
self.ps7_config = ps7_config
verilog_sources = os.listdir(verilog_dir)
self.add_sources(verilog_dir, *verilog_sources)
def do_finalize(self, fragment):
try:
XilinxPlatform.do_finalize(self, fragment)
self.add_period_constraint(self.lookup_request(self.default_clk_name, loose=True), self.default_clk_period)
except ValueError:
pass
except ConstraintError:
pass

View File

@ -0,0 +1,291 @@
# This file is part of Fast Servo Software Package.
#
# Copyright (C) 2023 Jakub Matyas
# Warsaw University of Technology <jakubk.m@gmail.com>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
import os
from migen import *
from misoc.interconnect import csr_bus
from misoc.interconnect.csr import AutoCSR, CSRStorage
from fast_servo.gateware.cores.adc import ADC, AUX_ADC_CTRL
from fast_servo.gateware.cores.dac import AUX_DAC_CTRL, DAC
from fast_servo.gateware.cores.pitaya_ps import Axi2Sys, Sys2CSR, SysCDC, SysInterconnect
from fast_servo.gateware.cores.ps7 import PS7
from fast_servo.gateware.cores.spi_phy import SpiInterface, SpiPhy
class CRG(Module):
def __init__(self, platform):
self.ps_rst = Signal()
self.locked = Signal()
self.clock_domains.cd_sys = ClockDomain()
self.clock_domains.cd_sys_double = ClockDomain()
self.clock_domains.cd_idelay = ClockDomain()
# # #
# Clk.
clk100 = platform.request("clk100")
platform.add_period_constraint(clk100, 10.0)
self.clkin = clk100
clk100_buf = Signal()
self.specials += Instance("IBUFG", i_I=clk100, o_O=clk100_buf)
clk_feedback = Signal()
clk_feedback_buf = Signal()
clk_sys = Signal()
clk_idelay = Signal()
self.specials += [
Instance(
"PLLE2_BASE",
p_BANDWIDTH="OPTIMIZED",
p_DIVCLK_DIVIDE=1,
p_CLKFBOUT_PHASE=0.0,
p_CLKFBOUT_MULT=10,
p_CLKIN1_PERIOD=10.0,
p_REF_JITTER1=0.01,
p_STARTUP_WAIT="FALSE",
i_CLKIN1=clk100_buf,
i_PWRDWN=0,
i_RST=self.ps_rst,
i_CLKFBIN=clk_feedback_buf,
o_CLKFBOUT=clk_feedback,
p_CLKOUT0_DIVIDE=10,
p_CLKOUT0_PHASE=0.0,
p_CLKOUT0_DUTY_CYCLE=0.5,
o_CLKOUT0=clk_sys, # 100 MHz <- sys_clk
p_CLKOUT1_DIVIDE=5,
p_CLKOUT1_PHASE=0.0,
p_CLKOUT1_DUTY_CYCLE=0.5,
o_CLKOUT1=clk_idelay, # 200 MHZ <- 2 * sys_clk = 2*100 MHz
o_LOCKED=self.locked,
)
]
self.specials += Instance("BUFG", i_I=clk_feedback, o_O=clk_feedback_buf)
self.specials += Instance("BUFG", i_I=clk_sys, o_O=self.cd_sys.clk)
self.specials += Instance("BUFG", i_I=clk_idelay, o_O=self.cd_idelay.clk)
self.specials += Instance("BUFG", i_I=clk_idelay, o_O=self.cd_sys_double.clk)
# Ignore sys_clk to pll clkin path created by SoC's rst.
platform.add_false_path_constraints(self.cd_sys.clk, self.clkin)
self.specials += Instance("FD", p_INIT=1, i_D=~self.locked, i_C=self.cd_sys.clk, o_Q=self.cd_sys.rst)
class BaseSoC(PS7, AutoCSR):
def __init__(self, platform, passthrouh=False):
PS7.__init__(self, platform)
# TODO:
# LINIEN SPECIFIC csr_map - in the future should be moved
# to csr_devices list
self.csr_map = {
"adc": 9,
"fp_led0": 10,
"fp_led1": 11,
"fp_led2": 12,
"fp_led3": 13,
"dac": 14,
"adc_aux_ctrl": 15,
"dac_aux_ctrl": 16,
}
self.soc_name = "FastServo"
self.interconnect_slaves = []
self.csr_devices = []
self.platform = platform
self.submodules.crg = CRG(platform)
# # # AXI to system bus bridge
self.submodules.axi2sys = Axi2Sys()
self.submodules.sys2csr = Sys2CSR()
self.submodules.syscdc = SysCDC()
self.add_axi_gp_master(self.axi2sys.axi)
self.comb += [
self.axi2sys.axi.aclk.eq(ClockSignal("sys")),
self.axi2sys.axi.arstn.eq(self.frstn),
self.syscdc.target.connect(self.sys2csr.sys),
]
# ETH LEDS
self.comb += [
platform.request("eth_led", 0).eq(platform.request("from_eth_phy", 0)),
platform.request("eth_led", 1).eq(platform.request("from_eth_phy", 1)),
]
# I2C0 to Si5340 on Fast Servo
self.add_i2c_emio(platform, "ps7_i2c", 0)
# SPI0 - interface to main ADC and auxiliary ADC
self.add_spi_interface(platform, SpiInterface.ADC)
# SPI1 - interface to main DAC and auxiliary DAC
self.add_spi_interface(platform, SpiInterface.DAC)
# self.add_main_adc(platform)
self.submodules.adc = ADC(platform)
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.submodules.dac = DAC(platform)
self.csr_devices.append("dac")
# DEBUG
if passthrouh:
DAC_DATA_WIDTH = 14
for ch in range(2):
saturate = Signal()
adc_signal = self.adc.data_out[ch]
self.comb += [
saturate.eq(adc_signal[-3:] != Replicate(adc_signal[-1], 3)),
self.dac.data_in[ch].eq(Mux(saturate,
Cat(Replicate(~adc_signal[-1], DAC_DATA_WIDTH-1), adc_signal[-1]),
adc_signal[:-2]))
]
si_5340_nrst = platform.request("nrst")
self.comb += si_5340_nrst.eq(1)
for i in range(4):
led_pin = platform.request("fp_led", i)
setattr(self.submodules, f"fp_led{i}", LED(led_pin))
self.csr_devices.append(f"fp_led{i}")
self.submodules.adc_aux_ctrl = AUX_ADC_CTRL(platform)
self.csr_devices.append("adc_aux_ctrl")
self.submodules.dac_aux_ctrl = AUX_DAC_CTRL(platform)
self.csr_devices.append("dac_aux_ctrl")
def add_spi_interface(self, platform, spi_type):
assert isinstance(spi_type, SpiInterface)
n = spi_type.value
ps7_spi_pads = platform.request("spi", spi_type.value)
spi_phy = SpiPhy(spi_type, ps7_spi_pads)
self.submodules += spi_phy
ps7_config_spi = {
f"PCW_SPI{n}_GRP_SS0_ENABLE" : "1",
f"PCW_SPI{n}_GRP_SS0_IO" : "EMIO",
f"PCW_SPI{n}_GRP_SS1_ENABLE" : "1",
f"PCW_SPI{n}_GRP_SS1_IO" : "EMIO",
f"PCW_SPI{n}_GRP_SS2_ENABLE" : "1",
f"PCW_SPI{n}_GRP_SS2_IO" : "EMIO",
f"PCW_SPI{n}_PERIPHERAL_ENABLE" : "1",
f"PCW_SPI{n}_SPI{n}_IO" : "EMIO",
f"PCW_SPI_PERIPHERAL_CLKSRC" : "IO PLL",
f"PCW_SPI_PERIPHERAL_DIVISOR0" : "10",
f"PCW_SPI_PERIPHERAL_FREQMHZ" : "166.666666",
}
self.add_ps7_config(ps7_config_spi)
self.cpu_params.update({
f"o_SPI{n}_MISO_O" : spi_phy.ps_miso_o,
f"o_SPI{n}_MISO_T" : spi_phy.ps_miso_t,
f"o_SPI{n}_MOSI_O" : spi_phy.ps_mosi_o,
f"o_SPI{n}_MOSI_T" : spi_phy.ps_mosi_t,
f"o_SPI{n}_SCLK_O" : spi_phy.ps_sclk_o,
f"o_SPI{n}_SCLK_T" : spi_phy.ps_sclk_t,
f"i_SPI{n}_SCLK_I" : spi_phy.ps_sclk_i,
f"i_SPI{n}_MOSI_I" : spi_phy.ps_mosi_i,
f"i_SPI{n}_MISO_I" : spi_phy.ps_miso_i,
f"i_SPI{n}_SS_I" : spi_phy.ps_ss_i,
f"o_SPI{n}_SS_O" : spi_phy.ps_ss[0],
f"o_SPI{n}_SS1_O" : spi_phy.ps_ss[1],
f"o_SPI{n}_SS2_O" : spi_phy.ps_ss[2],
f"o_SPI{n}_SS_T" : spi_phy.ps_ss_t,
})
def add_interconnect_slave(self, slave):
self.interconnect_slaves.append(slave)
def get_csr_dev_address(self, name, memory):
# TODO: switch to MiSoC-like address retriving from
# the list of CSR devices
if memory is not None:
name = name + "_" + memory.name_override
try:
return self.csr_map[name]
except KeyError:
return None
def soc_finalize(self):
# Overload this method to customize SystemInterconnect
# and csrbanks - especially useful in Linien
self.add_interconnect_slave(self.syscdc.source)
self.submodules.interconnect = SysInterconnect(
self.axi2sys.sys,
*self.interconnect_slaves
)
self.submodules.csrbanks = csr_bus.CSRBankArray(self,
self.get_csr_dev_address)
self.submodules.csrcon = csr_bus.Interconnect(
self.sys2csr.csr, self.csrbanks.get_buses()
)
def do_finalize(self):
self.soc_finalize()
PS7.do_finalize(self)
def build(self, *args, **kwargs):
self.platform.build(self, *args, **kwargs)
class LED(Module, AutoCSR):
def __init__(self, led):
self.led_out = CSRStorage(1)
self.comb += led.eq(self.led_out.storage)
if __name__ == "__main__":
import subprocess
from fast_servo.gateware.fast_servo_platform import Platform
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--debug", action="store_true", default=False, help="Hardwire ADC data to DAC")
args = parser.parse_args()
root_path = os.getcwd()
platform = Platform()
fast_servo = BaseSoC(platform, passthrouh=args.debug)
build_dir = "builds/fast_servo_gw_debug" if args.debug else"builds/fast_servo_gw"
build_name = "top"
fast_servo.build(build_dir=build_dir, build_name=build_name, run=True)
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

@ -0,0 +1,162 @@
///////////////////////////////////////////////////////////////////////////////
// LTC2195.v
//
// 8/03/21
// Jakub Matyas
//
// LTC2195 controller.
//
//
///////////////////////////////////////////////////////////////////////////////
// `include "timescale.v"
`timescale 1ns/1ps // this was in the SelectIO design
module LTC2195(
input rst_in,
input clk200,
input DCO,
input DCO_2D,
input FR_in_p,
input FR_in_n,
input [3:0] D0_in_p,
input [3:0] D0_in_n,
input [3:0] D1_in_p,
input [3:0] D1_in_n,
input bitslip,
input [4:0] delay_val,
output reg [15:0] ADC0_out,
output reg [15:0] ADC1_out,
output reg [3:0] FR_out,
output wire [8:0] o_data_from_pins,
output idelay_rdy
);
// ///////////////////////////////////////////////////////////////////////////////
// // LVDS inputs
localparam N_BITS = 4;
localparam N_LANES = 9; // for each channel 4 lanes + 1 lane for FRAME
wire [N_LANES-1:0] data_in_p, data_in_n, data_in_from_pins, data_in_from_pins_delay;
assign data_in_p = {FR_in_p, D1_in_p, D0_in_p};
assign data_in_n = {FR_in_n, D1_in_n, D0_in_n};
assign o_data_from_pins = data_in_from_pins_delay;
wire [N_LANES*4 -1:0] data_out;
wire [35:0 ]data_out_mod;
assign data_out_mod = {~data_out[35:24], data_out[23:20], ~data_out[19:16], data_out[15:0]};
always @(posedge DCO_2D) begin
ADC0_out <= {
data_out_mod[0], data_out_mod[4], data_out_mod[1], data_out_mod[5],
data_out_mod[2], data_out_mod[6], data_out_mod[3], data_out_mod[7],
data_out_mod[8], data_out_mod[12], data_out_mod[9], data_out_mod[13],
data_out_mod[10], data_out_mod[14], data_out_mod[11], data_out_mod[15]
};
ADC1_out <= {
data_out_mod[16 + 0], data_out_mod[16 + 4], data_out_mod[16 + 1], data_out_mod[16 + 5],
data_out_mod[16 + 2], data_out_mod[16 + 6], data_out_mod[16 + 3], data_out_mod[16 + 7],
data_out_mod[16 + 8], data_out_mod[16 + 12], data_out_mod[16 + 9], data_out_mod[16 + 13],
data_out_mod[16 + 10], data_out_mod[16 + 14], data_out_mod[16 + 11], data_out_mod[16 + 15]
};
FR_out <= {data_out_mod[32], data_out_mod[33], data_out_mod[34], data_out_mod[35]}; // value that arrived first is LSB, therefore reversing order
end
wire s_idelay_rdy;
IDELAYCTRL IDELAYCTRL_inst (
.RDY(s_idelay_rdy), // 1-bit output: Ready output
.REFCLK(clk200), // 1-bit input: Reference clock input
.RST(s_rst) // 1-bit input: Active high reset input
);
assign idelay_rdy = s_idelay_rdy;
reg s_rst;
reg [5:0] rst_cnt;
wire serdes_o;
always @(posedge DCO_2D) begin
if (rst_in) begin
s_rst <= 1'b1;
rst_cnt <= 'b0;
end else begin
if (rst_cnt == 22)
s_rst <= 'b0;
else
rst_cnt <= rst_cnt + 1;
end
end
genvar lane;
generate for (lane=0; lane<N_LANES; lane=lane+1) begin
IBUFDS #(
.DIFF_TERM("TRUE")
)
ibufds_inst (
.I(data_in_p[lane]),
.IB(data_in_n[lane]),
.O(data_in_from_pins[lane])
);
IDELAYE2 #(
.CINVCTRL_SEL("FALSE"), // Enable dynamic clock inversion (FALSE, TRUE)
.DELAY_SRC("IDATAIN"), // Delay input (IDATAIN, DATAIN)
.HIGH_PERFORMANCE_MODE("TRUE"), // Reduced jitter ("TRUE"), Reduced power ("FALSE")
.IDELAY_TYPE("VAR_LOAD"), // FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE
.IDELAY_VALUE(0), // Input delay tap setting (0-31)
.PIPE_SEL("FALSE"), // Select pipelined mode, FALSE, TRUE
.REFCLK_FREQUENCY(200.0), // IDELAYCTRL clock input frequency in MHz (190.0-210.0, 290.0-310.0).
.SIGNAL_PATTERN("DATA") // DATA, CLOCK input signal
)
IDELAYE2_inst (
.C(clk200),
.CE('b0),
.CNTVALUEIN(delay_val),
.LD(1'b1),
.DATAOUT(data_in_from_pins_delay[lane]), // 1-bit output: Delayed data output
.IDATAIN(data_in_from_pins[lane]), // 1-bit input: Data input from the I/O
.LDPIPEEN (1'b0),
.REGRST (1'b0),
.CINVCTRL (1'b0)
);
ISERDESE2 #(
.DATA_RATE("DDR"),
.DATA_WIDTH(3'd4),
.INTERFACE_TYPE("NETWORKING"),
.IOBDELAY("BOTH"),
.SERDES_MODE("MASTER"),
.NUM_CE(2'd2)
)
iserdes_inst (
.CE1(1'd1),
.CE2(1'd1),
.DYNCLKDIVSEL('b0),
.DYNCLKSEL('b0),
.CLK(DCO),
.CLKB(!DCO),
.CLKDIV(DCO_2D),
// .D(data_in_from_pins[lane]),
.DDLY(data_in_from_pins_delay[lane]),
.RST(s_rst),
.BITSLIP(bitslip),
// DATA is MSB first and OUTA is LANE0, so in case of OUTA:
// Q1 = D9
// Q2 = D11
// Q3 = D13
// Q4 = D15
.Q1(data_out[lane*N_BITS + 3]),
.Q2(data_out[lane*N_BITS + 2]),
.Q3(data_out[lane*N_BITS + 1]),
.Q4(data_out[lane*N_BITS + 0])
);
end
endgenerate
endmodule

View File

@ -0,0 +1,265 @@
/**
* $Id: axi_slave.v 961 2014-01-21 11:40:39Z matej.oblak $
*
* @brief Red Pitaya symplified AXI slave.
*
* @Author Matej Oblak
*
* (c) Red Pitaya http://www.redpitaya.com
*
* This part of code is written in Verilog hardware description language (HDL).
* Please visit http://en.wikipedia.org/wiki/Verilog
* for more details on the language used herein.
*/
/**
* GENERAL DESCRIPTION:
*
* AXI slave used also for simple bus master.
*
*
* /------\
* WR ADDRESS ----> | WR |
* WR DATA ----> | | -----------
* WR RESPONSE <---- | CH | |
* \------/ /--------\
* | SIMPLE | ---> WR/RD ADDRRESS
* AXI | | ---> WR DATA
* | RP | <--- RD DATA
* | BUS | <--- ACKNOWLEDGE
* /------\ \--------/
* RD ADDRESS ----> | RD | |
* RD DATA <---- | CH | -----------
* \------/
*
*
* Because AXI bus is quite complex simplier bus was created.
*
* It combines write and read channel, where write has bigger priority. Command
* is then send forward to red pitaya bus. When wite or read acknowledge is
* received AXI response is created and new AXI is accepted.
*
* To prevent AXI lockups because no response is received, this slave creates its
* own after 32 cycles (ack_cnt).
*
*/
module axi_slave
#(
parameter AXI_DW = 64 , // data width (8,16,...,1024)
parameter AXI_AW = 32 , // address width
parameter AXI_IW = 8 , // ID width
parameter AXI_SW = AXI_DW >> 3 // strobe width - 1 bit for every data byte
)
(
// global signals
input axi_clk_i , //!< AXI global clock
input axi_rstn_i , //!< AXI global reset
// axi write address channel
input [ AXI_IW-1: 0] axi_awid_i , //!< AXI write address ID
input [ AXI_AW-1: 0] axi_awaddr_i , //!< AXI write address
input [ 4-1: 0] axi_awlen_i , //!< AXI write burst length
input [ 3-1: 0] axi_awsize_i , //!< AXI write burst size
input [ 2-1: 0] axi_awburst_i , //!< AXI write burst type
input [ 2-1: 0] axi_awlock_i , //!< AXI write lock type
input [ 4-1: 0] axi_awcache_i , //!< AXI write cache type
input [ 3-1: 0] axi_awprot_i , //!< AXI write protection type
input axi_awvalid_i , //!< AXI write address valid
output axi_awready_o , //!< AXI write ready
// axi write data channel
input [ AXI_IW-1: 0] axi_wid_i , //!< AXI write data ID
input [ AXI_DW-1: 0] axi_wdata_i , //!< AXI write data
input [ AXI_SW-1: 0] axi_wstrb_i , //!< AXI write strobes
input axi_wlast_i , //!< AXI write last
input axi_wvalid_i , //!< AXI write valid
output axi_wready_o , //!< AXI write ready
// axi write response channel
output [ AXI_IW-1: 0] axi_bid_o , //!< AXI write response ID
output reg [ 2-1: 0] axi_bresp_o , //!< AXI write response
output reg axi_bvalid_o , //!< AXI write response valid
input axi_bready_i , //!< AXI write response ready
// axi read address channel
input [ AXI_IW-1: 0] axi_arid_i , //!< AXI read address ID
input [ AXI_AW-1: 0] axi_araddr_i , //!< AXI read address
input [ 4-1: 0] axi_arlen_i , //!< AXI read burst length
input [ 3-1: 0] axi_arsize_i , //!< AXI read burst size
input [ 2-1: 0] axi_arburst_i , //!< AXI read burst type
input [ 2-1: 0] axi_arlock_i , //!< AXI read lock type
input [ 4-1: 0] axi_arcache_i , //!< AXI read cache type
input [ 3-1: 0] axi_arprot_i , //!< AXI read protection type
input axi_arvalid_i , //!< AXI read address valid
output axi_arready_o , //!< AXI read address ready
// axi read data channel
output [ AXI_IW-1: 0] axi_rid_o , //!< AXI read response ID
output reg [ AXI_DW-1: 0] axi_rdata_o , //!< AXI read data
output reg [ 2-1: 0] axi_rresp_o , //!< AXI read response
output reg axi_rlast_o , //!< AXI read last
output reg axi_rvalid_o , //!< AXI read response valid
input axi_rready_i , //!< AXI read response ready
// RP system read/write channel
output [ AXI_AW-1: 0] sys_addr_o , //!< system bus read/write address.
output [ AXI_DW-1: 0] sys_wdata_o , //!< system bus write data.
output reg [ AXI_SW-1: 0] sys_sel_o , //!< system bus write byte select.
output reg sys_wen_o , //!< system bus write enable.
output reg sys_ren_o , //!< system bus read enable.
input [ AXI_DW-1: 0] sys_rdata_i , //!< system bus read data.
input sys_err_i , //!< system bus error indicator.
input sys_ack_i //!< system bus acknowledge signal.
);
//---------------------------------------------------------------------------------
//
// AXI slave Module
wire ack ;
reg [ 6-1: 0] ack_cnt ;
reg rd_do ;
reg [ AXI_IW-1: 0] rd_arid ;
reg [ AXI_AW-1: 0] rd_araddr ;
reg rd_error ;
wire rd_errorw ;
reg wr_do ;
reg [ AXI_IW-1: 0] wr_awid ;
reg [ AXI_AW-1: 0] wr_awaddr ;
reg [ AXI_IW-1: 0] wr_wid ;
reg [ AXI_DW-1: 0] wr_wdata ;
reg wr_error ;
wire wr_errorw ;
assign wr_errorw = (axi_awlen_i != 4'h0) || (axi_awsize_i != 3'b010); // error if write burst and more/less than 4B transfer
assign rd_errorw = (axi_arlen_i != 4'h0) || (axi_arsize_i != 3'b010); // error if read burst and more/less than 4B transfer
always @(posedge axi_clk_i) begin
if (axi_rstn_i == 1'b0) begin
rd_do <= 1'b0 ;
rd_error <= 1'b0 ;
end
else begin
if (axi_arvalid_i && !rd_do && !axi_awvalid_i && !wr_do) // accept just one read request - write has priority
rd_do <= 1'b1 ;
else if (axi_rready_i && rd_do && ack)
rd_do <= 1'b0 ;
if (axi_arvalid_i && axi_arready_o) begin // latch ID and address
rd_arid <= axi_arid_i ;
rd_araddr <= axi_araddr_i ;
rd_error <= rd_errorw ;
end
end
end
always @(posedge axi_clk_i) begin
if (axi_rstn_i == 1'b0) begin
wr_do <= 1'b0 ;
wr_error <= 1'b0 ;
end
else begin
if (axi_awvalid_i && !wr_do && !rd_do) // accept just one write request - if idle
wr_do <= 1'b1 ;
else if (axi_bready_i && wr_do && ack)
wr_do <= 1'b0 ;
if (axi_awvalid_i && axi_awready_o) begin // latch ID and address
wr_awid <= axi_awid_i ;
wr_awaddr <= axi_awaddr_i ;
wr_error <= wr_errorw ;
end
if (axi_wvalid_i && wr_do) begin // latch ID and write data
wr_wid <= axi_wid_i ;
wr_wdata <= axi_wdata_i ;
end
end
end
assign axi_awready_o = !wr_do && !rd_do ;
assign axi_wready_o = (wr_do && axi_wvalid_i) || (wr_errorw && axi_wvalid_i) ;
assign axi_bid_o = wr_awid ;
//assign axi_bresp_o = {wr_error,1'b0} ; // 2'b10 SLVERR
//assign axi_bvalid_o = (sys_wen_o && axi_bready_i) || (wr_error && axi_bready_i) ;
assign axi_arready_o = !rd_do && !wr_do && !axi_awvalid_i ;
assign axi_rid_o = rd_arid ;
//assign axi_rdata_o = sys_rdata_i ;
always @(posedge axi_clk_i) begin
if (axi_rstn_i == 1'b0) begin
axi_bvalid_o <= 1'b0 ;
axi_bresp_o <= 2'h0 ;
axi_rlast_o <= 1'b0 ;
axi_rvalid_o <= 1'b0 ;
axi_rresp_o <= 2'h0 ;
end
else begin
axi_bvalid_o <= wr_do && ack ;
axi_bresp_o <= {(wr_error || ack_cnt[5]),1'b0} ; // 2'b10 SLVERR 2'b00 OK
axi_rlast_o <= rd_do && ack ;
axi_rvalid_o <= rd_do && ack ;
axi_rresp_o <= {(rd_error || ack_cnt[5]),1'b0} ; // 2'b10 SLVERR 2'b00 OK
axi_rdata_o <= sys_rdata_i ;
end
end
// acknowledge protection
always @(posedge axi_clk_i) begin
if (axi_rstn_i == 1'b0) begin
ack_cnt <= 6'h0 ;
end
else begin
if ((axi_arvalid_i && axi_arready_o) || (axi_awvalid_i && axi_awready_o)) // rd || wr request
ack_cnt <= 6'h1 ;
else if (ack)
ack_cnt <= 6'h0 ;
else if (|ack_cnt)
ack_cnt <= ack_cnt + 6'h1 ;
end
end
assign ack = sys_ack_i || ack_cnt[5] || (rd_do && rd_errorw) || (wr_do && wr_errorw); // bus acknowledge or timeout or error
//------------------------------------------
// Simple slave interface
always @(posedge axi_clk_i) begin
if (axi_rstn_i == 1'b0) begin
sys_wen_o <= 1'b0 ;
sys_ren_o <= 1'b0 ;
sys_sel_o <= {AXI_SW{1'b0}} ;
end
else begin
sys_wen_o <= wr_do && axi_wvalid_i && !wr_errorw ;
sys_ren_o <= axi_arvalid_i && axi_arready_o && !rd_errorw ;
sys_sel_o <= {AXI_SW{1'b1}} ;
end
end
assign sys_addr_o = rd_do ? rd_araddr : wr_awaddr ;
assign sys_wdata_o = wr_wdata ;
endmodule

View File

@ -0,0 +1,128 @@
/**
* $Id: bus_clk_bridge.v 961 2014-01-21 11:40:39Z matej.oblak $
*
* @brief Red Pitaya system bus clock crossing bridge.
*
* @Author Matej Oblak
*
* (c) Red Pitaya http://www.redpitaya.com
*
* This part of code is written in Verilog hardware description language (HDL).
* Please visit http://en.wikipedia.org/wiki/Verilog
* for more details on the language used herein.
*/
/**
* GENERAL DESCRIPTION:
*
* Clock domain bridge for system bus.
*
*
* /------\
* SYSTEM | | PROCESSING
* BUS <-----> | SYNC | <-----> BUS
* | |
* \------/
*
*
* System bus runs on one clock domain while processing runs on separate. To
* simplify transition of writing and reading data this bridge was created.
*
*/
module bus_clk_bridge
(
// system bus
input sys_clk_i , //!< bus clock
input sys_rstn_i , //!< bus reset - active low
input [ 32-1: 0] sys_addr_i , //!< bus address
input [ 32-1: 0] sys_wdata_i , //!< bus write data
input [ 4-1: 0] sys_sel_i , //!< bus write byte select
input sys_wen_i , //!< bus write enable
input sys_ren_i , //!< bus read enable
output [ 32-1: 0] sys_rdata_o , //!< bus read data
output sys_err_o , //!< bus error indicator
output sys_ack_o , //!< bus acknowledge signal
// Destination bus
input clk_i , //!< clock
input rstn_i , //!< reset - active low
output reg [ 32-1: 0] addr_o , //!< address
output reg [ 32-1: 0] wdata_o , //!< write data
output wen_o , //!< write enable
output ren_o , //!< read enable
input [ 32-1: 0] rdata_i , //!< read data
input err_i , //!< error indicator
input ack_i //!< acknowledge signal
);
//---------------------------------------------------------------------------------
// Synchronize signals between clock domains
reg sys_rd ;
reg sys_wr ;
reg sys_do ;
reg [ 2-1: 0] sys_sync ;
reg sys_done ;
reg dst_do ;
reg [ 2-1: 0] dst_sync ;
reg dst_done ;
always @(posedge sys_clk_i) begin
if (sys_rstn_i == 1'b0) begin
sys_rd <= 1'b0 ;
sys_wr <= 1'b0 ;
sys_do <= 1'b0 ;
sys_sync <= 2'h0 ;
sys_done <= 1'b0 ;
end
else begin
if ((sys_do == sys_done) && (sys_wen_i || sys_ren_i)) begin
addr_o <= sys_addr_i ;
wdata_o <= sys_wdata_i ;
sys_rd <= sys_ren_i ;
sys_wr <= sys_wen_i ;
sys_do <= !sys_do ;
end
sys_sync <= {sys_sync[0], dst_done};
sys_done <= sys_sync[1];
end
end
always @(posedge clk_i) begin
if (rstn_i == 1'b0) begin
dst_do <= 1'b0 ;
dst_sync <= 2'h0 ;
dst_done <= 1'b0 ;
end
else begin
dst_sync <= {dst_sync[0], sys_do};
dst_do <= dst_sync[1];
if (ack_i && (dst_do != dst_done))
dst_done <= dst_do;
end
end
assign ren_o = sys_rd && (dst_sync[1]^dst_do);
assign wen_o = sys_wr && (dst_sync[1]^dst_do);
assign sys_rdata_o = rdata_i ;
assign sys_err_o = err_i ;
assign sys_ack_o = sys_done ^ sys_sync[1] ;
endmodule

View File

@ -0,0 +1,111 @@
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: WUT
// Engineer: Jakub Matyas
//
// Create Date: 03/02/2023 01:39:08 PM
// Design Name:
// Module Name: spi2threewire
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module spi2threewire (
output ps_sclk_i,
input ps_sclk_o,
input ps_sclk_t,
output ps_mosi_i,
input ps_mosi_o,
input ps_mosi_t,
output ps_miso_i,
input ps_miso_o,
input ps_miso_t,
output ps_ss_i,
input [2:0] ps_ss,
input ps_ss_t,
output o_ss,
output o_sclk,
inout sdio
);
assign ps_sclk_i = 1'b0;
assign ps_mosi_i = 1'b0;
assign ps_ss_i = 1'b1;
reg [3:0] bit_count = 'd0;
// rd_wr_n - whether it will be READ transaction or WRITE
// first bit of the command
reg rd_wr_n = 'd0;
reg sdio_buffer_direction = 'd0;
wire s_sclk;
wire s_csn;
wire s_sdio_buffer_direction;
assign s_sclk = ps_sclk_o;
assign s_csn = ps_ss[0];
assign o_ss = s_csn;
// 1 if there is a SPI tranmsission going on (CS_N is LOW)
// AND transmission is of READ type
// 0 otherwise
assign s_sdio_buffer_direction = sdio_buffer_direction & ~s_csn;
always @(posedge s_sclk or posedge s_csn) begin
if (s_csn == 1'b1) begin
// after the transmission, fill bit counter with ZEROS
// and zero transmission type (rd_wr_n)
bit_count <= 4'd0;
rd_wr_n <= 1'b0;
end else begin
// on every rising edge increment bit counter
// sample first bit to get the knowledge of the transmission type
bit_count <= (bit_count < 4'd15) ? bit_count + 1'b1 : bit_count;
if (bit_count == 4'b0)
rd_wr_n <= ps_mosi_o;
end
end
always @(negedge s_sclk or posedge s_csn) begin
if (s_csn == 1'b1)
sdio_buffer_direction <= 1'b0;
else begin
if (bit_count == 4'd8)
// after the 8th bit, on falling edge,
// set the SDIO buffer direction
// accordingly to the transmission type
sdio_buffer_direction <= rd_wr_n;
end
end
IOBUF IOBUF_inst (
.O(ps_miso_i),
.IO(sdio),
.I(ps_mosi_o),
.T(s_sdio_buffer_direction) // 3-state enable input, high=input (from ext), low=output
);
OBUFT sclk_buf (
.O(o_sclk),
.I(ps_sclk_o),
.T('b0)
);
endmodule

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

@ -0,0 +1,95 @@
# Fix for bus error issues when compiling cpython extensions in pyrp3 v1.2.0+
# Patch sourced from: https://github.com/linien-org/pyrp3/tree/e6688acf8bd79d2dbe1d192d09c1a1baf1f6c67b (setup.py & monitor/Makefile)
# Reference: https://github.com/elhep/Fast-Servo-Firmware/blob/master/OS/scripts/linien_install_requirements.sh#L28
diff --git a/monitor/Makefile b/monitor/Makefile
new file mode 100644
index 0000000..0c9bb53
--- /dev/null
+++ b/monitor/Makefile
@@ -0,0 +1,31 @@
+# Makefile for libmonitor
+
+OBJS = monitor.o
+SRCS = $(subst .o,.c, $(OBJS)))
+OSOBJS = monitor.os
+TARGETLIB=libmonitor.so
+CFLAGS=-g -std=gnu99 -Wall -Werror
+LIBS=-lm -lpthread
+
+# Use CROSS_COMPILE=arm-linux-gnueabi-
+CC=$(CROSS_COMPILE)gcc
+INSTALL_DIR ?= .
+
+
+all: $(TARGETLIB)
+lib: $(TARGETLIB)
+
+%.os: %.c
+ $(CC) -c -fPIC $(CFLAGS) $< -o $@
+
+$(TARGETLIB): $(OSOBJS)
+ $(CC) -o $@ -shared $^ $(CFLAGS) $(LIBS)
+
+clean:
+ rm -f $(TARGETLIB) *.o *.os
+
+# Install target - creates 'lib/' sub-directory in $(INSTALL_DIR) and copies all
+# executables to that location.
+install:
+ mkdir -p $(INSTALL_DIR)/lib
+ cp $(TARGETLIB) $(INSTALL_DIR)/lib
\ No newline at end of file
diff --git a/pyrp3/raw_memory.py b/pyrp3/raw_memory.py
index ce1b28e..233b82a 100644
--- a/pyrp3/raw_memory.py
+++ b/pyrp3/raw_memory.py
@@ -1,12 +1,9 @@
from ctypes import POINTER, c_uint32, cast, cdll, create_string_buffer, sizeof
-from importlib.machinery import EXTENSION_SUFFIXES
from pathlib import Path
import numpy as np
-libmonitor_file = str(
- Path(__file__).parent / ".." / "monitor{}".format(EXTENSION_SUFFIXES[0])
-)
+libmonitor_file = 'libmonitor.so'
libmonitor = cdll.LoadLibrary(libmonitor_file)
libmonitor.read_value.restype = c_uint32
diff --git a/setup.py b/setup.py
index 9302177..2258ddc 100644
--- a/setup.py
+++ b/setup.py
@@ -1,4 +1,28 @@
-from distutils.core import Extension, setup
+import os
+from distutils.core import setup
+from distutils.command.build import build
+
+
+build_dir = "monitor/"
+
+def compile_libmonitor():
+ cwd = os.getcwd() # get current directory
+ try:
+ os.chdir(build_dir)
+ os.system("make clean")
+ os.system("make all")
+ finally:
+ os.chdir(cwd)
+
+class lib_build(build):
+ def run(self):
+ compile_libmonitor()
+ build.run(self)
+
+setup_args = dict(
+ cmdclass={
+ "build": lib_build
+ }
+)
-setup_args = dict(ext_modules=[Extension("monitor", ["monitor/monitor.c"])])
setup(**setup_args)

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

@ -0,0 +1,5 @@
## Source Repository
Files in this directory were copied from [elhep/Fast-Servo-Firmware](https://github.com/elhep/Fast-Servo-Firmware/tree/master/fast_servo/pythonscripts).
## Commit ID
The files were copied from commit ID [7fae40c](https://github.com/elhep/Fast-Servo-Firmware/commit/7fae40c0f872a91218be378f8289b98b1e366729).

View File

View File

@ -0,0 +1,224 @@
# This file is part of Fast Servo Software Package.
#
# Copyright (C) 2023 Jakub Matyas
# Warsaw University of Technology <jakubk.m@gmail.com>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
import time
import spidev
from pyfastservo.common import (
ADC_AFE_CTRL_ADDR,
ADC_BITSLIP_ADDR,
ADC_CH0_HIGH_ADDR,
ADC_CH0_LOW_ADDR,
ADC_CH1_HIGH_ADDR,
ADC_CH1_LOW_ADDR,
ADC_DELAY_ADDR,
ADC_FRAME_ADDR,
AUX_ADC_ADDR,
MAP_MASK,
PAGESIZE,
write_to_memory,
read_from_memory
)
# /dev/spidev1.0 <=> spidev<BUS>.<DEVICE>
MAIN_ADC_BUS = 1
MAIN_ADC_DEVICE = 1
AUX_ADC_BUS = 1
AUX_ADC_PORT_A = 2
AUX_ADC_PORT_B = 3
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
low_word = test_pattern & 0xFF
spi_write(spi, 0x00, 0x80) # reset
spi_write(spi, 0x01, 0x20) # REGISTER A1: set to Two's complement Data Format
spi_write(spi, 0x02, 0x15) # REGISTER A2: set to LVDS output, set 4 data lanes and turn on test mode
spi_write(spi, 0x03, high_word) # REGISTER A3: test pattern high word
spi_write(spi, 0x04, low_word) # REGISTER A4: test pattern low word
def main_adc_test_mode(spi, enable):
reg_contents = 0x15 if enable else 0x11 # set to LVDS output, set 4 data lanes and turn on or off test mode
spi_write(spi, 0x02, reg_contents)
def verify_adc_registers(spi, reg_to_check):
for register, expected_value in reg_to_check.items():
value = spi_read(spi, register)
print(f"Spi readback register 0x{register:02x}: 0x{value:02x}")
if value != expected_value:
print(f"Different value read than sent in reg 0x{register:02x}")
def read_frame():
return read_from_memory(ADC_FRAME_ADDR, 1)[0]
def perform_bitslip():
for i in range(4):
current_frame = read_frame()
if current_frame & 0x0F != 0x0C:
print(f"Performing bitslip (iteration: {i}). Current frame: 0x{current_frame:02x}")
write_to_memory(ADC_BITSLIP_ADDR, 1)
else:
print(f"No bitslip required; Current frame: 0x{current_frame:02x}")
return
def mmcm_rst():
curr_cfg = read_from_memory(ADC_AFE_CTRL_ADDR, 1)[0] & 0x0F
write_to_memory(ADC_AFE_CTRL_ADDR, 0x10 | curr_cfg) # Reset MMCM
write_to_memory(ADC_AFE_CTRL_ADDR, 0x00 | curr_cfg) # Release MMCM Reset
while not(read_frame() & 0x10):
print(f"Waiting for MMCM to lock")
time.sleep(0.001)
def inc_ddr_clk_phase():
curr_cfg = read_from_memory(ADC_AFE_CTRL_ADDR, 1)[0] & 0x1F
write_to_memory(ADC_AFE_CTRL_ADDR, 0x40 | curr_cfg) # Set MMCM Phase Shift to be INC
write_to_memory(ADC_AFE_CTRL_ADDR, 0x60 | curr_cfg) # Assert MMCM Phase Shift EN High
write_to_memory(ADC_AFE_CTRL_ADDR, curr_cfg) # Deassert MMCM Phase Shift EN High
def dec_ddr_clk_phase():
curr_cfg = read_from_memory(ADC_AFE_CTRL_ADDR, 1)[0] & 0x1F
write_to_memory(ADC_AFE_CTRL_ADDR, 0x00 | curr_cfg) # Set MMCM Phase Shift to be DEC
write_to_memory(ADC_AFE_CTRL_ADDR, 0x20 | curr_cfg) # Assert MMCM Phase Shift EN High
write_to_memory(ADC_AFE_CTRL_ADDR, curr_cfg) # Deassert MMCM Phase Shift EN High
def find_edge():
prev_frame = read_frame()
for tap_delay in range(32):
write_to_memory(ADC_DELAY_ADDR, tap_delay)
current_frame = read_frame()
print(f"Tap delay: {tap_delay}, Current frame: 0x{current_frame:02x}")
print(f"prev_frame: 0x{prev_frame:02x}")
if current_frame != prev_frame:
final_delay = ((tap_delay+1) // 2) + 2
print(f"Edge detected; setting iDelay to: {final_delay}")
write_to_memory(ADC_DELAY_ADDR, final_delay)
return
prev_frame = current_frame
# If no edge detected
final_delay = 11
print(f"No edge detected; setting iDelay to: {final_delay}")
write_to_memory(ADC_DELAY_ADDR, final_delay)
def read_adc_channel(high_addr, low_addr):
return (read_from_memory(high_addr, 1)[0] << 8) | read_from_memory(low_addr, 1)[0]
def print_adc_channels():
adc_ch0 = read_adc_channel(ADC_CH0_HIGH_ADDR, ADC_CH0_LOW_ADDR)
adc_ch1 = read_adc_channel(ADC_CH1_HIGH_ADDR, ADC_CH1_LOW_ADDR)
print(f"Final ADC_CH0: 0x{adc_ch0:04x}")
print(f"Final ADC_CH1: 0x{adc_ch1:04x}")
def enable_adc_afe(ch1_x10=False, ch2_x10=False):
ctrl_value = (ch2_x10 << 1) | ch1_x10
write_to_memory(ADC_AFE_CTRL_ADDR, ctrl_value)
afe_ctrl = read_from_memory(ADC_AFE_CTRL_ADDR, 1)[0]
print(f"ADC_AFE_CTRL: 0x{afe_ctrl:02X}")
return afe_ctrl
def search_edge():
for tap_delay in range(32):
print(f"iDelay to: {tap_delay}")
write_to_memory(ADC_DELAY_ADDR, tap_delay)
time.sleep(1)
current_frame = read_frame()
print(f"Tap delay: {tap_delay}, Current frame: 0x{current_frame:02x}")
print_adc_channels()
def print_adc_channel(ch):
if ch == 0:
adc_ch0 = read_adc_channel(ADC_CH0_HIGH_ADDR, ADC_CH0_LOW_ADDR)
print(f"Final ADC_CH0: 0x{adc_ch0:04x}")
if ch == 1:
adc_ch1 = read_adc_channel(ADC_CH1_HIGH_ADDR, ADC_CH1_LOW_ADDR)
print(f"Final ADC_CH1: 0x{adc_ch1:04x}")
def find_min_max_ch(ch):
test = []
for i in range(100):
if ch == 0:
test.append(read_adc_channel(ADC_CH0_HIGH_ADDR, ADC_CH0_LOW_ADDR))
else:
test.append(read_adc_channel(ADC_CH1_HIGH_ADDR, ADC_CH1_LOW_ADDR))
print("ch", ch, hex(test[-1]))
print("Min:", hex(min(test)))
print("Max:", hex(max(test)))
print("Diff:", hex(max(test)-min(test)))
def configure_ltc2195():
spi = spidev.SpiDev()
try:
spi.open(MAIN_ADC_BUS, MAIN_ADC_DEVICE)
spi.max_speed_hz = 50000
spi.mode = 0b00 # CPOL = 0 CPHA = 0
spi.cshigh = False
test_pattern = 0x811F
main_adc_config(spi, test_pattern)
verify_adc_registers(spi, {
0x01: 0x20,
0x02: 0x15,
0x03: (test_pattern & 0xFF00) >> 8,
0x04: test_pattern & 0xFF
})
# ADC software reset put its PLL to sleep momentarily. Thus, MMCM needs to be reset as well.
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:
spi.close()
if __name__ == "__main__":
configure_ltc2195()

View File

@ -0,0 +1,120 @@
# This file is part of Fast Servo Software Package.
#
# Copyright (C) 2023 Jakub Matyas
# Warsaw University of Technology <jakubk.m@gmail.com>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
import os
import mmap
CSR_SIZE = 0x800
MAP_SIZE = 0x1000
MAP_MASK = 0xFFF
PAGESIZE = 0x1000
# LINIEN_OFFSET = 0x0
LINIEN_OFFSET = 0x300000
# ----------------------------------------------------------------
# FRONT PANEL LEDS REGISTER ADDRESSES
LED0_BASE_ADDR = 0x40005000 + LINIEN_OFFSET
LED1_BASE_ADDR = 0x40005800 + LINIEN_OFFSET
LED2_BASE_ADDR = 0x40006000 + LINIEN_OFFSET
LED3_BASE_ADDR = 0x40006800 + LINIEN_OFFSET
# ----------------------------------------------------------------
# DAC REGISTER ADDRESSES
ADC_BASE_ADDR = 0x40004800 + LINIEN_OFFSET
ADC_FRAME_OFFSET = 0x0
ADC_CH0_HIGH_OFFSET = 0x4
ADC_CH0_LOW_OFFSET = 0x8
ADC_CH1_HIGH_OFFSET = 0xC
ADC_CH1_LOW_OFFSET = 0x10
ADC_TAP_DELAY_OFFSET = 0x14
ADC_BITSLIP_OFFSET = 0x18
ADC_AFE_CTRL_OFFSET = 0x1C
ADC_FRAME_ADDR = ADC_BASE_ADDR + ADC_FRAME_OFFSET
ADC_CH0_HIGH_ADDR = ADC_BASE_ADDR + ADC_CH0_HIGH_OFFSET
ADC_CH0_LOW_ADDR = ADC_BASE_ADDR + ADC_CH0_LOW_OFFSET
ADC_CH1_HIGH_ADDR = ADC_BASE_ADDR + ADC_CH1_HIGH_OFFSET
ADC_CH1_LOW_ADDR = ADC_BASE_ADDR + ADC_CH1_LOW_OFFSET
ADC_DELAY_ADDR = ADC_BASE_ADDR + ADC_TAP_DELAY_OFFSET
ADC_BITSLIP_ADDR = ADC_BASE_ADDR + ADC_BITSLIP_OFFSET
ADC_AFE_CTRL_ADDR = ADC_BASE_ADDR + ADC_AFE_CTRL_OFFSET
AUX_ADC_ADDR = 0x40007800 + LINIEN_OFFSET
# ----------------------------------------------------------------
# DAC REGISTER ADDRESSES
DAC_BASE_ADDR = 0x40007000 + LINIEN_OFFSET
CTRL_OFFSET = 0x0
CH0_HIGH_WORD_OFFSET = 0x4
CH0_LOW_WORD_OFFSET = 0x8
CH1_HIGH_WORD_OFFSET = 0xC
CH1_LOW_WORD_OFFSET = 0x10
CTRL_ADDR = DAC_BASE_ADDR + CTRL_OFFSET
CH0_HIGH_WORD_ADDR = DAC_BASE_ADDR + CH0_HIGH_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_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

@ -0,0 +1,168 @@
# This file is part of Fast Servo Software Package.
#
# Copyright (C) 2023 Jakub Matyas
# Warsaw University of Technology <jakubk.m@gmail.com>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
import time
import spidev
from pyfastservo.common import (
CH0_HIGH_WORD_ADDR,
CH0_LOW_WORD_ADDR,
CH1_HIGH_WORD_ADDR,
CH1_LOW_WORD_ADDR,
CTRL_ADDR,
MAP_MASK,
PAGESIZE,
write_to_memory,
read_from_memory
)
# /dev/spidev2.0 <=> spidev<BUS>.<DEVICE>
MAIN_DAC_BUS = 2
MAIN_DAC_DEVICE = 0
DAC_VERSION = 0x0A
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 soft_reset(spi):
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)
def check_version(spi):
version = spi_read(spi, 0x1F)
print(f"DAC version: 0x{version:02X}")
return version == DAC_VERSION
def configure_dac(spi):
power_down_reg = spi_read(spi, 0x01)
spi_write(spi, 0x01, power_down_reg & ~(1 << 0)) # Clear EXTREF bit for internal reference
spi_write(spi, 0x0D, 0x00) # Set RREF to 10 kΩ for 1.0V reference
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)
def dac_self_calibration(spi):
spi_write(spi, 0x12, 0x00) # Reset calibration status
spi_write(spi, 0x0E, 0x08) # Enable calibration clock, default divide ratio
spi_write(spi, 0x0E, 0x38) # CALSELI = 1, CALSELQ = 1, CALCLK = 1
spi_write(spi, 0x12, 0x10) # Set CALEN bit
while True:
status = spi_read(spi, 0x0F)
if status & 0xC0 == 0xC0: # Both CALSTATI and CALSTATQ are 1
break
time.sleep(0.01)
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):
reg_contents = read_from_memory(CTRL_ADDR, 1)[0]
to_write = reg_contents | 0b1 if enable else reg_contents & 0b110
write_to_memory(CTRL_ADDR, to_write)
print(f"Set DAC Output Manual Override: {enable}")
def power_down_afe(channel, power_down=True):
assert channel in (0, 1)
bitmask = 1 << (channel + 1) & 0b111
reg_contents = read_from_memory(CTRL_ADDR, 1)[0]
value = (1 if power_down else 0) << (channel + 1)
reg_contents &= ~bitmask
to_write = reg_contents | value
write_to_memory(CTRL_ADDR, to_write)
reg_contents = read_from_memory(CTRL_ADDR, 1)[0]
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
# Note: DAC HIGH word and LOW word output are not updated
# at the same time. On scope, you will see more than one step
# of value changed.
write_to_memory(CH0_HIGH_WORD_ADDR, high_word)
write_to_memory(CH0_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:
print("Clock relationship is found")
return True
def configure_ad9117():
spi = spidev.SpiDev()
spi.open(MAIN_DAC_BUS, MAIN_DAC_DEVICE)
spi.max_speed_hz = 5000
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
power_down_afe(0, True)
power_down_afe(1, True)
configure_dac(spi)
check_clk_relationship(spi)
dac_self_calibration(spi)
# Enable DAC outputs
spi_write(spi, 0x01, spi_read(spi, 0x01) & ~((1 << 4) | (1 << 3)))
power_down_afe(0, False)
power_down_afe(1, False)
manual_override(False)
print("AD9117 configuration completed successfully")
return True
except Exception as e:
print(f"Error configuring AD9117: {e}")
return False
finally:
spi.close()
if __name__ == "__main__":
configure_ad9117()

View File

@ -0,0 +1,66 @@
# This file is part of Fast Servo Software Package.
#
# Copyright (C) 2023 Jakub Matyas
# Warsaw University of Technology <jakubk.m@gmail.com>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
import mmap
import os
import time
from pyfastservo.common import (
LED0_BASE_ADDR,
LED1_BASE_ADDR,
LED2_BASE_ADDR,
LED3_BASE_ADDR,
MAP_MASK,
PAGESIZE,
)
ON = 1
OFF = 0
def main():
addrs = [LED0_BASE_ADDR, LED1_BASE_ADDR, LED2_BASE_ADDR, LED3_BASE_ADDR]
f = os.open("/dev/mem", os.O_SYNC | os.O_RDWR)
for addr in addrs:
with mmap.mmap(
f,
PAGESIZE,
mmap.MAP_SHARED,
mmap.PROT_READ | mmap.PROT_WRITE,
offset=addr & ~MAP_MASK,
) as mem:
for i in range(6):
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] = ON.to_bytes(4, "little")
contents = mem[start_addr:stop_addr]
time.sleep(0.5)
mem[start_addr:stop_addr] = OFF.to_bytes(4, "little")
contents = mem[start_addr:stop_addr]
time.sleep(0.5)
os.close(f)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,28 @@
# This file is part of Fast Servo Software Package.
#
# Copyright (C) 2023 Jakub Matyas
# Warsaw University of Technology <jakubk.m@gmail.com>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from pyfastservo import adc, si5340, dac
def main():
si5340.configure_si5340()
adc.configure_ltc2195()
dac.configure_ad9117()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,280 @@
# This file is part of Fast Servo Software Package.
#
# Copyright (C) 2023 Jakub Matyas
# Warsaw University of Technology <jakubk.m@gmail.com>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# 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
BUS_NO = 0
IC_ADDR = 0x74
DEVICE_READY = 0x00FE
PLL_M_DEN = 0x023B
STATUS = 0x000C
STATUS_STICKY = 0x0011
STATUS_LOSREF = 0x04
STATUS_LOL = 0x08
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}")
def write_preamble(bus):
preamble = [
(0x0B24, 0xC0),
(0x0B25, 0x00),
(0x0502, 0x01),
(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():
with SMBus(BUS_NO) as bus:
if not wait_device_ready(bus):
print("Device not ready. Aborting.")
return
# Programming sequence from ClockBuilder Pro, default settings
# to initialize system using XTAL input
main_config = [
(0x0006, 0x00), # TOOL_VERSION
(0x0007, 0x00), # Not in datasheet
(0x0008, 0x00), # Not in datasheet
(0x000B, 0x74), # I2C_ADDR
(0x0017, 0xD0), # INT mask (disable interrupts)
(0x0018, 0xFF), # INT mask
(0x0021, 0x0F), # Select XTAL as input
(0x0022, 0x00), # Not in datasheet
(0x002B, 0x02), # SPI config
(0x002C, 0x20), # LOS enable for XTAL
(0x002D, 0x00), # LOS timing
(0x002E, 0x00), # LOS trigger (thresholds)
(0x002F, 0x00),
(0x0030, 0x00),
(0x0031, 0x00),
(0x0032, 0x00),
(0x0033, 0x00),
(0x0034, 0x00),
(0x0035, 0x00), # LOS trigger (thresholds) end
(0x0036, 0x00), # LOS clear (thresholds)
(0x0037, 0x00),
(0x0038, 0x00),
(0x0039, 0x00),
(0x003A, 0x00),
(0x003B, 0x00),
(0x003C, 0x00),
(0x003D, 0x00), # LOS clear (thresholds) end
(0x0041, 0x00), # LOS0_DIV_SEL
(0x0042, 0x00), # LOS1_DIV_SEL
(0x0043, 0x00), # LOS2_DIV_SEL
(0x0044, 0x00), # LOS3_DIV_SEL
(0x009E, 0x00), # LOL_SET_THR
(0x0102, 0x01), # Enable outputs
(0x013F, 0x00), # OUTX_ALWAYS_ON
(0x0140, 0x00), # OUTX_ALWAYS_ON
(0x0141, 0x40), # OUT_DIS_LOL_MSK, OUT_DIS_MSK_LOS_PFD
(0x0202, 0x00), # XAXB_FREQ_OFFSET (=0)
# PLL Configuration
(0x0235, 0x00), # M_NUM
(0x0236, 0x00),
(0x0237, 0x00),
(0x0238, 0x80),
(0x0239, 0x89),
(0x023A, 0x00),
(0x023B, 0x00), # M_DEN
(0x023C, 0x00),
(0x023D, 0x00),
(0x023E, 0x80),
# 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
# N1 Configuration (1:1 ratio)
(0x030D, 0x00), # N1_NUM
(0x030E, 0x00),
(0x030F, 0x00),
(0x0310, 0x00),
(0x0311, 0x00),
(0x0312, 0x01),
(0x0313, 0x00), # N1_DEN
(0x0314, 0x00),
(0x0315, 0x00),
(0x0316, 0x01),
(0x0317, 0x01), # N1_UPDATE
# N2 Configuration (1:1 ratio)
(0x0318, 0x00), # N2_NUM
(0x0319, 0x00),
(0x031A, 0x00),
(0x031B, 0x00),
(0x031C, 0x00),
(0x031D, 0x01),
(0x031E, 0x00), # N2_DEN
(0x031F, 0x00),
(0x0320, 0x00),
(0x0321, 0x01),
(0x0322, 0x01), # N2_UPDATE
# N3 Configuration (1:1 ratio)
(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
# Output configuration
(0x0112, 0x06), # OUT0 config
(0x0113, 0x09), # OUT0 format
(0x0114, 0x3B), # OUT0 CM/AMPL
(0x0115, 0x28), # OUT0 MUX_SEL
(0x0117, 0x06), # OUT1 config
(0x0118, 0x09), # OUT1 format
(0x0119, 0x3B), # OUT1 CM/AMPL
(0x011A, 0x28), # OUT1 MUX_SEL
(0x0126, 0x06), # OUT2 config
(0x0127, 0x09), # OUT2 format
(0x0128, 0x3B), # OUT2 CM/AMPL
(0x0129, 0x28), # OUT2 MUX_SEL
(0x012B, 0x06), # OUT3 config
(0x012C, 0xCC), # OUT3 format
(0x012D, 0x00), # OUT3 CM/AMPL
(0x012E, 0x58), # OUT3 MUX_SEL
# Miscellaneous configuration
(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)
]
write_preamble(bus)
time.sleep(0.3)
print("Writing main configuration...")
for address, value in main_config:
write_register(bus, address, value)
print("Main configuration written")
write_postamble(bus)
if not wait_for_lock(bus):
print("Error waiting for input clock or PLL lock")
else:
print("Input clock present and PLL locked")
bus.write_byte_data(IC_ADDR, STATUS_STICKY, 0)
# Final status check
pll_locked = check_pll_status(bus)
xaxb_signal_present = check_los_status(bus)
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__":
configure_si5340()

46
flake.lock generated
View File

@ -18,16 +18,16 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1703961334, "lastModified": 1734323986,
"narHash": "sha256-M1mV/Cq+pgjk0rt6VxoyyD+O8cOUiai8t9Q6Yyq4noY=", "narHash": "sha256-m/lh6hYMIWDYHCAsn81CDAiXoT3gmxXI9J987W5tZrE=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "b0d36bd0a420ecee3bc916c91886caca87c894e9", "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"
} }
@ -56,7 +56,43 @@
"root": { "root": {
"inputs": { "inputs": {
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"not-os": "not-os" "not-os": "not-os",
"src-migen": "src-migen",
"src-misoc": "src-misoc"
}
},
"src-migen": {
"flake": false,
"locked": {
"lastModified": 1727677091,
"narHash": "sha256-Zg3SQnTwMM/VkOGKogbPyuCC2NhLy8HB2SPEUWWNgCU=",
"owner": "m-labs",
"repo": "migen",
"rev": "c19ae9f8ae162ffe2d310a92bfce53ac2a821bc8",
"type": "github"
},
"original": {
"owner": "m-labs",
"repo": "migen",
"type": "github"
}
},
"src-misoc": {
"flake": false,
"locked": {
"lastModified": 1729234629,
"narHash": "sha256-TLsTCXV5AC2xh+bS7EhBVBKqdqIU3eKrnlWcFF9LtAM=",
"ref": "refs/heads/master",
"rev": "6085a312bca26adeca6584e37d08c8ba2e1d6e38",
"revCount": 2460,
"submodules": true,
"type": "git",
"url": "https://github.com/m-labs/misoc.git"
},
"original": {
"submodules": true,
"type": "git",
"url": "https://github.com/m-labs/misoc.git"
} }
} }
}, },

560
flake.nix
View File

@ -1,148 +1,379 @@
{ {
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";
outputs = { self, nixpkgs, not-os }: inputs.src-migen = { url = github:m-labs/migen; flake = false; };
inputs.src-misoc = { type = "git"; url = "https://github.com/m-labs/misoc.git"; submodules = true; flake = false; };
outputs = { self, nixpkgs, not-os, src-migen, src-misoc }:
let let
pkgs = import nixpkgs { system = "x86_64-linux"; }; pkgs = import nixpkgs { system = "x86_64-linux"; overlays = [ crosspkgs-overlay ]; };
not-os-cfg = not-os-configured.config.system; 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;
patches = [ patches = [
./network.patch ./not-os-patches/network.patch
./pr-28.patch ./not-os-patches/pr-28.patch
./pr-29.patch ./not-os-patches/pr-29.patch
./pr-30.patch ./not-os-patches/pr-30.patch
./not-os-patches/pr-31.patch
./not-os-patches/pr-33.patch
./not-os-patches/iproute2.patch
]; ];
}; };
not-os-configured = (import patched-not-os { crossSystem = {
inherit nixpkgs; system = "armv7l-linux";
extraModules = [ linux-kernel = {
"${patched-not-os}/zynq_image.nix" name = "zynq";
]; baseConfig = "multi_v7_defconfig";
system = "x86_64-linux"; target = "uImage";
crossSystem.system = "armv7l-linux"; installTarget = "uImage";
autoModules = false;
DTB = true;
makeFlags = [ "LOADADDR=0x8000" ];
};
};
crosspkgs-overlay = (self: super: {
pkgsCross = super.pkgsCross // {
zynq-baremetal = import super.path {
system = "x86_64-linux";
crossSystem = {
config = "arm-none-eabihf";
libc = "newlib";
gcc.cpu = "cortex-a9";
gcc.fpu = "vfpv3";
};
};
zynq-armv7l-linux = import super.path {
system = "x86_64-linux";
inherit crossSystem;
};
};
}); });
gnu-platform = "arm-none-eabi"; migen = pkgs.python3Packages.buildPythonPackage rec {
name = "migen";
binutils-pkg = { zlib, extraConfigureFlags ? [] }: pkgs.stdenv.mkDerivation rec { src = src-migen;
basename = "binutils"; format = "pyproject";
version = "2.30"; nativeBuildInputs = [ pkgs.python3Packages.setuptools ];
name = "${basename}-${gnu-platform}-${version}"; propagatedBuildInputs = [ pkgs.python3Packages.colorama ];
src = pkgs.fetchurl {
url = "https://ftp.gnu.org/gnu/binutils/binutils-${version}.tar.bz2";
sha256 = "028cklfqaab24glva1ks2aqa1zxa6w6xmc8q34zs1sb7h22dxspg";
};
configureFlags = [
"--enable-deterministic-archives"
"--target=${gnu-platform}"
"--with-cpu=cortex-a9"
"--with-fpu=vfpv3"
"--with-float=hard"
"--with-mode=thumb"
] ++ extraConfigureFlags;
outputs = [ "out" "info" "man" ];
depsBuildBuild = [ pkgs.buildPackages.stdenv.cc ];
buildInputs = [ zlib ];
enableParallelBuilding = true;
meta = {
description = "Tools for manipulating binaries (linker, assembler, etc.)";
longDescription = ''
The GNU Binutils are a collection of binary tools. The main
ones are `ld' (the GNU linker) and `as' (the GNU assembler).
They also include the BFD (Binary File Descriptor) library,
`gprof', `nm', `strip', etc.
'';
homepage = http://www.gnu.org/software/binutils/;
license = pkgs.lib.licenses.gpl3Plus;
/* Give binutils a lower priority than gcc-wrapper to prevent a
collision due to the ld/as wrappers/symlinks in the latter. */
priority = "10";
};
}; };
gcc-pkg = { gmp, mpfr, libmpc, platform-binutils, extraConfigureFlags ? [] }: pkgs.stdenv.mkDerivation rec { misoc = pkgs.python3Packages.buildPythonPackage {
basename = "gcc"; name = "misoc";
version = "9.1.0"; src = src-misoc;
name = "${basename}-${gnu-platform}-${version}"; propagatedBuildInputs = with pkgs.python3Packages; [ jinja2 numpy migen pyserial asyncserial ];
src = pkgs.fetchurl {
url = "https://ftp.gnu.org/gnu/gcc/gcc-${version}/gcc-${version}.tar.xz";
sha256 = "1817nc2bqdc251k0lpc51cimna7v68xjrnvqzvc50q3ax4s6i9kr";
};
preConfigure = ''
mkdir build
cd build
'';
configureScript = "../configure";
configureFlags = [
"--target=${gnu-platform}"
"--with-arch=armv7-a"
"--with-tune=cortex-a9"
"--with-fpu=vfpv3"
"--with-float=hard"
"--disable-libssp"
"--enable-languages=c"
"--with-as=${platform-binutils}/bin/${gnu-platform}-as"
"--with-ld=${platform-binutils}/bin/${gnu-platform}-ld" ] ++ extraConfigureFlags;
outputs = [ "out" "info" "man" ];
hardeningDisable = [ "format" "pie" ];
propagatedBuildInputs = [ gmp mpfr libmpc platform-binutils ];
enableParallelBuilding = true;
dontFixup = true;
}; };
newlib-pkg = { platform-binutils, platform-gcc }: pkgs.stdenv.mkDerivation rec { vivado = pkgs.buildFHSEnv {
pname = "newlib"; name = "vivado";
version = "3.1.0"; targetPkgs = pkgs: with pkgs; let
src = pkgs.fetchurl { # Apply patch from https://github.com/nix-community/nix-environments/pull/54
url = "ftp://sourceware.org/pub/newlib/newlib-${version}.tar.gz"; # to fix ncurses libtinfo.so's soname issue
sha256 = "0ahh3n079zjp7d9wynggwrnrs27440aac04340chf1p9476a2kzv"; ncurses' = ncurses5.overrideAttrs (old: {
}; configureFlags = old.configureFlags ++ [ "--with-termlib" ];
nativeBuildInputs = [ platform-binutils platform-gcc ]; postFixup = "";
configureFlags = [ });
"--target=${gnu-platform}" in [
libxcrypt-legacy
"--with-cpu=cortex-a9" (ncurses'.override { unicodeSupport = false; })
"--with-fpu=vfpv3" zlib
"--with-float=hard" libuuid
"--with-mode=thumb" xorg.libSM
"--enable-interwork" xorg.libICE
"--disable-multilib" xorg.libXrender
xorg.libX11
"--disable-newlib-supplied-syscalls" xorg.libXext
"--with-gnu-ld" xorg.libXtst
"--with-gnu-as" xorg.libXi
"--disable-newlib-io-float" freetype
"--disable-werror" fontconfig
]; ];
dontFixup = true; profile = "set -e; source /opt/Xilinx/Vivado/2024.2/settings64.sh";
runScript = "vivado";
}; };
gnutoolchain = rec { cma = pkgs-armv7l.python3Packages.buildPythonPackage rec {
binutils-bootstrap = pkgs.callPackage binutils-pkg { }; pname = "cma";
gcc-bootstrap = pkgs.callPackage gcc-pkg { version = "3.3.0";
platform-binutils = binutils-bootstrap; src = pkgs.fetchFromGitHub {
extraConfigureFlags = [ "--disable-libgcc" ]; owner = "CMA-ES";
repo = "pycma";
rev = "refs/tags/r${version}";
hash = "sha256-+UJI3hDVbDMfRF4bkwHED3eJCHzxS2hO4YPUzJqcoQI=";
}; };
newlib = pkgs.callPackage newlib-pkg {
platform-binutils = binutils-bootstrap; propagatedBuildInputs = [ pkgs-armv7l.python3Packages.numpy ];
platform-gcc = gcc-bootstrap;
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 {
pname = "pyrp3";
version = "2.1.0";
format = "pyproject";
src = pkgs.fetchFromGitHub {
owner = "linien-org";
repo = "pyrp3";
rev = "v${version}";
hash = "sha256-ol1QGXyCOei94iIPIocuTRHBxa5jKSH5RzjzROfZaBI=";
}; };
binutils = pkgs.callPackage binutils-pkg { patches = ./fast-servo/linien-pyrp3-monitor.patch;
extraConfigureFlags = [ "--with-lib-path=${newlib}/arm-none-eabi/lib" ]; nativeBuildInputs = [
}; pkgs-armv7l.python3Packages.setuptools
gcc = pkgs.callPackage gcc-pkg { pkgs-armv7l.gcc
platform-binutils = binutils; ];
extraConfigureFlags = [ "--enable-newlib" "--with-headers=${newlib}/arm-none-eabi/include" ]; postInstall = ''
cp monitor/libmonitor.so $out/lib
'';
postFixup = ''
substituteInPlace $out/${pkgs.python3.sitePackages}/pyrp3/raw_memory.py \
--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 {
pname = "linien-server";
inherit version;
src = linien-src;
pyproject = true;
sourceRoot = "${src.name}/linien-server";
postPatch = ''
cp ${fast-servo-gateware}/csrmap.py linien_server/csrmap.py
substituteInPlace linien_server/acquisition.py \
--replace " start_nginx()" "" \
--replace " stop_nginx()" "" \
--replace " flash_fpga()" ""
'';
nativeBuildInputs = [ pkgs-armv7l.python3Packages.setuptools ];
propagatedBuildInputs = with pkgs-armv7l.python3Packages; [
fire
influxdb-client
pylpsd
] ++ [
linien-common-armv7l
cma
pyrp3
];
};
fast-servo-gateware = pkgs.stdenv.mkDerivation rec {
name = "fast-servo-gateware";
src = linien-src;
nativeBuildInputs = [
(pkgs.python3.withPackages(ps: [
migen misoc
(ps.linien-common.overrideAttrs(oa: {
# config.py tries to access $HOME, but we do not need it for building gateware
postPatch = ''
echo > linien_common/config.py
echo > linien_common/__init__.py
'';
doCheck = false;
}))
]))
vivado
];
buildPhase = ''
python -m gateware.fpga_image_helper -p fastservo
'';
installPhase = ''
mkdir -p $out $out/nix-support
cp gateware/build/top.bit $out
cp linien-server/linien_server/gateware.bin $out
cp linien-server/linien_server/csrmap.py $out
echo file binary-dist $out/top.bit >> $out/nix-support/hydra-build-products
echo file binary-dist $out/gateware.bin >> $out/nix-support/hydra-build-products
'';
};
pyfastservo = pkgs-armv7l.python3Packages.buildPythonPackage rec {
name = "pyfastservo";
src = ./fast-servo;
preBuild = ''
cat > setup.py << EOF
from setuptools import setup
setup(
name="pyfastservo",
packages=["pyfastservo"],
install_requires=["spidev", "smbus2"],
entry_points = {"console_scripts": ["fp_leds=pyfastservo.fp_leds:main"]},
)
EOF
'';
propagatedBuildInputs = with pkgs-armv7l.python3Packages; [
spidev
smbus2
];
}; };
mkbootimage = pkgs.stdenv.mkDerivation { mkbootimage = pkgs.stdenv.mkDerivation {
@ -168,16 +399,38 @@
hardeningDisable = [ "fortify" ]; hardeningDisable = [ "fortify" ];
}; };
# Pinned qemu version due to networking errors in recent version 8.2.0
qemu = pkgs.qemu.overrideAttrs (oldAttrs: rec {
version = "8.1.3";
src = pkgs.fetchurl {
url = "https://download.qemu.org/qemu-${version}.tar.xz";
hash = "sha256-Q8wXaAQQVYb3T5A5jzTp+FeH3/QA07ZA2B93efviZbs=";
};
});
board-package-set = { board }: let board-package-set = { board }: let
not-os-configured = (import patched-not-os {
inherit nixpkgs;
extraModules = [
"${patched-not-os}/zynq_image.nix"
] ++ pkgs.lib.optionals (board == "fast-servo") [
({ config, pkgs, lib, ... }: {
environment.systemPackages = [
linien-server
(pkgs.python3.withPackages(ps: [ pyfastservo ]))
];
boot.postBootCommands = lib.mkAfter ''
# Program the FPGA
set +x
echo "Loading bitstream into SRAM..."
echo 0 > /sys/class/fpga_manager/fpga0/flags
mkdir -p /lib/firmware
cp ${fast-servo-gateware}/gateware.bin /lib/firmware/
echo gateware.bin > /sys/class/fpga_manager/fpga0/firmware
# Run device init scripts
echo "Initializing clock generator, ADC, and DAC..."
python3 -m pyfastservo.initialize
'';
})];
system = "x86_64-linux";
inherit crossSystem;
});
not-os-build = not-os-configured.config.system.build;
fsbl = pkgs.stdenv.mkDerivation { fsbl = pkgs.stdenv.mkDerivation {
name = "${board}-fsbl"; name = "${board}-fsbl";
src = pkgs.fetchFromGitHub { src = pkgs.fetchFromGitHub {
@ -187,9 +440,8 @@
sha256 = "sha256-UDz9KK/Hw3qM1BAeKif30rE8Bi6C2uvuZlvyvtJCMfw="; sha256 = "sha256-UDz9KK/Hw3qM1BAeKif30rE8Bi6C2uvuZlvyvtJCMfw=";
}; };
nativeBuildInputs = [ nativeBuildInputs = [
pkgs.gnumake pkgs.pkgsCross.zynq-baremetal.buildPackages.binutils
gnutoolchain.binutils pkgs.pkgsCross.zynq-baremetal.buildPackages.gcc
gnutoolchain.gcc
]; ];
postUnpack = '' postUnpack = ''
mkdir -p $sourceRoot/lib/sw_apps/zynq_fsbl/misc/fast-servo mkdir -p $sourceRoot/lib/sw_apps/zynq_fsbl/misc/fast-servo
@ -199,7 +451,11 @@
patches = [] ++ pkgs.lib.optional (board == "fast-servo") ./fast-servo/fsbl.patch; patches = [] ++ pkgs.lib.optional (board == "fast-servo") ./fast-servo/fsbl.patch;
postPatch = '' postPatch = ''
patchShebangs lib/sw_apps/zynq_fsbl/misc/copy_bsp.sh patchShebangs lib/sw_apps/zynq_fsbl/misc/copy_bsp.sh
echo 'SEARCH_DIR("${gnutoolchain.newlib}/arm-none-eabi/lib");' >> lib/sw_apps/zynq_fsbl/src/lscript.ld
for x in lib/sw_apps/zynq_fsbl/src/Makefile lib/sw_apps/zynq_fsbl/misc/copy_bsp.sh lib/bsp/standalone/src/arm/cortexa9/gcc/Makefile; do
substituteInPlace $x \
--replace "arm-none-eabi-" "arm-none-eabihf-"
done
''; '';
buildPhase = '' buildPhase = ''
cd lib/sw_apps/zynq_fsbl/src cd lib/sw_apps/zynq_fsbl/src
@ -213,9 +469,8 @@
dontFixup = true; dontFixup = true;
}; };
u-boot = let u-boot = (pkgs-armv7l.buildUBoot {
fast-servo-dts = fast-servo/fast-servo.dts; name = "${board}-u-boot";
in (pkgs.pkgsCross.armv7l-hf-multiplatform.buildUBoot {
defconfig = "xilinx_zynq_virt_defconfig"; defconfig = "xilinx_zynq_virt_defconfig";
patches = [] ++ pkgs.lib.optional (board == "fast-servo") ./fast-servo/u-boot.patch; patches = [] ++ pkgs.lib.optional (board == "fast-servo") ./fast-servo/u-boot.patch;
preConfigure = '' preConfigure = ''
@ -225,7 +480,7 @@
CONFIG_SYS_PROMPT="${board}-boot> " CONFIG_SYS_PROMPT="${board}-boot> "
CONFIG_AUTOBOOT=y CONFIG_AUTOBOOT=y
CONFIG_BOOTCOMMAND="${builtins.replaceStrings [ "\n" ] [ "; " ] '' CONFIG_BOOTCOMMAND="${builtins.replaceStrings [ "\n" ] [ "; " ] ''
setenv bootargs 'root=/dev/mmcblk0p2 console=ttyPS0,115200n8 systemConfig=${builtins.unsafeDiscardStringContext not-os-cfg.build.toplevel}' setenv bootargs 'root=/dev/mmcblk0p2 console=ttyPS0,115200n8 systemConfig=${builtins.unsafeDiscardStringContext not-os-build.toplevel}'
fatload mmc 0 0x6400000 uImage fatload mmc 0 0x6400000 uImage
fatload mmc 0 0x8000000 ${board}.dtb fatload mmc 0 0x8000000 ${board}.dtb
fatload mmc 0 0xA400000 uRamdisk.image.gz fatload mmc 0 0xA400000 uRamdisk.image.gz
@ -238,7 +493,7 @@
filesToInstall = [ "u-boot.elf" ]; filesToInstall = [ "u-boot.elf" ];
}).overrideAttrs (oldAttrs: { }).overrideAttrs (oldAttrs: {
postUnpack = '' postUnpack = ''
cp ${fast-servo-dts} $sourceRoot/arch/arm/dts/zynq-fast-servo.dts cp ${fast-servo/fast-servo.dts} $sourceRoot/arch/arm/dts/zynq-fast-servo.dts
''; '';
postInstall = '' postInstall = ''
mkdir -p $out/dts mkdir -p $out/dts
@ -269,7 +524,7 @@
echo file binary-dist $out/boot.bin >> $out/nix-support/hydra-build-products echo file binary-dist $out/boot.bin >> $out/nix-support/hydra-build-products
''; '';
dtb = pkgs.runCommand "dtb" dtb = pkgs.runCommand "${board}-dtb"
{ {
buildInputs = [ pkgs.gcc pkgs.dtc ]; buildInputs = [ pkgs.gcc pkgs.dtc ];
} }
@ -289,14 +544,14 @@
sd-image = let sd-image = let
rootfsImage = pkgs.callPackage (pkgs.path + "/nixos/lib/make-ext4-fs.nix") { rootfsImage = pkgs.callPackage (pkgs.path + "/nixos/lib/make-ext4-fs.nix") {
storePaths = [ not-os-cfg.build.toplevel ]; storePaths = [ not-os-build.toplevel ];
volumeLabel = "ROOT"; volumeLabel = "ROOT";
}; };
# Current firmware (kernel, bootimage, etc..) takes ~18MB # Current firmware (kernel, bootimage, etc..) takes ~18MB
firmwareSize = 30; firmwareSize = 30;
firmwarePartitionOffset = 8; firmwarePartitionOffset = 8;
in pkgs.stdenv.mkDerivation { in pkgs.stdenv.mkDerivation {
name = "sd-image"; name = "${board}-sd-image";
nativeBuildInputs = with pkgs; [ dosfstools mtools libfaketime util-linux parted ]; nativeBuildInputs = with pkgs; [ dosfstools mtools libfaketime util-linux parted ];
buildCommand = '' buildCommand = ''
mkdir -p $out/nix-support $out/sd-image mkdir -p $out/nix-support $out/sd-image
@ -330,8 +585,8 @@
mkdir firmware mkdir firmware
cp ${bootimage}/boot.bin firmware/ cp ${bootimage}/boot.bin firmware/
cp ${dtb}/${board}.dtb firmware/ cp ${dtb}/${board}.dtb firmware/
cp ${not-os-cfg.build.kernel}/uImage firmware/ cp ${not-os-build.kernel}/uImage firmware/
cp ${not-os-cfg.build.uRamdisk}/initrd firmware/uRamdisk.image.gz cp ${not-os-build.uRamdisk}/initrd firmware/uRamdisk.image.gz
(cd firmware; mcopy -psvm -i ../firmware_part.img ./* ::) (cd firmware; mcopy -psvm -i ../firmware_part.img ./* ::)
dd conv=notrunc if=firmware_part.img of=$img seek=$START count=$SECTORS dd conv=notrunc if=firmware_part.img of=$img seek=$START count=$SECTORS
@ -341,10 +596,12 @@
not-os-qemu = let not-os-qemu = let
qemuScript = '' qemuScript = ''
#!/bin/bash #!/bin/bash
export PATH=${qemu}/bin:$PATH export PATH=${pkgs.qemu}/bin:$PATH
IMGDIR=$(mktemp -d /tmp/not-os-qemu-XXXXXX) IMGDIR=$(mktemp -d /tmp/not-os-qemu-XXXXXX)
BASE=$(realpath $(dirname $0)) BASE=$(realpath $(dirname $0))
qemu-img create -F raw -f qcow2 -b $BASE/sd-image.img $IMGDIR/sd-overlay.qcow2 512M
qemu-img convert -O qcow2 -f raw -o preallocation=metadata $BASE/sd-image.img $IMGDIR/sd-sparse.qcow2
qemu-img create -F qcow2 -f qcow2 -b $IMGDIR/sd-sparse.qcow2 $IMGDIR/sd-overlay.qcow2 2G
# Some command arguments are based from samples in Xilinx QEMU User Documentation # Some command arguments are based from samples in Xilinx QEMU User Documentation
# See: https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/821854273/Running+Bare+Metal+Applications+on+QEMU # See: https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/821854273/Running+Bare+Metal+Applications+on+QEMU
@ -359,7 +616,7 @@
rm -rf $IMGDIR rm -rf $IMGDIR
''; '';
in pkgs.runCommand "not-os-qemu" { in pkgs.runCommand "${board}-qemu" {
inherit qemuScript; inherit qemuScript;
passAsFile = [ "qemuScript" ]; passAsFile = [ "qemuScript" ];
preferLocalBuild = true; preferLocalBuild = true;
@ -382,13 +639,22 @@
"${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;
}; };
packages.armv7l-linux = packages.armv7l-linux = {
(board-package-set { board = "zc706"; }) // inherit fast-servo-gateware linien-server;
(board-package-set { board = "fast-servo"; }); } //
(board-package-set { board = "zc706"; }) //
(board-package-set { board = "fast-servo"; });
hydraJobs = packages.x86_64-linux // packages.armv7l-linux; hydraJobs = packages.x86_64-linux // packages.armv7l-linux;
}; };

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..8e317ec 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,8 +14,24 @@ index 7eaee32..8e317ec 100644
not-os.simpleStaticIp = mkOption { not-os.simpleStaticIp = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
@@ -93,8 +98,14 @@ with lib; @@ -84,17 +89,25 @@ with lib;
build-cores = 4 };
environment.etc = {
"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.writeClosure [ pkgs.bash ]}); do if test -d $i; then echo $i; fi; done)
cat > $out << EOF
- build-use-sandbox = true
+ auto-optimise-store = true
build-users-group = nixbld
- build-sandbox-paths = /bin/sh=${pkgs.runtimeShell} $(echo $extraPaths)
- build-max-jobs = 1
- build-cores = 4
+ cores = 0
+ extra-sandbox-paths = /bin/sh=${pkgs.runtimeShell} $(echo $extraPaths)
+ max-jobs = auto
+ sandbox = true
+ trusted-users = root
EOF EOF
''; '';
+ "ssl/certs/ca-certificates.crt".source = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"; + "ssl/certs/ca-certificates.crt".source = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
@ -136,10 +152,10 @@ 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..727e3ef 100644 index 3fa23ab..069fe89 100644
--- a/zynq_image.nix --- a/zynq_image.nix
+++ b/zynq_image.nix +++ b/zynq_image.nix
@@ -1,66 +1,96 @@ @@ -1,66 +1,89 @@
-{ config, pkgs, ... }: -{ config, pkgs, ... }:
+{ lib, config, pkgs, ... }: +{ lib, config, pkgs, ... }:
@ -148,22 +164,7 @@ index 3fa23ab..727e3ef 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 {
+ crosspkgs = import pkgs.path { + customKernel = (pkgs.linux_6_6.override {
+ system = "x86_64-linux";
+ crossSystem = {
+ system = "armv7l-linux";
+ linux-kernel = {
+ name = "zynq";
+ baseConfig = "multi_v7_defconfig";
+ target = "uImage";
+ installTarget = "uImage";
+ autoModules = false;
+ DTB = true;
+ makeFlags = [ "LOADADDR=0x8000" ];
+ };
+ };
+ };
+ customKernel = (crosspkgs.linux.override {
extraConfig = '' extraConfig = ''
OVERLAY_FS y OVERLAY_FS y
+ MEDIA_SUPPORT n + MEDIA_SUPPORT n
@ -172,16 +173,23 @@ index 3fa23ab..727e3ef 100644
+ SOUND n + SOUND n
+ SQUASHFS n + SQUASHFS n
+ BACKLIGHT_CLASS_DEVICE n + BACKLIGHT_CLASS_DEVICE n
+ FPGA y
+ FPGA_BRIDGE y
+ FPGA_REGION y
+ OF_FPGA_REGION y
+ FPGA_MGR_ZYNQ_FPGA y
+ OF_OVERLAY y
''; '';
- }; - };
- customKernelPackages = pkgs.linuxPackagesFor customKernel;
+ }).overrideAttrs (oa: { + }).overrideAttrs (oa: {
+ postInstall = '' + postInstall = ''
+ cp arch/arm/boot/uImage $out + if [ -e arch/arm/boot/uImage ]; then
+ cp arch/arm/boot/uImage $out
+ fi
+ ${oa.postInstall} + ${oa.postInstall}
+ ''; + '';
+ }); + });
+ customKernelPackages = crosspkgs.linuxPackagesFor customKernel; customKernelPackages = pkgs.linuxPackagesFor customKernel;
in { in {
imports = [ ./arm32-cross-fixes.nix ]; imports = [ ./arm32-cross-fixes.nix ];
boot.kernelPackages = customKernelPackages; boot.kernelPackages = customKernelPackages;
@ -232,17 +240,17 @@ index 3fa23ab..727e3ef 100644
- chmod +x qemu-script - chmod +x qemu-script
- patchShebangs qemu-script - patchShebangs qemu-script
- ls -ltrh - ls -ltrh
''; - '';
- system.build.rpi_image_tar = pkgs.runCommand "dist.tar" {} '' - system.build.rpi_image_tar = pkgs.runCommand "dist.tar" {} ''
- mkdir -p $out/nix-support - mkdir -p $out/nix-support
- tar -cvf $out/dist.tar ${config.system.build.rpi_image} - tar -cvf $out/dist.tar ${config.system.build.rpi_image}
- echo "file binary-dist $out/dist.tar" >> $out/nix-support/hydra-build-products - echo "file binary-dist $out/dist.tar" >> $out/nix-support/hydra-build-products
- ''; '';
- environment.systemPackages = [ pkgs.strace ]; - environment.systemPackages = [ pkgs.strace ];
- 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

@ -0,0 +1,28 @@
diff --git a/runit.nix b/runit.nix
index d7b0bf3..64f99f2 100644
--- a/runit.nix
+++ b/runit.nix
@@ -57,6 +57,23 @@ in
'';
"runit/3".source = pkgs.writeScript "3" ''
#!${pkgs.runtimeShell}
+ echo Waiting for services to stop...
+ sv force-stop /etc/service/*
+ sv exit /etc/service/*
+
+ echo Sending TERM signal to processes...
+ pkill --inverse -s0,1 -TERM
+ sleep 1
+ echo Sending KILL signal to processes...
+ pkill --inverse -s0,1 -KILL
+
+ echo Unmounting filesystems, disabling swap...
+ swapoff -a
+ umount -r -a -t nosysfs,noproc,nodevtmpfs,notmpfs
+ echo Remounting rootfs read-only...
+ mount -o remount,ro /
+
+ sync
echo and down we go
'';
"service/sshd/run".source = pkgs.writeScript "sshd_run" ''

1105
not-os-patches/pr-33.patch Normal file

File diff suppressed because it is too large Load Diff