From f8e119d1ea51e0f3d8718ff966f1b1fa6acd8c63 Mon Sep 17 00:00:00 2001
From: dspitzba <daniel.spitzbart@cern.ch>
Date: Fri, 1 Dec 2023 19:57:39 -0500
Subject: [PATCH 1/5] always enable all elinks for readout

---
 test_tamalero.py | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/test_tamalero.py b/test_tamalero.py
index c1f8675..e8d321c 100644
--- a/test_tamalero.py
+++ b/test_tamalero.py
@@ -284,6 +284,9 @@ if __name__ == '__main__':
     # Module Status
     #-------------------------------------------------------------------------------
 
+    rb.enable_etroc_readout()
+    rb.enable_etroc_readout(slave=True)
+
     modules = []
     pb_channel = []
     if args.configuration == 'emulator' or args.configuration.count('modulev0'):
-- 
GitLab


From 4417a8871c806428de33553e74f83b299fd3a563 Mon Sep 17 00:00:00 2001
From: dspitzba <daniel.spitzbart@cern.ch>
Date: Fri, 1 Dec 2023 19:58:05 -0500
Subject: [PATCH 2/5] retry SCA I2C reads because they do fail sometimes

---
 tamalero/SCA.py | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/tamalero/SCA.py b/tamalero/SCA.py
index 0fdcc3b..fda4cec 100644
--- a/tamalero/SCA.py
+++ b/tamalero/SCA.py
@@ -582,7 +582,16 @@ class SCA:
     def I2C_read(self, reg=0x0, master=3, slave_addr=0x48, nbytes=1, adr_nbytes=2, freq=2):
         # wrapper function to have similar interface as lpGBT I2C_read
         if nbytes > 1 or adr_nbytes>1:
-            return self.I2C_read_multi(channel=master, servant=slave_addr, reg=reg, nbytes=nbytes, adr_nbytes=adr_nbytes, freq=freq)
+            start_time = time.time()
+            while True:
+                try:
+                    return self.I2C_read_multi(channel=master, servant=slave_addr, reg=reg, nbytes=nbytes, adr_nbytes=adr_nbytes, freq=freq)
+                except:
+                    if (time.time() - start_time) < 2:
+                        pass
+                    else:
+                        #print("I2C_read in SCA timed out.")  # not printing this. SCA will time out e.g. if we're trying to see if a module/ETROC is connected on an empty slot!
+                        raise RuntimeError("SCA timed out")
         else:
             return self.I2C_read_single_byte(channel=master, servant=slave_addr, reg=reg, freq=freq)
 
-- 
GitLab


From 28c8f7d88cf55ec150ff5fb7c919c3b6d8d842d7 Mon Sep 17 00:00:00 2001
From: dspitzba <daniel.spitzbart@cern.ch>
Date: Fri, 1 Dec 2023 19:59:56 -0500
Subject: [PATCH 3/5] using a proper chip ID, WIP

---
 tamalero/ETROC.py  | 12 +++++++++++-
 tamalero/Module.py |  4 +++-
 test_ETROC.py      | 26 +++++++++++++++++++++++---
 3 files changed, 37 insertions(+), 5 deletions(-)

diff --git a/tamalero/ETROC.py b/tamalero/ETROC.py
index 36ffab1..06d64f4 100644
--- a/tamalero/ETROC.py
+++ b/tamalero/ETROC.py
@@ -27,6 +27,7 @@ class ETROC():
             vref=None,
             vref_pd=False,
             vtemp = None,
+            chip_id = 0,
     ):
         self.QINJ_delay = 504  # this is a fixed value for the default settings of ETROC2
         self.isfake = False
@@ -47,8 +48,17 @@ class ETROC():
         else:
             self.ver = "X-X-X"
 
+        self.chip_id = chip_id
         self.regs = load_yaml(os.path.join(here, '../address_table/ETROC2_example.yaml'))
 
+        # NOTE: some ETROCs need to be hard reset, otherwise the I2C target does not come alive.
+        # This actually solves this issue, so please don't take it out (Chesterton's Fence, anyone?)
+        for i in range(2):
+            if self.is_connected():
+                break
+            self.reset(hard=True)
+            time.sleep(0.1)
+
         if self.is_connected():
             if vref_pd:
                 self.power_down_VRef()
@@ -436,7 +446,7 @@ class ETROC():
             self.invalid_FC_counter = self.get_invalidFCCount()
 
             # give some number to the ETROC
-            self.wr_reg("EFuse_Prog", 1234)  # gives a chip ID of 308.
+            self.wr_reg("EFuse_Prog", (self.chip_id)<<2)  # gives the correct chip ID
 
             # configuration as per discussion with ETROC2 developers
             self.wr_reg("onChipL1AConf", 0)  # this should be default anyway
diff --git a/tamalero/Module.py b/tamalero/Module.py
index 3a96cc5..bf8a74d 100644
--- a/tamalero/Module.py
+++ b/tamalero/Module.py
@@ -7,7 +7,7 @@ from tamalero.Monitoring import Lock
 from time import sleep
 
 class Module:
-    def __init__(self, rb, i=1, strict=False, enable_power_board=False):
+    def __init__(self, rb, i=1, strict=False, enable_power_board=False, moduleid=0):
         # don't like that this also needs a RB
         # think about a better solution
         self.config = rb.configuration['modules'][i]
@@ -17,6 +17,7 @@ class Module:
         #self.regs_em = ['disScrambler', 'singlePort', 'mergeTriggerData', 'triggerGranularity']
         self.i = i
         self.rb = rb
+        self.id = moduleid
 
         if enable_power_board:
             self.enable_power_board()
@@ -50,6 +51,7 @@ class Module:
                         vref = self.config['vref'][j],
                         vref_pd = self.config['disable_vref_gen'][j],
                         vtemp = self.config['vtemp'][j],
+                        chip_id = (self.id << 2) | j  # this gives every ETROC a unique ID, based on module ID and ETROC number on the module
                     ))
 
     #def configure(self):
diff --git a/test_ETROC.py b/test_ETROC.py
index f424c82..3d49240 100644
--- a/test_ETROC.py
+++ b/test_ETROC.py
@@ -254,7 +254,8 @@ if __name__ == '__main__':
         connected_modules = []
         for i in [1,2,3]:
             # FIXME we might want to hard reset all ETROCs at this point?
-            m_tmp = Module(rb=rb_0, i=i, enable_power_board=args.enable_power_board)
+            moduleid = int(args.moduleid) if i==int(args.module) else (i+200)  # NOTE: at some point we should also include the RB number, e.g. (rb << 4) | (module)
+            m_tmp = Module(rb=rb_0, i=i, enable_power_board=args.enable_power_board, moduleid = moduleid)
             modules.append(m_tmp)
             if m_tmp.ETROCs[0].is_connected():  # NOTE assume that module is connected if first ETROC is connected
                 connected_modules.append(i)
@@ -344,11 +345,30 @@ if __name__ == '__main__':
         # FIXME the below code is still pretty stupid
         modules = []
         connected_modules = []
+
         for i in [1,2,3]:
-            m_tmp = Module(rb=rb_0, i=i, enable_power_board=args.enable_power_board)
+            # FIXME we might want to hard reset all ETROCs at this point?
+            moduleid = int(args.moduleid) if i==int(args.module) else (i+200)
+            m_tmp = Module(rb=rb_0, i=i, enable_power_board=args.enable_power_board, moduleid = moduleid)
             modules.append(m_tmp)
-            if m_tmp.ETROCs[0].connected:  # NOTE assume that module is connected if first ETROC is connected
+            if m_tmp.ETROCs[0].is_connected():  # NOTE assume that module is connected if first ETROC is connected
                 connected_modules.append(i)
+                for e_tmp in m_tmp.ETROCs:
+                    if args.hard_reset:
+                        print(f"Running hard reset and default config on module {i}")
+                        e_tmp.reset(hard=True)
+                        e_tmp.default_config()
+                        time.sleep(1.1)
+                        #e_tmp.default_config()
+                        #
+                    print("Setting ETROCs into workMode 0")
+                    e_tmp.wr_reg("workMode", 0, broadcast=True)
+
+        #for i in [1,2,3]:
+        #    m_tmp = Module(rb=rb_0, i=i, enable_power_board=args.enable_power_board)
+        #    modules.append(m_tmp)
+        #    if m_tmp.ETROCs[0].connected:  # NOTE assume that module is connected if first ETROC is connected
+        #        connected_modules.append(i)
 
         print(f"Found {len(connected_modules)} connected modules")
         if int(args.module) > 0:
-- 
GitLab


From e285c175a4bf62104947406d556fac008a100458 Mon Sep 17 00:00:00 2001
From: dspitzba <daniel.spitzbart@cern.ch>
Date: Fri, 1 Dec 2023 20:00:41 -0500
Subject: [PATCH 4/5] proper init for any ETROC, including hard resets and
 PLL/FC resets

---
 tamalero/ETROC.py | 21 +++++++++--
 test_ETROC.py     | 92 +++++++++++++++++++++++++----------------------
 2 files changed, 68 insertions(+), 45 deletions(-)

diff --git a/tamalero/ETROC.py b/tamalero/ETROC.py
index 06d64f4..b2fc2e1 100644
--- a/tamalero/ETROC.py
+++ b/tamalero/ETROC.py
@@ -338,7 +338,7 @@ class ETROC():
         self.reset_PLL()
         self.reset_fast_command()
         self.reset()
-        self.default_config()
+        self.default_config(no_reset=True)
         self.rb.kcu.write_node("READOUT_BOARD_%s.BITSLIP_AUTO_EN"%self.rb.rb, 0x1)
         time.sleep(0.1)
         self.rb.kcu.write_node("READOUT_BOARD_%s.BITSLIP_AUTO_EN"%self.rb.rb, 0x0)
@@ -432,7 +432,7 @@ class ETROC():
     # === CONTROL FUNCTIONS ===
     # =========================
 
-    def default_config(self):
+    def default_config(self, no_reset=False):
         # FIXME should use higher level functions for better readability
         if self.is_connected():
             self.reset()  # soft reset of the global readout
@@ -474,6 +474,23 @@ class ETROC():
             self.wr_reg("lowerCalTrig", 0, broadcast=True)
 
             self.reset()  # soft reset of the global readout, 2nd reset needed for some ETROCs
+            #
+            # FIXME this is where the module_reset should happen if links are not locked??
+            if not no_reset:
+                elink_status = self.get_elink_status()
+                #print(elink_status)
+                stat = True
+                for elinks in elink_status:
+                    #print(elink_status[elinks])
+                    for elink in elink_status[elinks]:
+                        if elink == False:
+                            stat &= False
+
+                if not stat:
+                    print("elinks not locked, resetting PLL and FC modules")
+                    self.reset_modules()
+
+                #print(self.get_elink_status())
 
     def is_good(self):
         good = True
diff --git a/test_ETROC.py b/test_ETROC.py
index 3d49240..de31c5a 100644
--- a/test_ETROC.py
+++ b/test_ETROC.py
@@ -241,6 +241,8 @@ if __name__ == '__main__':
             sys.exit(1)
 
         fifo = FIFO(rb=rb_0)
+        fifo.send_l1a(1)
+        fifo.reset()
 
         is_configured = rb_0.DAQ_LPGBT.is_configured()
         if not is_configured:
@@ -266,6 +268,9 @@ if __name__ == '__main__':
                         e_tmp.default_config()
                         time.sleep(1.1)
                         #e_tmp.default_config()
+                        #
+                    print("Setting ETROCs into workMode 0")
+                    e_tmp.wr_reg("workMode", 0, broadcast=True)
 
 
         time.sleep(0.1)
@@ -473,49 +478,50 @@ if __name__ == '__main__':
 
         print("\n - Checking elinks")
 
-        print("Disabling readout for all elinks but the ETROC under test")
-        rb_0.disable_etroc_readout(all=True)
-        rb_0.reset_data_error_count()
-        #rb_0.enable_etroc_readout()
-        for lpgbt in etroc.elinks:
-            if lpgbt == 0:
-                slave = False
-            else:
-                slave = True
-            for link in etroc.elinks[lpgbt]:
-                print(f"Enabling elink {link}, slave is {slave}")
-                rb_0.enable_etroc_readout(link, slave=slave)
-                #time.sleep(0.5)
-                #rb_0.reset_data_error_count()
-                #fifo.select_elink(link, slave)
-                #fifo.ready()
-                rb_0.rerun_bitslip()
-                time.sleep(1.5)
-                rb_0.reset_data_error_count()
-                stat = rb_0.get_link_status(link, slave=slave, verbose=False)
-                if stat:
-                    rb_0.get_link_status(link, slave=slave)
-                start_time = time.time()
-                while not stat:
-                    #rb_0.disable_etroc_readout(link, slave=slave)
-                    rb_0.enable_etroc_readout(link, slave=slave)
-                    #time.sleep(0.5)
-                    #time.sleep(0.1)
-                    #rb_0.reset_data_error_count()
-                    #fifo.select_elink(link, slave)
-                    #fifo.ready()
-                    rb_0.rerun_bitslip()
-                    time.sleep(1.5)
-                    rb_0.reset_data_error_count()
-                    stat = rb_0.get_link_status(link, slave=slave, verbose=False
-                                                )
-                    if stat:
-                        rb_0.get_link_status(link, slave=slave)
-                        break
-                    if time.time() - start_time > 2:
-                        print('Link not good, but continuing')
-                        rb_0.get_link_status(link, slave=slave)
-                        break
+        #print("Disabling readout for all elinks but the ETROC under test")
+        ## FIXME this is still problematic...
+        #rb_0.disable_etroc_readout(all=True)
+        #rb_0.reset_data_error_count()
+        ##rb_0.enable_etroc_readout()
+        #for lpgbt in etroc.elinks:
+        #    if lpgbt == 0:
+        #        slave = False
+        #    else:
+        #        slave = True
+        #    for link in etroc.elinks[lpgbt]:
+        #        print(f"Enabling elink {link}, slave is {slave}")
+        #        rb_0.enable_etroc_readout(link, slave=slave)
+        #        #time.sleep(0.5)
+        #        #rb_0.reset_data_error_count()
+        #        #fifo.select_elink(link, slave)
+        #        #fifo.ready()
+        #        rb_0.rerun_bitslip()
+        #        time.sleep(1.5)
+        #        rb_0.reset_data_error_count()
+        #        stat = rb_0.get_link_status(link, slave=slave, verbose=False)
+        #        if stat:
+        #            rb_0.get_link_status(link, slave=slave)
+        #        start_time = time.time()
+        #        while not stat:
+        #            #rb_0.disable_etroc_readout(link, slave=slave)
+        #            rb_0.enable_etroc_readout(link, slave=slave)
+        #            #time.sleep(0.5)
+        #            #time.sleep(0.1)
+        #            #rb_0.reset_data_error_count()
+        #            #fifo.select_elink(link, slave)
+        #            #fifo.ready()
+        #            rb_0.rerun_bitslip()
+        #            time.sleep(1.5)
+        #            rb_0.reset_data_error_count()
+        #            stat = rb_0.get_link_status(link, slave=slave, verbose=False
+        #                                        )
+        #            if stat:
+        #                rb_0.get_link_status(link, slave=slave)
+        #                break
+        #            if time.time() - start_time > 2:
+        #                print('Link not good, but continuing')
+        #                rb_0.get_link_status(link, slave=slave)
+        #                break
 
         ## Bloc below to be retired
         ## Keeping it for one more iteration
-- 
GitLab


From e1efe67da491ae567a7c8f88cf57fdaf3a938322 Mon Sep 17 00:00:00 2001
From: dspitzba <daniel.spitzbart@cern.ch>
Date: Fri, 1 Dec 2023 20:11:49 -0500
Subject: [PATCH 5/5] fixing reset for emulators

---
 tamalero/ETROC.py | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/tamalero/ETROC.py b/tamalero/ETROC.py
index b2fc2e1..a2da9ad 100644
--- a/tamalero/ETROC.py
+++ b/tamalero/ETROC.py
@@ -321,14 +321,16 @@ class ETROC():
         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)
+        if self.breed not in ['software', 'emulator']:
+            # the emulators are not going to be reset at all
+            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)
         if not self.isfake:
             self.rb.rerun_bitslip()  # NOTE this is necessary to get the links to lock again
 
-- 
GitLab