From e6917688932208aa6f3da48f37fb105c770f03c6 Mon Sep 17 00:00:00 2001
From: dspitzba <daniel.spitzbart@cern.ch>
Date: Fri, 9 Jun 2023 17:14:56 -0400
Subject: [PATCH 01/14] occupancy plot from L1A

---
 tamalero/FIFO.py |  3 +++
 test_ETROC.py    | 58 ++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 59 insertions(+), 2 deletions(-)

diff --git a/tamalero/FIFO.py b/tamalero/FIFO.py
index 9d78d4f..346d8e7 100644
--- a/tamalero/FIFO.py
+++ b/tamalero/FIFO.py
@@ -172,6 +172,9 @@ class FIFO:
             print("uhal UDP error in FIFO.get_occupancy")
             raise
 
+    def is_full(self):
+        return self.rb.kcu.read_node(f"READOUT_BOARD_{self.rb.rb}.RX_FIFO_FULL").value()
+
     def get_lost_word_count(self):
         return self.rb.kcu.read_node(f"READOUT_BOARD_{self.rb.rb}.RX_FIFO_LOST_WORD_CNT").value()
 
diff --git a/test_ETROC.py b/test_ETROC.py
index e71ae89..a384937 100644
--- a/test_ETROC.py
+++ b/test_ETROC.py
@@ -8,6 +8,7 @@ from tamalero.colors import red, green, yellow
 import numpy as np
 from scipy.optimize import curve_fit
 from matplotlib import pyplot as plt
+from tqdm import tqdm
 
 import os
 import sys
@@ -276,7 +277,7 @@ if __name__ == '__main__':
 
         #fifo.reset()
         etroc.wr_reg("selfTestOccupancy", 2, broadcast=True)
-        etroc.wr_reg("singlePort", 0x0)
+        #etroc.wr_reg("singlePort", 0x0)
         etroc.wr_reg("mergeTriggerData", 0x1)
         #etroc.wr_reg("")
         if not args.partial:
@@ -359,7 +360,7 @@ if __name__ == '__main__':
                 ax=ax,
                 fontsize=15,
             )
-        name = 'hit_matrix'
+        name = 'hit_matrix_internal_test_pattern'
         fig.savefig(os.path.join(plot_dir, "{}.pdf".format(name)))
         fig.savefig(os.path.join(plot_dir, "{}.png".format(name)))
 
@@ -369,6 +370,59 @@ if __name__ == '__main__':
         for x in fifo.pretty_read(df):
             print(x)
 
+        ### Using noise hits for another occupancy map
+        i = 0
+        occupancy = 0
+        print("\n - Will send L1As until FIFO is full.")
+        occupancy = 0
+        with tqdm(total=65536) as pbar:
+            while not fifo.is_full():
+                fifo.send_l1a()
+                i +=1
+                if i%100 == 0:
+                    tmp = fifo.get_occupancy()
+                    pbar.update(tmp-occupancy)
+                    occupancy = tmp
+
+        test_data = []
+        while fifo.get_occupancy() > 0:
+            test_data += fifo.pretty_read(df)
+
+        hits_total = np.zeros((16,16))
+        hit_matrix = hist.Hist(col_axis,row_axis)
+        n_events_total = 0
+        n_events_hit   = 0
+        for d in test_data:
+            if d[0] == 'trailer':
+                n_events_total += 1
+                if d[1]['hits'] > 0:
+                    n_events_hit += 1
+            if d[0] == 'data':
+                hit_matrix.fill(row=d[1]['row_id'], col=d[1]['col_id'])
+                hits_total[d[1]['row_id']][d[1]['col_id']] += 1
+                # NOTE could do some CRC check.
+
+        print(f"Got number of total events {n_events_total=}")
+        print(f"Events with at least one hit {n_events_hit=}")
+
+        fig, ax = plt.subplots(1,1,figsize=(7,7))
+        hit_matrix.plot2d(
+            ax=ax,
+        )
+        ax.set_ylabel(r'$Row$')
+        ax.set_xlabel(r'$Column$')
+        hep.cms.label(
+                "ETL Preliminary",
+                data=True,
+                lumi='0',
+                com=0,
+                loc=0,
+                ax=ax,
+                fontsize=15,
+            )
+        name = 'hit_matrix_external_L1A'
+        fig.savefig(os.path.join(plot_dir, "{}.pdf".format(name)))
+        fig.savefig(os.path.join(plot_dir, "{}.png".format(name)))
 
 
     elif args.vth:
-- 
GitLab


From e5b765e187f95eccc698477f3215fcf48ca395f4 Mon Sep 17 00:00:00 2001
From: dspitzba <daniel.spitzbart@cern.ch>
Date: Mon, 12 Jun 2023 10:20:13 -0400
Subject: [PATCH 02/14] add sanity check histograms

---
 test_ETROC.py | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/test_ETROC.py b/test_ETROC.py
index a384937..e9c09fb 100644
--- a/test_ETROC.py
+++ b/test_ETROC.py
@@ -425,6 +425,11 @@ if __name__ == '__main__':
         fig.savefig(os.path.join(plot_dir, "{}.png".format(name)))
 
 
+        print("\nOccupancy vs column:")
+        hit_matrix[{"row":sum}].show(columns=100)
+        print("\nOccupancy vs row:")
+        hit_matrix[{"col":sum}].show(columns=100)
+
     elif args.vth:
         # ==============================
         # ======= Test Vth scan ========
-- 
GitLab


From 61d909e9c7b027f949dc2bbcc9ee3c63e1af0989 Mon Sep 17 00:00:00 2001
From: jocain <jgocain@bu.edu>
Date: Mon, 12 Jun 2023 14:26:22 -0400
Subject: [PATCH 03/14] Fix get_Qinj() typo

---
 tamalero/ETROC.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tamalero/ETROC.py b/tamalero/ETROC.py
index 2480ffa..d9068d1 100644
--- a/tamalero/ETROC.py
+++ b/tamalero/ETROC.py
@@ -357,10 +357,10 @@ class ETROC():
 
     def QInj_read(self, row=0, col=0, broadcast=True):
         if broadcast:
-            qinj = [[self.get_Qinj(row=y, col=x) for x in range(16)] for y in range(16)]
+            qinj = [[self.get_QInj(row=y, col=x) for x in range(16)] for y in range(16)]
             return qinj
         else:
-            return self.get_Qinj(row=row, col=col)
+            return self.get_QInj(row=row, col=col)
 
     def auto_threshold_scan(self):
         # FIXME not yet fully working
-- 
GitLab


From 947411c05f24adb6240aa8a62f143e6ad3b672ea Mon Sep 17 00:00:00 2001
From: dspitzba <daniel.spitzbart@cern.ch>
Date: Tue, 13 Jun 2023 13:13:48 -0400
Subject: [PATCH 04/14] updates, still using internal test data

---
 tamalero/ETROC.py |   2 +
 tamalero/FIFO.py  |  26 +++++++--
 test_ETROC.py     | 136 ++++++++++++++++++++++++++--------------------
 3 files changed, 98 insertions(+), 66 deletions(-)

diff --git a/tamalero/ETROC.py b/tamalero/ETROC.py
index 2480ffa..cc3af25 100644
--- a/tamalero/ETROC.py
+++ b/tamalero/ETROC.py
@@ -334,6 +334,7 @@ class ETROC():
     # =======================
 
     def QInj_set(self, charge, delay, row=0, col=0, broadcast=True, reset=True):
+        # FIXME this is a bad name, given that set_QInj also exists
         """
         High-level function to set the charge injection in the ETROC;
         requires \'charge\' (in fC) and \'delay\' (in 781 ps steps).
@@ -352,6 +353,7 @@ class ETROC():
         """
         if broadcast:
             self.set_ChargeInjReset(False)                             # Reset charge injection module
+            self.disable_QInj(broadcast=broadcast)   # Only disable charge injection for specified pixel
         else:
             self.disable_QInj(row=row, col=col, broadcast=broadcast)   # Only disable charge injection for specified pixel
 
diff --git a/tamalero/FIFO.py b/tamalero/FIFO.py
index 346d8e7..76e2aca 100644
--- a/tamalero/FIFO.py
+++ b/tamalero/FIFO.py
@@ -24,7 +24,10 @@ def merge_words(res):
         # offset is only needed when zero suppression is turned off, and packet boundaries are not defined
         # it relies on the fact that the second 32 bit word is half empty (8 bit ETROC data + 12 bits meta data)
         # if we ever add more meta data this has to be revisited
-        offset = 1 if (res[1] > res[0]) else 0
+        #offset = 1 if (res[1] > res[0]) else 0
+        offset = 0
+        print(f"## Offset is {offset=}")
+        #offset = 0
         res = res[offset:]
         #empty_frame_mask = np.array(res[0::2]) > (2**8)  # masking empty fifo entries
         #print(res)
@@ -105,12 +108,18 @@ class FIFO:
 
     def send_l1a(self, count=1):
         for i in range(count):
-            self.rb.kcu.write_node("SYSTEM.L1A_PULSE", 1)
+            try:
+                self.rb.kcu.write_node("SYSTEM.L1A_PULSE", 1)
+            except:
+                print("Couldn't send pulse.")
 
     def send_QInj(self, count=1, delay=0):
         self.rb.kcu.write_node("READOUT_BOARD_%s.L1A_INJ_DLY"%self.rb.rb, delay)
         for i in range(count):
-            self.rb.kcu.write_node("READOUT_BOARD_%s.L1A_QINJ_PULSE" % self.rb.rb, 0x01)
+            try:
+                self.rb.kcu.write_node("READOUT_BOARD_%s.L1A_QINJ_PULSE" % self.rb.rb, 0x01)
+            except:
+                print("Couldn't send pulse.")
 
     def reset(self):
         self.rb.kcu.write_node("READOUT_BOARD_%s.FIFO_RESET" % self.rb.rb, 0x01)
@@ -169,11 +178,16 @@ class FIFO:
         try:
             return self.rb.kcu.read_node(f"READOUT_BOARD_{self.rb.rb}.RX_FIFO_OCCUPANCY").value()
         except uhal_exception:
-            print("uhal UDP error in FIFO.get_occupancy")
-            raise
+            print("uhal UDP error in FIFO.get_occupancy, trying again")
+            return self.rb.kcu.read_node(f"READOUT_BOARD_{self.rb.rb}.RX_FIFO_OCCUPANCY").value()
+            #raise
 
     def is_full(self):
-        return self.rb.kcu.read_node(f"READOUT_BOARD_{self.rb.rb}.RX_FIFO_FULL").value()
+        try:
+            return self.rb.kcu.read_node(f"READOUT_BOARD_{self.rb.rb}.RX_FIFO_FULL").value()
+        except uhal_exception:
+            print("uhal UDP error in FIFO.is_full, trying again")
+            return self.rb.kcu.read_node(f"READOUT_BOARD_{self.rb.rb}.RX_FIFO_FULL").value()
 
     def get_lost_word_count(self):
         return self.rb.kcu.read_node(f"READOUT_BOARD_{self.rb.rb}.RX_FIFO_LOST_WORD_CNT").value()
diff --git a/test_ETROC.py b/test_ETROC.py
index e9c09fb..f074e8f 100644
--- a/test_ETROC.py
+++ b/test_ETROC.py
@@ -13,6 +13,7 @@ from tqdm import tqdm
 import os
 import sys
 import json
+import time
 from yaml import load, dump
 try:
     from yaml import CLoader as Loader, CDumper as Dumper
@@ -284,7 +285,8 @@ if __name__ == '__main__':
             etroc.wr_reg("workMode", 0x1, broadcast=True)
         else:
             etroc.wr_reg("workMode", 0x0, broadcast=True)
-            # center pixels
+            ## center pixels
+            #etroc.wr_reg("workMode", 0x1, row=15, col=7)
             etroc.wr_reg("workMode", 0x1, row=7, col=7)
             etroc.wr_reg("workMode", 0x1, row=7, col=8)
             etroc.wr_reg("workMode", 0x1, row=8, col=7)
@@ -370,65 +372,79 @@ if __name__ == '__main__':
         for x in fifo.pretty_read(df):
             print(x)
 
-        ### Using noise hits for another occupancy map
-        i = 0
-        occupancy = 0
-        print("\n - Will send L1As until FIFO is full.")
-        occupancy = 0
-        with tqdm(total=65536) as pbar:
-            while not fifo.is_full():
-                fifo.send_l1a()
-                i +=1
-                if i%100 == 0:
-                    tmp = fifo.get_occupancy()
-                    pbar.update(tmp-occupancy)
-                    occupancy = tmp
-
-        test_data = []
-        while fifo.get_occupancy() > 0:
-            test_data += fifo.pretty_read(df)
-
-        hits_total = np.zeros((16,16))
-        hit_matrix = hist.Hist(col_axis,row_axis)
-        n_events_total = 0
-        n_events_hit   = 0
-        for d in test_data:
-            if d[0] == 'trailer':
-                n_events_total += 1
-                if d[1]['hits'] > 0:
-                    n_events_hit += 1
-            if d[0] == 'data':
-                hit_matrix.fill(row=d[1]['row_id'], col=d[1]['col_id'])
-                hits_total[d[1]['row_id']][d[1]['col_id']] += 1
-                # NOTE could do some CRC check.
-
-        print(f"Got number of total events {n_events_total=}")
-        print(f"Events with at least one hit {n_events_hit=}")
-
-        fig, ax = plt.subplots(1,1,figsize=(7,7))
-        hit_matrix.plot2d(
-            ax=ax,
-        )
-        ax.set_ylabel(r'$Row$')
-        ax.set_xlabel(r'$Column$')
-        hep.cms.label(
-                "ETL Preliminary",
-                data=True,
-                lumi='0',
-                com=0,
-                loc=0,
-                ax=ax,
-                fontsize=15,
-            )
-        name = 'hit_matrix_external_L1A'
-        fig.savefig(os.path.join(plot_dir, "{}.pdf".format(name)))
-        fig.savefig(os.path.join(plot_dir, "{}.png".format(name)))
-
-
-        print("\nOccupancy vs column:")
-        hit_matrix[{"row":sum}].show(columns=100)
-        print("\nOccupancy vs row:")
-        hit_matrix[{"col":sum}].show(columns=100)
+        #etroc.QInj_unset(broadcast=True)
+        fifo.reset()
+        print("Will use workMode 1 to get some occupancy (no noise or charge injection)")
+        etroc.wr_reg("workMode", 0x1, broadcast=True)  # this was missing
+        if not args.partial:
+            for j in range(5):
+                print(j)
+                ### Another occupancy map
+                i = 0
+                occupancy = 0
+                print("\n - Will send L1As until FIFO is full.")
+
+                #etroc.QInj_set(30, 0, row=3, col=3, broadcast=False)
+                start_time = time.time()
+                with tqdm(total=65536) as pbar:
+                    while not fifo.is_full():
+                        fifo.send_l1a()
+                        #fifo.send_QInj(delay=j)
+                        #fifo.send_QInj()
+                        i +=1
+                        if i%100 == 0:
+                            tmp = fifo.get_occupancy()
+                            pbar.update(tmp-occupancy)
+                            occupancy = tmp
+                        #if time.time()-start_time>5:
+                        #    print("Time out")
+                        #    break
+
+                test_data = []
+                while fifo.get_occupancy() > 0:
+                    test_data += fifo.pretty_read(df)
+
+                hits_total = np.zeros((16,16))
+                hit_matrix = hist.Hist(col_axis,row_axis)
+                n_events_total = 0
+                n_events_hit   = 0
+                for d in test_data:
+                    if d[0] == 'trailer':
+                        n_events_total += 1
+                        if d[1]['hits'] > 0:
+                            n_events_hit += 1
+                    if d[0] == 'data':
+                        hit_matrix.fill(row=d[1]['row_id'], col=d[1]['col_id'])
+                        hits_total[d[1]['row_id']][d[1]['col_id']] += 1
+                        # NOTE could do some CRC check.
+
+                print(f"Got number of total events {n_events_total=}")
+                print(f"Events with at least one hit {n_events_hit=}")
+
+                fig, ax = plt.subplots(1,1,figsize=(7,7))
+                hit_matrix.plot2d(
+                    ax=ax,
+                )
+                ax.set_ylabel(r'$Row$')
+                ax.set_xlabel(r'$Column$')
+                hep.cms.label(
+                        "ETL Preliminary",
+                        data=True,
+                        lumi='0',
+                        com=0,
+                        loc=0,
+                        ax=ax,
+                        fontsize=15,
+                    )
+                name = 'hit_matrix_external_L1A'
+                fig.savefig(os.path.join(plot_dir, "{}.pdf".format(name)))
+                fig.savefig(os.path.join(plot_dir, "{}.png".format(name)))
+
+
+                print("\nOccupancy vs column:")
+                hit_matrix[{"row":sum}].show(columns=100)
+                print("\nOccupancy vs row:")
+                hit_matrix[{"col":sum}].show(columns=100)
 
     elif args.vth:
         # ==============================
-- 
GitLab


From 367c63a924e162dc45aed468082d23aa59f7b9d3 Mon Sep 17 00:00:00 2001
From: jocain <jgocain@bu.edu>
Date: Tue, 13 Jun 2023 13:34:29 -0400
Subject: [PATCH 05/14] Adding Single Pixel L1a Charge Injection Test

---
 test_ETROC.py | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)

diff --git a/test_ETROC.py b/test_ETROC.py
index f074e8f..26f63d5 100644
--- a/test_ETROC.py
+++ b/test_ETROC.py
@@ -446,6 +446,68 @@ if __name__ == '__main__':
                 print("\nOccupancy vs row:")
                 hit_matrix[{"col":sum}].show(columns=100)
 
+        fifo.reset()
+        q = 30
+        delay = 6
+        i = 4
+        j = 3
+        print(f"\n - Will send L1a/QInj pulse with delay of {delay} cycles and charge of {q} fC")
+        print(f"\n - to pixel at Row {i}, Col {j}.")
+        etroc.QInj_set(q, delay, row=row, col=col, broadcast = False)
+        with tqdm(total=65536) as pbar:
+            while not fifo.is_full():
+                try:
+                    kcu.write_node('READOUT_BOARD_0.L1A_QINJ_PULSE', 1)
+                except:
+                    println('uhal._core.exception: Failed to pulse', file)
+        etroc.QInj_unset(broadcast = True)
+        test_data = []
+        while fifo.get_occupancy() > 0:
+            test_data += fifo.pretty_read(df)
+
+        hits_total = np.zeros((16,16))
+        hit_matrix = hist.Hist(col_axis,row_axis)
+        n_events_total = 0
+        n_events_hit   = 0
+        for d in test_data:
+            if d[0] == 'trailer':
+                n_events_total += 1
+                if d[1]['hits'] > 0:
+                    n_events_hit += 1
+            if d[0] == 'data':
+                hit_matrix.fill(row=d[1]['row_id'], col=d[1]['col_id'])
+                hits_total[d[1]['row_id']][d[1]['col_id']] += 1
+                # NOTE could do some CRC check.
+
+        print(f"Got number of total events {n_events_total=}")
+        print(f"Events with at least one hit {n_events_hit=}")
+
+        fig, ax = plt.subplots(1,1,figsize=(7,7))
+        hit_matrix.plot2d(
+            ax=ax,
+        )
+        ax.set_ylabel(r'$Row$')
+        ax.set_xlabel(r'$Column$')
+        hep.cms.label(
+                "ETL Preliminary",
+                data=True,
+                lumi='0',
+                com=0,
+                loc=0,
+                ax=ax,
+                fontsize=15,
+            )
+        name = 'hit_matrix_external_L1A_QInj_Pulse'
+        fig.savefig(os.path.join(plot_dir, "{}.pdf".format(name)))
+        fig.savefig(os.path.join(plot_dir, "{}.png".format(name)))
+
+        print("\nOccupancy vs column:")
+        hit_matrix[{"row":sum}].show(columns=100)
+        print("\nOccupancy vs row:")
+        hit_matrix[{"col":sum}].show(columns=100)
+
+
+
     elif args.vth:
         # ==============================
         # ======= Test Vth scan ========
-- 
GitLab


From 3afd7285dc61761e432e308ba45fc341dcd4e510 Mon Sep 17 00:00:00 2001
From: jocain <jgocain@bu.edu>
Date: Tue, 13 Jun 2023 14:39:12 -0400
Subject: [PATCH 06/14] Fixed a couple of typos in last commit

---
 test_ETROC.py | 114 +++++++++++++++++++++++++-------------------------
 1 file changed, 58 insertions(+), 56 deletions(-)

diff --git a/test_ETROC.py b/test_ETROC.py
index 26f63d5..3c97e1d 100644
--- a/test_ETROC.py
+++ b/test_ETROC.py
@@ -196,7 +196,7 @@ if __name__ == '__main__':
         etroc.set_singlePort("right")
 
         #etroc = ETROC(rb=rb_0, i2c_adr=96, i2c_channel=1, elinks={0:[0,2]})
-
+        
         print("\n - Checking peripheral configuration:")
         etroc.print_perif_conf()
 
@@ -244,7 +244,7 @@ if __name__ == '__main__':
         else:
             print(f"Failed: {test0=}, {test1=}, {test2=}, {test3=}")
 
-
+        
         etroc.wr_reg('serRateLeft', 0)
         etroc.wr_reg('serRateRight', 0)
 
@@ -262,7 +262,7 @@ if __name__ == '__main__':
         #rb_0.SCA.set_gpio_direction('mod_d07', 1)
         #rb_0.SCA.set_gpio('mod_d07', 0)
         #rb_0.SCA.set_gpio('mod_d07', 1)
-
+        
         print("\n - Checking elinks")
         locked = kcu.read_node(f"READOUT_BOARD_0.ETROC_LOCKED").value()
         if (locked & 0b101) == 5:
@@ -275,12 +275,13 @@ if __name__ == '__main__':
             print(red('No elink is locked.'))
 
         print("\n - Getting internal test data")
-
+        
         #fifo.reset()
         etroc.wr_reg("selfTestOccupancy", 2, broadcast=True)
         #etroc.wr_reg("singlePort", 0x0)
         etroc.wr_reg("mergeTriggerData", 0x1)
         #etroc.wr_reg("")
+        
         if not args.partial:
             etroc.wr_reg("workMode", 0x1, broadcast=True)
         else:
@@ -445,66 +446,67 @@ if __name__ == '__main__':
                 hit_matrix[{"row":sum}].show(columns=100)
                 print("\nOccupancy vs row:")
                 hit_matrix[{"col":sum}].show(columns=100)
-
+        etroc.wr_reg("workMode", 0x0, broadcast=True) 
         fifo.reset()
         q = 30
-        delay = 6
+        delay = 3
         i = 4
         j = 3
         print(f"\n - Will send L1a/QInj pulse with delay of {delay} cycles and charge of {q} fC")
         print(f"\n - to pixel at Row {i}, Col {j}.")
-        etroc.QInj_set(q, delay, row=row, col=col, broadcast = False)
-        with tqdm(total=65536) as pbar:
-            while not fifo.is_full():
-                try:
-                    kcu.write_node('READOUT_BOARD_0.L1A_QINJ_PULSE', 1)
-                except:
-                    println('uhal._core.exception: Failed to pulse', file)
-        etroc.QInj_unset(broadcast = True)
-        test_data = []
-        while fifo.get_occupancy() > 0:
-            test_data += fifo.pretty_read(df)
-
-        hits_total = np.zeros((16,16))
-        hit_matrix = hist.Hist(col_axis,row_axis)
-        n_events_total = 0
-        n_events_hit   = 0
-        for d in test_data:
-            if d[0] == 'trailer':
-                n_events_total += 1
-                if d[1]['hits'] > 0:
-                    n_events_hit += 1
-            if d[0] == 'data':
-                hit_matrix.fill(row=d[1]['row_id'], col=d[1]['col_id'])
-                hits_total[d[1]['row_id']][d[1]['col_id']] += 1
-                # NOTE could do some CRC check.
-
-        print(f"Got number of total events {n_events_total=}")
-        print(f"Events with at least one hit {n_events_hit=}")
-
-        fig, ax = plt.subplots(1,1,figsize=(7,7))
-        hit_matrix.plot2d(
-            ax=ax,
-        )
-        ax.set_ylabel(r'$Row$')
-        ax.set_xlabel(r'$Column$')
-        hep.cms.label(
-                "ETL Preliminary",
-                data=True,
-                lumi='0',
-                com=0,
-                loc=0,
+        for m in range(5):
+            etroc.QInj_set(q, delay, row=i, col=j, broadcast = False)
+            with tqdm(total=65536) as pbar:
+                while not fifo.is_full():
+                    try:
+                        kcu.write_node('READOUT_BOARD_0.L1A_QINJ_PULSE', 1)
+                    except:
+                        print('uhal._core.exception: Failed to pulse', file)
+            etroc.QInj_unset(broadcast = True)
+            test_data = []
+            while fifo.get_occupancy() > 0:
+                test_data += fifo.pretty_read(df)
+
+            hits_total = np.zeros((16,16))
+            hit_matrix = hist.Hist(col_axis,row_axis)
+            n_events_total = 0
+            n_events_hit   = 0
+            for d in test_data:
+                if d[0] == 'trailer':
+                    n_events_total += 1
+                    if d[1]['hits'] > 0:
+                        n_events_hit += 1
+                if d[0] == 'data':
+                    hit_matrix.fill(row=d[1]['row_id'], col=d[1]['col_id'])
+                    hits_total[d[1]['row_id']][d[1]['col_id']] += 1
+                    # NOTE could do some CRC check.
+
+            print(f"Got number of total events {n_events_total=}")
+            print(f"Events with at least one hit {n_events_hit=}")
+
+            fig, ax = plt.subplots(1,1,figsize=(7,7))
+            hit_matrix.plot2d(
                 ax=ax,
-                fontsize=15,
             )
-        name = 'hit_matrix_external_L1A_QInj_Pulse'
-        fig.savefig(os.path.join(plot_dir, "{}.pdf".format(name)))
-        fig.savefig(os.path.join(plot_dir, "{}.png".format(name)))
-
-        print("\nOccupancy vs column:")
-        hit_matrix[{"row":sum}].show(columns=100)
-        print("\nOccupancy vs row:")
-        hit_matrix[{"col":sum}].show(columns=100)
+            ax.set_ylabel(r'$Row$')
+            ax.set_xlabel(r'$Column$')
+            hep.cms.label(
+                    "ETL Preliminary",
+                    data=True,
+                    lumi='0',
+                    com=0,
+                    loc=0,
+                    ax=ax,
+                    fontsize=15,
+                )
+            name = f'hit_matrix_external_L1A_QInj_Pulse_'+str(m)
+            fig.savefig(os.path.join(plot_dir, "{}.pdf".format(name)))
+            fig.savefig(os.path.join(plot_dir, "{}.png".format(name)))
+
+            print("\nOccupancy vs column:")
+            hit_matrix[{"row":sum}].show(columns=100)
+            print("\nOccupancy vs row:")
+            hit_matrix[{"col":sum}].show(columns=100)
 
 
 
-- 
GitLab


From aebab4855b83ce7a94a4485f267c9feed27128d1 Mon Sep 17 00:00:00 2001
From: dspitzba <daniel.spitzbart@cern.ch>
Date: Wed, 21 Jun 2023 18:39:40 -0400
Subject: [PATCH 07/14] clean up

---
 test_ETROC.py | 25 ++++++++-----------------
 1 file changed, 8 insertions(+), 17 deletions(-)

diff --git a/test_ETROC.py b/test_ETROC.py
index f074e8f..d1c2d49 100644
--- a/test_ETROC.py
+++ b/test_ETROC.py
@@ -192,8 +192,8 @@ if __name__ == '__main__':
         modules[module-1].show_status()
 
         etroc = modules[module-1].ETROCs[0]
-        print(f"Setting the ETROC in single port mode ('right')")
-        etroc.set_singlePort("right")
+        #print(f"Setting the ETROC in single port mode ('right')")
+        #etroc.set_singlePort("right")
 
         #etroc = ETROC(rb=rb_0, i2c_adr=96, i2c_channel=1, elinks={0:[0,2]})
 
@@ -245,10 +245,6 @@ if __name__ == '__main__':
             print(f"Failed: {test0=}, {test1=}, {test2=}, {test3=}")
 
 
-        etroc.wr_reg('serRateLeft', 0)
-        etroc.wr_reg('serRateRight', 0)
-
-
         # NOTE below is WIP code for tests of the actual data readout
         from tamalero.FIFO import FIFO
         from tamalero.DataFrame import DataFrame
@@ -258,11 +254,6 @@ if __name__ == '__main__':
         fifo.select_elink(2)
         fifo.ready()
 
-        ### this does in theory reset the ETROC, but not sure if it comes back up properly
-        #rb_0.SCA.set_gpio_direction('mod_d07', 1)
-        #rb_0.SCA.set_gpio('mod_d07', 0)
-        #rb_0.SCA.set_gpio('mod_d07', 1)
-
         print("\n - Checking elinks")
         locked = kcu.read_node(f"READOUT_BOARD_0.ETROC_LOCKED").value()
         if (locked & 0b101) == 5:
@@ -274,13 +265,13 @@ if __name__ == '__main__':
         else:
             print(red('No elink is locked.'))
 
+        fifo.send_l1a(10)
+        _ = fifo.pretty_read(df)
+        etroc.reset()
+
         print("\n - Getting internal test data")
 
-        #fifo.reset()
         etroc.wr_reg("selfTestOccupancy", 2, broadcast=True)
-        #etroc.wr_reg("singlePort", 0x0)
-        etroc.wr_reg("mergeTriggerData", 0x1)
-        #etroc.wr_reg("")
         if not args.partial:
             etroc.wr_reg("workMode", 0x1, broadcast=True)
         else:
@@ -374,9 +365,9 @@ if __name__ == '__main__':
 
         #etroc.QInj_unset(broadcast=True)
         fifo.reset()
-        print("Will use workMode 1 to get some occupancy (no noise or charge injection)")
-        etroc.wr_reg("workMode", 0x1, broadcast=True)  # this was missing
         if not args.partial:
+            print("Will use workMode 1 to get some occupancy (no noise or charge injection)")
+            etroc.wr_reg("workMode", 0x1, broadcast=True)  # this was missing
             for j in range(5):
                 print(j)
                 ### Another occupancy map
-- 
GitLab


From 68e02a6becdc26d02e27ac63f0acbd2cc19e393d Mon Sep 17 00:00:00 2001
From: dspitzba <daniel.spitzbart@cern.ch>
Date: Wed, 21 Jun 2023 18:40:01 -0400
Subject: [PATCH 08/14] debugging features

---
 configs/dataformat.yaml |  4 ++--
 tamalero/ETROC.py       | 16 +++++++++++++++-
 tamalero/Module.py      |  1 +
 3 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/configs/dataformat.yaml b/configs/dataformat.yaml
index 9ac80f3..4471c25 100644
--- a/configs/dataformat.yaml
+++ b/configs/dataformat.yaml
@@ -78,9 +78,9 @@ ETROC2:
       frame: 0x0000000000
       mask: 0x8000000000
   types:
-    0: [ea, col_id, row_id, toa, cal, tot]
+    0: [ea, col_id, row_id, toa, cal, tot, elink, full, any_full, global_full]
     1: [ea, col_id, row_id, col_id2, row_id2, bcid, counter_a, elink, full, any_full, global_full]
-    2: [ea, col_id, row_id, col_id2, row_id2, counter_b, test_pattern]
+    2: [ea, col_id, row_id, col_id2, row_id2, counter_b, test_pattern, elink, full, any_full, global_full]
   data:
     header: # Define the different masks here?
       elink:
diff --git a/tamalero/ETROC.py b/tamalero/ETROC.py
index 372f2d8..7a88e3b 100644
--- a/tamalero/ETROC.py
+++ b/tamalero/ETROC.py
@@ -1,6 +1,7 @@
 """
 For ETROC control
 """
+import time
 
 from tamalero.utils import load_yaml, ffs, bit_count
 from tamalero.colors import red, green, yellow
@@ -20,6 +21,7 @@ class ETROC():
             elinks={0:[0]},
             verbose=False,
             strict=True,
+            reset=None,
     ):
         self.isfake = False
         self.I2C_master = rb.DAQ_LPGBT if master.lower() == 'lpgbt' else rb.SCA
@@ -29,6 +31,7 @@ class ETROC():
         self.i2c_channel = i2c_channel
         self.i2c_adr = i2c_adr
         self.elinks = elinks
+        self.reset_pin = reset
         self.is_connected()
         if self.connected:
             self.ver = self.get_ver()
@@ -237,6 +240,16 @@ class ETROC():
             all_pass &= comp
         return all_pass
 
+    def reset(self, hard=False):
+        if hard:
+            self.rb.SCA.set_gpio(self.reset_pin, 0)
+            time.sleep(0.1)
+            self.rb.SCA.set_gpio(self.reset_pin, 1)
+        else:
+            self.wr_reg("asyResetGlobalReadout", 0)
+            time.sleep(0.1)
+            self.wr_reg("asyResetGlobalReadout", 1)
+
     # ============================
     # === MONITORING FUNCTIONS ===
     # ============================
@@ -319,6 +332,7 @@ class ETROC():
     def default_config(self):
         # FIXME should use higher level functions for better readability
         if self.connected:
+            self.reset()  # soft reset of the global readout
             self.set_singlePort('both')
             self.set_mergeTriggerData('separate')
             self.disable_Scrambler()
@@ -547,7 +561,7 @@ class ETROC():
     def set_workMode(self, mode, row=0, col=0, broadcast=True):
         val = {'normal': 0b00, 'self test fixed': 0b01, 'self test random': 0b10}
         try:
-            self.wr_reg('workMode', val(mode), row=row, col=col, broadcast=broadcast)
+            self.wr_reg('workMode', val[mode], row=row, col=col, broadcast=broadcast)
         except KeyError:
             print('Choose between \'normal\', \'self test fixed\', \'self test random\'.')
 
diff --git a/tamalero/Module.py b/tamalero/Module.py
index af512bc..da8113a 100644
--- a/tamalero/Module.py
+++ b/tamalero/Module.py
@@ -38,6 +38,7 @@ class Module:
                         #elinks      = self.config['elinks'][j],
                         i2c_adr     = self.config['addresses'][j],
                         strict      = strict,
+                        reset = self.config['reset'],
                     ))
 
     #def configure(self):
-- 
GitLab


From 4eb86e126cd472f74602ba9c7c6e525cd8e22ddb Mon Sep 17 00:00:00 2001
From: dspitzba <daniel.spitzbart@cern.ch>
Date: Wed, 21 Jun 2023 18:50:56 -0400
Subject: [PATCH 09/14] make qinj tests optional

---
 test_ETROC.py | 121 +++++++++++++++++++++++++-------------------------
 1 file changed, 61 insertions(+), 60 deletions(-)

diff --git a/test_ETROC.py b/test_ETROC.py
index 84c0e2f..febd138 100644
--- a/test_ETROC.py
+++ b/test_ETROC.py
@@ -110,6 +110,7 @@ if __name__ == '__main__':
     argParser.add_argument('--module', action='store', default=0, choices=['1','2','3'], help="Module to test")
     argParser.add_argument('--host', action='store', default='localhost', help="Hostname for control hub")
     argParser.add_argument('--partial', action='store_true', default=False, help="Only read data from corners and edges")
+    argParser.add_argument('--qinj', action='store_true', default=False, help="Run some charge injection tests")
     args = argParser.parse_args()
 
 
@@ -153,7 +154,6 @@ if __name__ == '__main__':
             print("Test passed.\n")
 
     elif args.test_chip:
-        # FIXME this is still hardcoded
         kcu = get_kcu(args.kcu, control_hub=True, host=args.host, verbose=False)
         if (kcu == 0):
             # if not basic connection was established the get_kcu function returns 0
@@ -436,67 +436,68 @@ if __name__ == '__main__':
                 print("\nOccupancy vs row:")
                 hit_matrix[{"col":sum}].show(columns=100)
 
-        etroc.wr_reg("workMode", 0x0, broadcast=True) 
-        fifo.reset()
-        q = 30
-        delay = 3
-        i = 4
-        j = 3
-        print(f"\n - Will send L1a/QInj pulse with delay of {delay} cycles and charge of {q} fC")
-        print(f"\n - to pixel at Row {i}, Col {j}.")
-        for m in range(5):
-            etroc.QInj_set(q, delay, row=i, col=j, broadcast = False)
-            with tqdm(total=65536) as pbar:
-                while not fifo.is_full():
-                    try:
-                        kcu.write_node('READOUT_BOARD_0.L1A_QINJ_PULSE', 1)
-                    except:
-                        print('uhal._core.exception: Failed to pulse', file)
-            etroc.QInj_unset(broadcast = True)
-            test_data = []
-            while fifo.get_occupancy() > 0:
-                test_data += fifo.pretty_read(df)
-
-            hits_total = np.zeros((16,16))
-            hit_matrix = hist.Hist(col_axis,row_axis)
-            n_events_total = 0
-            n_events_hit   = 0
-            for d in test_data:
-                if d[0] == 'trailer':
-                    n_events_total += 1
-                    if d[1]['hits'] > 0:
-                        n_events_hit += 1
-                if d[0] == 'data':
-                    hit_matrix.fill(row=d[1]['row_id'], col=d[1]['col_id'])
-                    hits_total[d[1]['row_id']][d[1]['col_id']] += 1
-                    # NOTE could do some CRC check.
-
-            print(f"Got number of total events {n_events_total=}")
-            print(f"Events with at least one hit {n_events_hit=}")
-
-            fig, ax = plt.subplots(1,1,figsize=(7,7))
-            hit_matrix.plot2d(
-                ax=ax,
-            )
-            ax.set_ylabel(r'$Row$')
-            ax.set_xlabel(r'$Column$')
-            hep.cms.label(
-                    "ETL Preliminary",
-                    data=True,
-                    lumi='0',
-                    com=0,
-                    loc=0,
+        if args.qinj:
+            etroc.wr_reg("workMode", 0x0, broadcast=True)
+            fifo.reset()
+            q = 30
+            delay = 3
+            i = 4
+            j = 3
+            print(f"\n - Will send L1a/QInj pulse with delay of {delay} cycles and charge of {q} fC")
+            print(f"\n - to pixel at Row {i}, Col {j}.")
+            for m in range(5):
+                etroc.QInj_set(q, delay, row=i, col=j, broadcast = False)
+                with tqdm(total=65536) as pbar:
+                    while not fifo.is_full():
+                        try:
+                            kcu.write_node('READOUT_BOARD_0.L1A_QINJ_PULSE', 1)
+                        except:
+                            print('uhal._core.exception: Failed to pulse', file)
+                etroc.QInj_unset(broadcast = True)
+                test_data = []
+                while fifo.get_occupancy() > 0:
+                    test_data += fifo.pretty_read(df)
+
+                hits_total = np.zeros((16,16))
+                hit_matrix = hist.Hist(col_axis,row_axis)
+                n_events_total = 0
+                n_events_hit   = 0
+                for d in test_data:
+                    if d[0] == 'trailer':
+                        n_events_total += 1
+                        if d[1]['hits'] > 0:
+                            n_events_hit += 1
+                    if d[0] == 'data':
+                        hit_matrix.fill(row=d[1]['row_id'], col=d[1]['col_id'])
+                        hits_total[d[1]['row_id']][d[1]['col_id']] += 1
+                        # NOTE could do some CRC check.
+
+                print(f"Got number of total events {n_events_total=}")
+                print(f"Events with at least one hit {n_events_hit=}")
+
+                fig, ax = plt.subplots(1,1,figsize=(7,7))
+                hit_matrix.plot2d(
                     ax=ax,
-                    fontsize=15,
                 )
-            name = f'hit_matrix_external_L1A_QInj_Pulse_'+str(m)
-            fig.savefig(os.path.join(plot_dir, "{}.pdf".format(name)))
-            fig.savefig(os.path.join(plot_dir, "{}.png".format(name)))
-
-            print("\nOccupancy vs column:")
-            hit_matrix[{"row":sum}].show(columns=100)
-            print("\nOccupancy vs row:")
-            hit_matrix[{"col":sum}].show(columns=100)
+                ax.set_ylabel(r'$Row$')
+                ax.set_xlabel(r'$Column$')
+                hep.cms.label(
+                        "ETL Preliminary",
+                        data=True,
+                        lumi='0',
+                        com=0,
+                        loc=0,
+                        ax=ax,
+                        fontsize=15,
+                    )
+                name = f'hit_matrix_external_L1A_QInj_Pulse_'+str(m)
+                fig.savefig(os.path.join(plot_dir, "{}.pdf".format(name)))
+                fig.savefig(os.path.join(plot_dir, "{}.png".format(name)))
+
+                print("\nOccupancy vs column:")
+                hit_matrix[{"row":sum}].show(columns=100)
+                print("\nOccupancy vs row:")
+                hit_matrix[{"col":sum}].show(columns=100)
 
 
 
-- 
GitLab


From a892423c8088e538f4a7b3584d96be15a99ec170 Mon Sep 17 00:00:00 2001
From: dspitzba <daniel.spitzbart@cern.ch>
Date: Thu, 22 Jun 2023 08:36:36 -0400
Subject: [PATCH 10/14] reset option

---
 test_ETROC.py | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/test_ETROC.py b/test_ETROC.py
index febd138..cf72207 100644
--- a/test_ETROC.py
+++ b/test_ETROC.py
@@ -111,6 +111,8 @@ if __name__ == '__main__':
     argParser.add_argument('--host', action='store', default='localhost', help="Hostname for control hub")
     argParser.add_argument('--partial', action='store_true', default=False, help="Only read data from corners and edges")
     argParser.add_argument('--qinj', action='store_true', default=False, help="Run some charge injection tests")
+    argParser.add_argument('--hard_reset', action='store_true', default=False, help="Hard reset of selected ETROC2 chip")
+    argParser.add_argument('--mode', action='store', default=['dual'], choices=['dual', 'single'] help="Port mode for ETROC2")
     args = argParser.parse_args()
 
 
@@ -192,8 +194,14 @@ if __name__ == '__main__':
         modules[module-1].show_status()
 
         etroc = modules[module-1].ETROCs[0]
-        #print(f"Setting the ETROC in single port mode ('right')")
-        #etroc.set_singlePort("right")
+        if args.hard_reset:
+            etroc.reset(hard=True)
+        if args.mode == 'single':
+            print(f"Setting the ETROC in single port mode ('right')")
+            etroc.set_singlePort("right")
+        elif args.mode == 'dual':
+            print(f"Setting the ETROC in dual port mode ('both')")
+            etroc.set_singlePort("both")
 
         #etroc = ETROC(rb=rb_0, i2c_adr=96, i2c_channel=1, elinks={0:[0,2]})
         
-- 
GitLab


From 1357534f832d9f9606a53e608ff976c312182b67 Mon Sep 17 00:00:00 2001
From: dspitzba <daniel.spitzbart@cern.ch>
Date: Thu, 22 Jun 2023 11:13:00 -0400
Subject: [PATCH 11/14] temporary fix for reset pin for emulator

---
 configs/emulator_v2.yaml | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/configs/emulator_v2.yaml b/configs/emulator_v2.yaml
index 71972d9..1d2ea92 100644
--- a/configs/emulator_v2.yaml
+++ b/configs/emulator_v2.yaml
@@ -65,6 +65,7 @@ modules:
      master: lpgbt
      channel: 1
    status: mod_d01
+   reset: None
   2:
    elinks: [[[4],[4]], [[6],[6]], [[16],[16]], [[18],[18]]]
    addresses: [0x72, 0x72, 0x72, 0x72]
@@ -72,10 +73,12 @@ modules:
      master: sca
      channel: 3
    status: mod_d09
+   reset: None
   3:
-    elinks: [[[8],[8]], [[10],[10]], [[12],[12]], [[14],[14]]]
-    addresses: [0x72, 0x72, 0x72, 0x72]
-    i2c:
-      master: sca
-      channel: 0
-    status: mod_d17
+   elinks: [[[8],[8]], [[10],[10]], [[12],[12]], [[14],[14]]]
+   addresses: [0x72, 0x72, 0x72, 0x72]
+   i2c:
+     master: sca
+     channel: 0
+   status: mod_d17
+   reset: None
-- 
GitLab


From 3ec0811d8ebec996806558d9bbc9a6565f8e0428 Mon Sep 17 00:00:00 2001
From: dspitzba <daniel.spitzbart@cern.ch>
Date: Thu, 22 Jun 2023 11:16:30 -0400
Subject: [PATCH 12/14] adding missing , in argParser

---
 test_ETROC.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test_ETROC.py b/test_ETROC.py
index cf72207..405db11 100644
--- a/test_ETROC.py
+++ b/test_ETROC.py
@@ -112,7 +112,7 @@ if __name__ == '__main__':
     argParser.add_argument('--partial', action='store_true', default=False, help="Only read data from corners and edges")
     argParser.add_argument('--qinj', action='store_true', default=False, help="Run some charge injection tests")
     argParser.add_argument('--hard_reset', action='store_true', default=False, help="Hard reset of selected ETROC2 chip")
-    argParser.add_argument('--mode', action='store', default=['dual'], choices=['dual', 'single'] help="Port mode for ETROC2")
+    argParser.add_argument('--mode', action='store', default=['dual'], choices=['dual', 'single'], help="Port mode for ETROC2")
     args = argParser.parse_args()
 
 
-- 
GitLab


From f3c9c6b56879619eb79a883da7e2ddf5719979ab Mon Sep 17 00:00:00 2001
From: dspitzba <daniel.spitzbart@cern.ch>
Date: Thu, 22 Jun 2023 11:30:40 -0400
Subject: [PATCH 13/14] updating elink status

---
 tamalero/Module.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tamalero/Module.py b/tamalero/Module.py
index da8113a..7efbb33 100644
--- a/tamalero/Module.py
+++ b/tamalero/Module.py
@@ -83,6 +83,7 @@ class Module:
         self.locked = {0:[], 1:[]}
         self.unlocked = {0:[], 1:[]}
         for etroc in self.ETROCs:
+            etroc.get_elink_status()
             for i in [0,1]:
                 if i in etroc.links_locked:
                     for j, link in enumerate(etroc.elinks[i]):
-- 
GitLab


From 279bdf6ae2d8609bd1b565f2d853654757ffc734 Mon Sep 17 00:00:00 2001
From: dspitzba <daniel.spitzbart@cern.ch>
Date: Thu, 22 Jun 2023 11:41:43 -0400
Subject: [PATCH 14/14] reconfigure ETROC after hard reset

---
 test_ETROC.py | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/test_ETROC.py b/test_ETROC.py
index 405db11..205ec9e 100644
--- a/test_ETROC.py
+++ b/test_ETROC.py
@@ -196,6 +196,8 @@ if __name__ == '__main__':
         etroc = modules[module-1].ETROCs[0]
         if args.hard_reset:
             etroc.reset(hard=True)
+            etroc.default_config()
+
         if args.mode == 'single':
             print(f"Setting the ETROC in single port mode ('right')")
             etroc.set_singlePort("right")
-- 
GitLab