From 3dd751f30e7541ac0d0e89508f222cc9d78301a3 Mon Sep 17 00:00:00 2001 From: dspitzba <daniel.spitzbart@cern.ch> Date: Fri, 5 May 2023 18:59:29 -0400 Subject: [PATCH 01/11] SCA mapping default change for module PCB v0, will be obsolete soon --- configs/SCA_mapping_v2.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/SCA_mapping_v2.yaml b/configs/SCA_mapping_v2.yaml index 7cd5e0e..47f9138 100644 --- a/configs/SCA_mapping_v2.yaml +++ b/configs/SCA_mapping_v2.yaml @@ -182,7 +182,7 @@ gpio: mod_d00: pin: 0x1E default: 0 - direction: out + direction: in flavor: small comment: pin 32 in ETROC 0 and 1 mod_d01: -- GitLab From 3c974d6c47c8055daa3a1abc748002a02c866d1f Mon Sep 17 00:00:00 2001 From: dspitzba <daniel.spitzbart@cern.ch> Date: Fri, 5 May 2023 19:00:04 -0400 Subject: [PATCH 02/11] increasing frequency tolerance by 500 Hz because we're sometimes just slightly outside --- tamalero/KCU.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tamalero/KCU.py b/tamalero/KCU.py index e65230b..7e35c84 100644 --- a/tamalero/KCU.py +++ b/tamalero/KCU.py @@ -177,7 +177,7 @@ class KCU: # print("%s = %6.2f MHz" % (id, freq)) errs = 0 - tolerance = 2500 # increased tolerance to 2.5kHz (from 2kHz) + tolerance = 3000 # increased tolerance to 3.0kHz (from 2kHz) for clock in clocks: freq = self.read_node(clock[0]).value() expect = clock[1] -- GitLab From b3b7aeab9d8fe72f95ec95ddc411504b68c6e0fb Mon Sep 17 00:00:00 2001 From: dspitzba <daniel.spitzbart@cern.ch> Date: Fri, 5 May 2023 19:01:06 -0400 Subject: [PATCH 03/11] adding utility functions for new configurations, fw download, majority vote --- tamalero/utils.py | 50 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/tamalero/utils.py b/tamalero/utils.py index f96bde7..d6d7ad9 100644 --- a/tamalero/utils.py +++ b/tamalero/utils.py @@ -1,5 +1,6 @@ import math import numpy as np +from itertools import combinations from time import sleep from yaml import load, dump import os @@ -210,6 +211,16 @@ def make_version_header(res): def chunk(in_list, n): return [in_list[i * n:(i + 1) * n] for i in range((len(in_list) + n - 1) // n )] +def get_last_commit_sha(version): + import requests + import json + + + r2 = requests.get(f"https://gitlab.cern.ch/api/v4/projects/107856/repository/commits?ref=devel") + log = json.loads(r2.content) + last_commit_sha = log[0]['id'][:7] + return last_commit_sha + def download_address_table(version): import os import requests @@ -219,7 +230,7 @@ def download_address_table(version): r2 = requests.get(f"https://gitlab.cern.ch/api/v4/projects/107856/repository/commits?ref=devel") log = json.loads(r2.content) - last_commit_sha = log[0]['id'][:7] + last_commit_sha = get_last_commit_sha(version) r = requests.get(f"https://gitlab.cern.ch/api/v4/projects/107856/repository/tree?ref={version}&&path=address_tables&&recursive=True") tree = json.loads(r.content) @@ -234,7 +245,7 @@ def download_address_table(version): tree = json.loads(r.content) print (f"Local firmware version detected. Will download address table corresponding to commit {version}.") - + print("Making directory: address_table/{version}") os.makedirs(f"address_table/{version}") for f in tree: if f['type'] == 'tree': @@ -316,9 +327,12 @@ def get_kcu(kcu_address, control_hub=True, host='localhost', verbose=False): if verbose: print (f"Address table hash: {xml_sha}") - if not os.path.isdir(f"address_table/{xml_sha}"): - print ("Downloading latest firmware version address table.") + last_commit = get_last_commit_sha(xml_sha) + if not os.path.isdir(f"address_table/{last_commit}"): + print (f"Downloading latest firmware version address table to address_table/{last_commit}") xml_sha = download_address_table(xml_sha) + else: + xml_sha = last_commit kcu = KCU(name="my_device", ipb_path=ipb_path, @@ -328,6 +342,34 @@ def get_kcu(kcu_address, control_hub=True, host='localhost', verbose=False): return kcu +def get_config(config, version='v2', verbose=False): + default_cfg = load_yaml(os.path.join(here, f'../configs/rb_default_{version}.yaml')) + if config != 'default': + updated_cfg = load_yaml(os.path.join(here, f'../configs/{config}_{version}.yaml')) + for chip in ['SCA', 'LPGBT']: + for interface in ['adc', 'gpio']: + if updated_cfg[chip][interface] is not None: + for k in updated_cfg[chip][interface]: + if verbose: + print(f"\n - Updating configuration for {chip}, {interface}, {k} to:") + print(updated_cfg[chip][interface][k]) + default_cfg[chip][interface][k] = updated_cfg[chip][interface][k] + return default_cfg + +def majority_vote(values, majority=None): + from functools import reduce + if majority is None: + majority = len(values)-1 + combs = combinations(range(len(values)), majority) + votes = [] + for comb in combs: + #print(comb) + tmp_list = [values[i] for i in comb] + votes.append(reduce(lambda x, y: x & y, tmp_list)) + + #print(votes) + return reduce(lambda x, y: x | y, votes) + if __name__ == '__main__': print ("Temperature example:") print (get_temp(0.8159, 1.5, 10000, 25, 10000, 3900)) -- GitLab From ea0fbfeca755d8d05105d0d7bde3588fd0e857b9 Mon Sep 17 00:00:00 2001 From: dspitzba <daniel.spitzbart@cern.ch> Date: Fri, 5 May 2023 19:02:22 -0400 Subject: [PATCH 04/11] single configurations for different setups instead of SCA and lpGBT files. fixing lpGBT serial number --- configs/emulator_v2.yaml | 25 ++ configs/modulev0_v2.yaml | 211 +++++++++++++++++ configs/rb_default_v2.yaml | 468 +++++++++++++++++++++++++++++++++++++ tamalero/LPGBT.py | 117 ++++++---- tamalero/ReadoutBoard.py | 19 +- tamalero/SCA.py | 37 ++- test_modulev0.py | 162 +++++++++++++ test_tamalero.py | 7 +- 8 files changed, 985 insertions(+), 61 deletions(-) create mode 100644 configs/emulator_v2.yaml create mode 100644 configs/modulev0_v2.yaml create mode 100644 configs/rb_default_v2.yaml create mode 100644 test_modulev0.py diff --git a/configs/emulator_v2.yaml b/configs/emulator_v2.yaml new file mode 100644 index 0000000..6321b87 --- /dev/null +++ b/configs/emulator_v2.yaml @@ -0,0 +1,25 @@ +SCA: + adc: + gpio: + mod_d01: + pin: 0x1F + default: 0 + direction: out + flavor: small + comment: pin 30 in ETROC 0 and 1 + mod_d09: + pin: 0x19 + default: 0 + direction: out + flavor: small + comment: pin 30 in ETROC 4 and 5 + mod_d17: + pin: 0x0E + default: 0 + direction: out + flavor: small + comment: pin 30 in ETROC 8 and 9 + +LPGBT: + adc: + gpio: diff --git a/configs/modulev0_v2.yaml b/configs/modulev0_v2.yaml new file mode 100644 index 0000000..65c2179 --- /dev/null +++ b/configs/modulev0_v2.yaml @@ -0,0 +1,211 @@ +SCA: + adc: + mod_a00: + pin: 0x0B + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 20 in ETROC 0 and 1 + mod_a01: + pin: 0x0C + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 18 in ETROC 0 and 1 + mod_a02: + pin: 0x0E + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 16 in ETROC 0 and 1 + mod_a03: + pin: 0x0F + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 14 in ETROC 0 and 1 + mod_a04: + pin: 0x03 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 21 in ETROC 2 and 3 + mod_a05: + pin: 0x01 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 23 in ETROC 2 and 3 + mod_a06: + pin: 0x02 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 25 in ETROC 2 and 3 + mod_a07: + pin: 0x0 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 27 in ETROC 2 and 3 + mod_a08: + pin: 0x12 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 20 in ETROC 4 and 5 + mod_a09: + pin: 0x15 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 18 in ETROC 4 and 5 + mod_a10: + pin: 0x14 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 16 in ETROC 4 and 5 + mod_a11: + pin: 0x11 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 14 in ETROC 4 and 5 + mod_a12: + pin: 0x05 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 21 in ETROC 6 and 7 + mod_a13: + pin: 0x06 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 23 in ETROC 6 and 7 + mod_a14: + pin: 0x08 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 25 in ETROC 6 and 7 + mod_a15: + pin: 0x09 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 27 in ETROC 6 and 7 + mod_a16: + pin: 0x17 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 20 in ETROC 8 and 9 + mod_a17: + pin: 0x16 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 18 in ETROC 8 and 9 + mod_a18: + pin: 0x13 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 16 in ETROC 8 and 9 + mod_a19: + pin: 0x10 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 14 in ETROC 8 and 9 + mod_a20: + pin: 0x0D + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 21 in ETROC 10 and 11 + mod_a21: + pin: 0x0A + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 23 in ETROC 10 and 11 + mod_a22: + pin: 0x07 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 25 in ETROC 10 and 11 + mod_a23: + pin: 0x04 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 27 in ETROC 10 and 11 + + gpio: + mod_d00: + pin: 0x1E + default: 1 + direction: out + flavor: small + comment: 2.5V for ETROC on module 1. 1 = 2.5V is OFF, 0 = 2.5V is ON + mod_d01: + pin: 0x1F + default: 0 + direction: out + flavor: small + comment: enable FEAST on module 1 + mod_d08: + pin: 0x16 + default: 1 + direction: out + flavor: small + comment: 2.5V for ETROC on module 2. 1 = 2.5V is OFF, 0 = 2.5V is ON + mod_d09: + pin: 0x19 + default: 0 + direction: out + flavor: small + comment: enable FEAST on module 2 + mod_d16: + pin: 0x0F + default: 1 + direction: out + flavor: small + comment: 2.5V for ETROC on module 3. 1 = 2.5V is OFF, 0 = 2.5V is ON + mod_d17: + pin: 0x0E + default: 0 + direction: out + flavor: small + comment: enable FEAST on module 3 +LPGBT: + adc: + gpio: diff --git a/configs/rb_default_v2.yaml b/configs/rb_default_v2.yaml new file mode 100644 index 0000000..7f99e79 --- /dev/null +++ b/configs/rb_default_v2.yaml @@ -0,0 +1,468 @@ +SCA: + adc: + mod_a00: + pin: 0x0B + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 20 in ETROC 0 and 1 + mod_a01: + pin: 0x0C + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 18 in ETROC 0 and 1 + mod_a02: + pin: 0x0E + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 16 in ETROC 0 and 1 + mod_a03: + pin: 0x0F + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 14 in ETROC 0 and 1 + mod_a04: + pin: 0x03 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 21 in ETROC 2 and 3 + mod_a05: + pin: 0x01 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 23 in ETROC 2 and 3 + mod_a06: + pin: 0x02 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 25 in ETROC 2 and 3 + mod_a07: + pin: 0x0 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 27 in ETROC 2 and 3 + mod_a08: + pin: 0x12 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 20 in ETROC 4 and 5 + mod_a09: + pin: 0x15 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 18 in ETROC 4 and 5 + mod_a10: + pin: 0x14 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 16 in ETROC 4 and 5 + mod_a11: + pin: 0x11 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 14 in ETROC 4 and 5 + mod_a12: + pin: 0x05 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 21 in ETROC 6 and 7 + mod_a13: + pin: 0x06 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 23 in ETROC 6 and 7 + mod_a14: + pin: 0x08 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 25 in ETROC 6 and 7 + mod_a15: + pin: 0x09 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 27 in ETROC 6 and 7 + mod_a16: + pin: 0x17 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 20 in ETROC 8 and 9 + mod_a17: + pin: 0x16 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 18 in ETROC 8 and 9 + mod_a18: + pin: 0x13 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 16 in ETROC 8 and 9 + mod_a19: + pin: 0x10 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 14 in ETROC 8 and 9 + mod_a20: + pin: 0x0D + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 21 in ETROC 10 and 11 + mod_a21: + pin: 0x0A + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 23 in ETROC 10 and 11 + mod_a22: + pin: 0x07 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 25 in ETROC 10 and 11 + mod_a23: + pin: 0x04 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 27 in ETROC 10 and 11 + LV_RB: + pin: 0x1C + conv: 11. + flavor: small + comment: low voltage + VDAC: + pin: 0x1D + conv: 1. + flavor: small + comment: temperature sensor + + gpio: + mod_d00: + pin: 0x1E + default: 1 + direction: in + flavor: small + comment: pin 32 in ETROC 0 and 1 + mod_d01: + pin: 0x1F + default: 0 + direction: in + flavor: small + comment: pin 30 in ETROC 0 and 1 + mod_d02: + pin: 0x1D + default: 0 + direction: in + flavor: small + comment: pin 28 in ETROC 0 and 1 + mod_d03: + pin: 0x1C + default: 0 + direction: in + flavor: small + comment: pin 26 in ETROC 0 and 1 + mod_d04: + pin: 0x00 + default: 0 + direction: in + flavor: small + comment: pin 9 in ETROC 2 and 3 + mod_d05: + pin: 0x02 + default: 0 + direction: in + flavor: small + comment: pin 11 in ETROC 2 and 3 + mod_d06: + pin: 0x01 + default: 0 + direction: in + flavor: small + comment: pin 13 in ETROC 2 and 3 + mod_d07: + pin: 0x03 + default: 0 + direction: in + flavor: small + comment: pin 15 in ETROC 2 and 3 + mod_d08: + pin: 0x16 + default: 1 + direction: in + flavor: small + comment: pin 32 in ETROC 4 and 5 + mod_d09: + pin: 0x19 + default: 0 + direction: in + flavor: small + comment: pin 30 in ETROC 4 and 5 + mod_d10: + pin: 0x13 + default: 0 + direction: in + flavor: small + comment: pin 28 in ETROC 4 and 5 + mod_d11: + pin: 0x10 + default: 0 + direction: in + flavor: small + comment: pin 26 in ETROC 4 and 5 + mod_d12: + pin: 0x0A + default: 0 + direction: in + flavor: small + comment: pin 9 in ETROC 6 and 7 + mod_d13: + pin: 0x04 + default: 0 + direction: in + flavor: small + comment: pin 11 in ETROC 6 and 7 + mod_d14: + pin: 0x07 + default: 0 + direction: in + flavor: small + comment: pin 13 in ETROC 6 and 7 + mod_d15: + pin: 0x0D + default: 0 + direction: in + flavor: small + comment: pin 15 in ETROC 6 and 7 + mod_d16: + pin: 0x0F + default: 1 + direction: in + flavor: small + comment: pin 32 in ETROC 8 and 9 + mod_d17: + pin: 0x0E + default: 0 + direction: in + flavor: small + comment: pin 30 in ETROC 8 and 9 + mod_d18: + pin: 0x0C + default: 0 + direction: in + flavor: small + comment: pin 28 in ETROC 8 and 9 + mod_d19: + pin: 0x0B + default: 0 + direction: in + flavor: small + comment: pin 26 in ETROC 8 and 9 + mod_d20: + pin: 0x09 + default: 0 + direction: in + flavor: small + comment: pin 9 in ETROC 10 and 11 + mod_d21: + pin: 0x08 + default: 0 + direction: in + flavor: small + comment: pin 11 in ETROC 10 and 11 + mod_d22: + pin: 0x06 + default: 0 + direction: in + flavor: small + comment: pin 13 in ETROC 10 and 11 + mod_d23: + pin: 0x05 + default: 0 + direction: in + flavor: small + comment: pin 15 in ETROC 10 and 11 + sca_led: + pin: 0x1B + default: 1 + direction: out + flavor: small + comment: SCA LED indicator + +LPGBT: + adc: + TH1: + pin: 0x00 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: VTRX TH1 + 1V4D_ADC: + pin: 0x01 + conv: 1.82 + min: 1.12 + max: 1.68 + flavor: small + comment: 1V4D * 0.55 + 1V5A_ADC: + pin: 0x02 + conv: 1.82 + min: 1.2 + max: 1.8 + flavor: small + comment: 1V5D * 0.55 + 2V5TX_ADC: + pin: 0x03 + conv: 3.0 + min: 2.0 + max: 3.0 + flavor: small + comment: 2V5TX * 0.33 + RSSI_ADC: + pin: 0x04 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: RSSI + ADC5: + pin: 0x05 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: N/A + 2V5RX_ADC: + pin: 0x06 + conv: 3.0 + min: 2.0 + max: 3.0 + flavor: small + comment: 2V5RX * 0.33 + VTEMP_ADC: + pin: 0x07 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: RT1 + EOM_ADC: + pin: 0x08 + conv: 1 + flavor: small + comment: EOM DAC (internal signal) + VDDIO: + pin: 0x09 + conv: 2.38 + flavor: small + comment: VDDIO * 0.42 (internal signal) + VDDTX: + pin: 0x0a + conv: 2.38 + flavor: small + comment: VDDTX * 0.42 (internal signal) + VDDRX: + pin: 0x0b + conv: 2.38 + flavor: small + comment: VDDRX * 0.42 (internal signal) + VDD: + pin: 0x0c + conv: 2.38 + flavor: small + comment: VDD * 0.42 (internal signal) + VDDA: + pin: 0x0d + conv: 2.38 + flavor: small + comment: VDDA * 0.42 (internal signal) + TEMP: + pin: 0x0e + conv: 1 + flavor: small + comment: Temperature sensor (internal signal) + VREF: + pin: 0x0f + conv: 2.0 + flavor: small + comment: VREF/2 (internal signal) + gpio: + SCA_RESETB: + pin: 0x00 + default: 1 + direction: out + flavor: small + comment: GBT SCA reset + LED_0: + pin: 0x01 + default: 1 + direction: out + flavor: small + comment: LPGBT GPIO configuration LED + LED_1: + pin: 0x02 + default: 0 + direction: out + flavor: small + comment: tamalero LED + LED_RHETT: + pin: 0x03 + default: 1 + direction: out + flavor: small + comment: success LED + LD_RSTN: + pin: 0x0A + default: 1 + direction: out + flavor: small + comment: VTRX reset + LD_DIS: + pin: 0x0D + default: 0 + direction: out + flavor: small + comment: VTRX DIS diff --git a/tamalero/LPGBT.py b/tamalero/LPGBT.py index 6f98b0e..7152a24 100644 --- a/tamalero/LPGBT.py +++ b/tamalero/LPGBT.py @@ -8,7 +8,7 @@ import json from functools import wraps import tamalero.colors as colors from tamalero.colors import red, green -from tamalero.utils import read_mapping, chunk, load_yaml +from tamalero.utils import read_mapping, chunk, load_yaml, get_config, majority_vote from time import sleep from datetime import datetime try: @@ -35,7 +35,7 @@ def gpio_byname(gpio_func): class LPGBT(RegParser): - def __init__(self, rb=0, trigger=False, flavor='small', master=None, kcu=None, do_adc_calibration=False): + def __init__(self, rb=0, trigger=False, flavor='small', master=None, kcu=None, do_adc_calibration=False, config='default'): ''' Initialize lpGBT for a certain readout board number (rb). The trigger lpGBT is accessed through I2C of the master (= DAQ lpGBT). @@ -54,6 +54,7 @@ class LPGBT(RegParser): if kcu != None: self.kcu = kcu + self.config = config self.configure(do_adc_calibration=do_adc_calibration) def configure(self, do_adc_calibration=True): @@ -168,22 +169,25 @@ class LPGBT(RegParser): def set_adc_mapping(self): assert self.ver in [0, 1], f"Unrecognized version {self.ver}" - if self.ver == 0: - self.adc_mapping = read_mapping(os.path.expandvars('$TAMALERO_BASE/configs/LPGBT_mapping.yaml'), 'adc') - elif self.ver == 1: - self.adc_mapping = read_mapping(os.path.expandvars('$TAMALERO_BASE/configs/LPGBT_mapping_v2.yaml'), 'adc') + self.adc_mapping = get_config(self.config, version=f'v{self.ver+1}')['LPGBT']['adc'] + #if self.ver == 0: + # self.adc_mapping = read_mapping(os.path.expandvars('$TAMALERO_BASE/configs/LPGBT_mapping.yaml'), 'adc') + #elif self.ver == 1: + # self.adc_mapping = read_mapping(os.path.expandvars('$TAMALERO_BASE/configs/LPGBT_mapping_v2.yaml'), 'adc') def set_gpio_mapping(self): assert self.ver in [0, 1], f"Unrecognized version {self.ver}" - if self.ver == 0: - self.gpio_mapping = read_mapping(os.path.expandvars('$TAMALERO_BASE/configs/LPGBT_mapping.yaml'), 'gpio') - elif self.ver == 1: - self.gpio_mapping = read_mapping(os.path.expandvars('$TAMALERO_BASE/configs/LPGBT_mapping_v2.yaml'), 'gpio') + self.gpio_mapping = get_config(self.config, version=f'v{self.ver+1}')['LPGBT']['gpio'] + #if self.ver == 0: + # self.gpio_mapping = read_mapping(os.path.expandvars('$TAMALERO_BASE/configs/LPGBT_mapping.yaml'), 'gpio') + #elif self.ver == 1: + # self.gpio_mapping = read_mapping(os.path.expandvars('$TAMALERO_BASE/configs/LPGBT_mapping_v2.yaml'), 'gpio') def update_ver(self, new_ver): - assert new_ver in [1, 2], f"Unrecognized version {new_ver}" + assert new_ver in [0, 1], f"Unrecognized version {new_ver}" self.ver = new_ver self.set_adc_mapping() + self.set_gpio_mapping() def link_status(self, verbose=False): if self.trigger: @@ -314,32 +318,36 @@ class LPGBT(RegParser): def wr_adr(self, adr, data): if self.trigger: - raise NotImplementedError("rd_adr does only read from the master lpGBT, and you're trying to write to a servant") - #defer = not self.kcu.auto_dispatch # if auto dispatch is turned off, keep it off. - #self.kcu.toggle_dispatch() # turn off auto dispatch for this transaction - #self.kcu.write_node("READOUT_BOARD_%d.SC.TX_GBTX_ADDR" % self.rb, 115) - self.kcu.write_node("READOUT_BOARD_%d.SC.TX_REGISTER_ADDR" % self.rb, adr) - self.kcu.write_node("READOUT_BOARD_%d.SC.TX_DATA_TO_GBTX" % self.rb, data) - self.kcu.action("READOUT_BOARD_%d.SC.TX_WR" % self.rb) - self.kcu.action("READOUT_BOARD_%d.SC.TX_START_WRITE" % self.rb) - #return self.kcu.read_node("READOUT_BOARD_%d.SC.RX_DATA_FROM_GBTX" % self.rb) - #if not defer: # turn auto dispatch back on only if it wasn't set to false before - # self.kcu.dispatch() - #self.rd_flush() + return self.master.I2C_write(adr, data) + #raise NotImplementedError("rd_adr does only read from the master lpGBT, and you're trying to write to a servant") + else: + #defer = not self.kcu.auto_dispatch # if auto dispatch is turned off, keep it off. + #self.kcu.toggle_dispatch() # turn off auto dispatch for this transaction + #self.kcu.write_node("READOUT_BOARD_%d.SC.TX_GBTX_ADDR" % self.rb, 115) + self.kcu.write_node("READOUT_BOARD_%d.SC.TX_REGISTER_ADDR" % self.rb, adr) + self.kcu.write_node("READOUT_BOARD_%d.SC.TX_DATA_TO_GBTX" % self.rb, data) + self.kcu.action("READOUT_BOARD_%d.SC.TX_WR" % self.rb) + self.kcu.action("READOUT_BOARD_%d.SC.TX_START_WRITE" % self.rb) + #return self.kcu.read_node("READOUT_BOARD_%d.SC.RX_DATA_FROM_GBTX" % self.rb) + #if not defer: # turn auto dispatch back on only if it wasn't set to false before + # self.kcu.dispatch() + #self.rd_flush() def rd_adr(self, adr): if self.trigger: - raise NotImplementedError("rd_adr does only read from the master lpGBT, and you're trying to read from a servant") - self.kcu.write_node("READOUT_BOARD_%d.SC.TX_REGISTER_ADDR" % self.rb, adr) - self.kcu.action("READOUT_BOARD_%d.SC.TX_START_READ" % self.rb) - valid = self.kcu.read_node("READOUT_BOARD_%d.SC.RX_DATA_VALID" % self.rb).valid() - if valid: - # this only means that the KCU successfully read data - # not necessarily does it mean there's communication with the lpGBT - return self.kcu.read_node("READOUT_BOARD_%d.SC.RX_DATA_FROM_GBTX" % self.rb) - - print("LpGBT read failed!") - return None + return self.master.I2C_read(adr) + #raise NotImplementedError("rd_adr does only read from the master lpGBT, and you're trying to read from a servant") + else: + self.kcu.write_node("READOUT_BOARD_%d.SC.TX_REGISTER_ADDR" % self.rb, adr) + self.kcu.action("READOUT_BOARD_%d.SC.TX_START_READ" % self.rb) + valid = self.kcu.read_node("READOUT_BOARD_%d.SC.RX_DATA_VALID" % self.rb).valid() + if valid: + # this only means that the KCU successfully read data + # not necessarily does it mean there's communication with the lpGBT + return self.kcu.read_node("READOUT_BOARD_%d.SC.RX_DATA_FROM_GBTX" % self.rb) + + print("LpGBT read failed!") + return None def wr_reg(self, id, data): node = self.get_node(id) @@ -752,9 +760,9 @@ class LPGBT(RegParser): return serial != 0 if (self.ver==0): - serial = self.get_chip_userid() + serial = str(self.get_chip_userid()) else: - serial = self.get_chip_serial() + serial = str(self.get_chip_serial()) cal_file = "lpgbt_adc_calibrations.json" @@ -769,7 +777,7 @@ class LPGBT(RegParser): if serial_valid(serial) and serial in cal_data and not recalibrate: gain = cal_data[serial]['gain'] offset = cal_data[serial]['offset'] - print("Loaded ADC calibration data for chip %d. Gain: %f / Offset: %d" % (serial, gain, offset)) + print("Loaded ADC calibration data for chip %s. Gain: %f / Offset: %d" % (serial, gain, offset)) # else, determine calibration constants else: @@ -788,6 +796,7 @@ class LPGBT(RegParser): self.wr_reg("LPGBT.RW.ADC.VDDMONENA", initial_val) type = "Trigger" if self.trigger else "DAQ" print("Calibrated %s ADC. Gain: %f / Offset: %d" % (type, gain, offset)) + print("Chip %s"%serial) if gain < 1.65 or gain > 2 or offset < 490 or offset > 530: raise RuntimeError("ADC Calibration Failed!") @@ -1429,10 +1438,36 @@ class LPGBT(RegParser): self.rd_reg("LPGBT.RWF.CHIPID.USERID0") def get_chip_serial(self): - return self.rd_reg("LPGBT.RWF.CHIPID.CHIPID3") << 24 |\ - self.rd_reg("LPGBT.RWF.CHIPID.CHIPID2") << 16 |\ - self.rd_reg("LPGBT.RWF.CHIPID.CHIPID1") << 8 |\ - self.rd_reg("LPGBT.RWF.CHIPID.CHIPID0") + if self.ver == 1: + # NOTE we have to read from the fuses directly. + # ideally this can still be verified (May 2023) + self.wr_adr(0x119, 0x1 << 1) # write FuseRead https://lpgbt.web.cern.ch/lpgbt/v1/registermap.html#reg-fusecontrol + while True: + # wait for FuseDataValid https://lpgbt.web.cern.ch/lpgbt/v1/registermap.html#reg-fusestatus + if self.rd_adr(0x1b1) >> 2 == 1: break + + chipids = [] + # there should be 5 copies of the chipid, but I can only find 4 + # there's nothing else in the fuses that's non-zero + for i in range(4): + self.wr_adr(0x11f, i) + chipids.append(self.rd_adr(0x1b2) << 24 | self.rd_adr(0x1b3) << 16 | self.rd_adr(0x1b4) << 8 | self.rd_adr(0x1b5) << 24) + + self.wr_adr(0x119, 0) # write FuseRead https://lpgbt.web.cern.ch/lpgbt/v1/registermap.html#reg-fusecontrol + + if all([c==chipids[0] for c in chipids]): + return chipids[0] + else: + print("CHIPD serial needs majority vote") + return majority_vote(chipids, majority=3) + + elif self.ver == 0: + # NOTE: this is what's supposed to work for lpGBT v0 + # but note sure if that's actually true + return self.rd_reg("LPGBT.RWF.CHIPID.CHIPID3") << 24 |\ + self.rd_reg("LPGBT.RWF.CHIPID.CHIPID2") << 16 |\ + self.rd_reg("LPGBT.RWF.CHIPID.CHIPID1") << 8 |\ + self.rd_reg("LPGBT.RWF.CHIPID.CHIPID0") def get_power_up_state_machine(self, quiet=True): diff --git a/tamalero/ReadoutBoard.py b/tamalero/ReadoutBoard.py index 92dd53c..ff35243 100644 --- a/tamalero/ReadoutBoard.py +++ b/tamalero/ReadoutBoard.py @@ -8,22 +8,23 @@ from time import sleep class ReadoutBoard: - def __init__(self, rb=0, trigger=True, flavor='small', kcu=None): + def __init__(self, rb=0, trigger=True, flavor='small', kcu=None, config='default'): ''' create a readout board. trigger: if true, also configure a trigger lpGBT ''' self.rb = rb self.flavor = flavor - self.ver = 1 + self.ver = 2 + self.config = config self.trigger = trigger - self.DAQ_LPGBT = LPGBT(rb=rb, flavor=flavor, kcu=kcu) + self.DAQ_LPGBT = LPGBT(rb=rb, flavor=flavor, kcu=kcu, config=self.config) self.VTRX = VTRX(self.DAQ_LPGBT) # This is not yet recommended: #for adr in [0x06, 0x0A, 0x0E, 0x12]: # self.VTRX.wr_adr(adr, 0x20) - self.SCA = SCA(rb=rb, flavor=flavor, ver=self.DAQ_LPGBT.ver) + self.SCA = SCA(rb=rb, flavor=flavor, ver=self.DAQ_LPGBT.ver, config=self.config) if kcu != None: self.kcu = kcu @@ -32,7 +33,11 @@ class ReadoutBoard: if self.DAQ_LPGBT.ver == 1: self.ver = 2 self.SCA.update_ver(self.ver) - self.DAQ_LPGBT.set_adc_mapping() + self.DAQ_LPGBT.update_ver(self.ver-1) # FIXME we need to disentangle lpGBT version from RB version + elif self.DAQ_LPGBT.ver == 0: + self.ver = 1 + self.SCA.update_ver(self.ver) + self.DAQ_LPGBT.update_ver(self.ver-1) # FIXME we need to disentangle lpGBT version from RB version self.SCA.connect_KCU(kcu) def get_trigger(self): @@ -52,7 +57,7 @@ class ReadoutBoard: print ("Trigger lpGBT was found, but will not be added.") if self.trigger: - self.TRIG_LPGBT = LPGBT(rb=self.rb, flavor=self.flavor, trigger=True, master=self.DAQ_LPGBT, kcu=self.kcu) + self.TRIG_LPGBT = LPGBT(rb=self.rb, flavor=self.flavor, trigger=True, master=self.DAQ_LPGBT, kcu=self.kcu, config=self.config) def connect_KCU(self, kcu): @@ -291,6 +296,8 @@ class ReadoutBoard: self.SCA.reset() self.SCA.connect() try: + print("version in SCA", self.SCA.ver) + print("config in SCA", self.SCA.config) self.SCA.config_gpios() # this sets the directions etc according to the mapping except TimeoutError: print ("SCA config failed. Will continue without SCA.") diff --git a/tamalero/SCA.py b/tamalero/SCA.py index f744058..2809d9c 100644 --- a/tamalero/SCA.py +++ b/tamalero/SCA.py @@ -1,6 +1,7 @@ import os import random -from tamalero.utils import read_mapping +from tamalero.utils import read_mapping, get_config +from functools import wraps import time try: from tabulate import tabulate @@ -110,34 +111,43 @@ class SCA_I2C: I2C_R_DATA3 = 0x71 # read from data register 3 I2C_RW_DATA_OFFSET = 16 # offset to access data register 1, 2, 3 +def gpio_byname(gpio_func): + @wraps(gpio_func) + def wrapper(lpgbt, pin, direction=1): + if isinstance(pin, str): + gpio_dict = lpgbt.gpio_mapping + pin = gpio_dict[pin]['pin'] + return gpio_func(lpgbt, pin, direction) + elif isinstance(pin, int): + return gpio_func(lpgbt, pin, direction) + else: + invalid_type = type(pin) + raise TypeError(f"{gpio_func.__name__} can only take positional arguments of type int or str, but argument of type {invalid_type} was given.") + + return wrapper class SCA: - def __init__(self, rb=0, flavor='small', ver=0): + def __init__(self, rb=0, flavor='small', ver=0, config='default'): self.rb = rb self.flavor = flavor self.err_count = 0 self.ver = ver + 1 # NOTE don't particularly like this, but we're giving it the lpGBT version + self.config = config + self.locked = False self.set_adc_mapping() self.set_gpio_mapping() - self.locked = False def connect_KCU(self, kcu): self.kcu = kcu def set_adc_mapping(self): assert self.ver in [1, 2], f"Unrecognized version {self.ver}" - if self.ver == 1: - self.adc_mapping = read_mapping(os.path.expandvars('$TAMALERO_BASE/configs/SCA_mapping.yaml'), 'adc') - elif self.ver == 2: - self.adc_mapping = read_mapping(os.path.expandvars('$TAMALERO_BASE/configs/SCA_mapping_v2.yaml'), 'adc') + self.adc_mapping = get_config(self.config, version=f'v{self.ver}')['SCA']['adc'] def set_gpio_mapping(self): assert self.ver in [1, 2], f"Unrecognized version {self.ver}" - if self.ver == 1: - self.gpio_mapping = read_mapping(os.path.expandvars('$TAMALERO_BASE/configs/SCA_mapping.yaml'), 'gpio') - elif self.ver == 2: - self.gpio_mapping = read_mapping(os.path.expandvars('$TAMALERO_BASE/configs/SCA_mapping_v2.yaml'), 'gpio') + self.gpio_mapping = get_config(self.config, version=f'v{self.ver}')['SCA']['gpio'] def update_ver(self, new_ver): assert new_ver in [1, 2], f"Unrecognized version {new_ver}" @@ -447,6 +457,7 @@ class SCA: val = self.rw_reg(SCA_GPIO.GPIO_R_DATAIN).value() return int((val >> line) & 1) + @gpio_byname def set_gpio(self, line, to=1): self.enable_gpio() # enable GPIO currently_set = self.rw_reg(SCA_GPIO.GPIO_R_DATAOUT).value() @@ -458,6 +469,7 @@ class SCA: self.rw_reg(SCA_GPIO.GPIO_W_DATAOUT, currently_set) return self.read_gpio(line) # in order to check it is actually set + @gpio_byname def set_gpio_direction(self, line, to=1): self.enable_gpio() # enable GPIO currently_set = self.rw_reg(SCA_GPIO.GPIO_R_DIRECTION).value() @@ -491,8 +503,9 @@ class SCA: default = gpio_dict[gpio_reg]['default'] if verbose: print("Setting SCA GPIO pin %s (%s) to %s"%(pin, comment, gpio_dict[gpio_reg]['direction'])) + self.set_gpio(pin, default) # NOTE this is important because otherwise the GPIO pin can be set to a false default value when switched to output self.set_gpio_direction(pin, direction) - self.set_gpio(pin, default) + self.set_gpio(pin, default) # redundant but keep it def get_I2C_channel(self, channel): channel_str = hex(channel).upper()[-1] diff --git a/test_modulev0.py b/test_modulev0.py new file mode 100644 index 0000000..5a4692e --- /dev/null +++ b/test_modulev0.py @@ -0,0 +1,162 @@ +from tamalero.KCU import KCU +from tamalero.ReadoutBoard import ReadoutBoard +from tamalero.utils import header, make_version_header, get_kcu, check_repo_status +from tamalero.FIFO import FIFO +from tamalero.DataFrame import DataFrame +from tamalero.ETROC import ETROC +from tamalero.Module import Module + +from tamalero.SCA import SCA_CONTROL + +import time +import random +import sys +import os +import uhal +from emoji import emojize + +if __name__ == '__main__': + + + import argparse + + argParser = argparse.ArgumentParser(description = "Argument parser") + argParser.add_argument('--verbose', action='store_true', default=False, help="Verbose power up sequence") + argParser.add_argument('--power_up', action='store_true', default=False, help="Do lpGBT power up init?") + argParser.add_argument('--reconfigure', action='store_true', default=False, help="Configure the RB electronics: SCA and lpGBT?") + argParser.add_argument('--adcs', action='store_true', default=False, help="Read ADCs?") + argParser.add_argument('--i2c_temp', action='store_true', default=False, help="Do temp monitoring on I2C from lpGBT?") + argParser.add_argument('--i2c_sca', action='store_true', default=False, help="I2C tests on SCA?") + argParser.add_argument('--kcu', action='store', default="192.168.0.10", help="Specify the IP address for KCU") + argParser.add_argument('--control_hub', action='store_true', default=False, help="Use control hub for communication?") + argParser.add_argument('--host', action='store', default='localhost', help="Specify host for control hub") + argParser.add_argument('--configuration', action='store', default='modulev0', choices=['default', 'emulator', 'modulev0'], help="Specify a configuration of the RB, e.g. emulator or modulev0") + argParser.add_argument('--devel', action='store_true', default=False, help="Don't check repo status (not recommended)") + argParser.add_argument('--connection_test', action='store_true', default=False, help="Check the PCB connections.") + args = argParser.parse_args() + + + verbose = args.verbose + + #------------------------------------------------------------------------------- + # Try to Connect to the KCU105 + #------------------------------------------------------------------------------- + + print ("Using KCU at address: %s"%args.kcu) + + kcu = None + rb_0 = None + + # write to the loopback node of the KCU105 to check ethernet communication + kcu = get_kcu(args.kcu, control_hub=args.control_hub, host=args.host, verbose=args.verbose) + if (kcu == 0): + # if not basic connection was established the get_kcu function returns 0 + # this would cause the RB init to fail. + sys.exit(1) + + + rb_0 = ReadoutBoard(0, kcu=kcu, config=args.configuration) + data = 0xabcd1234 + kcu.write_node("LOOPBACK.LOOPBACK", data) + if (data != kcu.read_node("LOOPBACK.LOOPBACK")): + print("No communications with KCU105... quitting") + sys.exit(1) + + is_configured = rb_0.DAQ_LPGBT.is_configured() + if not is_configured: + print("RB is not configured, exiting.") + exit(0) + header(configured=is_configured) + + if not args.devel: + check_repo_status(kcu_version=kcu.get_firmware_version(verbose=True)) + + rb_0.VTRX.get_version() + + if not hasattr(rb_0, "TRIG_LPGBT"): + rb_0.get_trigger() + + res = rb_0.DAQ_LPGBT.get_board_id() + res['trigger'] = 'yes' if rb_0.trigger else 'no' + + if (verbose): + make_version_header(res) + + if args.adcs: + print("\n\nReading GBT-SCA ADC values:") + rb_0.SCA.read_adcs(check=True, strict_limits=args.strict) + + print("\n\nReading DAQ lpGBT ADC values:") + rb_0.DAQ_LPGBT.read_adcs(check=True, strict_limits=args.strict) + + # High level reading of temperatures + temp = rb_0.read_temp(verbose=True) + + #------------------------------------------------------------------------------- + # Read SCA + #------------------------------------------------------------------------------- + + if args.i2c_sca: + + print("Writing and Reading I2C_ctrl register:") + for n in range(10): + wr = random.randint(0, 100) + rb_0.SCA.I2C_write_ctrl(channel=3, data=wr) + rd = rb_0.SCA.I2C_read_ctrl(channel=3) + print("write: {} \t read: {}".format(wr, rd)) + + print("Testing multi-byte read:") + multi_out = rb_0.SCA.I2C_read_multi(channel=3, servant = 0x48, nbytes=2) + print("servant: 0x48, channel: 3, nbytes: 2, output = {}".format(multi_out)) + + print("Testing multi-byte write:") + + write_value = [0x2, 25, (27&240)] + print("servant: 0x48, channel: 3, nbytes: 2, data:{}".format(write_value)) + rb_0.SCA.I2C_write_multi(write_value, channel=3, servant=0x48) + read_value = rb_0.SCA.I2C_read_multi(channel=3, servant=0x48, nbytes = 2, reg=0x2) + + if read_value == write_value[1:]: + print ("write/read successful!") + print("read value = {}".format(rb_0.SCA.I2C_read_multi(channel=3, servant=0x48, nbytes = 2, reg=0x2))) + + + #------------------------------------------------------------------------------- + # Success LEDs + #------------------------------------------------------------------------------- + rb_0.DAQ_LPGBT.set_gpio("LED_1", 1) # Set LED1 after tamalero finishes succesfully + rb_0.DAQ_LPGBT.set_gpio("LED_RHETT", 1) # Set LED1 after tamalero finishes succesfully + if rb_0.DAQ_LPGBT.ver == 1 and args.connection_test: + print("Toggling FEAST and 2.5V on/off for 1min") + t_end = time.time() + 60 + while time.time() < t_end: + rb_0.DAQ_LPGBT.set_gpio("LED_1", 1) # Let Rhett LED blink for 10s + rb_0.DAQ_LPGBT.set_gpio("LED_RHETT", 1) # Let Rhett LED blink for 10s + rb_0.SCA.set_gpio("mod_d00", 1) + rb_0.SCA.set_gpio("mod_d01", 1) + rb_0.SCA.set_gpio("mod_d08", 1) + rb_0.SCA.set_gpio("mod_d09", 1) + rb_0.SCA.set_gpio("mod_d16", 1) + rb_0.SCA.set_gpio("mod_d17", 1) + time.sleep(2.0) + rb_0.DAQ_LPGBT.set_gpio("LED_1", 0) + rb_0.DAQ_LPGBT.set_gpio("LED_RHETT", 0) + rb_0.SCA.set_gpio("mod_d00", 0) + rb_0.SCA.set_gpio("mod_d01", 0) + rb_0.SCA.set_gpio("mod_d08", 0) + rb_0.SCA.set_gpio("mod_d09", 0) + rb_0.SCA.set_gpio("mod_d16", 0) + rb_0.SCA.set_gpio("mod_d17", 0) + time.sleep(2.0) + rb_0.DAQ_LPGBT.set_gpio("LED_1", 1) + rb_0.DAQ_LPGBT.set_gpio("LED_RHETT", 1) + + # disabling 2.5V + rb_0.SCA.set_gpio("mod_d00", 1) + rb_0.SCA.set_gpio("mod_d08", 1) + rb_0.SCA.set_gpio("mod_d16", 1) + + # enabling FEAST + rb_0.SCA.set_gpio("mod_d01", 1) + rb_0.SCA.set_gpio("mod_d09", 1) + rb_0.SCA.set_gpio("mod_d17", 1) diff --git a/test_tamalero.py b/test_tamalero.py index a1adf0f..57d941c 100644 --- a/test_tamalero.py +++ b/test_tamalero.py @@ -39,6 +39,7 @@ if __name__ == '__main__': argParser.add_argument('--recal_lpgbt', action='store_true', default=False, help="Recalibrate ADC in LPGBT? (instead of using saved values)") argParser.add_argument('--control_hub', action='store_true', default=False, help="Use control hub for communication?") argParser.add_argument('--host', action='store', default='localhost', help="Specify host for control hub") + argParser.add_argument('--configuration', action='store', default='default', choices=['default', 'emulator', 'modulev0'], help="Specify a configuration of the RB, e.g. emulator or modulev0") argParser.add_argument('--devel', action='store_true', default=False, help="Don't check repo status (not recommended)") argParser.add_argument('--monitor', action='store_true', default=False, help="Start up montoring threads in the background") argParser.add_argument('--strict', action='store_true', default=False, help="Enforce strict limits on ADC reads for SCA and LPGBT") @@ -63,7 +64,9 @@ if __name__ == '__main__': # if not basic connection was established the get_kcu function returns 0 # this would cause the RB init to fail. sys.exit(1) - rb_0 = ReadoutBoard(0, trigger=(not args.force_no_trigger), kcu=kcu) + + + rb_0 = ReadoutBoard(0, trigger=(not args.force_no_trigger), kcu=kcu, config=args.configuration) data = 0xabcd1234 kcu.write_node("LOOPBACK.LOOPBACK", data) if (data != kcu.read_node("LOOPBACK.LOOPBACK")): @@ -159,7 +162,7 @@ if __name__ == '__main__': # Module Status #------------------------------------------------------------------------------- - if args.verbose: + if args.verbose and args.configuration == 'emulator': print("Configuring ETROCs") modules = [] for i in range(res['n_module']): -- GitLab From 8551043583e0131bdade4e9b2de4a7a2d72605b0 Mon Sep 17 00:00:00 2001 From: dspitzba <daniel.spitzbart@cern.ch> Date: Fri, 5 May 2023 18:59:29 -0400 Subject: [PATCH 05/11] SCA mapping default change for module PCB v0, will be obsolete soon --- configs/SCA_mapping_v2.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/SCA_mapping_v2.yaml b/configs/SCA_mapping_v2.yaml index 7cd5e0e..47f9138 100644 --- a/configs/SCA_mapping_v2.yaml +++ b/configs/SCA_mapping_v2.yaml @@ -182,7 +182,7 @@ gpio: mod_d00: pin: 0x1E default: 0 - direction: out + direction: in flavor: small comment: pin 32 in ETROC 0 and 1 mod_d01: -- GitLab From c60a5e314067014e348f74afb699a1cf6a6b45e9 Mon Sep 17 00:00:00 2001 From: dspitzba <daniel.spitzbart@cern.ch> Date: Fri, 5 May 2023 19:00:04 -0400 Subject: [PATCH 06/11] increasing frequency tolerance by 500 Hz because we're sometimes just slightly outside --- tamalero/KCU.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tamalero/KCU.py b/tamalero/KCU.py index e65230b..7e35c84 100644 --- a/tamalero/KCU.py +++ b/tamalero/KCU.py @@ -177,7 +177,7 @@ class KCU: # print("%s = %6.2f MHz" % (id, freq)) errs = 0 - tolerance = 2500 # increased tolerance to 2.5kHz (from 2kHz) + tolerance = 3000 # increased tolerance to 3.0kHz (from 2kHz) for clock in clocks: freq = self.read_node(clock[0]).value() expect = clock[1] -- GitLab From 6a2643f2897b56bd0bebfa15b4b4c6efac75d67b Mon Sep 17 00:00:00 2001 From: dspitzba <daniel.spitzbart@cern.ch> Date: Fri, 5 May 2023 19:01:06 -0400 Subject: [PATCH 07/11] adding utility functions for new configurations, fw download, majority vote --- tamalero/utils.py | 50 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/tamalero/utils.py b/tamalero/utils.py index f96bde7..d6d7ad9 100644 --- a/tamalero/utils.py +++ b/tamalero/utils.py @@ -1,5 +1,6 @@ import math import numpy as np +from itertools import combinations from time import sleep from yaml import load, dump import os @@ -210,6 +211,16 @@ def make_version_header(res): def chunk(in_list, n): return [in_list[i * n:(i + 1) * n] for i in range((len(in_list) + n - 1) // n )] +def get_last_commit_sha(version): + import requests + import json + + + r2 = requests.get(f"https://gitlab.cern.ch/api/v4/projects/107856/repository/commits?ref=devel") + log = json.loads(r2.content) + last_commit_sha = log[0]['id'][:7] + return last_commit_sha + def download_address_table(version): import os import requests @@ -219,7 +230,7 @@ def download_address_table(version): r2 = requests.get(f"https://gitlab.cern.ch/api/v4/projects/107856/repository/commits?ref=devel") log = json.loads(r2.content) - last_commit_sha = log[0]['id'][:7] + last_commit_sha = get_last_commit_sha(version) r = requests.get(f"https://gitlab.cern.ch/api/v4/projects/107856/repository/tree?ref={version}&&path=address_tables&&recursive=True") tree = json.loads(r.content) @@ -234,7 +245,7 @@ def download_address_table(version): tree = json.loads(r.content) print (f"Local firmware version detected. Will download address table corresponding to commit {version}.") - + print("Making directory: address_table/{version}") os.makedirs(f"address_table/{version}") for f in tree: if f['type'] == 'tree': @@ -316,9 +327,12 @@ def get_kcu(kcu_address, control_hub=True, host='localhost', verbose=False): if verbose: print (f"Address table hash: {xml_sha}") - if not os.path.isdir(f"address_table/{xml_sha}"): - print ("Downloading latest firmware version address table.") + last_commit = get_last_commit_sha(xml_sha) + if not os.path.isdir(f"address_table/{last_commit}"): + print (f"Downloading latest firmware version address table to address_table/{last_commit}") xml_sha = download_address_table(xml_sha) + else: + xml_sha = last_commit kcu = KCU(name="my_device", ipb_path=ipb_path, @@ -328,6 +342,34 @@ def get_kcu(kcu_address, control_hub=True, host='localhost', verbose=False): return kcu +def get_config(config, version='v2', verbose=False): + default_cfg = load_yaml(os.path.join(here, f'../configs/rb_default_{version}.yaml')) + if config != 'default': + updated_cfg = load_yaml(os.path.join(here, f'../configs/{config}_{version}.yaml')) + for chip in ['SCA', 'LPGBT']: + for interface in ['adc', 'gpio']: + if updated_cfg[chip][interface] is not None: + for k in updated_cfg[chip][interface]: + if verbose: + print(f"\n - Updating configuration for {chip}, {interface}, {k} to:") + print(updated_cfg[chip][interface][k]) + default_cfg[chip][interface][k] = updated_cfg[chip][interface][k] + return default_cfg + +def majority_vote(values, majority=None): + from functools import reduce + if majority is None: + majority = len(values)-1 + combs = combinations(range(len(values)), majority) + votes = [] + for comb in combs: + #print(comb) + tmp_list = [values[i] for i in comb] + votes.append(reduce(lambda x, y: x & y, tmp_list)) + + #print(votes) + return reduce(lambda x, y: x | y, votes) + if __name__ == '__main__': print ("Temperature example:") print (get_temp(0.8159, 1.5, 10000, 25, 10000, 3900)) -- GitLab From edd66fb63ff1e8e8c00fb8bfe27dfccc5138c5e6 Mon Sep 17 00:00:00 2001 From: dspitzba <daniel.spitzbart@cern.ch> Date: Fri, 5 May 2023 19:02:22 -0400 Subject: [PATCH 08/11] single configurations for different setups instead of SCA and lpGBT files. fixing lpGBT serial number --- configs/emulator_v2.yaml | 25 ++ configs/modulev0_v2.yaml | 211 +++++++++++++++++ configs/rb_default_v2.yaml | 468 +++++++++++++++++++++++++++++++++++++ tamalero/LPGBT.py | 117 ++++++---- tamalero/ReadoutBoard.py | 19 +- tamalero/SCA.py | 37 ++- test_modulev0.py | 162 +++++++++++++ test_tamalero.py | 7 +- 8 files changed, 985 insertions(+), 61 deletions(-) create mode 100644 configs/emulator_v2.yaml create mode 100644 configs/modulev0_v2.yaml create mode 100644 configs/rb_default_v2.yaml create mode 100644 test_modulev0.py diff --git a/configs/emulator_v2.yaml b/configs/emulator_v2.yaml new file mode 100644 index 0000000..6321b87 --- /dev/null +++ b/configs/emulator_v2.yaml @@ -0,0 +1,25 @@ +SCA: + adc: + gpio: + mod_d01: + pin: 0x1F + default: 0 + direction: out + flavor: small + comment: pin 30 in ETROC 0 and 1 + mod_d09: + pin: 0x19 + default: 0 + direction: out + flavor: small + comment: pin 30 in ETROC 4 and 5 + mod_d17: + pin: 0x0E + default: 0 + direction: out + flavor: small + comment: pin 30 in ETROC 8 and 9 + +LPGBT: + adc: + gpio: diff --git a/configs/modulev0_v2.yaml b/configs/modulev0_v2.yaml new file mode 100644 index 0000000..65c2179 --- /dev/null +++ b/configs/modulev0_v2.yaml @@ -0,0 +1,211 @@ +SCA: + adc: + mod_a00: + pin: 0x0B + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 20 in ETROC 0 and 1 + mod_a01: + pin: 0x0C + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 18 in ETROC 0 and 1 + mod_a02: + pin: 0x0E + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 16 in ETROC 0 and 1 + mod_a03: + pin: 0x0F + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 14 in ETROC 0 and 1 + mod_a04: + pin: 0x03 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 21 in ETROC 2 and 3 + mod_a05: + pin: 0x01 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 23 in ETROC 2 and 3 + mod_a06: + pin: 0x02 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 25 in ETROC 2 and 3 + mod_a07: + pin: 0x0 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 27 in ETROC 2 and 3 + mod_a08: + pin: 0x12 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 20 in ETROC 4 and 5 + mod_a09: + pin: 0x15 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 18 in ETROC 4 and 5 + mod_a10: + pin: 0x14 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 16 in ETROC 4 and 5 + mod_a11: + pin: 0x11 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 14 in ETROC 4 and 5 + mod_a12: + pin: 0x05 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 21 in ETROC 6 and 7 + mod_a13: + pin: 0x06 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 23 in ETROC 6 and 7 + mod_a14: + pin: 0x08 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 25 in ETROC 6 and 7 + mod_a15: + pin: 0x09 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 27 in ETROC 6 and 7 + mod_a16: + pin: 0x17 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 20 in ETROC 8 and 9 + mod_a17: + pin: 0x16 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 18 in ETROC 8 and 9 + mod_a18: + pin: 0x13 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 16 in ETROC 8 and 9 + mod_a19: + pin: 0x10 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 14 in ETROC 8 and 9 + mod_a20: + pin: 0x0D + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 21 in ETROC 10 and 11 + mod_a21: + pin: 0x0A + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 23 in ETROC 10 and 11 + mod_a22: + pin: 0x07 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 25 in ETROC 10 and 11 + mod_a23: + pin: 0x04 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 27 in ETROC 10 and 11 + + gpio: + mod_d00: + pin: 0x1E + default: 1 + direction: out + flavor: small + comment: 2.5V for ETROC on module 1. 1 = 2.5V is OFF, 0 = 2.5V is ON + mod_d01: + pin: 0x1F + default: 0 + direction: out + flavor: small + comment: enable FEAST on module 1 + mod_d08: + pin: 0x16 + default: 1 + direction: out + flavor: small + comment: 2.5V for ETROC on module 2. 1 = 2.5V is OFF, 0 = 2.5V is ON + mod_d09: + pin: 0x19 + default: 0 + direction: out + flavor: small + comment: enable FEAST on module 2 + mod_d16: + pin: 0x0F + default: 1 + direction: out + flavor: small + comment: 2.5V for ETROC on module 3. 1 = 2.5V is OFF, 0 = 2.5V is ON + mod_d17: + pin: 0x0E + default: 0 + direction: out + flavor: small + comment: enable FEAST on module 3 +LPGBT: + adc: + gpio: diff --git a/configs/rb_default_v2.yaml b/configs/rb_default_v2.yaml new file mode 100644 index 0000000..7f99e79 --- /dev/null +++ b/configs/rb_default_v2.yaml @@ -0,0 +1,468 @@ +SCA: + adc: + mod_a00: + pin: 0x0B + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 20 in ETROC 0 and 1 + mod_a01: + pin: 0x0C + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 18 in ETROC 0 and 1 + mod_a02: + pin: 0x0E + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 16 in ETROC 0 and 1 + mod_a03: + pin: 0x0F + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 14 in ETROC 0 and 1 + mod_a04: + pin: 0x03 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 21 in ETROC 2 and 3 + mod_a05: + pin: 0x01 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 23 in ETROC 2 and 3 + mod_a06: + pin: 0x02 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 25 in ETROC 2 and 3 + mod_a07: + pin: 0x0 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 27 in ETROC 2 and 3 + mod_a08: + pin: 0x12 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 20 in ETROC 4 and 5 + mod_a09: + pin: 0x15 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 18 in ETROC 4 and 5 + mod_a10: + pin: 0x14 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 16 in ETROC 4 and 5 + mod_a11: + pin: 0x11 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 14 in ETROC 4 and 5 + mod_a12: + pin: 0x05 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 21 in ETROC 6 and 7 + mod_a13: + pin: 0x06 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 23 in ETROC 6 and 7 + mod_a14: + pin: 0x08 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 25 in ETROC 6 and 7 + mod_a15: + pin: 0x09 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 27 in ETROC 6 and 7 + mod_a16: + pin: 0x17 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 20 in ETROC 8 and 9 + mod_a17: + pin: 0x16 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 18 in ETROC 8 and 9 + mod_a18: + pin: 0x13 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 16 in ETROC 8 and 9 + mod_a19: + pin: 0x10 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 14 in ETROC 8 and 9 + mod_a20: + pin: 0x0D + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 21 in ETROC 10 and 11 + mod_a21: + pin: 0x0A + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 23 in ETROC 10 and 11 + mod_a22: + pin: 0x07 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 25 in ETROC 10 and 11 + mod_a23: + pin: 0x04 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: pin 27 in ETROC 10 and 11 + LV_RB: + pin: 0x1C + conv: 11. + flavor: small + comment: low voltage + VDAC: + pin: 0x1D + conv: 1. + flavor: small + comment: temperature sensor + + gpio: + mod_d00: + pin: 0x1E + default: 1 + direction: in + flavor: small + comment: pin 32 in ETROC 0 and 1 + mod_d01: + pin: 0x1F + default: 0 + direction: in + flavor: small + comment: pin 30 in ETROC 0 and 1 + mod_d02: + pin: 0x1D + default: 0 + direction: in + flavor: small + comment: pin 28 in ETROC 0 and 1 + mod_d03: + pin: 0x1C + default: 0 + direction: in + flavor: small + comment: pin 26 in ETROC 0 and 1 + mod_d04: + pin: 0x00 + default: 0 + direction: in + flavor: small + comment: pin 9 in ETROC 2 and 3 + mod_d05: + pin: 0x02 + default: 0 + direction: in + flavor: small + comment: pin 11 in ETROC 2 and 3 + mod_d06: + pin: 0x01 + default: 0 + direction: in + flavor: small + comment: pin 13 in ETROC 2 and 3 + mod_d07: + pin: 0x03 + default: 0 + direction: in + flavor: small + comment: pin 15 in ETROC 2 and 3 + mod_d08: + pin: 0x16 + default: 1 + direction: in + flavor: small + comment: pin 32 in ETROC 4 and 5 + mod_d09: + pin: 0x19 + default: 0 + direction: in + flavor: small + comment: pin 30 in ETROC 4 and 5 + mod_d10: + pin: 0x13 + default: 0 + direction: in + flavor: small + comment: pin 28 in ETROC 4 and 5 + mod_d11: + pin: 0x10 + default: 0 + direction: in + flavor: small + comment: pin 26 in ETROC 4 and 5 + mod_d12: + pin: 0x0A + default: 0 + direction: in + flavor: small + comment: pin 9 in ETROC 6 and 7 + mod_d13: + pin: 0x04 + default: 0 + direction: in + flavor: small + comment: pin 11 in ETROC 6 and 7 + mod_d14: + pin: 0x07 + default: 0 + direction: in + flavor: small + comment: pin 13 in ETROC 6 and 7 + mod_d15: + pin: 0x0D + default: 0 + direction: in + flavor: small + comment: pin 15 in ETROC 6 and 7 + mod_d16: + pin: 0x0F + default: 1 + direction: in + flavor: small + comment: pin 32 in ETROC 8 and 9 + mod_d17: + pin: 0x0E + default: 0 + direction: in + flavor: small + comment: pin 30 in ETROC 8 and 9 + mod_d18: + pin: 0x0C + default: 0 + direction: in + flavor: small + comment: pin 28 in ETROC 8 and 9 + mod_d19: + pin: 0x0B + default: 0 + direction: in + flavor: small + comment: pin 26 in ETROC 8 and 9 + mod_d20: + pin: 0x09 + default: 0 + direction: in + flavor: small + comment: pin 9 in ETROC 10 and 11 + mod_d21: + pin: 0x08 + default: 0 + direction: in + flavor: small + comment: pin 11 in ETROC 10 and 11 + mod_d22: + pin: 0x06 + default: 0 + direction: in + flavor: small + comment: pin 13 in ETROC 10 and 11 + mod_d23: + pin: 0x05 + default: 0 + direction: in + flavor: small + comment: pin 15 in ETROC 10 and 11 + sca_led: + pin: 0x1B + default: 1 + direction: out + flavor: small + comment: SCA LED indicator + +LPGBT: + adc: + TH1: + pin: 0x00 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: VTRX TH1 + 1V4D_ADC: + pin: 0x01 + conv: 1.82 + min: 1.12 + max: 1.68 + flavor: small + comment: 1V4D * 0.55 + 1V5A_ADC: + pin: 0x02 + conv: 1.82 + min: 1.2 + max: 1.8 + flavor: small + comment: 1V5D * 0.55 + 2V5TX_ADC: + pin: 0x03 + conv: 3.0 + min: 2.0 + max: 3.0 + flavor: small + comment: 2V5TX * 0.33 + RSSI_ADC: + pin: 0x04 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: RSSI + ADC5: + pin: 0x05 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: N/A + 2V5RX_ADC: + pin: 0x06 + conv: 3.0 + min: 2.0 + max: 3.0 + flavor: small + comment: 2V5RX * 0.33 + VTEMP_ADC: + pin: 0x07 + conv: 1 + min: 0 + max: 1.0 + flavor: small + comment: RT1 + EOM_ADC: + pin: 0x08 + conv: 1 + flavor: small + comment: EOM DAC (internal signal) + VDDIO: + pin: 0x09 + conv: 2.38 + flavor: small + comment: VDDIO * 0.42 (internal signal) + VDDTX: + pin: 0x0a + conv: 2.38 + flavor: small + comment: VDDTX * 0.42 (internal signal) + VDDRX: + pin: 0x0b + conv: 2.38 + flavor: small + comment: VDDRX * 0.42 (internal signal) + VDD: + pin: 0x0c + conv: 2.38 + flavor: small + comment: VDD * 0.42 (internal signal) + VDDA: + pin: 0x0d + conv: 2.38 + flavor: small + comment: VDDA * 0.42 (internal signal) + TEMP: + pin: 0x0e + conv: 1 + flavor: small + comment: Temperature sensor (internal signal) + VREF: + pin: 0x0f + conv: 2.0 + flavor: small + comment: VREF/2 (internal signal) + gpio: + SCA_RESETB: + pin: 0x00 + default: 1 + direction: out + flavor: small + comment: GBT SCA reset + LED_0: + pin: 0x01 + default: 1 + direction: out + flavor: small + comment: LPGBT GPIO configuration LED + LED_1: + pin: 0x02 + default: 0 + direction: out + flavor: small + comment: tamalero LED + LED_RHETT: + pin: 0x03 + default: 1 + direction: out + flavor: small + comment: success LED + LD_RSTN: + pin: 0x0A + default: 1 + direction: out + flavor: small + comment: VTRX reset + LD_DIS: + pin: 0x0D + default: 0 + direction: out + flavor: small + comment: VTRX DIS diff --git a/tamalero/LPGBT.py b/tamalero/LPGBT.py index 6f98b0e..7152a24 100644 --- a/tamalero/LPGBT.py +++ b/tamalero/LPGBT.py @@ -8,7 +8,7 @@ import json from functools import wraps import tamalero.colors as colors from tamalero.colors import red, green -from tamalero.utils import read_mapping, chunk, load_yaml +from tamalero.utils import read_mapping, chunk, load_yaml, get_config, majority_vote from time import sleep from datetime import datetime try: @@ -35,7 +35,7 @@ def gpio_byname(gpio_func): class LPGBT(RegParser): - def __init__(self, rb=0, trigger=False, flavor='small', master=None, kcu=None, do_adc_calibration=False): + def __init__(self, rb=0, trigger=False, flavor='small', master=None, kcu=None, do_adc_calibration=False, config='default'): ''' Initialize lpGBT for a certain readout board number (rb). The trigger lpGBT is accessed through I2C of the master (= DAQ lpGBT). @@ -54,6 +54,7 @@ class LPGBT(RegParser): if kcu != None: self.kcu = kcu + self.config = config self.configure(do_adc_calibration=do_adc_calibration) def configure(self, do_adc_calibration=True): @@ -168,22 +169,25 @@ class LPGBT(RegParser): def set_adc_mapping(self): assert self.ver in [0, 1], f"Unrecognized version {self.ver}" - if self.ver == 0: - self.adc_mapping = read_mapping(os.path.expandvars('$TAMALERO_BASE/configs/LPGBT_mapping.yaml'), 'adc') - elif self.ver == 1: - self.adc_mapping = read_mapping(os.path.expandvars('$TAMALERO_BASE/configs/LPGBT_mapping_v2.yaml'), 'adc') + self.adc_mapping = get_config(self.config, version=f'v{self.ver+1}')['LPGBT']['adc'] + #if self.ver == 0: + # self.adc_mapping = read_mapping(os.path.expandvars('$TAMALERO_BASE/configs/LPGBT_mapping.yaml'), 'adc') + #elif self.ver == 1: + # self.adc_mapping = read_mapping(os.path.expandvars('$TAMALERO_BASE/configs/LPGBT_mapping_v2.yaml'), 'adc') def set_gpio_mapping(self): assert self.ver in [0, 1], f"Unrecognized version {self.ver}" - if self.ver == 0: - self.gpio_mapping = read_mapping(os.path.expandvars('$TAMALERO_BASE/configs/LPGBT_mapping.yaml'), 'gpio') - elif self.ver == 1: - self.gpio_mapping = read_mapping(os.path.expandvars('$TAMALERO_BASE/configs/LPGBT_mapping_v2.yaml'), 'gpio') + self.gpio_mapping = get_config(self.config, version=f'v{self.ver+1}')['LPGBT']['gpio'] + #if self.ver == 0: + # self.gpio_mapping = read_mapping(os.path.expandvars('$TAMALERO_BASE/configs/LPGBT_mapping.yaml'), 'gpio') + #elif self.ver == 1: + # self.gpio_mapping = read_mapping(os.path.expandvars('$TAMALERO_BASE/configs/LPGBT_mapping_v2.yaml'), 'gpio') def update_ver(self, new_ver): - assert new_ver in [1, 2], f"Unrecognized version {new_ver}" + assert new_ver in [0, 1], f"Unrecognized version {new_ver}" self.ver = new_ver self.set_adc_mapping() + self.set_gpio_mapping() def link_status(self, verbose=False): if self.trigger: @@ -314,32 +318,36 @@ class LPGBT(RegParser): def wr_adr(self, adr, data): if self.trigger: - raise NotImplementedError("rd_adr does only read from the master lpGBT, and you're trying to write to a servant") - #defer = not self.kcu.auto_dispatch # if auto dispatch is turned off, keep it off. - #self.kcu.toggle_dispatch() # turn off auto dispatch for this transaction - #self.kcu.write_node("READOUT_BOARD_%d.SC.TX_GBTX_ADDR" % self.rb, 115) - self.kcu.write_node("READOUT_BOARD_%d.SC.TX_REGISTER_ADDR" % self.rb, adr) - self.kcu.write_node("READOUT_BOARD_%d.SC.TX_DATA_TO_GBTX" % self.rb, data) - self.kcu.action("READOUT_BOARD_%d.SC.TX_WR" % self.rb) - self.kcu.action("READOUT_BOARD_%d.SC.TX_START_WRITE" % self.rb) - #return self.kcu.read_node("READOUT_BOARD_%d.SC.RX_DATA_FROM_GBTX" % self.rb) - #if not defer: # turn auto dispatch back on only if it wasn't set to false before - # self.kcu.dispatch() - #self.rd_flush() + return self.master.I2C_write(adr, data) + #raise NotImplementedError("rd_adr does only read from the master lpGBT, and you're trying to write to a servant") + else: + #defer = not self.kcu.auto_dispatch # if auto dispatch is turned off, keep it off. + #self.kcu.toggle_dispatch() # turn off auto dispatch for this transaction + #self.kcu.write_node("READOUT_BOARD_%d.SC.TX_GBTX_ADDR" % self.rb, 115) + self.kcu.write_node("READOUT_BOARD_%d.SC.TX_REGISTER_ADDR" % self.rb, adr) + self.kcu.write_node("READOUT_BOARD_%d.SC.TX_DATA_TO_GBTX" % self.rb, data) + self.kcu.action("READOUT_BOARD_%d.SC.TX_WR" % self.rb) + self.kcu.action("READOUT_BOARD_%d.SC.TX_START_WRITE" % self.rb) + #return self.kcu.read_node("READOUT_BOARD_%d.SC.RX_DATA_FROM_GBTX" % self.rb) + #if not defer: # turn auto dispatch back on only if it wasn't set to false before + # self.kcu.dispatch() + #self.rd_flush() def rd_adr(self, adr): if self.trigger: - raise NotImplementedError("rd_adr does only read from the master lpGBT, and you're trying to read from a servant") - self.kcu.write_node("READOUT_BOARD_%d.SC.TX_REGISTER_ADDR" % self.rb, adr) - self.kcu.action("READOUT_BOARD_%d.SC.TX_START_READ" % self.rb) - valid = self.kcu.read_node("READOUT_BOARD_%d.SC.RX_DATA_VALID" % self.rb).valid() - if valid: - # this only means that the KCU successfully read data - # not necessarily does it mean there's communication with the lpGBT - return self.kcu.read_node("READOUT_BOARD_%d.SC.RX_DATA_FROM_GBTX" % self.rb) - - print("LpGBT read failed!") - return None + return self.master.I2C_read(adr) + #raise NotImplementedError("rd_adr does only read from the master lpGBT, and you're trying to read from a servant") + else: + self.kcu.write_node("READOUT_BOARD_%d.SC.TX_REGISTER_ADDR" % self.rb, adr) + self.kcu.action("READOUT_BOARD_%d.SC.TX_START_READ" % self.rb) + valid = self.kcu.read_node("READOUT_BOARD_%d.SC.RX_DATA_VALID" % self.rb).valid() + if valid: + # this only means that the KCU successfully read data + # not necessarily does it mean there's communication with the lpGBT + return self.kcu.read_node("READOUT_BOARD_%d.SC.RX_DATA_FROM_GBTX" % self.rb) + + print("LpGBT read failed!") + return None def wr_reg(self, id, data): node = self.get_node(id) @@ -752,9 +760,9 @@ class LPGBT(RegParser): return serial != 0 if (self.ver==0): - serial = self.get_chip_userid() + serial = str(self.get_chip_userid()) else: - serial = self.get_chip_serial() + serial = str(self.get_chip_serial()) cal_file = "lpgbt_adc_calibrations.json" @@ -769,7 +777,7 @@ class LPGBT(RegParser): if serial_valid(serial) and serial in cal_data and not recalibrate: gain = cal_data[serial]['gain'] offset = cal_data[serial]['offset'] - print("Loaded ADC calibration data for chip %d. Gain: %f / Offset: %d" % (serial, gain, offset)) + print("Loaded ADC calibration data for chip %s. Gain: %f / Offset: %d" % (serial, gain, offset)) # else, determine calibration constants else: @@ -788,6 +796,7 @@ class LPGBT(RegParser): self.wr_reg("LPGBT.RW.ADC.VDDMONENA", initial_val) type = "Trigger" if self.trigger else "DAQ" print("Calibrated %s ADC. Gain: %f / Offset: %d" % (type, gain, offset)) + print("Chip %s"%serial) if gain < 1.65 or gain > 2 or offset < 490 or offset > 530: raise RuntimeError("ADC Calibration Failed!") @@ -1429,10 +1438,36 @@ class LPGBT(RegParser): self.rd_reg("LPGBT.RWF.CHIPID.USERID0") def get_chip_serial(self): - return self.rd_reg("LPGBT.RWF.CHIPID.CHIPID3") << 24 |\ - self.rd_reg("LPGBT.RWF.CHIPID.CHIPID2") << 16 |\ - self.rd_reg("LPGBT.RWF.CHIPID.CHIPID1") << 8 |\ - self.rd_reg("LPGBT.RWF.CHIPID.CHIPID0") + if self.ver == 1: + # NOTE we have to read from the fuses directly. + # ideally this can still be verified (May 2023) + self.wr_adr(0x119, 0x1 << 1) # write FuseRead https://lpgbt.web.cern.ch/lpgbt/v1/registermap.html#reg-fusecontrol + while True: + # wait for FuseDataValid https://lpgbt.web.cern.ch/lpgbt/v1/registermap.html#reg-fusestatus + if self.rd_adr(0x1b1) >> 2 == 1: break + + chipids = [] + # there should be 5 copies of the chipid, but I can only find 4 + # there's nothing else in the fuses that's non-zero + for i in range(4): + self.wr_adr(0x11f, i) + chipids.append(self.rd_adr(0x1b2) << 24 | self.rd_adr(0x1b3) << 16 | self.rd_adr(0x1b4) << 8 | self.rd_adr(0x1b5) << 24) + + self.wr_adr(0x119, 0) # write FuseRead https://lpgbt.web.cern.ch/lpgbt/v1/registermap.html#reg-fusecontrol + + if all([c==chipids[0] for c in chipids]): + return chipids[0] + else: + print("CHIPD serial needs majority vote") + return majority_vote(chipids, majority=3) + + elif self.ver == 0: + # NOTE: this is what's supposed to work for lpGBT v0 + # but note sure if that's actually true + return self.rd_reg("LPGBT.RWF.CHIPID.CHIPID3") << 24 |\ + self.rd_reg("LPGBT.RWF.CHIPID.CHIPID2") << 16 |\ + self.rd_reg("LPGBT.RWF.CHIPID.CHIPID1") << 8 |\ + self.rd_reg("LPGBT.RWF.CHIPID.CHIPID0") def get_power_up_state_machine(self, quiet=True): diff --git a/tamalero/ReadoutBoard.py b/tamalero/ReadoutBoard.py index 92dd53c..ff35243 100644 --- a/tamalero/ReadoutBoard.py +++ b/tamalero/ReadoutBoard.py @@ -8,22 +8,23 @@ from time import sleep class ReadoutBoard: - def __init__(self, rb=0, trigger=True, flavor='small', kcu=None): + def __init__(self, rb=0, trigger=True, flavor='small', kcu=None, config='default'): ''' create a readout board. trigger: if true, also configure a trigger lpGBT ''' self.rb = rb self.flavor = flavor - self.ver = 1 + self.ver = 2 + self.config = config self.trigger = trigger - self.DAQ_LPGBT = LPGBT(rb=rb, flavor=flavor, kcu=kcu) + self.DAQ_LPGBT = LPGBT(rb=rb, flavor=flavor, kcu=kcu, config=self.config) self.VTRX = VTRX(self.DAQ_LPGBT) # This is not yet recommended: #for adr in [0x06, 0x0A, 0x0E, 0x12]: # self.VTRX.wr_adr(adr, 0x20) - self.SCA = SCA(rb=rb, flavor=flavor, ver=self.DAQ_LPGBT.ver) + self.SCA = SCA(rb=rb, flavor=flavor, ver=self.DAQ_LPGBT.ver, config=self.config) if kcu != None: self.kcu = kcu @@ -32,7 +33,11 @@ class ReadoutBoard: if self.DAQ_LPGBT.ver == 1: self.ver = 2 self.SCA.update_ver(self.ver) - self.DAQ_LPGBT.set_adc_mapping() + self.DAQ_LPGBT.update_ver(self.ver-1) # FIXME we need to disentangle lpGBT version from RB version + elif self.DAQ_LPGBT.ver == 0: + self.ver = 1 + self.SCA.update_ver(self.ver) + self.DAQ_LPGBT.update_ver(self.ver-1) # FIXME we need to disentangle lpGBT version from RB version self.SCA.connect_KCU(kcu) def get_trigger(self): @@ -52,7 +57,7 @@ class ReadoutBoard: print ("Trigger lpGBT was found, but will not be added.") if self.trigger: - self.TRIG_LPGBT = LPGBT(rb=self.rb, flavor=self.flavor, trigger=True, master=self.DAQ_LPGBT, kcu=self.kcu) + self.TRIG_LPGBT = LPGBT(rb=self.rb, flavor=self.flavor, trigger=True, master=self.DAQ_LPGBT, kcu=self.kcu, config=self.config) def connect_KCU(self, kcu): @@ -291,6 +296,8 @@ class ReadoutBoard: self.SCA.reset() self.SCA.connect() try: + print("version in SCA", self.SCA.ver) + print("config in SCA", self.SCA.config) self.SCA.config_gpios() # this sets the directions etc according to the mapping except TimeoutError: print ("SCA config failed. Will continue without SCA.") diff --git a/tamalero/SCA.py b/tamalero/SCA.py index f744058..2809d9c 100644 --- a/tamalero/SCA.py +++ b/tamalero/SCA.py @@ -1,6 +1,7 @@ import os import random -from tamalero.utils import read_mapping +from tamalero.utils import read_mapping, get_config +from functools import wraps import time try: from tabulate import tabulate @@ -110,34 +111,43 @@ class SCA_I2C: I2C_R_DATA3 = 0x71 # read from data register 3 I2C_RW_DATA_OFFSET = 16 # offset to access data register 1, 2, 3 +def gpio_byname(gpio_func): + @wraps(gpio_func) + def wrapper(lpgbt, pin, direction=1): + if isinstance(pin, str): + gpio_dict = lpgbt.gpio_mapping + pin = gpio_dict[pin]['pin'] + return gpio_func(lpgbt, pin, direction) + elif isinstance(pin, int): + return gpio_func(lpgbt, pin, direction) + else: + invalid_type = type(pin) + raise TypeError(f"{gpio_func.__name__} can only take positional arguments of type int or str, but argument of type {invalid_type} was given.") + + return wrapper class SCA: - def __init__(self, rb=0, flavor='small', ver=0): + def __init__(self, rb=0, flavor='small', ver=0, config='default'): self.rb = rb self.flavor = flavor self.err_count = 0 self.ver = ver + 1 # NOTE don't particularly like this, but we're giving it the lpGBT version + self.config = config + self.locked = False self.set_adc_mapping() self.set_gpio_mapping() - self.locked = False def connect_KCU(self, kcu): self.kcu = kcu def set_adc_mapping(self): assert self.ver in [1, 2], f"Unrecognized version {self.ver}" - if self.ver == 1: - self.adc_mapping = read_mapping(os.path.expandvars('$TAMALERO_BASE/configs/SCA_mapping.yaml'), 'adc') - elif self.ver == 2: - self.adc_mapping = read_mapping(os.path.expandvars('$TAMALERO_BASE/configs/SCA_mapping_v2.yaml'), 'adc') + self.adc_mapping = get_config(self.config, version=f'v{self.ver}')['SCA']['adc'] def set_gpio_mapping(self): assert self.ver in [1, 2], f"Unrecognized version {self.ver}" - if self.ver == 1: - self.gpio_mapping = read_mapping(os.path.expandvars('$TAMALERO_BASE/configs/SCA_mapping.yaml'), 'gpio') - elif self.ver == 2: - self.gpio_mapping = read_mapping(os.path.expandvars('$TAMALERO_BASE/configs/SCA_mapping_v2.yaml'), 'gpio') + self.gpio_mapping = get_config(self.config, version=f'v{self.ver}')['SCA']['gpio'] def update_ver(self, new_ver): assert new_ver in [1, 2], f"Unrecognized version {new_ver}" @@ -447,6 +457,7 @@ class SCA: val = self.rw_reg(SCA_GPIO.GPIO_R_DATAIN).value() return int((val >> line) & 1) + @gpio_byname def set_gpio(self, line, to=1): self.enable_gpio() # enable GPIO currently_set = self.rw_reg(SCA_GPIO.GPIO_R_DATAOUT).value() @@ -458,6 +469,7 @@ class SCA: self.rw_reg(SCA_GPIO.GPIO_W_DATAOUT, currently_set) return self.read_gpio(line) # in order to check it is actually set + @gpio_byname def set_gpio_direction(self, line, to=1): self.enable_gpio() # enable GPIO currently_set = self.rw_reg(SCA_GPIO.GPIO_R_DIRECTION).value() @@ -491,8 +503,9 @@ class SCA: default = gpio_dict[gpio_reg]['default'] if verbose: print("Setting SCA GPIO pin %s (%s) to %s"%(pin, comment, gpio_dict[gpio_reg]['direction'])) + self.set_gpio(pin, default) # NOTE this is important because otherwise the GPIO pin can be set to a false default value when switched to output self.set_gpio_direction(pin, direction) - self.set_gpio(pin, default) + self.set_gpio(pin, default) # redundant but keep it def get_I2C_channel(self, channel): channel_str = hex(channel).upper()[-1] diff --git a/test_modulev0.py b/test_modulev0.py new file mode 100644 index 0000000..5a4692e --- /dev/null +++ b/test_modulev0.py @@ -0,0 +1,162 @@ +from tamalero.KCU import KCU +from tamalero.ReadoutBoard import ReadoutBoard +from tamalero.utils import header, make_version_header, get_kcu, check_repo_status +from tamalero.FIFO import FIFO +from tamalero.DataFrame import DataFrame +from tamalero.ETROC import ETROC +from tamalero.Module import Module + +from tamalero.SCA import SCA_CONTROL + +import time +import random +import sys +import os +import uhal +from emoji import emojize + +if __name__ == '__main__': + + + import argparse + + argParser = argparse.ArgumentParser(description = "Argument parser") + argParser.add_argument('--verbose', action='store_true', default=False, help="Verbose power up sequence") + argParser.add_argument('--power_up', action='store_true', default=False, help="Do lpGBT power up init?") + argParser.add_argument('--reconfigure', action='store_true', default=False, help="Configure the RB electronics: SCA and lpGBT?") + argParser.add_argument('--adcs', action='store_true', default=False, help="Read ADCs?") + argParser.add_argument('--i2c_temp', action='store_true', default=False, help="Do temp monitoring on I2C from lpGBT?") + argParser.add_argument('--i2c_sca', action='store_true', default=False, help="I2C tests on SCA?") + argParser.add_argument('--kcu', action='store', default="192.168.0.10", help="Specify the IP address for KCU") + argParser.add_argument('--control_hub', action='store_true', default=False, help="Use control hub for communication?") + argParser.add_argument('--host', action='store', default='localhost', help="Specify host for control hub") + argParser.add_argument('--configuration', action='store', default='modulev0', choices=['default', 'emulator', 'modulev0'], help="Specify a configuration of the RB, e.g. emulator or modulev0") + argParser.add_argument('--devel', action='store_true', default=False, help="Don't check repo status (not recommended)") + argParser.add_argument('--connection_test', action='store_true', default=False, help="Check the PCB connections.") + args = argParser.parse_args() + + + verbose = args.verbose + + #------------------------------------------------------------------------------- + # Try to Connect to the KCU105 + #------------------------------------------------------------------------------- + + print ("Using KCU at address: %s"%args.kcu) + + kcu = None + rb_0 = None + + # write to the loopback node of the KCU105 to check ethernet communication + kcu = get_kcu(args.kcu, control_hub=args.control_hub, host=args.host, verbose=args.verbose) + if (kcu == 0): + # if not basic connection was established the get_kcu function returns 0 + # this would cause the RB init to fail. + sys.exit(1) + + + rb_0 = ReadoutBoard(0, kcu=kcu, config=args.configuration) + data = 0xabcd1234 + kcu.write_node("LOOPBACK.LOOPBACK", data) + if (data != kcu.read_node("LOOPBACK.LOOPBACK")): + print("No communications with KCU105... quitting") + sys.exit(1) + + is_configured = rb_0.DAQ_LPGBT.is_configured() + if not is_configured: + print("RB is not configured, exiting.") + exit(0) + header(configured=is_configured) + + if not args.devel: + check_repo_status(kcu_version=kcu.get_firmware_version(verbose=True)) + + rb_0.VTRX.get_version() + + if not hasattr(rb_0, "TRIG_LPGBT"): + rb_0.get_trigger() + + res = rb_0.DAQ_LPGBT.get_board_id() + res['trigger'] = 'yes' if rb_0.trigger else 'no' + + if (verbose): + make_version_header(res) + + if args.adcs: + print("\n\nReading GBT-SCA ADC values:") + rb_0.SCA.read_adcs(check=True, strict_limits=args.strict) + + print("\n\nReading DAQ lpGBT ADC values:") + rb_0.DAQ_LPGBT.read_adcs(check=True, strict_limits=args.strict) + + # High level reading of temperatures + temp = rb_0.read_temp(verbose=True) + + #------------------------------------------------------------------------------- + # Read SCA + #------------------------------------------------------------------------------- + + if args.i2c_sca: + + print("Writing and Reading I2C_ctrl register:") + for n in range(10): + wr = random.randint(0, 100) + rb_0.SCA.I2C_write_ctrl(channel=3, data=wr) + rd = rb_0.SCA.I2C_read_ctrl(channel=3) + print("write: {} \t read: {}".format(wr, rd)) + + print("Testing multi-byte read:") + multi_out = rb_0.SCA.I2C_read_multi(channel=3, servant = 0x48, nbytes=2) + print("servant: 0x48, channel: 3, nbytes: 2, output = {}".format(multi_out)) + + print("Testing multi-byte write:") + + write_value = [0x2, 25, (27&240)] + print("servant: 0x48, channel: 3, nbytes: 2, data:{}".format(write_value)) + rb_0.SCA.I2C_write_multi(write_value, channel=3, servant=0x48) + read_value = rb_0.SCA.I2C_read_multi(channel=3, servant=0x48, nbytes = 2, reg=0x2) + + if read_value == write_value[1:]: + print ("write/read successful!") + print("read value = {}".format(rb_0.SCA.I2C_read_multi(channel=3, servant=0x48, nbytes = 2, reg=0x2))) + + + #------------------------------------------------------------------------------- + # Success LEDs + #------------------------------------------------------------------------------- + rb_0.DAQ_LPGBT.set_gpio("LED_1", 1) # Set LED1 after tamalero finishes succesfully + rb_0.DAQ_LPGBT.set_gpio("LED_RHETT", 1) # Set LED1 after tamalero finishes succesfully + if rb_0.DAQ_LPGBT.ver == 1 and args.connection_test: + print("Toggling FEAST and 2.5V on/off for 1min") + t_end = time.time() + 60 + while time.time() < t_end: + rb_0.DAQ_LPGBT.set_gpio("LED_1", 1) # Let Rhett LED blink for 10s + rb_0.DAQ_LPGBT.set_gpio("LED_RHETT", 1) # Let Rhett LED blink for 10s + rb_0.SCA.set_gpio("mod_d00", 1) + rb_0.SCA.set_gpio("mod_d01", 1) + rb_0.SCA.set_gpio("mod_d08", 1) + rb_0.SCA.set_gpio("mod_d09", 1) + rb_0.SCA.set_gpio("mod_d16", 1) + rb_0.SCA.set_gpio("mod_d17", 1) + time.sleep(2.0) + rb_0.DAQ_LPGBT.set_gpio("LED_1", 0) + rb_0.DAQ_LPGBT.set_gpio("LED_RHETT", 0) + rb_0.SCA.set_gpio("mod_d00", 0) + rb_0.SCA.set_gpio("mod_d01", 0) + rb_0.SCA.set_gpio("mod_d08", 0) + rb_0.SCA.set_gpio("mod_d09", 0) + rb_0.SCA.set_gpio("mod_d16", 0) + rb_0.SCA.set_gpio("mod_d17", 0) + time.sleep(2.0) + rb_0.DAQ_LPGBT.set_gpio("LED_1", 1) + rb_0.DAQ_LPGBT.set_gpio("LED_RHETT", 1) + + # disabling 2.5V + rb_0.SCA.set_gpio("mod_d00", 1) + rb_0.SCA.set_gpio("mod_d08", 1) + rb_0.SCA.set_gpio("mod_d16", 1) + + # enabling FEAST + rb_0.SCA.set_gpio("mod_d01", 1) + rb_0.SCA.set_gpio("mod_d09", 1) + rb_0.SCA.set_gpio("mod_d17", 1) diff --git a/test_tamalero.py b/test_tamalero.py index a1adf0f..57d941c 100644 --- a/test_tamalero.py +++ b/test_tamalero.py @@ -39,6 +39,7 @@ if __name__ == '__main__': argParser.add_argument('--recal_lpgbt', action='store_true', default=False, help="Recalibrate ADC in LPGBT? (instead of using saved values)") argParser.add_argument('--control_hub', action='store_true', default=False, help="Use control hub for communication?") argParser.add_argument('--host', action='store', default='localhost', help="Specify host for control hub") + argParser.add_argument('--configuration', action='store', default='default', choices=['default', 'emulator', 'modulev0'], help="Specify a configuration of the RB, e.g. emulator or modulev0") argParser.add_argument('--devel', action='store_true', default=False, help="Don't check repo status (not recommended)") argParser.add_argument('--monitor', action='store_true', default=False, help="Start up montoring threads in the background") argParser.add_argument('--strict', action='store_true', default=False, help="Enforce strict limits on ADC reads for SCA and LPGBT") @@ -63,7 +64,9 @@ if __name__ == '__main__': # if not basic connection was established the get_kcu function returns 0 # this would cause the RB init to fail. sys.exit(1) - rb_0 = ReadoutBoard(0, trigger=(not args.force_no_trigger), kcu=kcu) + + + rb_0 = ReadoutBoard(0, trigger=(not args.force_no_trigger), kcu=kcu, config=args.configuration) data = 0xabcd1234 kcu.write_node("LOOPBACK.LOOPBACK", data) if (data != kcu.read_node("LOOPBACK.LOOPBACK")): @@ -159,7 +162,7 @@ if __name__ == '__main__': # Module Status #------------------------------------------------------------------------------- - if args.verbose: + if args.verbose and args.configuration == 'emulator': print("Configuring ETROCs") modules = [] for i in range(res['n_module']): -- GitLab From 9d6140491083038cd4a260e0945976ff495171ce Mon Sep 17 00:00:00 2001 From: dspitzba <daniel.spitzbart@cern.ch> Date: Mon, 15 May 2023 17:32:42 -0400 Subject: [PATCH 09/11] trying to get rid of all the configs --- configs/current_adcs.yaml | 5 ----- configs/emulator_v2.yaml | 33 +++++++++++++++++++++++++++++++++ configs/modulev0_v2.yaml | 33 +++++++++++++++++++++++++++++++++ configs/rb_default_v2.yaml | 22 ++++++++++++++++++++++ tamalero/LPGBT.py | 36 ++++++++++++++++++++---------------- tamalero/Module.py | 10 +++++----- tamalero/ReadoutBoard.py | 2 -- tamalero/utils.py | 2 ++ 8 files changed, 115 insertions(+), 28 deletions(-) delete mode 100644 configs/current_adcs.yaml diff --git a/configs/current_adcs.yaml b/configs/current_adcs.yaml deleted file mode 100644 index 239b5eb..0000000 --- a/configs/current_adcs.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# FIXME: these should be moved to the readout board yaml -# this file doesn't really make sense -lpGBT: - - 0 - - 7 diff --git a/configs/emulator_v2.yaml b/configs/emulator_v2.yaml index 6321b87..3694d87 100644 --- a/configs/emulator_v2.yaml +++ b/configs/emulator_v2.yaml @@ -23,3 +23,36 @@ SCA: LPGBT: adc: gpio: + +inversions: + clocks: + - 3 + - 4 + - 5 + - 22 + - 23 + - 25 + - 26 + - 27 + downlink: + - 2 + - 4 + - 8 + - 10 + - 12 + uplink: + - 6 + - 12 + - 14 + - 16 + - 18 + - 20 + - 22 + trigger: + - 2 + - 6 + - 10 + - 16 + - 18 + - 20 + - 22 diff --git a/configs/modulev0_v2.yaml b/configs/modulev0_v2.yaml index 65c2179..346d56f 100644 --- a/configs/modulev0_v2.yaml +++ b/configs/modulev0_v2.yaml @@ -209,3 +209,36 @@ SCA: LPGBT: adc: gpio: + +inversions: + clocks: + - 3 + - 4 + - 5 + - 22 + - 23 + - 25 + - 26 + - 27 + downlink: + - 2 + - 4 + - 8 + - 10 + - 12 + uplink: + - 6 + - 12 + - 14 + - 16 + - 18 + - 20 + - 22 + trigger: + - 2 + - 6 + - 10 + - 16 + - 18 + - 20 + - 22 diff --git a/configs/rb_default_v2.yaml b/configs/rb_default_v2.yaml index 7f99e79..1279acc 100644 --- a/configs/rb_default_v2.yaml +++ b/configs/rb_default_v2.yaml @@ -335,6 +335,7 @@ LPGBT: adc: TH1: pin: 0x00 + current: 1 conv: 1 min: 0 max: 1.0 @@ -342,6 +343,7 @@ LPGBT: comment: VTRX TH1 1V4D_ADC: pin: 0x01 + current: 0 conv: 1.82 min: 1.12 max: 1.68 @@ -349,6 +351,7 @@ LPGBT: comment: 1V4D * 0.55 1V5A_ADC: pin: 0x02 + current: 0 conv: 1.82 min: 1.2 max: 1.8 @@ -356,6 +359,7 @@ LPGBT: comment: 1V5D * 0.55 2V5TX_ADC: pin: 0x03 + current: 0 conv: 3.0 min: 2.0 max: 3.0 @@ -363,6 +367,7 @@ LPGBT: comment: 2V5TX * 0.33 RSSI_ADC: pin: 0x04 + current: 0 conv: 1 min: 0 max: 1.0 @@ -370,6 +375,7 @@ LPGBT: comment: RSSI ADC5: pin: 0x05 + current: 0 conv: 1 min: 0 max: 1.0 @@ -377,6 +383,7 @@ LPGBT: comment: N/A 2V5RX_ADC: pin: 0x06 + current: 0 conv: 3.0 min: 2.0 max: 3.0 @@ -384,6 +391,7 @@ LPGBT: comment: 2V5RX * 0.33 VTEMP_ADC: pin: 0x07 + current: 1 conv: 1 min: 0 max: 1.0 @@ -391,41 +399,49 @@ LPGBT: comment: RT1 EOM_ADC: pin: 0x08 + current: 0 conv: 1 flavor: small comment: EOM DAC (internal signal) VDDIO: pin: 0x09 + current: 0 conv: 2.38 flavor: small comment: VDDIO * 0.42 (internal signal) VDDTX: pin: 0x0a + current: 0 conv: 2.38 flavor: small comment: VDDTX * 0.42 (internal signal) VDDRX: pin: 0x0b + current: 0 conv: 2.38 flavor: small comment: VDDRX * 0.42 (internal signal) VDD: pin: 0x0c + current: 0 conv: 2.38 flavor: small comment: VDD * 0.42 (internal signal) VDDA: pin: 0x0d + current: 0 conv: 2.38 flavor: small comment: VDDA * 0.42 (internal signal) TEMP: pin: 0x0e + current: 0 conv: 1 flavor: small comment: Temperature sensor (internal signal) VREF: pin: 0x0f + current: 0 conv: 2.0 flavor: small comment: VREF/2 (internal signal) @@ -466,3 +482,9 @@ LPGBT: direction: out flavor: small comment: VTRX DIS + +inversions: + clocks: + downlink: + uplink: + trigger: diff --git a/tamalero/LPGBT.py b/tamalero/LPGBT.py index 7152a24..be2c147 100644 --- a/tamalero/LPGBT.py +++ b/tamalero/LPGBT.py @@ -116,9 +116,6 @@ class LPGBT(RegParser): print (" > unsure about lpGBT version. This case should have been impossible to reach.") raise Exception("Spurious lpGBT version.") - self.set_adc_mapping() - self.set_gpio_mapping() - self.base_config = load_yaml(os.path.expandvars('$TAMALERO_BASE/configs/lpgbt_config.yaml'))['base'][f'v{self.ver}'] self.ec_config = load_yaml(os.path.expandvars('$TAMALERO_BASE/configs/lpgbt_config.yaml'))['ec'][f'v{self.ver}'] @@ -132,10 +129,13 @@ class LPGBT(RegParser): self.wr_reg("LPGBT.RWF.POWERUP.DLLCONFIGDONE", 0x1) # NOTE untested change self.wr_reg("LPGBT.RWF.POWERUP.PLLCONFIGDONE", 0x1) + self.set_adc_mapping() + self.set_gpio_mapping() + # Get LPGBT Serial Num self.serial_num = 0# self.get_board_id()['lpgbt_serial'] - self.link_inversions = load_yaml(os.path.expandvars('$TAMALERO_BASE/configs/link_inversions.yaml')) + self.link_inversions = get_config(self.config, version=f'v{self.ver+1}')['inversions'] if not self.power_up_done(): print("Running power up within LPGBT.configure()") @@ -147,9 +147,9 @@ class LPGBT(RegParser): if do_adc_calibration and not self.calibrated: self.calibrate_adc() - self.current_adcs = load_yaml(os.path.expandvars('$TAMALERO_BASE/configs/current_adcs.yaml'))['lpGBT'] - for adc in self.current_adcs: - self.set_current_adc(adc) + #self.current_adcs = load_yaml(os.path.expandvars('$TAMALERO_BASE/configs/current_adcs.yaml'))['lpGBT'] + #for adc in self.current_adcs: + # self.set_current_adc(adc) def read_base_config(self): # @@ -170,6 +170,10 @@ class LPGBT(RegParser): def set_adc_mapping(self): assert self.ver in [0, 1], f"Unrecognized version {self.ver}" self.adc_mapping = get_config(self.config, version=f'v{self.ver+1}')['LPGBT']['adc'] + for channel in self.adc_mapping: + if self.adc_mapping[channel]['current'] == 1: + print(f'Setting {channel} to current DAC') + self.set_current_dac(self.adc_mapping[channel]['pin']) #if self.ver == 0: # self.adc_mapping = read_mapping(os.path.expandvars('$TAMALERO_BASE/configs/LPGBT_mapping.yaml'), 'adc') #elif self.ver == 1: @@ -485,38 +489,38 @@ class LPGBT(RegParser): def invert_links(self, trigger=False): if trigger: - for link in self.link_inversions['emulator_adapter']['trigger']: + for link in self.link_inversions['trigger']: self.set_uplink_invert(link) else: - for link in self.link_inversions['emulator_adapter']['clocks']: + for link in self.link_inversions['clocks']: self.set_clock_invert(link) - for link in self.link_inversions['emulator_adapter']['downlink']: + for link in self.link_inversions['downlink']: self.set_downlink_invert(link) - for link in self.link_inversions['emulator_adapter']['uplink']: + for link in self.link_inversions['uplink']: self.set_uplink_invert(link) def read_inversions(self): if self.trigger: print("Trigger LPGBT Registers -- Uplinks") - for link in self.link_inversions['emulator_adapter']['trigger']: + for link in self.link_inversions['trigger']: register = "LPGBT.RWF.EPORTRX.EPRX_CHN_CONTROL.EPRX%dINVERT" % link val = self.rd_reg(register) print(register, "\t", val) else: print("DAQ LPGBT Registers -- Clocks") - for link in self.link_inversions['emulator_adapter']['clocks']: + for link in self.link_inversions['clocks']: register = "LPGBT.RWF.EPORTCLK.EPCLK%dINVERT" % link val = self.rd_reg(register) print(register, "\t", val) print("DAQ LPGBT Registers -- Downlinks") - for link in self.link_inversions['emulator_adapter']['downlink']: + for link in self.link_inversions['downlink']: group = link // 4 elink = link % 4 register = "LPGBT.RWF.EPORTTX.EPTX%d%dINVERT" % (group, elink) val = self.rd_reg(register) print(register, "\t", val) print("DAQ LPGBT Registers -- Uplinks") - for link in self.link_inversions['emulator_adapter']['uplink']: + for link in self.link_inversions['uplink']: register = "LPGBT.RWF.EPORTRX.EPRX_CHN_CONTROL.EPRX%dINVERT" % link val = self.rd_reg(register) print(register, "\t", val) @@ -817,7 +821,7 @@ class LPGBT(RegParser): self.wr_reg("LPGBT.RWF.VOLTAGE_DAC.CURDACENABLE", 0x1) if verbose: - print("Set current DAC...", self.rd_reg("LPGBT.RWF.VOLTAGE_DAC.CURDACENABLE")) + print("Enable DAC current source...", self.rd_reg("LPGBT.RWF.VOLTAGE_DAC.CURDACENABLE")) if channel == 0: adc_chn = self.LPGBT_CONST.CURDAC_CHN0_bm diff --git a/tamalero/Module.py b/tamalero/Module.py index 5b454cc..4b5f462 100644 --- a/tamalero/Module.py +++ b/tamalero/Module.py @@ -113,15 +113,15 @@ class Module: if etroc.daq_locked: status += 1 - self.rb.SCA.set_gpio(self.rb.SCA.gpio_mapping[self.config['status']]['pin'], to=0) + self.rb.SCA.set_gpio(self.rb.SCA.gpio_mapping[self.config['status']]['pin'], 0) sleep(0.25) for i in range(status): - self.rb.SCA.set_gpio(self.rb.SCA.gpio_mapping[self.config['status']]['pin'], to=1) + self.rb.SCA.set_gpio(self.rb.SCA.gpio_mapping[self.config['status']]['pin'], 1) sleep(0.25) - self.rb.SCA.set_gpio(self.rb.SCA.gpio_mapping[self.config['status']]['pin'], to=0) + self.rb.SCA.set_gpio(self.rb.SCA.gpio_mapping[self.config['status']]['pin'], 0) sleep(0.25) if status > 0: - self.rb.SCA.set_gpio(self.rb.SCA.gpio_mapping[self.config['status']]['pin'], to=1) + self.rb.SCA.set_gpio(self.rb.SCA.gpio_mapping[self.config['status']]['pin'], 1) else: - self.rb.SCA.set_gpio(self.rb.SCA.gpio_mapping[self.config['status']]['pin'], to=0) + self.rb.SCA.set_gpio(self.rb.SCA.gpio_mapping[self.config['status']]['pin'], 0) diff --git a/tamalero/ReadoutBoard.py b/tamalero/ReadoutBoard.py index ff35243..3285fe6 100644 --- a/tamalero/ReadoutBoard.py +++ b/tamalero/ReadoutBoard.py @@ -296,8 +296,6 @@ class ReadoutBoard: self.SCA.reset() self.SCA.connect() try: - print("version in SCA", self.SCA.ver) - print("config in SCA", self.SCA.config) self.SCA.config_gpios() # this sets the directions etc according to the mapping except TimeoutError: print ("SCA config failed. Will continue without SCA.") diff --git a/tamalero/utils.py b/tamalero/utils.py index d6d7ad9..8571bf6 100644 --- a/tamalero/utils.py +++ b/tamalero/utils.py @@ -354,6 +354,8 @@ def get_config(config, version='v2', verbose=False): print(f"\n - Updating configuration for {chip}, {interface}, {k} to:") print(updated_cfg[chip][interface][k]) default_cfg[chip][interface][k] = updated_cfg[chip][interface][k] + for links in ['trigger', 'clocks', 'downlink', 'uplink']: + default_cfg['inversions'][links] = updated_cfg['inversions'][links] return default_cfg def majority_vote(values, majority=None): -- GitLab From 342507d59639bb79894ab290558e9160e0579ee1 Mon Sep 17 00:00:00 2001 From: dspitzba <daniel.spitzbart@cern.ch> Date: Mon, 15 May 2023 17:38:50 -0400 Subject: [PATCH 10/11] fixing current DAC bug --- tamalero/LPGBT.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tamalero/LPGBT.py b/tamalero/LPGBT.py index be2c147..bb8fc70 100644 --- a/tamalero/LPGBT.py +++ b/tamalero/LPGBT.py @@ -173,7 +173,7 @@ class LPGBT(RegParser): for channel in self.adc_mapping: if self.adc_mapping[channel]['current'] == 1: print(f'Setting {channel} to current DAC') - self.set_current_dac(self.adc_mapping[channel]['pin']) + self.set_current_adc(self.adc_mapping[channel]['pin']) #if self.ver == 0: # self.adc_mapping = read_mapping(os.path.expandvars('$TAMALERO_BASE/configs/LPGBT_mapping.yaml'), 'adc') #elif self.ver == 1: -- GitLab From c6230196cc8a39b71d644ea3e7db360e19585c88 Mon Sep 17 00:00:00 2001 From: dspitzba <daniel.spitzbart@cern.ch> Date: Mon, 15 May 2023 18:05:25 -0400 Subject: [PATCH 11/11] fixing startup script --- tests/startup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/startup.sh b/tests/startup.sh index 922e165..b62a71b 100644 --- a/tests/startup.sh +++ b/tests/startup.sh @@ -108,7 +108,7 @@ fi # run test_tamalero with power up info "Running test_tamalero..." -/usr/bin/env python3 test_tamalero.py --kcu "${KCU}" --power_up --control_hub --verbose --adcs --strict +/usr/bin/env python3 test_tamalero.py --kcu "${KCU}" --power_up --control_hub --verbose --adcs --strict --configuration emulator EXIT=$? if [ ${EXIT} -ne 0 ]; then error "Failure when running test_tamalero.py; exit code is ${EXIT}. Blocking merge." -- GitLab