From 38f2343a3183e110cb107e139cdf8a5dca209e40 Mon Sep 17 00:00:00 2001 From: ROBBE Patrick <robbe@lal.in2p3.fr> Date: Sun, 27 Jan 2019 17:00:45 +0100 Subject: [PATCH] add Si534x file --- Python/components/si534x_comp.py | 1165 ++++++++++++++++++++++++++++++ 1 file changed, 1165 insertions(+) create mode 100644 Python/components/si534x_comp.py diff --git a/Python/components/si534x_comp.py b/Python/components/si534x_comp.py new file mode 100644 index 0000000..b2f8348 --- /dev/null +++ b/Python/components/si534x_comp.py @@ -0,0 +1,1165 @@ +#!/usr/bin/python +# -*- coding: iso-8859-1 -*- +""" + si534x_comp.py -- module for programming and monitoring Silicon Si5344/Si5345 PLL components + + Note: + This code will be running on FC + No Firmware today + Author + MJ 18/10/2017 + JPC 06/12/2017 added an exhaustive test of the 3 PLLs in Main + JPC 22/01/2018 suppressed prints to simplify display + JPC 22/0/12018 corrected bug in read_loss_of_lock (bad address) + JPC 22/01/2018 corrected bug in clear_lol_flg_bit (wrong bit) + JPC 13/04/2018 corrected bug in read_free_run (bad address) + JPC 04/05/2018 added methods for enabling/disabling outputs + JPC 12/09/2018 added hard reset method + JPC 11/10/2018 added bit handling methods + JPC 15/11/2018 added patch to correct OOF and LOS flag issue in rev B chip + added speed grade detection + +""" + +import sys +import os +import time +# from string import find, split +from string import find +from string import split + +# dummy_i2c instead i2c from lli +sys.path.append("./dummy_lli") +from lli import i2c +#import i2c +from fpga_comp import Arria10 + +class Si534x(object): + """ + Note: Register Address of the Si534x Device Table Register + PAGE : There is the “Page Register†which is located at address 0x01 on every page. + When read, it will indicate the current page. When written, it will change the page + to the value entered. There is a page register at address 0x0001, 0x0101, 0x0201,… + PN_BASE_LSB, PN_BASE_MSB: Base Part Number (ex:"5345") + INTERNAL_STATUS_BITS : + INTERNAL_STATUS_BITS[0]: SYSINCAL (1 if device is calibrating) + INTERNAL_STATUS_BITS[1]: LOSXAXB (1 if there is no signal at the XAXB pins) + INTERNAL_STATUS_BITS[5]: SMBBUS_TIMEOUT (1 if there is an SMBus timeout error) + LOS_OOF_ALARMS : Loss-Of-Signals (LOS) and Out-Of-Frequency (OOF) inputs alarms + LOS_OOF_ALARMS[0] : LOS_IN0 1 if the clock input0 is currently loss + LOS_OOF_ALARMS[1] : LOS_IN1 1 if the clock input1 is currently loss + LOS_OOF_ALARMS[2] : LOS_IN2 1 if the clock input2 is currently loss + LOS_OOF_ALARMS[3] : LOS_IN3 1 if the clock input3 is currently loss + LOS_OOF_ALARMS[4] : OOF_IN0 1 if the clock input0 is currently oof + LOS_OOF_ALARMS[5] : OOF_IN1 1 if the clock input1 is currently oof + LOS_OOF_ALARMS[6] : OOF_IN2 1 if the clock input2 is currently oof + LOS_OOF_ALARMS[7] : OOF_IN3 1 if the clock input3 is currently oof + HOLDOVER_LOS_STATUS : + HOLDOVER_LOS_STATUS[1] : LOL 1 if the DSPLL (output) is out of lock + HOLDOVER_LOS_STATUS[5] : HOLD 1 if the DSPLL (output) is in holdover (or free run mode) + CALIBRATION_STATUS : + CALIBRATION_STATUS[5] : CAL_PLL 1 if the DSPLL internal calibration is busy + CLOCK_OUTPUT_DRIVER[9..0] : + CLOCK_OUTPUT_DRIVER[i][1] : OUTi_OE 1 if Ouput0 is enabled, 0 if disabled + INTERNAL_STATUS_BITS_FLG : Sticky version of INTERNAL_STATUS_BITS_FLG + INTERNAL_STATUS_BITS_FLG[0]: SYSINCAL_FLG,write a 0 to this bit to clear + INTERNAL_STATUS_BITS_FLG[1]: LOSXAXB_FLG,write a 0 to this bit to clear + INTERNAL_STATUS_BITS_FLG[5]: SMBBUS_TIMEOUT_FLG,write 0 to this bit to clear + LOS_OOF_ALARMS_FLG : Sticky version of LOS_OOF_ALARMS + LOS_OOF_ALARMS_FLG[0] : LOS_IN0_FLG,write a 0 to this bit to clear + LOS_OOF_ALARMS_FLG[1] : LOS_IN1_FLG,write a 0 to this bit to clear + LOS_OOF_ALARMS_FLG[2] : LOS_IN2_FLG,write a 0 to this bit to clear + LOS_OOF_ALARMS_FLG[3] : LOS_IN3_FLG,write a 0 to this bit to clear + LOS_OOF_ALARMS_FLG[4] : OOF_IN0_FLG,write a 0 to this bit to clear + LOS_OOF_ALARMS_FLG[5] : OOF_IN1_FLG,write a 0 to this bit to clear + LOS_OOF_ALARMS_FLG[6] : OOF_IN2_FLG,write a 0 to this bit to clear + LOS_OOF_ALARMS_FLG[7] : OOF_IN3_FLG,write a 0 to this bit to clear + HOLDOVER_LOS_STATUS_FLG : Sticky version of HOLDOVER_LOS_STATUS + HOLDOVER_LOS_STATUS[1] : LOL_FLG,write a 0 to this bit to clear + HOLDOVER_LOS_STATUS[5] : HOLD_FLG,write a 0 to this bit to clear + CALIBRATION_STATUS_FLG : Sticky version of CALIBRATION_STATUS + CALIBRATION_STATUS_FLG[5] : CAL_PLL_FLG,write a 0 to this bit to clear + HOLD_HIST_VALID : + HOLD_HIST_VALID[1] : HOLD_HIST_VALID bit, 1 if History data is valid + """ + PAGE = 0x0001 + PN_BASE_LSB = 0x0002 + PN_BASE_MSB = 0x0003 + DEVICE_REVISION = 0x0005 + + + INTERNAL_STATUS_BITS = 0x000C + # Position Bits of INTERNAL_STATUS_BITS: + SYSINCAL = 0 + LOSXAXB = 1 + SMBBUS_TIMEOUT = 5 + + LOS_OOF_ALARMS = 0x000D + # Position Bits of LOS_OOF_ALARMS: + LOS_IN0 = 0 + LOS_IN1 = 1 + LOS_IN2 = 2 + LOS_IN3 = 3 + OOF_IN0 = 4 + OOF_IN1 = 5 + OOF_IN2 = 6 + OOF_IN3 = 7 + + STATUS_FLAGS_MASKS = 0X0017 + # Position Bits of STATUS_FLAGS_MASKS: + SYSINCAL_INTR_MSK = 0 + LOSXAXB_INTR_MSK = 1 + SMBUS_TIMEOUT_INTR_MSK = 5 + + LOS_OOF_FLAGS_MASKS = 0x0018 + # Position Bits of LOS_OOF_FLAGS_MASKS: + LOS_INTR_MSK0 = 0 + LOS_INTR_MSK1 = 1 + LOS_INTR_MSK2 = 2 + LOS_INTR_MSK3 = 3 + OOF_INTR_MSK0 = 4 + OOF_INTR_MSK1 = 5 + OOF_INTR_MSK2 = 6 + OOF_INTR_MSK3 = 7 + + HOLDOVER_LOL_MASKS = 0x0019 + # Position Bits of HOLDOVER_LOL_MASKS: + LOL_INTR_MSK = 1 + HOLD_INTR_MSK = 5 + + SOFT_RESET_CAL = 0x001C + # Position Bits of SOFT_RESET_CAL + SOFT_RST_ALL = 0 + SOFT_RST = 1 + + PWR_DOWN_HARD_RESET = 0x001E + # Position Bits of PWR_DOWN_HARD_RESET + PDN = 0 + HARD_RST = 1 + SYNC = 2 + + LOS_ENABLE = 0x002C + # Position Bits of LOS_ENABLE + LOS_EN0 = 0 + LOS_EN1 = 1 + LOS_EN2 = 2 + LOS_EN3 = 3 + LOSXAXB_DIS = 4 + + OOF_ENABLE = 0x003F + # Position Bits of OOF_ENABLE + OOF_EN0 = 0 + OOF_EN1 = 1 + OOF_EN2 = 2 + OOF_EN3 = 3 + FAST_OOF_EN0 = 4 + FAST_OOF_EN1 = 5 + FAST_OOF_EN2 = 6 + FAST_OOF_EN3 = 7 + + HOLDOVER_LOS_STATUS = 0x000E + # Position Bits of HOLDOVER_LOS_STATUSHOLDOVER_LOS_STATUS: + LOL = 1 + HOLD = 5 + + CALIBRATION_STATUS = 0x000F + # Position Bits of CALIBRATION_STATUS: + CALL_PLL = 5 + + CLOCK_OUTPUT_DRIVER = [0x0108, 0x010D, 0x0112, 0x0117, 0x011C, 0x121, 0x126, 0x12B, 0x130, 0x13A] + # Position Bits of CLOCK_OUTPUT_DRIVER[]: + OUT_OE = 1 + + + #-------------Sticky registers--------------------------------- + + INTERNAL_STATUS_BITS_FLG = 0x0011 + # Position Bits of INTERNAL_STATUS_BITS_FLG: + SYSINCAL_FLG = 0 + LOSXAXB_FLG = 1 + SMBBUS_TIMEOUT_FLG = 5 + + LOS_OOF_ALARMS_FLG = 0x0012 + # Position Bits of LOS_OOF_ALARMS_FLG: + LOS_IN0_FLG = 0 + LOS_IN1_FLG = 1 + LOS_IN2_FLG = 2 + LOS_IN3_FLG = 3 + OOF_IN0_FLG = 4 + OOF_IN1_FLG = 5 + OOF_IN2_FLG = 6 + OOF_IN3_FLG = 7 + + HOLDOVER_LOS_STATUS_FLG = 0x0013 + # Position Bits of HOLDOVER_LOS_STATUS_FLG: + LOL_FLG = 1 + HOLD_FLG = 5 + + CALIBRATION_STATUS_FLG = 0x0014 + # Position Bits of CALIBRATION_STATUS: + CALL_PLL_FLG = 5 + + # Set and clear thehold for LOL signal + LOL_SET_THR = 0x009E + LOL_CLR_THR = 0x00A0 + + HOLD_HIST_VALID = 0x053F + # Position Bits of HOLD_HIST_VALID: + ENOUGH_HISTORICAL_FREQUENCY_DATA = 1 + + def __init__(self, dev, bus, add): + """ + Args: + dev (int): board identifier + bus (int): selected i2c bus on the board + add (int): address of device on the i2c bus + """ + self.dev = dev + self.bus = bus + self.add = add + + def test_bit(self, reg, offset): + """ Test a bit + Args: + reg : register address + offset : bit number + returns: + a nonzero result, 2**offset, if the bit at 'offset' is one. + """ + status, val = self.read_pagined_register(reg) + mask = 1 << offset + return (val & mask) >> offset + + def set_bit(self, reg, offset): + """ Set a bit + Args: + reg : register address + offset : bit number + + """ + status, val = self.read_pagined_register(reg) + mask = 1 << offset + status = self.write_pagined_register(reg, val | mask) + + def clear_bit(self, reg, offset): + """ Clear a bit + Args: + reg : register address + offset : bit number + + """ + status, val = self.read_pagined_register(reg) + mask = ~(1 << offset) + status = self.write_pagined_register(reg, val & mask) + + def toggle_bit(self, reg, offset): + """ Togle a bit + Args: + reg : register address + offset : bit number + + """ + status, val = self.read_pagined_register(reg) + mask = 1 << offset + status = self.write_pagined_register(reg, val ^ mask) + + + def write_pagined_register(self, register_address, value_to_write): + """ write one register of the Device Table Register + Args: + register_address (int): 16 bits register address of the Device Table Register + bit[11..8] contains the page of the table + value_to_write (int) : 16 bits value to write on the device at register_address + + Returns: + status (int) : 0 if successfull, -1 if error + + Notes: about pagination + I2C use only 8 bits for address, so there is a pagination on Si534x register space: + 0x0000-0x0FF : page 0 + 0x0100-0x1FF : page 1 + 0x0200-0x2FF : page 2 + 0x0300-0x3FF : page 3 ..... + There is the “Page Register†which is located at address 0x01 on every page. + When read, it will indicate the current page. When written, it will change the page to the + value entered. There is a page register at address 0x0001, 0x0101, 0x0201, 0x0301, … etc. + To write "value_to_write" at "register_adress", we must perform the steps: + 1) Extract from "register_address" the "msbyte_register_address" that gives the page + 2) Extract from "register_address" the "lsbyte_register_address" that gives the 8 bits + address to transmit with I2C + 3) read the current page with a read I2C on the device at adresse 0x0001 + 4) if the current page is not equal to "msbyte_register_address", then write I2C the + value "msbyte_register_address" at adresse 0x0001 on the device + 5) then write I2C the value "value_to_write" at address "lsbyte_register_address" + on the device + """ + msbyte_register_address = register_address >> 8 + lsbyte_register_address = 0xFF & register_address + page_register_address = self.PAGE + (status1, current_page) = i2c.read(self.dev, self.bus, self.add, page_register_address) + if current_page != msbyte_register_address: + (status2, value) = i2c.write(self.dev, self.bus, self.add, page_register_address, msbyte_register_address) + else: + status2 = 0 + (status3, value) = i2c.write(self.dev, self.bus, self.add, lsbyte_register_address, value_to_write) + status = 0 + if status1 == -1 or status2 == -1 or status3 == -1: + status = -1 + return status + + def read_pagined_register(self, register_address): + """read one register of the Device Table Register + Args: + register_address (int): 16 bits register address of the Device Table Register + bit[11..8] contains the page of the table + + Returns: + tuple: + (status(int), val(int)) + status : 0 if successfull, -1 if error + val : read value on the device + + Notes: about pagination + see read_pagined_register() notes + """ + msbyte_register_address = register_address >> 8 + lsbyte_register_address = 0xFF & register_address + page_register_address = self.PAGE + (status1, current_page) = i2c.read(self.dev, self.bus, self.add, page_register_address) + if current_page != msbyte_register_address: + (status2, value) = i2c.write(self.dev, self.bus, self.add, page_register_address, msbyte_register_address) + else: + status2 = 0 + (status3, val) = i2c.read(self.dev, self.bus, self.add, lsbyte_register_address) + status = 0 + if status1 == -1 or status2 == -1 or status3 == -1: + status = -1 + return (status, val) + + def si534x_programming(self, filename): + """programming the device with a wizard files + Args: + filename (string) = wizard file CBPro, example: "Si5345-RevD-5345EVB1-Registers.txt" + + Returns: + status (int) : 0 if successfull, -1 if error + + Notes: about si534x_programming (Si5345-44-42-D-RM.pdf page 16 Dynamic PLL Changes) + 1) in first preamble (we assume we have a Revision D circuit) + 0x0B24,0xC0 + 0x0B25,0x00 + 0x0540,0x01 ???? + 0x540 register is in the wizard files of CBPro + but in Si5345-44-42-D-RM.pdf 0x540 register doesn't exist... + 2) Wait 300 ms + 3) Then perform the desired register modifications + (write all the register map of the wizard file) + 4) Write the post-amble and SOFT_RST + 0x0514, 0x01 ???? + 0x514 register programmation is in preamble of wizard files of CBPro but not in + Si5345-44-42-D-RM.pdf...0x514 is "BW_UPDATE_PLL" + 0x001C,0x01 ( SOFT_RST : set bit 0 of Register 0x001C x001C[0] = 1 ) + 0x0540,0x00 ???? + 0x540 register is in the wizard files of CBPro + but in Si5345-44-42-D-RM.pdf 0x540 register doesn't exist... + 0x0B24,0xC3 + 0x0B25,0x02 + the wizard files merges the steps "Write post-amble" and ""SOFT_RST" + the wizard files appends the programming of registers 0x540 and 0x514 in preamble and + postamble + """ + try: + #print os.path.join(os.environ.get('LLI_DAT')+filename) + # fic = open(os.path.join(os.environ.get('LLI_DAT'), filename), "r") + fic = open(os.path.join("../data", filename), "r") + except IOError: + print 'file not found' + exit(0) + # **********************************1) in first preamble*********************************** + # header suppress + indice_entete = 0 + while find(fic.readline(), 'Start configuration preamble') == -1: + indice_entete += 1 + # indice_entete is dummy.... + # typical data line : "0x0B24,0xC0" + # last line of preamble is "# End configuration preamble" + #print 'hostname' # JEVAUD PRINT DEBUG A EFFACER EN FINAL + while 1: + current_line = fic.readline() + if find(current_line, 'End configuration preamble') <> -1: + #print 'End of preamble' # JEVAUD PRINT DEBUG A EFFACER EN FINAL + break + [current_regstr, current_valstr] = split(current_line, ',') + current_reg = int(current_regstr, 16) + current_val = int((current_valstr), 16) + status1 = self.write_pagined_register(current_reg, current_val) + + # **********************************2) wait 300ms ***************************************** + #print 'wait 300ms' #JEVAUD PRINT DEBUG A EFFACER EN FINAL + time.sleep(0.3) + + # ********************3) Then perform the desired register modifications ****************** + # text suppress + indice_entete = 0 + while find(fic.readline(), 'Start configuration registers') == -1: + indice_entete += 1 + # indice_entete is dummy.... + # typical data line : "0x000B,0x68" + # last line of configuration registers is "End configuration registers" + #print 'Start of configuration registers' # JEVAUD PRINT DEBUG A EFFACER EN FINAL + while 1: + current_line = fic.readline() + if find(current_line, 'End configuration registers') <> -1: + #print 'End of configuration registers' # JEVAUD PRINT DEBUG A EFFACER EN FINAL + break + [current_regstr, current_valstr] = split(current_line, ',') + current_reg = int(current_regstr, 16) + current_val = int((current_valstr), 16) + status2 = self.write_pagined_register(current_reg, current_val) + + # ********************4) Write the post-amble and SOFT_RST ******************************** + # text suppress + indice_entete = 0 + while find(fic.readline(), 'Start configuration postamble') == -1: + indice_entete += 1 + # indice_entete is dummy.... + # typical data line : "0x0514,0x01" + # last line of configuration registers is "End configuration postamble" + #print 'Start configuration postamble' # JEVAUD PRINT DEBUG A EFFACER EN FINAL + while 1: + current_line = fic.readline() + if find(current_line, 'End configuration postamble') <> -1: + #print 'End configuration postamble' # JEVAUD PRINT DEBUG A EFFACER EN FINAL + break + [current_regstr, current_valstr] = split(current_line, ',') + current_reg = int(current_regstr, 16) + current_val = int((current_valstr), 16) + status3 = self.write_pagined_register(current_reg, current_val) + + fic.close() + status = 0 + if status1 == -1 or status2 == -1 or status3 == -1: + status = -1 + return status + + def read_part_number(self): + """read part number from the device : "5345" for a Si5345 + No Args + + Returns: + tuple: + (status(int), part_number(int)) + status : 0 if successfull, -1 if error + val : 16 bit integer (0x5345 for a Si5345) + """ + register_address = self.PN_BASE_LSB + (status1, lsbyte_part_number) = self.read_pagined_register(register_address) + register_address = self.PN_BASE_MSB + (status2, msbyte_part_number) = self.read_pagined_register(register_address) + status = 0 + if status1 == -1 or status2 == -1: + status = -1 + part_number = (msbyte_part_number<<8) + lsbyte_part_number + return (status, part_number) + + def read_device_revision(self): + """read device grade from the device : 0=A, 1=B, 2=C, 3=D + No Args + + Returns: + status(int) : 0 if successfull, -1 if error + val(string) : "A" if 0, "B" if 1, "C"cif 2, "D" if 3 + """ + (status, val) = self.read_pagined_register(self.DEVICE_REVISION) + if val == 0: + revision = "A" + elif val == 1: + revision = "B" + elif val == 2: + revision = "C" + elif val == 3: + revision = "D" + else: + revision = "Not found : " + str(val) + return (status, revision) + + def hard_reset(self): + """sends a hard reset to the chip + No Args + """ + status = self.set_bit(self.PWR_DOWN_HARD_RESET, self.PDN) + status = self.clear_bit(self.PWR_DOWN_HARD_RESET, self.PDN) + status = self.set_bit(self.PWR_DOWN_HARD_RESET, self.HARD_RST) + status = self.clear_bit(self.PWR_DOWN_HARD_RESET, self.HARD_RST) + return + + def soft_reset(self): + """sends a hard reset to the chip + No Args + """ + status = self.set_bit(self.SOFT_RESET_CAL, self.SOFT_RST_ALL) + status = self.clear_bit(self.SOFT_RESET_CAL, self.SOFT_RST_ALL) + return + + def read_mask_values(self): + """ Read all interrupt mask values + Args: + none + Returns: + masks: a dictionary with all the flags values + + """ + masks ={} + masks["SysInCal mask"] = self.test_bit(self.STATUS_FLAGS_MASKS, self.SYSINCAL_INTR_MSK) + masks["LOS XAXB"] = self.test_bit(self.STATUS_FLAGS_MASKS, self.LOSXAXB_INTR_MSK) + masks["SMBbusTimeout"] = self.test_bit(self.STATUS_FLAGS_MASKS, self.SMBUS_TIMEOUT_INTR_MSK) + masks["LOS input 0"] = self.test_bit(self.LOS_OOF_FLAGS_MASKS, self.LOS_INTR_MSK0) + masks["LOS input 1"] = self.test_bit(self.LOS_OOF_FLAGS_MASKS, self.LOS_INTR_MSK1) + masks["LOS input 2"] = self.test_bit(self.LOS_OOF_FLAGS_MASKS, self.LOS_INTR_MSK2) + masks["LOS input 3"] = self.test_bit(self.LOS_OOF_FLAGS_MASKS, self.LOS_INTR_MSK3) + masks["OOF input 0"] = self.test_bit(self.LOS_OOF_FLAGS_MASKS, self.OOF_INTR_MSK0) + masks["OOF input 1"] = self.test_bit(self.LOS_OOF_FLAGS_MASKS, self.OOF_INTR_MSK1) + masks["OOF input 2"] = self.test_bit(self.LOS_OOF_FLAGS_MASKS, self.OOF_INTR_MSK2) + masks["OOF input 3"] = self.test_bit(self.LOS_OOF_FLAGS_MASKS, self.OOF_INTR_MSK3) + masks["LOL outputs"] = self.test_bit(self.HOLDOVER_LOL_MASKS, self.LOL_INTR_MSK) + masks["Hold Over"] = self.test_bit(self.HOLDOVER_LOL_MASKS, self.HOLD_INTR_MSK) + return masks + + def init_mask_values(self): + """ sett all interrupt mask values to 1 except input 0 + Args: + none + Returns: + masks: a dictionary with all the flags values + + """ + masks ={} + masks["SysInCal mask"] = self.set_bit(self.STATUS_FLAGS_MASKS, self.SYSINCAL_INTR_MSK) + masks["LOS XAXB"] = self.set_bit(self.STATUS_FLAGS_MASKS, self.LOSXAXB_INTR_MSK) + masks["SMBbusTimeout"] = self.set_bit(self.STATUS_FLAGS_MASKS, self.SMBUS_TIMEOUT_INTR_MSK) + masks["LOS input 0"] = self.clear_bit(self.LOS_OOF_FLAGS_MASKS, self.LOS_INTR_MSK0) + masks["LOS input 1"] = self.set_bit(self.LOS_OOF_FLAGS_MASKS, self.LOS_INTR_MSK1) + masks["LOS input 2"] = self.set_bit(self.LOS_OOF_FLAGS_MASKS, self.LOS_INTR_MSK2) + masks["LOS input 3"] = self.set_bit(self.LOS_OOF_FLAGS_MASKS, self.LOS_INTR_MSK3) + masks["OOF input 0"] = self.clear_bit(self.LOS_OOF_FLAGS_MASKS, self.OOF_INTR_MSK0) + masks["OOF input 1"] = self.set_bit(self.LOS_OOF_FLAGS_MASKS, self.OOF_INTR_MSK1) + masks["OOF input 2"] = self.set_bit(self.LOS_OOF_FLAGS_MASKS, self.OOF_INTR_MSK2) + masks["OOF input 3"] = self.set_bit(self.LOS_OOF_FLAGS_MASKS, self.OOF_INTR_MSK3) + masks["LOL outputs"] = self.set_bit(self.HOLDOVER_LOL_MASKS, self.LOL_INTR_MSK) + masks["Hold Over"] = self.set_bit(self.HOLDOVER_LOL_MASKS, self.HOLD_INTR_MSK) + return masks + + def read_loss_of_lock(self): + """read loss_of_lock from the device + No Args + + Returns: + tuple: + (status(int), loss_of_lock(boolean)) + status : 0 if successfull, -1 if error + loss_of_lock : boolean true if the DSPLL is out of lock, false if not + """ + register_address = self.HOLDOVER_LOS_STATUS + bit_position = self.LOL + loss_of_lock = False + (status, value) = self.read_pagined_register(register_address) + if (value >> bit_position) & 1: + loss_of_lock = True + return (status, loss_of_lock) + + def write_LOL_thresholf_values(self): + """set default loss_of_lock thresholds + No Args + + Returns: + status(int) : 0 if successfull, -1 if error + + Notes: + set_value = 100 ppm + clr_value = 30 ppm + """ + + thresholds = \ + {0 : "0.1 ppm", + 1 : "0.3 ppm", + 2 : "1 ppm", + 3 : "3 ppm", + 4 : "10 ppm", + 5 : "30 ppm", + 6 : "100 ppm", + 7 : "300 ppm", + 8 : "1000 ppm", + 9 : "3000 ppm", + 10 : "10000 ppm" + } + register_address = self.LOL_SET_THR + print hex(6<<4) + status1 = self.write_pagined_register(register_address, 6<<4) + print status1 + register_address = self.LOL_CLR_THR + print hex(5<<4) + status2 = self.write_pagined_register(register_address, 5<<4) + print status2 + status = 0 + if (status1 == -1) or (status2 == -1): + status = -1 + return status + + def read_LOL_threshold_values(self): + """read loss_of_lock set and clear thresholds in ppm from the device + No Args + + Returns: + tuple: + (status(int), set_threshold(str), clear_threshold(str)) + status : 0 if successfull, -1 if error + set_threshold : value in ppm + clear_threhold : value in ppm + """ + thresholds = \ + {0 : "0.1 ppm", + 1 : "0.3 ppm", + 2 : "1 ppm", + 3 : "3 ppm", + 4 : "10 ppm", + 5 : "30 ppm", + 6 : "100 ppm", + 7 : "300 ppm", + 8 : "1000 ppm", + 9 : "3000 ppm", + 10 : "10000 ppm" + } + register_address = self.LOL_SET_THR + (status, set_threshold) = self.read_pagined_register(register_address) + register_address = self.LOL_CLR_THR + (status, clr_threshold) = self.read_pagined_register(register_address) + return (status, thresholds[set_threshold>>4], thresholds[clr_threshold>>4]) + + + def read_loss_of_lock_flg(self): + """read loss_of_lock_flg (sticky bit of loss_of_lock) from the device + No Args + + Returns: + tuple: + (status(int), loss_of_lock_flg(boolean)) + status : 0 if successfull, -1 if error + loss_of_lock_flg : boolean true if loss_of_lock_flg = 1, false if not + """ + register_address = self.HOLDOVER_LOS_STATUS_FLG + bit_position = self.LOL_FLG + loss_of_lock_flg = False + (status, value) = self.read_pagined_register(register_address) + if (value >> bit_position) & 1: + loss_of_lock_flg = True + return (status, loss_of_lock_flg) + + def read_run_mode(self): + """read_run_mode which is the image of the state machine + No Args + + Returns: + tuple: + (status(int), free_run_mode(boolean)) + status : 0 if successfull, -1 if error + free_run_holdover_mode : boolean true if the DSPLL is in free-run or holdover mode, + false if not + """ + register_address = self.HOLDOVER_LOS_STATUS + bit_position = self.HOLD + mode = "Normal" + (status, value) = self.read_pagined_register(register_address) + if (value >> bit_position) & 1: + register_address = self.HOLD_HIST_VALID + bit_position = self.ENOUGH_HISTORICAL_FREQUENCY_DATA + (status, value) = self.read_pagined_register(register_address) + if (value >> bit_position) & 1: + mode = "Hold over" + else: + mode = "Free run" + else: + mode = "Normal" + return (status, mode) + + def read_free_run_mode_flg(self): + """read free_run_holdover_mode_flg (sticky bit of free_run_mode) from the device + No Args + + Returns: + tuple: + (status(int), mode (string) + status : 0 if successfull, -1 if error + mode: sting = "Free run" if free run mode + = "Hold over" if hold over mode + = "Normal" is normal mode + """ + register_address = self.HOLDOVER_LOS_STATUS_FLG + bit_position = self.HOLD_FLG + free_run_mode_flg = False + (status, value) = self.read_pagined_register(register_address) + if (value >> bit_position) & 1: + free_run_mode_flg = True + return (status, free_run_mode_flg) + + def read_hold_hist_valid(self): + """read hold_hist_valid bit (1 when history data is valid) from the device + No Args + + Returns: + tuple: + (status(int), hold_hist_valid(boolean)) + status : 0 if successfull, -1 if error + hold_hist_valid : boolean true if hold_hist_valid = 1, false if not + """ + register_address = self.HOLD_HIST_VALID + bit_position = self.ENOUGH_HISTORICAL_FREQUENCY_DATA + hold_hist_valid = False + (status, value) = self.read_pagined_register(register_address) + if (value >> bit_position) & 1: + hold_hist_valid = True + return (status, hold_hist_valid) + + def clear_lol_flg_bit(self): + """clear LOL_FLG sticky bit of Loss of Lock LOL + No Args + + Returns: + status(int) : 0 if successfull, -1 if error + + Notes: + to clear LOL_FLG bit: + -- read HOLDOVER_LOS_STATUS_FLG register + -- in value_read, clear only the bit 1 (LOL_FLG) + -- write the result in HOLDOVER_LOS_STATUS_FLG register + """ + register_address = self.HOLDOVER_LOS_STATUS_FLG + (status1, value) = self.read_pagined_register(register_address) + value = value & ~(1 << self.LOL_FLG) + status2 = self.write_pagined_register(register_address, value) + (status1, value) = self.read_pagined_register(register_address) + status = 0 + if (status1 == -1) or (status2 == -1): + status = -1 + return status + + def clear_hold_flg_bit(self): + """clear HOLD_FLG sticky bit of Holdover mode HOLD + No Args + + Returns: + status(int): 0 if successfull, -1 if error + + Notes: + to clear HOD_FLG bit: + -- read HOLDOVER_LOS_STATUS_FLG register + -- in value_read, clear only the bit 5 (HOLD_FLG) + -- write the result in HOLDOVER_LOS_STATUS_FLG register + """ + register_address = self.HOLDOVER_LOS_STATUS_FLG + (status1, value) = self.read_pagined_register(register_address) + value = value & ~(1<<self.HOLD_FLG) + status2 = self.write_pagined_register(register_address, value) + status = 0 + if (status1 == -1) or (status2 == -1): + status = -1 + return status + + def read_output_enable(self, num_output): + """read the output enable of the output num_ouput + Args + num_output(int) : number of the ouput 0 to 9 + + Returns: + tuple: + (status(int), output_enable(boolean)) + status : 0 if successfull, -1 if error + output_enable : True if output of num_output is enabled, False otherwise + """ + if num_output > 9: + num_output = 9 + register_address = self.CLOCK_OUTPUT_DRIVER[num_output] + bit_position = self.OUT_OE + output_enable = False + (status, value) = self.read_pagined_register(register_address) + if (value >> bit_position) & 1: + output_enable = True + return (status, output_enable) + + def write_output_enable(self, num_output, output_enable): + """write the output enable of the output num_ouput + Args + num_output(int) : number of the ouput 0 to 9 + output_enable (boolean) : True if one wants output enabled, False otherwise + + Returns: + status (int) : 0 if successfull, -1 if error + + Notes: + to write output_enable bit: + -- read CLOCK_OUTPUT_DRIVER[num_output] register + -- in value_read, clear only the bit 5 (HOLD_FLG) + -- write the result in HOLDOVER_LOS_STATUS_FLG register + """ + if num_output > 9: + num_output = 9 + register_address = self.CLOCK_OUTPUT_DRIVER[num_output] + (status1, value) = self.read_pagined_register(register_address) + if output_enable: + value = value | (1<<self.OUT_OE) + else: + value = value & ~(1<<self.OUT_OE) + status2 = self.write_pagined_register(register_address, value) + if (status1 == -1) or (status2 == -1): + status = -1 + else: + status = 0 + return status + + def disable_outputs(self): + """disable all the outputs + + """ + status = self.write_pagined_register(0x102, 0) + return + + def enable_outputs(self): + """enable all the outputs + + """ + status = self.write_pagined_register(0x102, 1) + return + + def read_loss_of_signal(self, num_input): + """read loss_of_signal LOS bit of num_input given in argument + Args: + num_input(int) : number of the input 0 to 3 + + Returns: + tuple: + (status(int), loss_of_signal(boolean)) + status : 0 if successfull, -1 if error + loss_of_signal : boolean true if the Loss Of Signal LOS is 1, false if not + """ + if num_input > 3: + num_input = 3 + print "wrong input number" + register_address = self.LOS_OOF_ALARMS + los_in_list = [self.LOS_IN0, self.LOS_IN1, self.LOS_IN2, self.LOS_IN3] + bit_position = los_in_list[num_input] + (status, value) = self.read_pagined_register(register_address) + if (value >> bit_position) & 1: + loss_of_signal = True + else: + loss_of_signal = False + return (status, loss_of_signal) + + def enable_los(self, num_input): + """enable out of LOS bits + """ + status = self.set_bit(self.LOS_ENABLE, num_input) + return status + + def disable_los(self, num_input): + """disable out of LOS bits + """ + status = self.clear_bit(self.LOS_ENABLE, num_input) + return status + + def enable_oof(self, num_input): + """enable out of OOF bits + """ + status = self.set_bit(self.OOF_ENABLE, num_input) + return (status) + + def disable_oof(self, num_input): + """disable out of OOF bits + """ + status = self.clear_bit(self.OOF_ENABLE, num_input) + return (status) + + + def read_out_of_frequency(self, num_input): + """read out_of_frequency OOF bit of num_input given in argument + Args: + num_input(int) : number of the input 0 to 3 + + Returns: + tuple: + (status(int), out_of_frequency(boolean)) + status : 0 if successfull, -1 if error + out_of_frequency : boolean true if the Out Of Frequency OOF is 1, false if not + """ + if num_input > 3: + num_input = 3 + print "wrong input number" + register_address = self.LOS_OOF_ALARMS + oof_in_list = [self.OOF_IN0, self.OOF_IN1, self.OOF_IN2, self.OOF_IN3] + bit_position = oof_in_list[num_input] + (status, value) = self.read_pagined_register(register_address) + if (value >> bit_position) & 1: + out_of_frequency = True + else: + out_of_frequency = False + return (status, out_of_frequency) + + def read_loss_of_signal_flg(self, num_input): + """read loss_of_signal_flg LOS_FLG bit of num_input given in argument + (sticky bit of loss_of_signal LOS) + Args: + num_input(int) : number of the input 0 to 3 + + Returns: + tuple: + (status(int), loss_of_signal_flg(boolean)) + status : 0 if successfull, -1 if error + loss_of_signal_flg : boolean true if the LOS_FLG is 1, false if not + """ + # if num_input > 3: + # num_input = 3 + # print "wrong input number" + # register_address = self.LOS_OOF_ALARMS_FLG + # los_in_flg_list = [self.LOS_IN0_FLG, self.LOS_IN1_FLG, self.LOS_IN2_FLG, self.LOS_IN3_FLG] + # bit_position = los_in_flg_list[num_input] + # (status, value) = self.read_pagined_register(register_address) + # if (value >> bit_position) & 1: + # loss_of_signal_flg = True + # else: + # loss_of_signal_flg = False + if self.test_bit(self.LOS_OOF_ALARMS_FLG, num_input) == 1: + loss_of_signal_flg = True + else: + loss_of_signal_flg = False + status = 0 + return (status, loss_of_signal_flg) + + def read_out_of_frequency_flg(self, num_input): + """read out_of_frequency_flg OOF_FLG bit of num_input given in argument + (sticky bit of out_of_frequency OOF) + Args: + num_input(int) : number of the input 0 to 3 + + Returns: + tuple: + (status(int), out_of_frequency_flg(boolean)) + status : 0 if successfull, -1 if error + out_of_frequency_flg : boolean true if the OOF_FLG is 1, false if not + """ + if num_input > 3: + num_input = 3 + print "wrong input number" + register_address = self.LOS_OOF_ALARMS_FLG + oof_in_flg_list = [self.OOF_IN0_FLG, self.OOF_IN1_FLG, self.OOF_IN2_FLG, self.OOF_IN3_FLG] + bit_position = oof_in_flg_list[num_input] + (status, value) = self.read_pagined_register(register_address) + if (value >> bit_position) & 1: + out_of_frequency_flg = True + else: + out_of_frequency_flg = False + return (status, out_of_frequency_flg) + + def clear_los_flg_bit(self, num_input): + """clear the sticky bit LOS_FLG of num_input given in argument + (sticky bit of loss of signal LOS) + Args: + num_input(int) : number of the input 0 to 3 + + Returns: + status (int) : 0 if successfull, -1 if error + + Notes: + to clear LOS_FLG bit: + -- read LOS_OOF_ALARMS_FLG register + -- in value_read, clear only the bit: + --0 (LOS_IN0_FLG) if num_input = 0 + --1 (LOS_IN1_FLG) if num_input = 1 + --2 (LOS_IN2_FLG) if num_input = 2 + --3 (LOS_IN3_FLG) if num_input = 3 + -- write the result in LOS_OOF_ALARMS_FLG register + """ + + # if num_input > 3: + # num_input = 3 + # print "wrong input number" + # los_in_flg_list = [self.LOS_IN0_FLG, self.LOS_IN1_FLG, self.LOS_IN2_FLG, self.LOS_IN3_FLG] + # register_address = self.LOS_OOF_ALARMS_FLG + # (status1, value) = self.read_pagined_register(register_address) + # value = value & ~(1<<los_in_flg_list[num_input]) + # status2 = self.write_pagined_register(register_address, value) + # status = 0 + # if (status1 == -1) or (status2 == -1): + # status = -1 + return status + + + + + + def clear_oof_flg_bit(self, num_input): + """clear the sticky bit OOF_FLG of num_input given in argument + (sticky bit of out of frequency OOF) + Args: + num_input(int) : number of the input 0 to 3 + + Returns: + status (int) : 0 if successfull, -1 if error + + Notes: + to clear OOF_FLG bit: + -- read LOS_OOF_ALARMS_FLG register + -- in value_read, clear only the bit: + --4 (OOF_IN0_FLG) if num_input = 0 + --5 (OOF_IN1_FLG) if num_input = 1 + --6 (OOF_IN2_FLG) if num_input = 2 + --7 (OOF_IN3_FLG) if num_input = 3 + -- write the result in LOS_OOF_ALARMS_FLG register + """ + if num_input > 3: + num_input = 3 + print "wrong input number" + oof_in_flg_list = [self.OOF_IN0_FLG, self.OOF_IN1_FLG, self.OOF_IN2_FLG, self.OOF_IN3_FLG] + register_address = self.LOS_OOF_ALARMS_FLG + (status1, value) = self.read_pagined_register(register_address) + value = value & ~(1<<oof_in_flg_list[num_input]) + status2 = self.write_pagined_register(register_address, value) + status = 0 + if (status1 == -1) or (status2 == -1): + status = -1 + return status + + def clear_los_oof_flg_reg(self): + dic ={} + # Read raised flags + status, current_alarms = self.read_pagined_register(self.LOS_OOF_ALARMS) + # Read enabled alarms + status, enabled_alarms = self.read_pagined_register(self.LOS_ENABLE) + # Disable all alarms with raised flags + status = self.write_pagined_register(self.LOS_ENABLE, enabled_alarms & ~(current_alarms & 0xF)) + # Clear sticky bits + status = self.write_pagined_register(self.LOS_OOF_ALARMS_FLG, 0x00) + # Re-enable alarms with a raised flag + status = self.write_pagined_register(self.LOS_ENABLE, enabled_alarms | (current_alarms & 0xF)) + dic["1_los_oof_alarms : "] = str(hex(current_alarms)) + dic["2_enabled alarms: "] = str(hex(enabled_alarms)) + dic["3_disable raised alarms : "] = str(hex(enabled_alarms & ~(current_alarms & 0xF))) + dic["4_restored enabled : "] = str(hex(enabled_alarms | (current_alarms & 0xF))) + return dic + + def dump_registers(self): + print "===== Dumping registers =====" + for register_address in (0xC, 0xD, 0xE, 0xF, 0x12, 0x13, 0x2C, 0x536, 0x52A): + (status, value) = self.read_pagined_register(register_address) + print "Address = ",hex(register_address),", Value = ", hex(value) + + def program_with_file(self, filename, device): + """programs the targeted device with a file + + Args: + filename: name of the file + device : name of the device (SI5345_U23, SI5345_U48 or SI5344_U54) + + """ + + print "..... Configuration file is ", filename + (status, part_number) = self.read_part_number() + print "..... Part number detected is : ", hex(part_number) + print "..... Programming device" + self.si534x_programming(filename) + + + + def test(self, filename, device, port): + """hardtest() only for local debug + Notes: + to launch hardtest from the current directorie (FC0/devices_lli/components) + enter "./si534x_comp.py dev" + """ + print "..... Hard resetting PLL" + self.hard_reset() + print "..... Configuration file is ",filename + (status, part_number) = self.read_part_number() + print "..... Part number detected is : ",hex(part_number) + print "===== Programming device" + self.si534x_programming(filename) + time.sleep(1.0) # wait 1 second to allow frequency measurement to stabilize + fpga = Arria10(0) + start = time.time() + store = fpga.read_pll_port_frequency(device, 0)[1] + print "..... Clearing LOL_Flag" + self. clear_lol_flg_bit() + print "..... Clearing Cal_busy_Flag" + self.write_pagined_register(0x14, 0x00) + while time.time() - start < 10 : + if fpga.read_pll_port_frequency(device, 0)[1] != store: + end = time.time() + (status, value) = self.read_pagined_register(0x14) + print "..... Cal busy =", hex(value), + (status, loss_of_lock) = self.read_loss_of_lock() + print ", LOL =",loss_of_lock, + (status, loss_of_lock_flg) = self.read_loss_of_lock_flg() + print ", LOL_flag =", loss_of_lock_flg, + (status, value) = self.read_pagined_register(0xC) + print ", Reg", hex(0xC), "=", hex(value), + for port_number in port: + print "|",fpga.read_pll_port_frequency(device, port_number)[1], + print "|Time =", end - start + store = fpga.read_pll_port_frequency(device, 0)[1] + print "..... Output status :" + (status, free_run_mode) = self.read_free_run_mode() + print "..... Free run mode is : ", free_run_mode + (status) = self.clear_lol_flg_bit() # clears lol flag + (status, loss_of_lock) = self.read_loss_of_lock() # read lol flag + print "..... Loss of lock flag is ",loss_of_lock + print "..... Input status :" + for input in range(0, 4): + (status, loss_of_signal) = self.read_loss_of_signal(input) + print "..... pll input :", input, " loss of lock is : ", loss_of_signal + (status, out_of_frequency) = self.read_out_of_frequency(input) + print "..... pll input :", input," out of frequency is : ",out_of_frequency + #self.dump_registers() + + + return 0 + + +def main(device): + """ Main function + instanciation of Class Si534x() + execute hard test for all PLLs + """ + devices = \ + {1 : "SI5345_U23", + 2 : "SI5345_U48", + 3 : "SI5344_U54" + } + ports = \ + {1 : [0, 1, 2, 3], + 2 : [0, 1, 3, 4, 8], + 3 : [0, 1] + } + files = \ + {1 : "../data/Si5345-RevD-JIT1_40_jitter1_input0_40MHz-Registers.txt", + 2 : "../data/Si5345-RevD-JIT2_40_jitter2_input0_40MHz-Registers.txt", + 3 : "../data/Si5344-RevD-TFC_40-Registers.txt" + } + + dev = device # Creates a list of objects with the 3 PLLs + add = 0x68 + pll = [Si534x(dev, bus, add) for bus in devices.keys()] + + for i in devices.keys(): # Tests the 3 PLLs + print "=========== Testing PLL ", devices[i], "============" + pll[i-1].test(files[i], devices[i], ports[i]) # i-1 because list index starts with 0 + # pll[i-1].clear_lol_flg_bit() + status, val = pll[i-1].read_loss_of_lock() # i-1 because list index starts with 0 + print ".....",devices[i], + if val == True : print "Loss of lock" + else : print "Locked" + print + + + +if __name__ == "__main__": + if (len(sys.argv) > 1): + main(int(sys.argv[1])) + else : + main(0) -- GitLab