class FEMB_CONFIG(FEMB_CONFIG_BASE): def __init__(self): super().__init__() #declare board specific registers self.FEMB_VER = "adctest" self.REG_RESET = 0 self.REG_ASIC_RESET = 1 self.REG_ASIC_SPIPROG = 2 self.REG_SEL_ASIC = 7 self.REG_SEL_CH = 7 self.REG_FESPI_BASE = 592 self.REG_ADCSPI_BASE = 512 self.REG_FESPI_RDBACK_BASE = 632 self.REG_ADCSPI_RDBACK_BASE = 552 self.REG_HS = 17 self.REG_LATCHLOC = 4 self.REG_CLKPHASE = 6 self.ADC_TESTPATTERN = [ 0x12, 0x345, 0x678, 0xf1f, 0xad, 0xc01, 0x234, 0x567, 0x89d, 0xeca, 0xff0, 0x123, 0x456, 0x789, 0xabc, 0xdef ] self.NASICS = 1 #initialize FEMB UDP object self.femb = FEMB_UDP() def resetBoard(self): #Reset system self.femb.write_reg(self.REG_RESET, 1) time.sleep(5.) #Reset registers self.femb.write_reg(self.REG_RESET, 2) time.sleep(1.) #Time stamp reset #femb.write_reg( 0, 4) #time.sleep(0.5) #Reset ADC ASICs self.femb.write_reg(self.REG_ASIC_RESET, 1) time.sleep(0.5) def initBoard(self): nRetries = 5 for iRetry in range(nRetries): #set up default registers #Reset ADC ASICs self.femb.write_reg(self.REG_ASIC_RESET, 1) time.sleep(0.5) #Set ADC test pattern register self.femb.write_reg(3, 0x01230000) # test pattern off #self.femb.write_reg( 3, 0x81230000) # test pattern on #Set ADC latch_loc self.femb.write_reg(self.REG_LATCHLOC, 0x66666667) #Set ADC clock phase self.femb.write_reg(self.REG_CLKPHASE, 0xfffc0054) #internal test pulser control self.femb.write_reg(5, 0x00000000) self.femb.write_reg(13, 0x0) #enable #Set test and readout mode register self.femb.write_reg( 7, 0x0000) #11-8 = channel select, 3-0 = ASIC select #Set number events per header self.femb.write_reg(8, 0x0) #ADC ASIC SPI registers print("Config ADC ASIC SPI") print("ADCADC") self.femb.write_reg(self.REG_ADCSPI_BASE + 0, 0xC0C0C0C) self.femb.write_reg(self.REG_ADCSPI_BASE + 1, 0xC0C0C0C) self.femb.write_reg(self.REG_ADCSPI_BASE + 2, 0xC0C0C0C) self.femb.write_reg(self.REG_ADCSPI_BASE + 3, 0xC0C0C0C) self.femb.write_reg(self.REG_ADCSPI_BASE + 4, 0xC0C0C0C) self.femb.write_reg(self.REG_ADCSPI_BASE + 5, 0xC0C0C0C) self.femb.write_reg(self.REG_ADCSPI_BASE + 6, 0xC0C0C0C) self.femb.write_reg(self.REG_ADCSPI_BASE + 7, 0xC0C0C0C) self.femb.write_reg(self.REG_ADCSPI_BASE + 8, 0x18321832) self.femb.write_reg(self.REG_ADCSPI_BASE + 9, 0x18181818) self.femb.write_reg(self.REG_ADCSPI_BASE + 10, 0x18181818) self.femb.write_reg(self.REG_ADCSPI_BASE + 11, 0x18181818) self.femb.write_reg(self.REG_ADCSPI_BASE + 12, 0x18181818) self.femb.write_reg(self.REG_ADCSPI_BASE + 13, 0x18181818) self.femb.write_reg(self.REG_ADCSPI_BASE + 14, 0x18181818) self.femb.write_reg(self.REG_ADCSPI_BASE + 15, 0x18181818) self.femb.write_reg(self.REG_ADCSPI_BASE + 16, 0x64186418) self.femb.write_reg(self.REG_ADCSPI_BASE + 17, 0x30303030) self.femb.write_reg(self.REG_ADCSPI_BASE + 18, 0x30303030) self.femb.write_reg(self.REG_ADCSPI_BASE + 19, 0x30303030) self.femb.write_reg(self.REG_ADCSPI_BASE + 20, 0x30303030) self.femb.write_reg(self.REG_ADCSPI_BASE + 21, 0x30303030) self.femb.write_reg(self.REG_ADCSPI_BASE + 22, 0x30303030) self.femb.write_reg(self.REG_ADCSPI_BASE + 23, 0x30303030) self.femb.write_reg(self.REG_ADCSPI_BASE + 24, 0x30303030) self.femb.write_reg(self.REG_ADCSPI_BASE + 25, 0x60c868c8) self.femb.write_reg(self.REG_ADCSPI_BASE + 26, 0x60606868) self.femb.write_reg(self.REG_ADCSPI_BASE + 27, 0x60606868) self.femb.write_reg(self.REG_ADCSPI_BASE + 28, 0x60606868) self.femb.write_reg(self.REG_ADCSPI_BASE + 29, 0x60606868) self.femb.write_reg(self.REG_ADCSPI_BASE + 30, 0x60606868) self.femb.write_reg(self.REG_ADCSPI_BASE + 31, 0x60606868) self.femb.write_reg(self.REG_ADCSPI_BASE + 32, 0x60606868) self.femb.write_reg(self.REG_ADCSPI_BASE + 33, 0x9060A868) self.femb.write_reg(self.REG_ADCSPI_BASE + 34, 0x10001) #ADC ASIC sync self.femb.write_reg(17, 0x1) # controls HS link, 0 for on, 1 for off self.femb.write_reg(17, 0x0) # controls HS link, 0 for on, 1 for off #Write ADC ASIC SPI print("Program ADC ASIC SPI") self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) time.sleep(0.1) self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) time.sleep(0.1) print("Check ADC ASIC SPI") for regNum in range(self.REG_ADCSPI_RDBACK_BASE, self.REG_ADCSPI_RDBACK_BASE + 34, 1): val = self.femb.read_reg(regNum) print(hex(val)) #enable streaming #self.femb.write_reg( 9, 0x8) #LBNE_ADC_MODE self.femb.write_reg(16, 0x1) # Check that board streams data data = self.femb.get_data(1) if data == None: print("Board not streaming data, retrying initialization...") continue # try initializing again print("FEMB_CONFIG--> Reset FEMB is DONE") return print( "Error: Board not streaming data after trying to initialize {} times. Exiting." .format(nRetries)) sys.exit(1) def selectChannel(self, asic, chan, hsmode=None): asicVal = int(asic) if (asicVal < 0) or (asicVal >= self.NASICS): print( "femb_config_femb : selectChan - invalid ASIC number, only 0 to {} allowed" .format(self.NASICS - 1)) return chVal = int(chan) if (chVal < 0) or (chVal > 15): print( "femb_config_femb : selectChan - invalid channel number, only 0 to 15 allowed" ) return #print( "Selecting ASIC " + str(asicVal) + ", channel " + str(chVal)) regVal = (chVal << 8) + asicVal self.femb.write_reg(self.REG_SEL_CH, regVal) def syncADC(self): #turn on ADC test mode print("Start sync ADC") reg3 = self.femb.read_reg(3) newReg3 = (reg3 | 0x80000000) self.femb.write_reg(3, newReg3) #31 - enable ADC test pattern alreadySynced = True for a in range(0, self.NASICS, 1): print("Test ADC " + str(a)) unsync = self.testUnsync(a) if unsync != 0: alreadySynced = False print("ADC not synced, try to fix") self.fixUnsync(a) LATCH = self.femb.read_reg(self.REG_LATCHLOC) PHASE = self.femb.read_reg(self.REG_CLKPHASE) print("Latch latency " + str(hex(LATCH)) + "\tPhase " + str(hex(PHASE))) print("End sync ADC") return not alreadySynced, LATCH, None, PHASE def testUnsync(self, adc): adcNum = int(adc) if (adcNum < 0) or (adcNum >= self.NASICS): print("femb_config_femb : testLink - invalid asic number") return #loop through channels, check test pattern against data badSync = 0 for ch in range(0, 16, 1): self.selectChannel(adcNum, ch) time.sleep(0.1) for test in range(0, 1000, 1): data = self.femb.get_data(1) for samp in data: chNum = ((samp >> 12) & 0xF) sampVal = (samp & 0xFFF) if sampVal != self.ADC_TESTPATTERN[ch]: badSync = 1 if badSync == 1: break if badSync == 1: break if badSync == 1: break return badSync def fixUnsync(self, adc): adcNum = int(adc) if (adcNum < 0) or (adcNum >= self.NASICS): print("femb_config_femb : testLink - invalid asic number") return initLATCH = self.femb.read_reg(self.REG_LATCHLOC) initPHASE = self.femb.read_reg(self.REG_CLKPHASE) #loop through sync parameters for phase in range(0, 2, 1): clkMask = (0x1 << adcNum) testPhase = ((initPHASE & ~(clkMask)) | (phase << adcNum)) self.femb.write_reg(self.REG_CLKPHASE, testPhase) for shift in range(0, 16, 1): shiftMask = (0xF << 4 * adcNum) testShift = ((initLATCH & ~(shiftMask)) | (shift << 4 * adcNum)) self.femb.write_reg(self.REG_LATCHLOC, testShift) #reset ADC ASIC self.femb.write_reg(self.REG_ASIC_RESET, 1) time.sleep(0.1) self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) time.sleep(0.1) self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) time.sleep(0.1) #test link unsync = self.testUnsync(adcNum) if unsync == 0: print("ADC synchronized") return #if program reaches here, sync has failed print("ADC SYNC process failed for ADC # " + str(adc))
class FEMB_CONFIG(FEMB_CONFIG_BASE): def __init__(self, exitOnError=False): super().__init__(exitOnError=exitOnError) #declare board specific registers self.FEMB_VER = "adctestP1quad" self.REG_RESET = 0 # bit 0 system, 1 reg, 2 alg, 3 udp self.REG_PWR_CTRL = 1 # bit 0-3 pwr, 8-15 blue LEDs near buttons self.REG_ASIC_SPIPROG_RESET = 2 # bit 0 FE SPI, 1 ADC SPI, 4 FE ASIC RESET, 5 ADC ASIC RESET, 6 SOFT ADC RESET & SPI readback check self.REG_SEL_CH = 3 # bit 0-7 chip, 8-15 channel, 31 WIB mode self.REG_DAC1 = 4 # bit 0-15 DAC val, 16-19 tp mode select, 31 set dac self.REG_DAC2 = 5 # bit 0-15 tp period, 16-31 tp shift self.REG_FPGA_TST_PATT = 6 # bit 0-11 tst patt, 16 enable self.REG_ADC_CLK = 7 # bit 0-3 clk phase, 8 clk speed sel self.REG_LATCHLOC = 8 # bit 0-7 ADC1, 8-15 ADC2, 16-23 ADC3, 24-31 ADC4 self.REG_STOP_ADC = 9 # bit 0 stops sending convert, read ADC HEADER redundant with reg 2 self.REG_UDP_FRAME_SIZE = 63 # bits 0-11 self.REG_FIRMWARE_VERSION = 0xFF # 255 in decimal self.CONFIG_FIRMWARE_VERSION = 0x105 # this file is written for this self.REG_LATCHLOC_data_2MHz = 0x02010201 self.REG_LATCHLOC_data_1MHz = 0x0 self.REG_LATCHLOC_data_2MHz_cold = 0x02010201 self.REG_LATCHLOC_data_1MHz_cold = 0x0 self.REG_CLKPHASE_data_2MHz = 0x4 self.REG_CLKPHASE_data_1MHz = 0x1 self.REG_CLKPHASE_data_2MHz_cold = 0x0 #double check socket 1 value self.REG_CLKPHASE_data_1MHz_cold = 0x0 self.REG_HDR_ERROR_RESET = 47 self.REG_HDR_ERROR_BASES = [49, 51, 53, 55] # for each chip self.DEFAULT_FPGA_TST_PATTERN = 0x12 self.ADC_TESTPATTERN = [ 0x12, 0x345, 0x678, 0xf1f, 0xad, 0xc01, 0x234, 0x567, 0x89d, 0xeca, 0xff0, 0x123, 0x456, 0x789, 0xabc, 0xdef ] # registers 64-88 are SPI to ASICs # 88 is last register besides 255 which is firmware version self.REG_FESPI_BASE = 84 # this configures all FE ASICs self.REG_ADCSPI_BASES = [64, 69, 74, 79] # for each chip self.REG_EXTCLK_INV = 10 self.REG_EXTCLK_BASES = [11, 20, 29, 38] # for each chip self.FPGA_FREQ_MHZ = 200 # frequency of FPGA clock in MHz self.REG_PLL_BASES = [17, 26, 35, 44] # for each chip self.NASICS = 4 self.F2DEFAULT = 0 self.CLKDEFAULT = "fifo" self.isExternalClock = True #False = internal monostable, True = external self.is1MHzSAMPLERATE = False #True = 1MHz, False = 2MHz self.COLD = False self.enableTest = 0 self.doSpiWrite = True self.doReSync = True self.scanSyncSettings = True self.adcSyncStatus = False self.maxSyncAttempts = 10 self.numSyncTests = 25 #initialize FEMB UDP object self.femb = FEMB_UDP() #list of adc configuration register mappings self.adc_regs = ADC_ASIC_REG_MAPPING() def printParameters(self): print("External ADC Clocks \t", self.isExternalClock) print("Cryogenic temperature \t", self.COLD) print("Enable ADC test input \t", self.enableTest) print("Enable SPI writing \t", self.doSpiWrite) print("MAX SYNC ATTEMPTS \t", self.maxSyncAttempts) print("Do resync \t", self.doReSync) print("Try all sync settings \t", self.scanSyncSettings) print("1MHz Sampling \t", self.is1MHzSAMPLERATE) print("SYNC STATUS \t", self.adcSyncStatus) def resetBoard(self): """ Reset registers and state machines NOT udp Make sure to set reg 0 back to zero or there will be much sadness! """ #Reset registers self.femb.write_reg(self.REG_RESET, 2) time.sleep(1.) #Reset state machines self.femb.write_reg(self.REG_RESET, 4) time.sleep(1.) #Reset reset register to 0 self.femb.write_reg(self.REG_RESET, 0) time.sleep(0.2) def initBoard(self): # test readback readback = self.femb.read_reg(self.REG_FIRMWARE_VERSION) if readback is None: print("FEMB_CONFIG: Error reading register 0, Exiting.") return False if readback is False: if self.exitOnError: print("FEMB_CONFIG: Error reading register 0, Exiting.") sys.exit(1) else: raise ReadRegError("Couldn't read register 0") return False ##### Start Top-level Labview stacked sequence struct 0 firmwareVersion = self.femb.read_reg( self.REG_FIRMWARE_VERSION) & 0xFFFF if firmwareVersion == None: print("FEMB_CONFIG: Error reading register 0, Exiting.") return False if firmwareVersion != self.CONFIG_FIRMWARE_VERSION: raise FEMBConfigError( "Board firmware version {} doesn't match configuration firmware version {}" .format(firmwareVersion, self.CONFIG_FIRMWARE_VERSION)) return False print("Firmware Version: ", firmwareVersion) self.femb.write_reg(self.REG_UDP_FRAME_SIZE, 0x1FB) time.sleep(0.05) self.setFPGADac(0, 0, 0, 0) # write regs 4 and 5 #self.femb.write_reg(1,0) # pwr ctrl --disabled BK self.femb.write_reg(3, (5 << 8)) # chn sel self.femb.write_reg(6, self.DEFAULT_FPGA_TST_PATTERN) #tst pattern self.femb.write_reg(7, 13) #adc clk self.femb.write_reg(8, 0) #latchloc ##### End Top-level Labview stacked sequence struct 0 #Set FPGA test pattern register self.femb.write_reg(self.REG_FPGA_TST_PATT, self.DEFAULT_FPGA_TST_PATTERN) # test pattern off #self.femb.write_reg(self.REG_FPGA_TST_PATT, self.DEFAULT_FPGA_TST_PATTERN+(1 << 16)) # test pattern on #Set ADC latch_loc and clock phase and sample rate if self.is1MHzSAMPLERATE == True: if self.COLD: self.femb.write_reg(self.REG_LATCHLOC, self.REG_LATCHLOC_data_1MHz_cold) self.femb.write_reg(self.REG_ADC_CLK, (self.REG_CLKPHASE_data_1MHz_cold & 0xF) | (1 << 8)) else: self.femb.write_reg(self.REG_LATCHLOC, self.REG_LATCHLOC_data_1MHz) self.femb.write_reg(self.REG_ADC_CLK, (self.REG_CLKPHASE_data_1MHz & 0xF) | (1 << 8)) else: # use 2 MHz values if self.COLD: self.femb.write_reg(self.REG_LATCHLOC, self.REG_LATCHLOC_data_2MHz_cold) self.femb.write_reg(self.REG_ADC_CLK, (self.REG_CLKPHASE_data_2MHz_cold & 0xF)) else: self.femb.write_reg(self.REG_LATCHLOC, self.REG_LATCHLOC_data_2MHz) self.femb.write_reg(self.REG_ADC_CLK, (self.REG_CLKPHASE_data_2MHz & 0xF)) #External timing config #self.writePLLs(0,0x20001,0) #writePLL(0,0x60017,0x5000B,0x801E0003) #writePLL(1,0x10000E,0x50009,0x801C0002) #writePLL(2,0x10000E,0x5000D,0x80180005) self.setExtClockRegs() #specify wib mode self.femb.write_reg_bits(self.REG_SEL_CH, 31, 1, 1) #turn ON ASICs when initializing board self.turnOnAsics() #turn OFF ASICs when initializing board #self.turnOffAsics() #test only, leave EXT TP mode ON #self.setFPGADac(0,1,0,0) # write regs 4 and 5 return True def initAsic(self, asicNum=None): if asicNum == None: print( "FEMB_CONFIG: Invalid ASIC # defined, will not initialize ASIC." ) return False asicNumVal = int(asicNum) if (asicNumVal < 0) or (asicNumVal >= self.NASICS): print( "FEMB_CONFIG: Invalid ASIC # defined, will not initialize ASIC." ) return False #turn on ASIC #self.turnOnAsic(asicNumVal) #Reset ASICs self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 0x0) # zero out reg self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 0x30) # reset FE and ADC self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 0x0) # zero out reg time.sleep(1.) #specify ASIC for streaming data output self.selectAsic(asicNumVal) #Configure ADC ASIC registers (and external clock inside) if self.isExternalClock == True: self.configAdcAsic(asicNum=asicNumVal, testInput=self.enableTest, clockExternal=True) else: self.configAdcAsic(asicNum=asicNumVal, testInput=self.enableTest, clockMonostable=True) #acutally program the ADC using the default parameters self.doAdcAsicConfig(asicNumVal) #if sync fails, optionally attempt to try all other parameters to achieve sync if (self.adcSyncStatus == False) and (self.scanSyncSettings == True): self.fixUnsync(asicNumVal) #check SPI + SYNC status here syncStatus = self.getSyncStatus() if syncStatus == None: print("FEMB_CONFIG: ASIC initialization failed") return False adcSpi = syncStatus[1][asicNumVal] if adcSpi == False: print("FEMB_CONFIG: ADC ASIC SPI readback failed") return False #check sync here #self.printSyncRegister() print("SYNC STATUS:\t", self.adcSyncStatus) if self.adcSyncStatus == False: print("FEMB_CONFIG: ASIC NOT SYNCHRONIZED") return False return True def configAdcAsic(self, asicNum=None, enableOffsetCurrent=None, offsetCurrent=None, testInput=None, freqInternal=None, sleep=None, pdsr=None, pcsr=None, clockMonostable=None, clockExternal=None, clockFromFIFO=None, sLSB=None, f0=None, f1=None, f2=None, f3=None, f4=None, f5=None): """ Configure ADCs enableOffsetCurrent: 0 disable offset current, 1 enable offset current offsetCurrent: 0-15, amount of current to draw from sample and hold testInput: 0 digitize normal input, 1 digitize test input freqInternal: internal clock frequency: 0 1MHz, 1 2MHz sleep: 0 disable sleep mode, 1 enable sleep mode pdsr: if pcsr=0: 0 PD is low, 1 PD is high pcsr: 0 power down controlled by pdsr, 1 power down controlled externally Only one of these can be enabled: clockMonostable: True ADC uses monostable clock clockExternal: True ADC uses external clock clockFromFIFO: True ADC uses digital generator FIFO clock sLSB: LSB current steering mode. 0 for full, 1 for partial (ADC7 P1) f0, f1, f2, f3, f4, f5: version specific """ if asicNum == None: return None asicNumVal = int(asicNum) if (asicNumVal < 0) or (asicNumVal >= self.NASICS): return None #check requested clocks if clockMonostable and clockExternal: return None if clockMonostable and clockFromFIFO: return None if clockExternal and clockFromFIFO: return None if enableOffsetCurrent is None: enableOffsetCurrent = 0 if offsetCurrent is None: offsetCurrent = 0 else: offsetCurrent = int( "{:04b}".format(offsetCurrent)[::-1], 2) # need to reverse bits, use string/list tricks if testInput is None: testInput = 1 if freqInternal is None: freqInternal = 1 if sleep is None: sleep = 0 if pdsr is None: pdsr = 0 if pcsr is None: pcsr = 0 if sLSB is None: sLSB = 0 if f1 is None: f1 = 0 if f2 is None: f2 = 0 if f3 is None: f3 = 0 if f4 is None: f4 = 1 if f5 is None: f5 = 0 if not (clockMonostable or clockExternal or clockFromFIFO): clockExternal = True # a bunch of things depend on the clock choice clk0 = 0 clk1 = 0 if clockExternal: clk0 = 1 clk1 = 0 elif clockFromFIFO: clk0 = 0 clk1 = 1 if f0 is None: if clockExternal: f0 = 1 else: f0 = 0 #moved external clock reg config to init function for now #if clockExternal: # self.extClock(enable=True) #else: # self.extClock(enable=False) #determine register values for requested config self.adc_regs.set_chip(en_gr=enableOffsetCurrent, d=offsetCurrent, tstin=testInput, frqc=freqInternal, slp=sleep, pdsr=pdsr, pcsr=pcsr, clk0=clk0, clk1=clk1, f0=f0, f1=f1, f2=f2, f3=f3, f4=f4, f5=f5, slsb=sLSB) #write config registers self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 0) for iReg in range(0, 5, 1): self.femb.write_reg(self.REG_ADCSPI_BASES[asicNumVal] + iReg, self.adc_regs.REGS[iReg]) #print("{:3} {:#010x}".format(self.REG_ADCSPI_BASES[iChip]+iReg, chipRegs[iReg])) #function programs ADC SPI and does multiple tests to ensure sync is good, note uses recursion def doAdcAsicConfig(self, asicNum=None, syncAttempt=0): if asicNum == None: return None asicNumVal = int(asicNum) if (asicNumVal < 0) or (asicNumVal >= self.NASICS): return None #write ADC ASIC SPI, do on intial sync attempt ONLY if (self.doSpiWrite == True) and (syncAttempt == 0): print("Program ADC ASIC SPI") #self.REG_ASIC_SPIPROG_RESET = 2 # bit 0 FE SPI, 1 ADC SPI, 4 FE ASIC RESET, 5 ADC ASIC RESET, 6 SOFT ADC RESET & SPI readback check self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 0x0) self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 0x20) #ADC reset time.sleep(0.01) self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 0x0) self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 0x2) #ADC SPI write time.sleep(0.01) self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 0x0) self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 0x2) #ADC SPI write time.sleep(0.01) #soft reset self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 0) self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 0x40) # soft reset self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 0) #optionally check the ADC sync if self.doReSync == False: return #self.checkAdcSyncBits(asicNumVal) self.checkAdcErrorCount(asicNumVal) #try again if sync not achieved, note recursion, stops after some maximum number of attempts if self.adcSyncStatus == False: if syncAttempt >= self.maxSyncAttempts: print( "doAsicConfig: Could not sync ADC ASIC, giving up after " + str(self.maxSyncAttempts) + " attempts.") return None else: self.doAdcAsicConfig(asicNumVal, syncAttempt + 1) #check ADC sync bits several times to ensure sync is stable def checkAdcSyncBits(self, asicNum): if asicNum == None: return None asicNumVal = int(asicNum) if (asicNumVal < 0) or (asicNumVal >= self.NASICS): return None self.adcSyncStatus = False #assume sync is BAD initially isSync = True for syncTest in range(0, self.numSyncTests, 1): regVal = self.femb.read_reg(2) if regVal == None: print("doAdcAsicConfig: Could not check SYNC status, bad") self.adcSyncStatus = False return None syncVal = ((regVal >> 24) & 0xFF) syncVal = ((syncVal >> 2 * asicNumVal) & 0x3) if syncVal != 0x0: #bad sync detected isSync = False break self.adcSyncStatus = isSync def checkAdcErrorCount(self, asicNum): if asicNum == None: return None asicNumVal = int(asicNum) if (asicNumVal < 0) or (asicNumVal >= self.NASICS): return None #check header error count self.adcSyncStatus = False #assume sync is BAD initially self.femb.write_reg(self.REG_HDR_ERROR_RESET, 0) self.femb.write_reg(self.REG_HDR_ERROR_RESET, 0x1) #reset counters self.femb.write_reg(self.REG_HDR_ERROR_RESET, 0) time.sleep(0.05) #optional delay errRegNum = self.REG_HDR_ERROR_BASES[asicNumVal] errorCount = self.femb.read_reg(errRegNum) if errorCount == None: print("doAdcAsicConfig: Could not check SYNC status, bad") return None if errorCount == 0: self.adcSyncStatus = True def fixUnsync(self, asicNum): if asicNum == None: return None asicNumVal = int(asicNum) if (asicNumVal < 0) or (asicNumVal >= self.NASICS): return None initLATCH = self.femb.read_reg(self.REG_LATCHLOC) initPHASE = self.femb.read_reg( self.REG_ADC_CLK) # remember bit 16 sample rate phases = [0, 1] if self.COLD: phases = [0, 1, 0, 1, 0] #loop through sync parameters for shift in range(0, 6, 1): shiftMask = (0xFF << 8 * asicNum) testShift = ((initLATCH & ~(shiftMask)) | (shift << 8 * asicNum)) self.femb.write_reg(self.REG_LATCHLOC, testShift) time.sleep(0.01) for phase in phases: clkMask = (0x1 << asicNum) testPhase = ((initPHASE & ~(clkMask)) | (phase << asicNum)) self.femb.write_reg(self.REG_ADC_CLK, testPhase) time.sleep(0.01) print("try shift: {} phase: {} testingUnsync...".format( shift, phase)) #try ADC config with new self.doAdcAsicConfig(asicNumVal) if self.adcSyncStatus == True: print("FEMB_CONFIG--> ADC synchronized") return True #if program reaches here, sync has failed print("Error: FEMB_CONFIG--> ADC SYNC process failed for ADC # " + str(asicNumVal)) print( "Setting back to original values: LATCHLOC: {:#010x}, PHASE: {:#010x}" .format(initLATCH, initPHASE & 0xF)) self.femb.write_reg(self.REG_LATCHLOC, initLATCH) self.femb.write_reg(self.REG_ADC_CLK, initPHASE) self.adcSyncStatus = False def getSyncStatus(self): syncBits = None adc0 = None fe0 = None adc1 = None fe1 = None adc2 = None fe2 = None adc3 = None fe3 = None reg = self.femb.read_reg(self.REG_ASIC_SPIPROG_RESET) if reg is None: print("Error: can't read back sync register") return None else: print("Register 2: {:#010x}".format(reg)) syncBits = reg >> 24 reg = reg >> 16 adc0 = ((reg >> 0) & 1) == 1 fe0 = ((reg >> 1) & 1) == 1 adc1 = ((reg >> 2) & 1) == 1 fe1 = ((reg >> 3) & 1) == 1 adc2 = ((reg >> 4) & 1) == 1 fe2 = ((reg >> 5) & 1) == 1 adc3 = ((reg >> 6) & 1) == 1 fe3 = ((reg >> 7) & 1) == 1 return (fe0, fe1, fe2, fe3), (adc0, adc1, adc2, adc3), syncBits def printSyncRegister(self): (fe0, fe1, fe2, fe3), (adc0, adc1, adc2, adc3), syncBits = self.getSyncStatus() print("ASIC Readback Status:") print(" ADC 0:", adc0, "FE 0:", fe0) print(" ADC 1:", adc1, "FE 1:", fe1) print(" ADC 2:", adc2, "FE 2:", fe2) print(" ADC 3:", adc3, "FE 3:", fe3) print("ADC Sync Bits: {:#010b} (0 is good)".format(syncBits)) def selectAsic(self, asic): """ asic is chip number 0 to 7 """ asicVal = int(asic) if (asicVal < 0) or (asicVal >= self.NASICS): print( "femb_config_femb : selectChan - invalid ASIC number, only 0 to {} allowed" .format(self.NASICS - 1)) return #self.femb.write_reg( self.REG_STOP_ADC, 1) #time.sleep(0.05) # in this firmware asic = 0 disables readout, so asics are 1,2,3,4 self.femb.write_reg_bits(self.REG_SEL_CH, 0, 0x7, asicVal + 1) #self.femb.write_reg( self.REG_STOP_ADC, 0) def extClock(self, enable=False, period=500, mult=1, offset_rst=0, offset_read=480, offset_msb=230, offset_lsb=480, width_rst=50, width_read=20, width_msb=270, width_lsb=20, offset_lsb_1st_1=50, width_lsb_1st_1=190, offset_lsb_1st_2=480, width_lsb_1st_2=20, inv_rst=True, inv_read=True, inv_msb=False, inv_lsb=False, inv_lsb_1st=False): """ Programs external clock. All non-boolean arguments except mult are in nanoseconds IDXM = msb IDXL = lsb IDL = lsb_1st """ rd_off = 0 rst_off = 0 rst_wid = 0 msb_off = 0 msb_wid = 0 lsb_fc_wid2 = 0 lsb_fc_off1 = 0 rd_wid = 0 lsb_fc_wid1 = 0 lsb_fc_off2 = 0 lsb_wid = 0 lsb_off = 0 inv = 0 if enable: clock = 1. / self.FPGA_FREQ_MHZ * 1000. # clock now in ns denominator = clock / mult period_val = period // denominator rd_off = int(offset_read // denominator) & 0xFFFF rst_off = int(offset_rst // denominator) & 0xFFFF rst_wid = int(width_rst // denominator) & 0xFFFF msb_off = int(offset_msb // denominator) & 0xFFFF msb_wid = int(width_msb // denominator) & 0xFFFF lsb_fc_wid2 = int(width_lsb_1st_2 // denominator) & 0xFFFF lsb_fc_off1 = int(offset_lsb_1st_1 // denominator) & 0xFFFF rd_wid = int(width_read // denominator) & 0xFFFF lsb_fc_wid1 = int(width_lsb_1st_1 // denominator) & 0xFFFF lsb_fc_off2 = int(offset_lsb_1st_2 // denominator) & 0xFFFF lsb_wid = int(width_lsb // denominator) & 0xFFFF lsb_off = int(offset_lsb // denominator) & 0xFFFF if inv_rst: inv += 1 << 0 if inv_read: inv += 1 << 1 if inv_msb: inv += 1 << 2 if inv_lsb: inv += 1 << 3 if inv_lsb_1st: inv += 1 << 4 def writeRegAndPrint(name, reg, val): #print("ExtClock Register {0:15} number {1:3} set to {2:10} = {2:#010x}".format(name,reg,val)) #print("ExtClock Register {0:15} number {1:3} set to {2:#034b}".format(name,reg,val)) self.femb.write_reg(reg, val) writeRegAndPrint("inv", self.REG_EXTCLK_INV, inv), for iChip, regBase in enumerate(self.REG_EXTCLK_BASES): iStr = str(iChip) asicRegs = [ ("RST_ADC" + iStr, (rst_wid << 16) | rst_off), ("READ_ADC" + iStr, (rd_wid << 16) | rd_off), ("IDXM_ADC" + iStr, (msb_wid << 16) | msb_off), # msb ("IDXL_ADC" + iStr, (lsb_wid << 16) | lsb_off), # lsb ("IDL1_ADC" + iStr, (lsb_fc_wid1 << 16) | lsb_fc_off1), # lsb_fc_1 ("IDL2_ADC" + iStr, (lsb_fc_wid2 << 16) | lsb_fc_off2), # lsb_fc_1 ] for iReg, tup in enumerate(asicRegs): name = tup[0] val = tup[1] writeRegAndPrint(name, regBase + iReg, val) def setExtClockRegs(self): #Coarse Control self.femb.write_reg(10, 0x03030103) #Invert/Disable all ADC Clocks #For ADC1 self.femb.write_reg(11, 0x00090001) #ADC1 - RST Offset and Width self.femb.write_reg(12, 0x0004005E) #ADC1 - READ Offset and Width self.femb.write_reg(13, 0x0035002C) #ADC1 - IDXM Offset and Width self.femb.write_reg(14, 0x0003005E) #ADC1 - IDXL Offset and Width self.femb.write_reg(15, 0x00250008) #ADC1 - IDL1 Offset and Width self.femb.write_reg(16, 0x0003005E) #ADC1 - IDL2 Offset and Width #For ADC2 self.femb.write_reg(20, 0x00090001) #ADC2 - RST Offset and Width self.femb.write_reg(21, 0x0003005F) #ADC2 - READ Offset and Width self.femb.write_reg(22, 0x0035002D) #ADC2 - IDXM Offset and Width self.femb.write_reg(23, 0x0003005F) #ADC2 - IDXL Offset and Width self.femb.write_reg(24, 0x00250008) #ADC2 - IDL1 Offset and Width self.femb.write_reg(25, 0x0003005E) #ADC2 - IDL2 Offset and Width #For ADC3 self.femb.write_reg(29, 0x00090001) #ADC2 - RST Offset and Width self.femb.write_reg(30, 0x0003005F) #ADC3 - READ Offset and Width self.femb.write_reg(31, 0x0035002D) #ADC3 - IDXM Offset and Width self.femb.write_reg(32, 0x0003005F) #ADC3 - IDXL Offset and Width self.femb.write_reg(33, 0x00250008) #ADC3 - IDL1 Offset and Width self.femb.write_reg(34, 0x0003005E) #ADC3 - IDL2 Offset and Width #Fine Control #For ADC1 self.femb.write_reg(17, 0x00060009) #ADC1 - READ and IDXM Phase Shift self.femb.write_reg(18, 0x0005000B) #ADC1 - IDXL and IDL1 Phase Shift self.femb.write_reg(19, 0x001F0003) #ADC1 - IDL2 Phase Shift and inversion self.femb.write_reg(19, 0x801F0003) #ADC1 - OK #For ADC2 self.femb.write_reg(26, 0x0010000E) #ADC2 - READ and IDXM Phase Shift self.femb.write_reg(27, 0x00030009) #ADC2 - IDXL and IDL1 Phase Shift self.femb.write_reg(28, 0x001C0002) #ADC2 - IDL2 Phase Shift and inversion self.femb.write_reg(28, 0x801C0002) #ADC2 - OK time.sleep(0.1) #For ADC3 self.femb.write_reg(35, 0x0010000E) #ADC3 - READ and IDXM Phase Shift self.femb.write_reg(36, 0x0005000D) #ADC3 - IDXL and IDL1 Phase Shift self.femb.write_reg(37, 0x00180004) #ADC3 - IDL2 Phase Shift and inversion self.femb.write_reg(37, 0x80180004) #ADC3 - OK def turnOffAsics(self): self.femb.write_reg_bits(self.REG_PWR_CTRL, 0, 0xF, 0x0) #pause after turning off ASICs time.sleep(2) def turnOnAsic(self, asic): if asic == None: return None asicVal = int(asic) if (asicVal < 0) or (asicVal >= self.NASICS): print( "femb_config_femb : turnOnAsics - invalid ASIC number, only 0 to {} allowed" .format(self.NASICS - 1)) return None #check if ASIC is already on in attempt to save time regVal = self.femb.read_reg(self.REG_PWR_CTRL) if regVal == None: return None isAsicOn = int(regVal) isAsicOn = ((isAsicOn >> asicVal) & 0x1) #print("isAsicOn ", hex(regVal), isAsicOn) if isAsicOn == 0x1: return print("Turning on ASIC ", asicVal) self.femb.write_reg_bits(self.REG_PWR_CTRL, asicVal, 0x1, 0x1) time.sleep(5) #pause after turn on def turnOnAsics(self): print("turnOnAsics 0-{}".format(int(self.NASICS - 1))) for iAsic in range(0, self.NASICS, 1): self.turnOnAsic(iAsic) def setFPGADac(self, amp, mode, freq, delay): """ mode: 0 DAC only, 1 ext tp, 2 gnd, 3 1.8V, 4 test pulse, 5 1.8V FE, 6 ASIC TP DAC """ ampRegVal = ((mode & 0xFFFF) << 16) | (amp & 0xFFFF) freqRegVal = ((delay & 0xFFFF) << 16) | (freq & 0xFFFF) self.femb.write_reg(self.REG_DAC2, freqRegVal) time.sleep(0.05) self.femb.write_reg(self.REG_DAC1, ampRegVal) time.sleep(0.05) self.femb.write_reg(self.REG_DAC1, ampRegVal & 0x80000000) time.sleep(0.05) self.femb.write_reg(self.REG_DAC1, ampRegVal) def writePLLs(self, step0, step1, step2): for iChip in range(0, 3, 1): self.writePLL(iChip, step0, step1, step2) def writePLL(self, asic, step0, step1, step2): if asic == None: return None asicVal = int(asic) if (asicVal < 0) or (asicVal >= self.NASICS): print( "femb_config_femb : writePLL - invalid ASIC number, only 0 to {} allowed" .format(self.NASICS - 1)) return regBase = self.REG_PLL_BASES[asicVal] self.femb.write_reg(regBase + 0, step0) self.femb.write_reg(regBase + 1, step1) self.femb.write_reg(regBase + 2, step2)
class FEMB_CONFIG: def __init__(self): self.NASICS = 4 #declare board specific registers self.REG_RESET = 0 self.REG_FEASIC_SPI = 5 self.REG_FESPI_BASE = 20 self.REG_FESPI_RDBACK_BASE = None self.REG_ADCSPI_RDBACK_BASE = None self.REG_HS = 17 self.REG_TEST_PULSE = 99 self.REG_TEST_PULSE_FREQ = 500 self.REG_TEST_PULSE_DLY = 80 self.REG_TEST_PULSE_AMPL = 0 % 32 self.REG_EN_CALI = 16 self.REG_RESET = 0 self.REG_DAC_VALUE = 1 self.REG_SET_DAC = 2 self.REG_START = 3 self.REG_SEL_ASIC = 4 self.REG_SEL_CH = 4 self.REG_ASIC_RESET = 5 self.REG_ASIC_SPIPROG = 5 self.REG_SAMPLE_STOP = 6 self.REG_TP_PERIOD_P = 7 self.REG_TP_PERIOD_N = 7 self.REG_TP_MODE = 9 self.REG_TST_SW = 12 self.REG_LED_CNTL = 13 self.REG_FESPI_BASE = 20 self.REG_FRAME_SIZE = 40 self.REG_DAC_ADC_EN = 60 self.REG_TST_SW = 12 self.plot = plot_functions() self.comm_settings = None #initialize FEMB UDP object self.femb = FEMB_UDP() self.fe_reg = FE_ASIC_REG_MAPPING() self.WIB_RESET = 1 self.BPS = 13 #Bytes per sample self.selected_chip = None self.selected_chn = None def resetFEMBBoard(self): print("FEMB_CONFIG--> Reset FEMB (4 seconds)") sys.stdout.flush() #Reset FEMB system self.femb.write_reg(self.REG_RESET, 1) time.sleep(4) print("FEMB_CONFIG--> Reset FEMB is DONE") def initBoard(self): print("FEMB_CONFIG--> Initialize FEMB") #set up default registers #Tells the FPGA to turn on the ASICs self.femb.write_reg(12, 0x0) #self.turnOnAsics() #added #Tells the FPGA to turn off each DAC self.femb.write_reg(61, 0xF) #Set to Regular Mode (as opposed to Sampling Scope mode) and pick a chip/channel output self.femb.write_reg(10, 0) self.select_chip_chn(chip=2, chn=7) #Select TP FE Mode self.femb.write_reg(9, 8) #Give a default DAC value self.femb.write_reg(1, settings.default_DAC) self.femb.write_reg(2, 1) self.femb.write_reg(2, 0) #Give a default pulse timing self.femb.write_reg(7, (settings.default_TP_Shift << 16) + settings.default_TP_Period) #Write the default ADC settings i = 0 for reg in range(65, 69, 1): self.femb.write_reg(reg, settings.Latch_Settings[i]) i = i + 1 i = 0 for reg in range(69, 73, 1): self.femb.write_reg(reg, settings.Phase_Settings[i]) i = i + 1 self.femb.write_reg(73, settings.test_ADC_Settings) self.femb.write_reg(74, settings.pre_buffer) #Write the frame size as a multiple of 16 frame_size = settings.frame_size if (frame_size % 16 != 0): frame_size = 16 * (frame_size // 16) #Write the defaul ASIC settings self.fe_reg.set_fe_board(sts=1, snc=1, sg=1, st=1, smn=0, sbf=1, slk=0, stb=0, s16=0, slkh=0, sdc=0, sdacsw2=1, sdacsw1=0, sdac=settings.sync_peak_height) print("FEMB_CONFIG --> FE ASIC SPI") self.configFeAsic() print("FEMB_CONFIG--> Initialize FEMB is DONE") def turnOffAsics(self): self.femb.write_reg(self.REG_TST_SW, 0xF) #pause after turning off ASICs time.sleep(2) def turnOnAsic(self, asic): asicVal = int(asic) if (asicVal < 0) or (asicVal >= self.NASICS): print( "femb_config_femb : turnOnAsics - invalid ASIC number, only 0 to {} allowed" .format(self.NASICS - 1)) return print("turnOnAsic " + str(asicVal)) #self.femb.write_reg( self.REG_TST_SW, 0xF) #turn off all self.femb.write_reg_bits(self.REG_TST_SW, asicVal, 0x1, 0x0) time.sleep(2) #pause after turn on #start ASICs self.femb.write_reg(self.REG_START, 1) self.configFeAsic() def turnOnAsics(self): #print( "Turn On Asics" ) #self.femb.write_reg( self.REG_TST_SW, 0x0) #time.sleep(1) #pause after turn on #start ASICs #self.femb.write_reg( self.REG_START, 1) #self.configFeAsic() self.turnOnAsic(0) self.turnOnAsic(1) self.turnOnAsic(2) self.turnOnAsic(3) #pause after turning on ASICs time.sleep(2) def configFeAsic(self, to_print=False): #Grab ASIC settings from linked class Feasic_regs = self.fe_reg.REGS #Choose to output status updates or not if (to_print == True): print("FEMB_CONFIG--> Config FE ASIC SPI") #Try 10 times (ocassionally it wont work the first time) for k in range(10): i = 0 for regNum in range(self.REG_FESPI_BASE, self.REG_FESPI_BASE + len(Feasic_regs), 1): self.femb.write_reg(regNum, Feasic_regs[i]) # print (hex(Feasic_regs[i])) i = i + 1 #Write ADC ASIC SPI if (to_print == True): print("FEMB_CONFIG--> Program FE ASIC SPI") #Reset, then write twice self.femb.write_reg(self.REG_FEASIC_SPI, 2) self.femb.write_reg(self.REG_FEASIC_SPI, 0) time.sleep(.2) self.femb.write_reg(self.REG_FEASIC_SPI, 1) self.femb.write_reg(self.REG_FEASIC_SPI, 0) time.sleep(.2) self.femb.write_reg(self.REG_FEASIC_SPI, 1) self.femb.write_reg(self.REG_FEASIC_SPI, 0) time.sleep(.2) if (to_print == True): print("FEMB_CONFIG--> Check FE ASIC SPI") #The FPGA automatically compares the readback to check if it matches what was written. That result is read back #A bit that's zero means the corresponding ASIC didn't write properly val = self.femb.read_reg(self.REG_FEASIC_SPI) wrong = False if (((val & 0x10000) >> 16) != 1 and (0 in settings.chips_to_use)): print( "FEMB_CONFIG--> Something went wrong when programming FE 1" ) wrong = True if (((val & 0x20000) >> 17) != 1 and (1 in settings.chips_to_use)): print( "FEMB_CONFIG--> Something went wrong when programming FE 2" ) wrong = True if (((val & 0x40000) >> 18) != 1 and (2 in settings.chips_to_use)): print( "FEMB_CONFIG--> Something went wrong when programming FE 3" ) wrong = True if (((val & 0x80000) >> 19) != 1 and (3 in settings.chips_to_use)): print( "FEMB_CONFIG--> Something went wrong when programming FE 4" ) wrong = True if (wrong == True and k == 9): print("FEMB_CONFIG--> SPI_Status is {}").format(hex(val)) #sys.exit("FEMB_CONFIG--> femb_config_femb : Wrong readback. FE SPI failed") return elif (wrong == False): self.fe_reg.info.fe_regs_sent = Feasic_regs if (to_print == True): print("FEMB_CONFIG--> FE ASIC SPI is OK") break #ASSUMES ASICS HAVE BEEN SET FOR THE INTERNAL PULSER def syncADC(self, chips): print("FEMB_CONFIG--> Start sync ADC") #Don't ask me why, but you need to set the channel at this point for it to output the right data self.select_chip_chn(chip=0, chn=1) for chip in chips: #Tells the FPGA to turn on each DAC self.femb.write_reg(61, 0x0) #Read from DATA output ADCs self.femb.write_reg(60, 0) #Set to Regular Mode (not sampling scope mode) self.femb.write_reg(10, 0) #Select the internal DAC readout self.femb.write_reg(9, 3) #Get the ASIC to send out pulses. Bit 6 needs to be high for ASIC DAC self.reg_17_value = (settings.default_TP_Period << 16) + ( settings.default_TP_Shift << 8) + (0b01000000) self.femb.write_reg(17, self.reg_17_value) print("FEMB_CONFIG--> Test ADC {}".format(chip)) for chn in range(settings.channels): #Tests if it's synchronized, returns True if it is unsync = self.testUnsync(chip=chip, chn=chn) if unsync != True: print( "FEMB_CONFIG--> Chip {}, Chn {} not synced, try to fix" .format(chip, chn)) response = self.fixUnsync_outputADC(chip=chip, chn=chn) if (response != True): print( "FEMB_CONFIG--> Something is wrong with Chip {}, Chn {}" .format(chip, chn)) # sys.exit ("FEMB_CONFIG--> ADC {} could not sync".format(chip)) print("FEMB_CONFIG--> ADC {} synced!".format(chip)) print("FEMB_CONFIG--> Trying to sync test ADC".format(chip)) #Have one of the channels output its pulse to the test monitor pin self.fe_reg.set_fe_chn(chip=chip, chn=0, smn=1) self.configFeAsic() #Read from TEST output ADCs self.femb.write_reg(60, 1) #Select the monitor readout self.femb.write_reg(9, 3) unsync = self.testUnsync(chip=chip, chn=chn) if unsync != True: print( "FEMB_CONFIG--> Chip {} (test ADC) not synced, try to fix". format(chip)) response = self.fixUnsync_testADC(chip=chip) if (response != True): print( "FEMB_CONFIG--> Something is wrong with Chip {} (test ADC)" .format(chip)) else: print("FEMB_CONFIG--> Chip {} (test ADC) synced!".format(chip)) self.comm_settings = [] print("FEMB_CONFIG--> Final Shift Settings: ") for reg in range(65, 69, 1): value = self.femb.read_reg(reg) print("Register {}: {}".format(reg, hex(value))) self.comm_settings.append(value) print("FEMB_CONFIG--> Final Phase Settings: ") for reg in range(69, 73, 1): value = self.femb.read_reg(reg) print("Register {}: {}".format(reg, hex(value))) self.comm_settings.append(value) value = self.femb.read_reg(73) print("Register {}: {}".format(73, hex(value))) self.comm_settings.append(value) self.femb.write_reg(17, 0) print("FEMB_CONFIG--> ADC passed Sync Test!") def testUnsync(self, chip, chn): #Get some packets of data self.select_chip_chn(chip=chip, chn=chn) data = self.get_data_chipXchnX(chip=chip, chn=chn, packets=25, data_format="counts") #Find some peaks peaks_index = detect_peaks(x=data, mph=settings.sync_peak_min, mpd=100) #Make sure you have more than 0 peaks (so it's not flat) and less than the maximum #(if there's no peak, the baseline will give hundreds of peaks) #If it's bad, print it, so we see (must enable inline printing for iPython) if (len(peaks_index) == 0) or (len(peaks_index) > settings.sync_peaks_max): print("Chip {}, Channel {} has {} peaks!".format( chip, chn, len(peaks_index))) # print (peaks_index) figure_data = self.plot.quickPlot(data) ax = figure_data[0] for j in peaks_index: y_value = data[j] ax.scatter(j / 2, y_value, marker='x') ax.set_ylabel('mV') ax.set_title("Error") ax.title.set_fontsize(30) for item in ([ax.xaxis.label, ax.yaxis.label] + ax.get_xticklabels() + ax.get_yticklabels()): item.set_fontsize(20) plt.show() plt.close() return False #So that function before only gives you the X locations of where the peaks are. Let's get the Y values from that peaks_value = [] for i in peaks_index: peaks_value.append(data[i]) # print ("Chip {}, Channel {} has peak values {}".format(chip, chn, peaks_value)) #Check if the peak is at the wrong height (happens when it's not synced, the peak will be havled or doubled) for peak in peaks_value: if ((peak < settings.sync_peak_min) or (peak > settings.sync_peak_max)): print("FEMB CONFIG--> Chip {}, Chn {} has a peak that's {}". format(chip, chn, peak)) figure_data = self.plot.quickPlot(data) ax = figure_data[0] for j in peaks_index: y_value = data[j] ax.scatter(j / 2, y_value, marker='x') ax.set_ylabel('mV') ax.set_title("Error") ax.title.set_fontsize(30) for item in ([ax.xaxis.label, ax.yaxis.label] + ax.get_xticklabels() + ax.get_yticklabels()): item.set_fontsize(20) plt.show() plt.close() return False #Check if the baseline is right (this also gets halved and doubled with unsynced ADCs) (avoid the peak to grab a middle section) try: baseline_area_start = peaks_index[0] + 200 baseline_area_end = peaks_index[1] - 200 except IndexError: baseline_area_start = 100 baseline_area_end = 500 baseline_data = data[baseline_area_start:baseline_area_end] baseline = np.mean(baseline_data) if ((baseline < settings.sync_baseline_min) or (baseline > settings.sync_baseline_max)): print("FEMB CONFIG--> Chip {}, Chn {} has a baseline that's {}". format(chip, chn, baseline)) figure_data = self.plot.quickPlot(data) ax = figure_data[0] for j in peaks_index: y_value = data[j] ax.scatter(j / 2, y_value, marker='x') ax.set_ylabel('mV') ax.set_title("Error") ax.title.set_fontsize(30) for item in ([ax.xaxis.label, ax.yaxis.label] + ax.get_xticklabels() + ax.get_yticklabels()): item.set_fontsize(20) plt.show() plt.close() return False return True #Shifts through all possible delay and phase options, checking to see if each one fixed the issue def fixUnsync_outputADC(self, chip, chn): self.select_chip_chn(chip=chip, chn=chn) shift_reg = chip + 65 phase_reg = chip + 69 #Get the initial setting you don't disturb the other channels init_shift = self.femb.read_reg(shift_reg) init_phase = self.femb.read_reg(phase_reg) #Because Python can't have a friggin NAND or XOR function that works right at the bitwise level, this is how we get the bitmask #This will find the 2 bits in the register that correspond to the channel you want to change. Say it's channel 2 #In binary, it makes 0b00000000000000000000000000110000 #Then inverts it to 0b11111111111111111111111111001111 #Now you AND that with the initial result to get the initial values WITHOUT the channel you want to change #Now you can bitshift your desired setting to that empty space with zeroes, like say you wanted to write a 0b10, #It would be 0b100000. Then add that to whatever the result of the initial values AND mask was. Boom, you've done it. init_mask = (0x3 << (2 * chn)) neg_mask = 0 for i in range(32): FF_bit = (0xFFFFFFFF >> i) & 0x1 test_bit = (init_mask >> i) & 0x1 if (FF_bit != test_bit): result_bit = 1 else: result_bit = 0 neg_mask = neg_mask + (result_bit << i) #There are 16 possible sync permutations for every ADC for shift in range(4): for phase in range(4): shift_setting = shift << (2 * chn) init_shift_with_mask = init_shift & neg_mask final_shift = shift_setting + init_shift_with_mask # print ("Shift is {}".format(shift)) # print ("phase is {}".format(phase)) # print ("Negative mask is {}".format(bin(neg_mask))) # print ("Initial reading is {}".format(bin(init_shift))) # print ("The new setting is {}".format(bin(shift_setting))) # print ("Making space for the new setting is {}".format(bin(init_shift_with_mask))) # print ("Adding together is {}".format(bin(final_shift))) self.femb.write_reg(shift_reg, final_shift) phase_setting = phase << (2 * chn) init_phase_with_mask = init_phase & neg_mask final_phase = phase_setting + init_phase_with_mask self.femb.write_reg(phase_reg, final_phase) #See if this new setting fixed it unsync = self.testUnsync(chip=chip, chn=chn) if unsync == True: print("FEMB_CONFIG--> Chip {}, Chn {} fixed!".format( chip, chn)) return True print("FEMB_CONFIG--> ADC SYNC process failed for Chip {}, Channel {}". format(chip, chn)) self.femb.write_reg(shift_reg, init_shift) self.femb.write_reg(phase_reg, init_phase) return False #Same thing as above, except the timing register is different, so the bitmath has to be changed. def fixUnsync_testADC(self, chip): self.select_chip_chn(chip=chip, chn=2) init_mask = (0xF << (2 * chip)) neg_mask = 0 for i in range(32): FF_bit = (0xFFFFFFFF >> i) & 0x1 test_bit = (init_mask >> i) & 0x1 if (FF_bit != test_bit): result_bit = 1 else: result_bit = 0 neg_mask = neg_mask + (result_bit << i) init_shift = self.femb.read_reg(73) print("Init shift is {}".format(hex(init_shift))) print("Init mask is {}".format(bin(init_mask))) print("Negative mask is {}".format(bin(neg_mask))) for shift in range(4): for phase in range(4): setting = (phase << 2) + shift print("Setting is {}".format(bin(setting))) final_setting = setting << (chip * 4) print("Final Setting is {}".format(bin(setting))) init_shift_with_mask = init_shift & neg_mask print("Initshift with mask is {}".format( hex(init_shift_with_mask))) really_final = init_shift_with_mask + final_setting print("Final setting to write is {}".format(bin(really_final))) # init_shift_with_mask = init_shift & neg_mask # final_shift = shift_setting + init_shift_with_mask # print ("Shift is {}".format(shift)) # print ("phase is {}".format(phase)) # print ("Negative mask is {}".format(bin(neg_mask))) # print ("Initial reading is {}".format(bin(init_shift))) # print ("The new setting is {}".format(bin(shift_setting))) # print ("Making space for the new setting is {}".format(bin(init_shift_with_mask))) # print ("Adding together is {}".format(bin(final_shift))) unsync = self.testUnsync(chip=chip, chn=1) if unsync == True: print( "FEMB_CONFIG--> Chip {} test ADC fixed!".format(chip)) return True print("FEMB_CONFIG--> ADC SYNC process failed for Chip {} ADC".format( chip)) return False #Select the chip and channel and read it out. And check that it was actually set. It's weirdly a problem def select_chip_chn(self, chip, chn): if (chip < 0) or (chip > settings.chip_num): print( "FEMB CONFIG -> Error in get_data_chipXchnX: Chip must be between 0 and {}" .format(settings.chip_num)) return if (chn < 0) or (chn > 15): print( "FEMB CONFIG -> Error in get_data_chipXchnX: Channel must be between 0 and 15" ) return chip_int = int(chip + 1) chn_int = int(chn) reg4_value = chn_int + (chip_int << 8) for i in range(10): self.femb.write_reg(4, reg4_value) time.sleep(0.1) reg4_read = self.femb.read_reg(4) try: if ((reg4_read & 0xF) != chn) or (( (reg4_read >> 8) & 0xF) != chip + 1): if (i == 9): sys.exit( "FEMB CONFIG--> Register response was {}, should have been {}, trying again..." .format(hex(reg4_read), hex(reg4_value))) else: print( "FEMB CONFIG--> Register response was {}, should have been {}, trying again..." .format(hex(reg4_read), hex(reg4_value))) else: self.selected_chip = chip self.selected_chn = chn break except TypeError: print("FEMB CONFIG--> No readback value, trying again...") #Get data in a variety of ways. You can even pre-convert it to mV! def get_data_chipXchnX(self, chip, chn, packets=1, data_format="counts"): if (chn < -1) or (chn > 15): print( "FEMB CONFIG -> Error in get_data_chipXchnX: Channel must be between 0 and 15, or -1 for all channels" ) return if (chip < 0) or (chip > settings.chip_num): print( "FEMB CONFIG -> Error in get_data_chipXchnX: Chip must be between 0 and {}, but it's {}" .format(settings.chip_num, chip)) return if (self.selected_chip != chip) or (self.selected_chn != chn): self.select_chip_chn(chip=chip, chn=chn) if (data_format == "bin"): data = self.femb.get_data_packets(data_type="bin", num=packets, header=True) data = self.femb.get_data_packets(data_type="int", num=packets, header=False) if (data_format == "mV"): for i in range(len(data)): data[i] = data[i] * (0.0018 / 16384) elif (data_format == "V"): for i in range(len(data)): data[i] = data[i] * (1.8 / 16384) return data #Get a whole chip's worth of data def get_data_chipX(self, chip, packets=1, data_format="counts"): chip_data = [ chip, [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [] ] for chn in range(16): for i in range(packets): chip_data[chn + 1].extend( list( self.get_data_chipXchnX(chip, chn, packets=1, data_format=data_format)[1:])) return chip_data #Placeholder for the full chip readout def get_data_chipXchnX_SS(self, chip, chn, packets=1): if (chn < -1) or (chn > 15): print( "FEMB CONFIG -> Error in get_data_chipXchnX: Channel must be between 0 and 15, or -1 for all channels" ) return if (chip < 0) or (chip > settings.chip_num): print( "FEMB CONFIG -> Error in get_data_chipXchnX: Chip must be between 0 and {}, but it's {}" .format(settings.chip_num, chip)) return if (self.selected_chip != chip) or (self.selected_chn != chn): self.select_chip(chip=chip, chn=chn) k = 0 for i in range(10): data = self.femb.get_data_packets(data_type="int", num=packets, header=False) try: if (k > 0): print("FEMB CONFIG --> Now doing another test") print(hex(data[0])) print(data[0] == 0xFACE) print(data[0] != 0xFACE) if (data[0] != 0xFACE): #If FACE isn't the first 2 bytes, do the equivalent of turning WIB mode off and then on and try again self.femb.write_reg(3, chip + 1) self.select_chip(chip) if (k > 8): print( "FEMB CONFIG --> Error in get_data_chipXchnX: Packet format error" ) print(hex(data[0])) print(data) return None else: print( "FEMB CONFIG --> Error in get_data_chipXchnX: Packet format error, trying again..." ) print("k = {}".format(k)) print(data[0:13]) print(hex(data[0])) print(data[0] == 0xFACE) k += 1 else: break except IndexError: print( "FEMB CONFIG --> Something was wrong with the incoming data" ) print(data) test_length = len(data) # if ((test_length % self.BPS) != 0): # print ("FEMB CONFIG -> Error in get_data_chipXchnX: Irregular packet size") # print (data) # return None full_samples = test_length // self.BPS chn_data = [] for i in range(full_samples): if (chn == 7): chn_data.append(data[(self.BPS * i) + 1] & 0x0FFF) if (chn == 6): chn_data.append(((data[(self.BPS * i) + 2] & 0x00FF) << 4) + ((data[(self.BPS * i) + 1] & 0xF000) >> 12)) if (chn == 5): chn_data.append(((data[(self.BPS * i) + 3] & 0x000F) << 8) + ((data[(self.BPS * i) + 2] & 0xFF00) >> 8)) if (chn == 4): chn_data.append(((data[(self.BPS * i) + 3] & 0xFFF0) >> 4)) if (chn == 3): chn_data.append(data[(self.BPS * i) + 4] & 0x0FFF) if (chn == 2): chn_data.append(((data[(self.BPS * i) + 5] & 0x00FF) << 4) + ((data[(self.BPS * i) + 4] & 0xF000) >> 12)) if (chn == 1): chn_data.append(((data[(self.BPS * i) + 6] & 0x000F) << 8) + ((data[(self.BPS * i) + 5] & 0xFF00) >> 8)) if (chn == 0): chn_data.append(((data[(self.BPS * i) + 6] & 0xFFF0) >> 4)) if (chn == 15): chn_data.append(data[(self.BPS * i) + 7] & 0x0FFF) if (chn == 14): chn_data.append(((data[(self.BPS * i) + 8] & 0x00FF) << 4) + ((data[(self.BPS * i) + 7] & 0xF000) >> 12)) if (chn == 13): chn_data.append(((data[(self.BPS * i) + 9] & 0x000F) << 8) + ((data[(self.BPS * i) + 8] & 0xFF00) >> 8)) if (chn == 12): chn_data.append(((data[(self.BPS * i) + 9] & 0xFFF0) >> 4)) if (chn == 11): chn_data.append(data[(self.BPS * i) + 10] & 0x0FFF) if (chn == 10): chn_data.append(((data[(self.BPS * i) + 11] & 0x00FF) << 4) + ((data[(self.BPS * i) + 10] & 0xF000) >> 12)) if (chn == 9): chn_data.append(((data[(self.BPS * i) + 12] & 0x000F) << 8) + ((data[(self.BPS * i) + 11] & 0xFF00) >> 8)) if (chn == 8): chn_data.append(((data[(self.BPS * i) + 12] & 0xFFF0) >> 4)) if (chn == -1): return (data) return chn_data
class FEMB_CONFIG(FEMB_CONFIG_BASE): #__INIT__# def __init__(self): #declare basic system parameters self.NFEMBS = 4 self.NASICS = 8 self.NASICCH = 16 #declare board specific registers self.FEMB_VER = "WIB_PROTODUNE" self.REG_RESET = 0 self.REG_ASIC_RESET = 1 self.REG_ASIC_SPIPROG = 2 self.REG_SOFT_ADC_RESET = 1 self.REG_LATCHLOC_3_TO_0 = 4 self.REG_LATCHLOC_7_TO_4 = 14 self.REG_FPGA_TP_EN = 16 self.REG_ASIC_TP_EN = 16 self.REG_DAC_SELECT = 16 self.REG_TP = 5 self.CLK_SELECT = 6 self.CLK_SELECT2 = 15 self.REG_SEL_ASIC = 7 self.REG_SEL_ASIC_LSB = 8 self.REG_WIB_MODE = 8 self.REG_ADC_DISABLE = 8 self.REG_HS_DATA = 9 self.REG_HS = 17 self.INT_TP_EN = 18 self.EXT_TP_EN = 18 self.REG_SPI_BASE = 0x200 self.REG_SPI_RDBACK_BASE = 0x250 #internal variables self.fembNum = 0 self.useExtAdcClock = True self.isRoomTemp = False self.maxSyncAttempts = 100 self.doReSync = True self.spiStatus = 0x0 self.syncStatus = 0x0 self.CLKSELECT_val_RT = 0xFF self.CLKSELECT2_val_RT = 0xFF self.CLKSELECT_val_CT = 0xEF self.CLKSELECT2_val_CT = 0xEF self.REG_LATCHLOC_3_TO_0_val = 0x04040404 self.REG_LATCHLOC_7_TO_4_val = 0x04040404 #initialize FEMB UDP object self.femb = FEMB_UDP() self.femb.UDP_IP = "192.168.121.1" self.femb.UDP_PORT_WREG = 32000 #WIB PORTS self.femb.UDP_PORT_RREG = 32001 self.femb.UDP_PORT_RREGRESP = 32002 self.femb.doReadBack = True #WIB register interface is unreliable #ASIC config variables self.feasicLeakage = 0 #0 = 500pA, 1 = 100pA self.feasicLeakagex10 = 0 #0 = pA, 1 = pA*10 self.feasicAcdc = 0 #AC = 0, DC = 1 self.feasicEnableTestInput = 0 #0 = disabled, 1 = enabled self.feasicBaseline = 0 #0 = 200mV, 1 = 900mV self.feasicGain = 2 #4.7,7.8,14,25 self.feasicShape = 1 #0.5,1,2,3 self.feasicBuf = 0 #0 = OFF, 1 = ON def printParameters(self): print("FEMB # \t", self.fembNum) print("External ADC Clocks\t", self.useExtAdcClock) print("Room temperature \t", self.isRoomTemp) print("MAX SYNC ATTEMPTS \t", self.maxSyncAttempts) print("Do resync \t", self.doReSync) print("CLKSELECT RT \t", str(hex(self.CLKSELECT_val_RT))) print("CLKSELECT2 RT \t", str(hex(self.CLKSELECT2_val_RT))) print("CLKSELECT CT \t", str(hex(self.CLKSELECT_val_CT))) print("CLKSELECT2 CT \t", str(hex(self.CLKSELECT2_val_CT))) print("LATCHLOC_3_TO_0 \t", str(hex(self.REG_LATCHLOC_3_TO_0_val))) print("LATCHLOC_7_TO_4 \t", str(hex(self.REG_LATCHLOC_7_TO_4_val))) print("FE-ASIC leakage \t", self.feasicLeakage) print("FE-ASIC leakage x10\t", self.feasicLeakagex10) print("FE-ASIC AD/DC \t", self.feasicAcdc) print("FE-ASIC test input \t", self.feasicEnableTestInput) print("FE-ASIC baseline \t", self.feasicBaseline) print("FE-ASIC gain \t", self.feasicGain) print("FE-ASIC shape \t", self.feasicShape) print("FE-ASIC buffer \t", self.feasicBuf) print("FE-ASIC config") for regNum in range(self.REG_SPI_BASE, self.REG_SPI_BASE + 72, 1): regVal = self.femb.read_reg(regNum) if regVal == None: continue print(str(regNum) + "\t" + str(hex(regVal))) def resetBoard(self): print("Reset") def initBoard(self): self.initWib() for femb in range(0, 4, 1): self.selectFemb(femb) self.initFemb() def initWib(self): #WIB initialization #set UDP ports to WIB registers self.femb.UDP_PORT_WREG = 32000 self.femb.UDP_PORT_RREG = 32001 self.femb.UDP_PORT_RREGRESP = 32002 self.femb.REG_SLEEP = 0.001 #register 2, LED self.femb.write_reg_bits(2, 0, 0xFF, 0) #set jumbo size self.femb.write_reg(0x1F, 0xEFB) #clock select (firmware version dependent) #self.femb.write_reg_bits(4 , 2, 0x3, 2 ) #initialize clock #self.initSI5338() #set external clock self.femb.write_reg(0x4, 8) self.femb.write_reg(16, 0x7F00) self.femb.write_reg(15, 0) #sync timestamp /WIB self.femb.write_reg(1, 0) self.femb.write_reg(1, 0) self.femb.write_reg(1, 2) self.femb.write_reg(1, 2) self.femb.write_reg(1, 0) self.femb.write_reg(1, 0) #Reset error /WIB self.femb.write_reg(18, 0x8000) self.femb.write_reg(18, 0x8000) #return register interface to FEMB self.selectFemb(self.fembNum) def initFemb(self): if (self.fembNum < 0) or (self.fembNum >= self.NFEMBS): return #FEMB power enable on WIB self.powerOnFemb(self.fembNum) time.sleep(4) #Make sure register interface is for correct FEMB self.selectFemb(self.fembNum) #check if FEMB register interface is working print("Checking register interface") regVal = self.femb.read_reg(6) if (regVal == None) or (regVal == -1): print("Error - FEMB register interface is not working.") print(" Will not initialize FEMB.") return checkFirmware = self.checkFirmwareVersion() if checkFirmware == False: print( "Error - invalid firmware, will not attempt to initialize board" ) return #turn off pulser self.femb.write_reg_bits(self.REG_FPGA_TP_EN, 0, 0x1, 0) #test pulse enable self.femb.write_reg_bits(self.REG_ASIC_TP_EN, 1, 0x1, 0) #test pulse enable self.femb.write_reg_bits(self.REG_DAC_SELECT, 8, 0x1, 0) #test pulse enable self.femb.write_reg_bits(self.REG_TP, 0, 0x1F, 0x00) #test pulse amplitude self.femb.write_reg_bits(self.REG_TP, 16, 0xFFFF, 0x100) #test pulse frequency self.femb.write_reg_bits(self.REG_TP, 8, 0xFF, 0x00) #test pulse delay #phase control if self.isRoomTemp == True: print("ADC clock phase:", self.CLKSELECT_val_RT, self.CLKSELECT2_val_RT) self.femb.write_reg_bits(self.CLK_SELECT, 0, 0xFF, self.CLKSELECT_val_RT) #clock select self.femb.write_reg_bits(self.CLK_SELECT2, 0, 0xFF, self.CLKSELECT2_val_RT) #clock select 2 else: print("Using cryogenic parameters, ADC clock phase:", self.CLKSELECT_val_CT, self.CLKSELECT2_val_CT) self.femb.write_reg_bits(self.CLK_SELECT, 0, 0xFF, self.CLKSELECT_val_CT) #clock select self.femb.write_reg_bits(self.CLK_SELECT2, 0, 0xFF, self.CLKSELECT2_val_CT) #clock select 2 self.femb.write_reg_bits(self.REG_LATCHLOC_3_TO_0, 0, 0xFFFFFFFF, self.REG_LATCHLOC_3_TO_0_val) #datashift self.femb.write_reg_bits(self.REG_LATCHLOC_7_TO_4, 0, 0xFFFFFFFF, self.REG_LATCHLOC_7_TO_4_val) #datashift #enable streaming self.femb.write_reg_bits(self.REG_HS_DATA, 0, 0x1, 1) #Enable streaming self.femb.write_reg_bits(self.REG_HS_DATA, 3, 0x1, 1) #Enable ADC data #EXTERNAL CLOCK STUFF self.ext_clk_config_femb() #Set FE ASIC SPI configuration registers self.configFeAsic() #check ASIC SPI self.checkFembSpi() print("SPI STATUS", "\t", self.spiStatus) #check ADC SYNC self.checkSync() print("SYNC STATUS", "\t", self.syncStatus) #Test FEMB SPI working def checkFembSpi(self): print("Check ASIC SPI") self.spiStatus = 0 for regNum in range(0, 72, 1): progVal = self.femb.read_reg(self.REG_SPI_BASE + regNum) if progVal == None: print("Error - FEMB register interface is not working.") return rdbckVal = self.femb.read_reg(self.REG_SPI_RDBACK_BASE + regNum) if rdbckVal == None: print("Error - FEMB register interface is not working.") return print(hex(progVal), "\t", hex(rdbckVal)) if progVal != rdbckVal: print("SPI readback failed.") self.spiStatus = 1 return def checkSync(self): print("Check ASIC SYNC") regVal = self.femb.read_reg(6) if regVal == None: print("doAsicConfigcheckFembSpi: Could not check SYNC status, bad") return syncVal = 0 syncVal = ((regVal >> 16) & 0xFFFF) self.syncStatus = syncVal #FEMB power enable on WIB def powerOnFemb(self, femb): fembVal = int(femb) if (fembVal < 0) or (fembVal > 3): return #set UDP ports to WIB registers self.femb.UDP_PORT_WREG = 32000 self.femb.UDP_PORT_RREG = 32001 self.femb.UDP_PORT_RREGRESP = 32002 regBase = int(fembVal * 4) #always enable extra DC converter self.femb.write_reg(8, 0x100000) #FEMB power enable self.femb.write_reg_bits(8, regBase + 0, 0x1, 1) #3.6V self.femb.write_reg_bits(8, regBase + 1, 0x1, 1) #2.8V self.femb.write_reg_bits(8, regBase + 2, 0x1, 1) #2.5V self.femb.write_reg_bits(8, regBase + 3, 0x1, 1) #1.5V self.femb.write_reg_bits(8, 16 + fembVal, 0x1, 1) #BIAS enable regVal = self.femb.read_reg(8) if regVal == None: return print("FEMB Power on: ", hex(regVal)) #set UDP ports back to normal self.selectFemb(self.fembNum) def powerOffFemb(self, femb): fembVal = int(femb) if (fembVal < 0) or (fembVal > 3): return #set UDP ports to WIB registers self.femb.UDP_PORT_WREG = 32000 self.femb.UDP_PORT_RREG = 32001 self.femb.UDP_PORT_RREGRESP = 32002 regBase = int(fembVal * 4) #FEMB power disable self.femb.write_reg_bits(8, 16 + fembVal, 0x1, 0) #BIAS self.femb.write_reg_bits(8, regBase + 0, 0x1, 0) #3.6V self.femb.write_reg_bits(8, regBase + 1, 0x1, 0) #2.8V self.femb.write_reg_bits(8, regBase + 2, 0x1, 0) #2.5V self.femb.write_reg_bits(8, regBase + 3, 0x1, 0) #1.5V regVal = self.femb.read_reg(8) if regVal == None: return print("FEMB Power off: ", hex(regVal)) #set UDP ports back to normal self.selectFemb(self.fembNum) def selectChannel(self, asic, chan): #print("Select channel") asicVal = int(asic) if (asicVal < 0) or (asicVal > self.NASICS): return #set UDP ports to WIB self.femb.UDP_PORT_WREG = 32000 self.femb.UDP_PORT_RREG = 32001 self.femb.UDP_PORT_RREGRESP = 32002 #select ASIC #print("Selecting ASIC " + str(asicVal) ) self.femb.write_reg_bits(self.REG_SEL_ASIC, self.REG_SEL_ASIC_LSB, 0xF, asicVal) #Note: WIB data format streams all 16 channels, don't need to select specific channel #set UDP ports back to normal self.selectFemb(self.fembNum) def configFeAsic(self): print("CONFIG ASICs") #global config varibles feasicLeakageVal = int(self.feasicLeakage) #0 = 500pA, 1 = 100pA feasicLeakagex10Val = int(self.feasicLeakagex10) #0 = x1, 1 = x10 acdcVal = int(self.feasicAcdc) #DC = 0, AC = 1 #channel specific variables testVal = int(self.feasicEnableTestInput) baseVal = int(self.feasicBaseline) #0 = 900mV, 1 = 200mV gainVal = int(self.feasicGain) shapeVal = int(self.feasicShape) bufVal = int(self.feasicBuf) #0 = OFF, 1 = ON if (testVal < 0) or (testVal > 1): return if (baseVal < 0) or (baseVal > 1): return if (gainVal < 0) or (gainVal > 3): return if (shapeVal < 0) or (shapeVal > 3): return if (acdcVal < 0) or (acdcVal > 1): return if (bufVal < 0) or (bufVal > 1): return if (feasicLeakageVal < 0) or (feasicLeakageVal > 1): return if (feasicLeakagex10Val < 0) or (feasicLeakagex10Val > 1): return chReg = 0 #test capacitor, bit 7 chReg = chReg + ((testVal & 0x01) << 7) #baseline control, bit 6 baseVal = 1 - baseVal #assign 0 = 200mV, 1 = 900mV chReg = chReg + ((baseVal & 0x01) << 6) #gain control, bits 4-5 gainArray = [0, 2, 1, 3] chReg = chReg + ((gainArray[gainVal] & 0x03) << 4) #shape control, bits 2-3 shapeArray = [2, 0, 3, 1] #I don't know why chReg = chReg + ((shapeArray[shapeVal] & 0x03) << 2) #buffer control, bit 0 chReg = chReg + ((bufVal & 0x01) << 0) #construct the channel word chWord = (chReg << 24) + (chReg << 16) + (chReg << 8) + chReg asicReg = int(0) #asicReg = int(0x0A00) #leakage control 1, bit 0 asicReg = asicReg + ((feasicLeakageVal & 0x01) << 0) #leakage control 2, bit 4 asicReg = asicReg + ((feasicLeakagex10Val & 0x01) << 4) #AC/DC control #monitor control, bits 1-2 #internal DAC enable, bit 8 #external DAC enable, bit 9 #DAC OUTPUT bits 8-9 , 0xA00 = external DAC #ADC ASIC config adc_globalReg = 0x0000 #FRQC=1, all other general register bits are 0 if self.useExtAdcClock == True: adc_globalReg = 0x8000 #CLK0=1,CLK1=0,FRQC=0,F0=0 #turn off HS data before register writes self.femb.write_reg_bits(9, 0, 0x1, 0) print("HS link turned off") time.sleep(2) #write SPI regs - very rough version chWord = (chReg << 24) + (chReg << 16) + (chReg << 8) + chReg for asic in range(0, self.NASICS, 1): baseReg = self.REG_SPI_BASE + int(asic) * 9 self.femb.write_reg_bits(baseReg + 4, 0, 0xFFFF, adc_globalReg) #ADC ASIC global registers self.femb.write_reg_bits(baseReg + 4, 16, 0xFF, chReg) #ch0 self.femb.write_reg_bits(baseReg + 4, 24, 0xFF, chReg) #ch1 self.femb.write_reg(baseReg + 5, chWord) #ch2-5 self.femb.write_reg(baseReg + 6, chWord) #ch6-9 self.femb.write_reg(baseReg + 7, chWord) #ch10-13 self.femb.write_reg_bits(baseReg + 8, 0, 0xFF, chReg) #ch14 self.femb.write_reg_bits(baseReg + 8, 8, 0xFF, chReg) #ch15 self.femb.write_reg_bits(baseReg + 8, 16, 0xFFFF, asicReg) #ASIC gen reg print("adc_globalReg ", "\t", adc_globalReg) print("chReg ", "\t", hex(chReg)) print("chWord ", "\t", hex(chWord)) print("asicReg ", "\t", hex(asicReg)) # find a good phase, if necessary self.findADCPhase() #run the SPI programming self.doAsicConfig() #turn HS link back on print("HS link turned back on") time.sleep(2) self.femb.write_reg_bits(9, 0, 0x1, 1) def findADCPhase(self, trial=0): print("Find ADC phases that sync all ADCs") #Write ADC ASIC SPI if True: print("ADC reconfig") self.femb.write_reg(self.REG_RESET, 0x4) #reset timestamp time.sleep(0.01) self.femb.write_reg(self.REG_ASIC_RESET, 1) #reset ASIC SPI time.sleep(0.01) self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) #configure ASICs time.sleep(0.01) self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) #configure ASICs time.sleep(0.01) syncSuccess = False oldSyncVal = 0xFFFF # start with the default values for the configuration def_clksel_rt = self.CLKSELECT_val_RT def_clksel2_rt = self.CLKSELECT2_val_RT def_clksel_ct = self.CLKSELECT_val_CT def_clksel2_ct = self.CLKSELECT2_val_CT #first step will always go +1 lastStep = 1 didJump = False while (syncSuccess == False): # give up after 50 trials if trial == 50: print("Could not find good clock phase, SYNC STATUS:", hex(syncVal)) return #phase control if self.isRoomTemp == True: print("ADC clock phase:", self.CLKSELECT_val_RT, self.CLKSELECT2_val_RT) self.femb.write_reg_bits(self.CLK_SELECT, 0, 0xFF, self.CLKSELECT_val_RT) #clock select self.femb.write_reg_bits( self.CLK_SELECT2, 0, 0xFF, self.CLKSELECT2_val_RT) #clock select 2 else: print("Using cryogenic parameters, ADC clock phase:", self.CLKSELECT_val_CT, self.CLKSELECT2_val_CT) self.femb.write_reg_bits(self.CLK_SELECT, 0, 0xFF, self.CLKSELECT_val_CT) #clock select self.femb.write_reg_bits( self.CLK_SELECT2, 0, 0xFF, self.CLKSELECT2_val_CT) #clock select 2 # check sync regVal = self.femb.read_reg(6) if regVal == None: print("doAsicConfig: Could not check SYNC status, bad") return syncVal = 0 syncVal = ((regVal >> 16) & 0xFFFF) self.syncStatus = syncVal print("SYNC ATTEMPT\t", trial, "\tSYNC VAL ", hex(syncVal)) #try again if sync not achieved if syncVal != 0x0: if syncVal <= oldSyncVal: # keep going this direction if lastStep == 1: if self.isRoomTemp == True: if self.CLKSELECT_val_RT < 0xFF: self.CLKSELECT_val_RT = self.CLKSELECT_val_RT + 1 if self.CLKSELECT2_val_RT < 0xFF: self.CLKSELECT2_val_RT = self.CLKSELECT2_val_RT + 1 else: if self.CLKSELECT_val_CT < 0xFF: self.CLKSELECT_val_CT = self.CLKSELECT_val_CT + 1 if self.CLKSELECT2_val_CT < 0xFF: self.CLKSELECT2_val_CT = self.CLKSELECT2_val_CT + 1 lastStep = 1 else: if self.isRoomTemp == True: if self.CLKSELECT_val_RT < 0xFF: self.CLKSELECT_val_RT = self.CLKSELECT_val_RT - 1 if self.CLKSELECT2_val_RT < 0xFF: self.CLKSELECT2_val_RT = self.CLKSELECT2_val_RT - 1 else: if self.CLKSELECT_val_CT < 0xFF: self.CLKSELECT_val_CT = self.CLKSELECT_val_CT - 1 if self.CLKSELECT2_val_CT < 0xFF: self.CLKSELECT2_val_CT = self.CLKSELECT2_val_CT - 1 lastStep = -1 oldSyncVal = syncVal else: # already jumped once if didJump == True: print("Could not find good clock phase, SYNC STATUS:", hex(syncVal)) return # jump back to start and switch directions if self.isRoomTemp == True: if self.CLKSELECT_val_RT < 0xFF: self.CLKSELECT_val_RT = def_clksel_rt - 1 if self.CLKSELECT2_val_RT < 0xFF: self.CLKSELECT2_val_RT = def_clksel2_rt - 1 else: if self.CLKSELECT_val_CT < 0xFF: self.CLKSELECT_val_CT = def_clksel_ct - 1 if self.CLKSELECT2_val_CT < 0xFF: self.CLKSELECT2_val_CT = def_clksel2_ct - 1 lastStep = -1 didJump = True oldSyncVal = 0xFFFF syncSuccess = False else: syncSuccess = True if self.isRoomTemp == True: print("Found good RT clock phase:", hex(self.CLKSELECT_val_RT), hex(self.CLKSELECT2_val_RT)) else: print("Found good CT clock phase:", hex(self.CLKSELECT_val_CT), hex(self.CLKSELECT2_val_CT)) trial = trial + 1 def doAsicConfig(self, syncAttempt=0): if syncAttempt == 0: print("Program ASIC SPI") #for regNum in range(self.REG_SPI_BASE,self.REG_SPI_BASE+72,1): # regVal = self.femb.read_reg( regNum) # print( str(regNum) + "\t" + str(hex(regVal)) ) #phase control """ if self.isRoomTemp == True: self.femb.write_reg_bits(self.CLK_SELECT , 0, 0xFF, 0xDF ) #clock select self.femb.write_reg_bits(self.CLK_SELECT2 , 0, 0xFF, 0x20 ) #clock select 2 else: print("Using cryogenic parameters") self.femb.write_reg_bits(self.CLK_SELECT , 0, 0xFF, 0x83 ) #clock select self.femb.write_reg_bits(self.CLK_SELECT2 , 0, 0xFF, 0xFF ) #clock select 2 self.femb.write_reg_bits(self.REG_LATCHLOC_3_TO_0 , 0, 0xFFFFFFFF, 0x00000000 ) #datashift self.femb.write_reg_bits(self.REG_LATCHLOC_7_TO_4 , 0, 0xFFFFFFFF, 0x00000000 ) #datashift """ #Write ADC ASIC SPI #if syncAttempt == 0: if True: #print("ADC reconfig") self.femb.write_reg(self.REG_RESET, 0x4) #reset timestamp time.sleep(0.01) self.femb.write_reg(self.REG_ASIC_RESET, 1) #reset ASIC SPI time.sleep(0.01) self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) #configure ASICs time.sleep(0.01) self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) #configure ASICs time.sleep(0.01) #soft reset #self.femb.write_reg( self.REG_SOFT_ADC_RESET, 0x4) #time.sleep(0.01) #for regNum in range(self.REG_SPI_RDBACK_BASE,self.REG_SPI_RDBACK_BASE+72,1): # regVal = self.femb.read_reg( regNum) # print( str(regNum) + "\t" + str(hex(regVal)) ) #check the sync if self.doReSync == False: return regVal = self.femb.read_reg(6) if regVal == None: print("doAsicConfig: Could not check SYNC status, bad") return syncVal = 0 syncVal = ((regVal >> 16) & 0xFFFF) self.syncStatus = syncVal #print("SYNC ATTEMPT\t",syncAttempt,"\tSYNC VAL " , hex(syncVal) ) #try again if sync not achieved, note recursion if syncVal != 0x0: if syncAttempt >= self.maxSyncAttempts: print("doAsicConfig: Could not sync ADC ASIC, sync val\t", hex(syncVal)) return else: self.doAsicConfig(syncAttempt + 1) def syncADC(self): print("Sync") def selectFemb(self, fembIn): fembVal = int(fembIn) if (fembVal < 0) or (fembVal > self.NFEMBS): print("Invalid FEMB # requested") return self.fembNum = fembVal #set data streaming for requested FEMB #set UDP ports to WIB self.femb.UDP_PORT_WREG = 32000 self.femb.UDP_PORT_RREG = 32001 self.femb.UDP_PORT_RREGRESP = 32002 self.femb.write_reg_bits(7, 16, 0x3, self.fembNum) #set read/write ports if fembVal == 0: self.femb.UDP_PORT_WREG = 32016 self.femb.UDP_PORT_RREG = 32017 self.femb.UDP_PORT_RREGRESP = 32018 if fembVal == 1: self.femb.UDP_PORT_WREG = 32032 self.femb.UDP_PORT_RREG = 32033 self.femb.UDP_PORT_RREGRESP = 32034 if fembVal == 2: self.femb.UDP_PORT_WREG = 32048 self.femb.UDP_PORT_RREG = 32049 self.femb.UDP_PORT_RREGRESP = 32050 if fembVal == 3: self.femb.UDP_PORT_WREG = 32064 self.femb.UDP_PORT_RREG = 32065 self.femb.UDP_PORT_RREGRESP = 32066 #slow down register interface for FEMBs self.femb.REG_SLEEP = 0.05 time.sleep(0.1) def initSI5338(self): #set UDP ports to WIB self.femb.UDP_PORT_WREG = 32000 self.femb.UDP_PORT_RREG = 32001 self.femb.UDP_PORT_RREGRESP = 32002 self.femb.REG_SLEEP = 0.001 #disable all outputs #i2c_reg_wr(i2c_bus_base_addr, si5338_i2c_addr, 230, 0x10); self.write_reg_SI5338(230, 0x10) #pause lol #i2c_reg_wr(i2c_bus_base_addr, si5338_i2c_addr, 241, 0xE5); self.write_reg_SI5338(241, 0xE5) import femb_python.configuration.femb_config_wib_sbnd_si5338_data for word in range(0, 349, 1): wordNum = int(word) addr = int(femb_python.configuration. femb_config_wib_sbnd_si5338_data.data[3 * wordNum + 0]) val = int(femb_python.configuration. femb_config_wib_sbnd_si5338_data.data[3 * wordNum + 1]) mask = int(femb_python.configuration. femb_config_wib_sbnd_si5338_data.data[3 * wordNum + 2]) if wordNum % 10 == 0: print("Writing SI5338 register # " + str(wordNum) + " out of 349") if mask == 0: continue writeVal = val if mask != 0xFF: curr_val = self.read_reg_SI5338(addr) if curr_val == None: print("Did not finish clock initialization") return clear_curr_val = curr_val & (~mask) clear_new_val = val & mask writeVal = clear_curr_val | clear_new_val self.write_reg_SI5338(addr, writeVal) #print(str(addr) + "\t" + str(writeVal)) #validate input clock status #i2c_reg_rd(i2c_bus_base_addr, si5338_i2c_addr, 218); regVal = self.read_reg_SI5338(218) if regVal == None: print("Did not finish clock initialization") return clkStatus = (regVal & 0x04) count = 0 while count < 100: regVal = self.read_reg_SI5338(218) if regVal == None: print("Did not finish clock initialization") return clkStatus = (regVal & 0x04) if clkStatus != 0x04: break count = count + 1 if clkStatus == 0x04: print("Did not finish clock initialization") return #configure pll pllWord = int( femb_python.configuration.femb_config_wib_sbnd_si5338_data.data[ 3 * 49 + 1]) self.write_reg_SI5338(49, (0x7F & pllWord)) #reset the chip self.write_reg_SI5338(246, 0x02) time.sleep(0.1) #restart lol self.write_reg_SI5338(241, 0x65) #validate pll pllStatus = self.read_reg_SI5338(218) if pllStatus == None: print("Did not finish clock initialization") return count = 0 while count < 100: pllStatus = self.read_reg_SI5338(218) if pllStatus == None: print("Did not finish clock initialization") return if pllStatus == 0: break count = count + 1 if pllStatus != 0: print("Did not finish clock initialization") return #copy FCAL values to active registers fcalVal = self.read_reg_SI5338(235) if fcalVal == None: print("Did not finish clock initialization") return self.write_reg_SI5338(45, fcalVal) fcalVal = self.read_reg_SI5338(236) if fcalVal == None: print("Did not finish clock initialization") return self.write_reg_SI5338(46, fcalVal) fcalVal = self.read_reg_SI5338(237) if fcalVal == None: print("Did not finish clock initialization") return fcalVal = (0x14 | (fcalVal & 0x3)) self.write_reg_SI5338(47, fcalVal) #set pll to use FCAL values #i2c_reg_wr(i2c_bus_base_addr, si5338_i2c_addr, 49, 0x80|SI5338Reg[49*3+1]); setPllWord = (0x80 | pllWord) self.write_reg_SI5338(49, setPllWord) #enable outputs self.write_reg_SI5338(230, 0x00) print("Done initalizing Si5338 clock") #set UDP ports back to normal self.selectFemb(self.fembNum) def read_reg_SI5338(self, addr): addrVal = int(addr) if (addrVal < 0) or (addrVal > 255): return None self.femb.write_reg(11, 0) self.femb.write_reg(12, addrVal) self.femb.write_reg(15, 0xE0) self.femb.write_reg(10, 1) self.femb.write_reg(10, 0) self.femb.write_reg(11, 1) self.femb.write_reg(10, 2) self.femb.write_reg(10, 0) regVal = self.femb.read_reg(14) if regVal == None: return None return regVal def write_reg_SI5338(self, addr, val): addrVal = int(addr) if (addrVal < 0) or (addrVal > 255): return regVal = int(val) if (regVal < 0) or (regVal > 255): return self.femb.write_reg(11, 1) self.femb.write_reg(12, addrVal) self.femb.write_reg(13, regVal) self.femb.write_reg(10, 1) self.femb.write_reg(10, 0) def setFpgaPulser(self, enable, dac): enableVal = int(enable) if (enableVal < 0) or (enableVal > 1): print("femb_config_femb : setFpgaPulser - invalid enable value") return dacVal = int(dac) if (dacVal < 0) or (dacVal > 0x3F): print("femb_config_femb : setFpgaPulser - invalid dac value") return self.femb.write_reg_bits(self.REG_FPGA_TP_EN, 0, 0x3, enableVal) #test pulse enable self.femb.write_reg_bits(self.REG_FPGA_TP_EN, 8, 0x1, enableVal) #test pulse enable self.femb.write_reg_bits(self.REG_TP, 0, 0x3F, dacVal) #TP Amplitude self.femb.write_reg_bits(self.REG_TP, 8, 0xFF, 219) #DLY self.femb.write_reg_bits(self.REG_TP, 16, 0xFFFF, 497) #FREQ #set pulser enable bit if enableVal == 1: self.femb.write_reg(self.EXT_TP_EN, 0x2) #this register is confusing, check else: self.femb.write_reg(self.EXT_TP_EN, 0x3) #pulser disabled #connect channel test input to external pin for asic in range(0, self.NASICS, 1): baseReg = self.REG_SPI_BASE + int(asic) * 9 if enableVal == 1: self.femb.write_reg_bits(baseReg + 8, 24, 0x3, 0x2) #ASIC gen reg else: self.femb.write_reg_bits(baseReg + 8, 24, 0x3, 0x0) #ASIC gen reg self.doAsicConfig() def setInternalPulser(self, enable, dac): enableVal = int(enable) if (enableVal < 0) or (enableVal > 1): print( "femb_config_femb : setInternalPulser - invalid enable value") return dacVal = int(dac) if (dacVal < 0) or (dacVal > 0x3F): print("femb_config_femb : setInternalPulser - invalid dac value") return self.femb.write_reg_bits(self.REG_DAC_SELECT, 8, 0x1, 0) #test pulse enable self.femb.write_reg_bits(self.REG_TP, 0, 0x3F, 0) #TP Amplitude self.femb.write_reg_bits(self.REG_TP, 8, 0xFF, 219) #DLY self.femb.write_reg_bits(self.REG_TP, 16, 0xFFFF, 497) #FREQ #set pulser enable bit if enableVal == 1: self.femb.write_reg(self.INT_TP_EN, 0x2) #this register is confusing, check else: self.femb.write_reg(self.INT_TP_EN, 0x3) #pulser disabled dacVal = (dacVal & 0x3F) newDacVal = int('{:08b}'.format(dacVal)[::-1], 2) asicWord = ((newDacVal << 8) & 0xFFFF) if enableVal == 1: asicWord = asicWord + (0x1 << 8) #connect channel test input to external pin for asic in range(0, self.NASICS, 1): baseReg = self.REG_SPI_BASE + int(asic) * 9 if enableVal == 1: self.femb.write_reg_bits(baseReg + 8, 24, 0xFF, newDacVal) self.femb.write_reg_bits(baseReg + 8, 24, 0x3, 0x1) #ASIC gen reg else: self.femb.write_reg_bits(baseReg + 8, 24, 0xFF, 0x0) #ASIC gen reg self.doAsicConfig() if enableVal == 1: self.femb.write_reg_bits( self.REG_ASIC_TP_EN, 0, 0x3, 0x2) #NOTE, also disabling FPGA pulser here else: self.femb.write_reg_bits(self.REG_ASIC_TP_EN, 0, 0x3, 0x0) def selectPulserChannels(self, setchannels): # attach test cap to a set of channels given by the array testchannels testchannels = [] # check channel list for i in range(0, len(setchannels), 1): if (setchannels[i] >= 0 and setchannels[i] <= 127): testchannels.append(setchannels[i]) else: print("Invalid channel:", setchannels[i], "removed from list") print("Selecting channels for pulser:", testchannels) ch = [[-1 for i in range(self.NASICCH)] for j in range(self.NASICS)] for asic in range(0, self.NASICS, 1): baseReg = self.REG_SPI_BASE + int(asic) * 9 # read back current state of channel regs ch[asic][15] = (self.femb.read_reg(baseReg + 4) & 0xFF0000) >> 16 ch[asic][14] = (self.femb.read_reg(baseReg + 4) & 0xFF000000) >> 24 ch[asic][13] = (self.femb.read_reg(baseReg + 5) & 0xFF) ch[asic][12] = (self.femb.read_reg(baseReg + 5) & 0xFF00) >> 8 ch[asic][11] = (self.femb.read_reg(baseReg + 5) & 0xFF0000) >> 16 ch[asic][10] = (self.femb.read_reg(baseReg + 5) & 0xFF000000) >> 24 ch[asic][9] = (self.femb.read_reg(baseReg + 6) & 0xFF) ch[asic][8] = (self.femb.read_reg(baseReg + 6) & 0xFF00) >> 8 ch[asic][7] = (self.femb.read_reg(baseReg + 6) & 0xFF0000) >> 16 ch[asic][6] = (self.femb.read_reg(baseReg + 6) & 0xFF000000) >> 24 ch[asic][5] = (self.femb.read_reg(baseReg + 7) & 0xFF) ch[asic][4] = (self.femb.read_reg(baseReg + 7) & 0xFF00) >> 8 ch[asic][3] = (self.femb.read_reg(baseReg + 7) & 0xFF0000) >> 16 ch[asic][2] = (self.femb.read_reg(baseReg + 7) & 0xFF000000) >> 24 ch[asic][1] = (self.femb.read_reg(baseReg + 8) & 0xFF) ch[asic][0] = (self.femb.read_reg(baseReg + 8) & 0xFF00) >> 8 # 0 test cap all channels for i in range(0, self.NASICCH, 1): ch[asic][i] = ch[asic][i] & 0x7F # 1 test cap if channel is in list for tc in range(0, len(testchannels), 1): thisasic = int(testchannels[tc] / self.NASICCH) thischan = int( (testchannels[tc] / self.NASICCH - thisasic) * self.NASICCH) ch[thisasic][thischan] = ch[thisasic][thischan] + 0x80 #write channel regs for asic in range(0, self.NASICS, 1): baseReg = self.REG_SPI_BASE + int(asic) * 9 self.femb.write_reg_bits(baseReg + 4, 16, 0xFF, ch[asic][15]) self.femb.write_reg_bits(baseReg + 4, 24, 0xFF, ch[asic][14]) self.femb.write_reg_bits(baseReg + 5, 0, 0xFF, ch[asic][13]) self.femb.write_reg_bits(baseReg + 5, 8, 0xFF, ch[asic][12]) self.femb.write_reg_bits(baseReg + 5, 16, 0xFF, ch[asic][11]) self.femb.write_reg_bits(baseReg + 5, 24, 0xFF, ch[asic][10]) self.femb.write_reg_bits(baseReg + 6, 0, 0xFF, ch[asic][9]) self.femb.write_reg_bits(baseReg + 6, 8, 0xFF, ch[asic][8]) self.femb.write_reg_bits(baseReg + 6, 16, 0xFF, ch[asic][7]) self.femb.write_reg_bits(baseReg + 6, 24, 0xFF, ch[asic][6]) self.femb.write_reg_bits(baseReg + 7, 0, 0xFF, ch[asic][5]) self.femb.write_reg_bits(baseReg + 7, 8, 0xFF, ch[asic][4]) self.femb.write_reg_bits(baseReg + 7, 16, 0xFF, ch[asic][3]) self.femb.write_reg_bits(baseReg + 7, 24, 0xFF, ch[asic][2]) self.femb.write_reg_bits(baseReg + 8, 0, 0xFF, ch[asic][1]) self.femb.write_reg_bits(baseReg + 8, 8, 0xFF, ch[asic][0]) self.doAsicConfig() def checkFirmwareVersion(self): #set UDP ports to WIB self.femb.UDP_PORT_WREG = 32000 self.femb.UDP_PORT_RREG = 32001 self.femb.UDP_PORT_RREGRESP = 32002 #check WIB fw version reg wibVerReg = self.femb.read_reg(255) if wibVerReg == None: return False wibVerReg = (wibVerReg & 0xFFF) #set UDP ports back to normal self.selectFemb(self.fembNum) fembVerReg = self.femb.read_reg(257) if fembVerReg == None: return False fembVerReg = (fembVerReg & 0xFFF) #print( "FEMB Firmware Version HERE : " + str(hex(fembVerReg)) ) if wibVerReg != 0x116: print("Invalid WIB firmware version detected " + str(hex(wibVerReg)) + ", this configuration requires version 0x116") return False if fembVerReg != 0x323: print("Invalid FEMB firmware version detected " + str(hex(fembVerReg)) + ", this configuration requires version 0x323") return False print("WIB Firmware Version : " + str(hex(wibVerReg))) print("FEMB Firmware Version : " + str(hex(fembVerReg))) #good firmware id return True def readCurrent(self): self.femb.UDP_PORT_WREG = 32000 #WIB PORTS self.femb.UDP_PORT_RREG = 32001 self.femb.UDP_PORT_RREGRESP = 32002 for j in range(0, 100): self.femb.write_reg(5, 0) self.femb.write_reg(5, 0x10000) self.femb.write_reg(5, 0) time.sleep(0.01) results = [] for pwrSel in range(1, 25): self.femb.write_reg(5, pwrSel) time.sleep(0.1) regVal = self.femb.read_reg(6) if regVal == None: results.append(0) continue #return None val = regVal & 0xFFFFFFFF results.append(val) self.selectFemb(0) return results def ext_clk_config_femb(self): #EXTERNAL CLOCK VARIABLES ####################external clokc timing clk_period = 5 #ns self.clk_dis = 0 #0 --> enable, 1 disable self.d14_rst_oft = 0 // clk_period self.d14_rst_wdt = (45 // clk_period) self.d14_rst_inv = 1 self.d14_read_oft = 480 // clk_period self.d14_read_wdt = 20 // clk_period self.d14_read_inv = 1 self.d14_idxm_oft = 230 // clk_period self.d14_idxm_wdt = 270 // clk_period self.d14_idxm_inv = 0 self.d14_idxl_oft = 480 // clk_period self.d14_idxl_wdt = 20 // clk_period self.d14_idxl_inv = 0 self.d14_idl0_oft = 50 // clk_period self.d14_idl0_wdt = (190 // clk_period) - 1 self.d14_idl1_oft = 480 // clk_period self.d14_idl1_wdt = 20 // clk_period self.d14_idl_inv = 0 self.d58_rst_oft = 0 // clk_period self.d58_rst_wdt = (45 // clk_period) self.d58_rst_inv = 1 self.d58_read_oft = 480 // clk_period self.d58_read_wdt = 20 // clk_period self.d58_read_inv = 1 self.d58_idxm_oft = 230 // clk_period self.d58_idxm_wdt = 270 // clk_period self.d58_idxm_inv = 0 self.d58_idxl_oft = 480 // clk_period self.d58_idxl_wdt = 20 // clk_period self.d58_idxl_inv = 0 self.d58_idl0_oft = 50 // clk_period self.d58_idl0_wdt = (190 // clk_period) - 1 self.d58_idl1_oft = 480 // clk_period self.d58_idl1_wdt = 20 // clk_period self.d58_idl_inv = 0 ####################external clock phase for V323 firmware self.d14_read_step = 11 self.d14_read_ud = 0 self.d14_idxm_step = 9 self.d14_idxm_ud = 0 self.d14_idxl_step = 7 self.d14_idxl_ud = 0 self.d14_idl0_step = 12 self.d14_idl0_ud = 0 self.d14_idl1_step = 10 self.d14_idl1_ud = 0 self.d14_phase_en = 1 self.d58_read_step = 0 self.d58_read_ud = 0 self.d58_idxm_step = 5 self.d58_idxm_ud = 0 self.d58_idxl_step = 4 self.d58_idxl_ud = 1 self.d58_idl0_step = 3 self.d58_idl0_ud = 0 self.d58_idl1_step = 4 self.d58_idl1_ud = 0 self.d58_phase_en = 1 #END EXTERNAL CLOCK VARIABLES #config timing d14_inv = (self.d14_rst_inv << 0) + (self.d14_read_inv << 1) + ( self.d14_idxm_inv << 2) + (self.d14_idxl_inv << 3) + ( self.d14_idl_inv << 4) d58_inv = (self.d58_rst_inv << 0) + (self.d58_read_inv << 1) + ( self.d58_idxm_inv << 2) + (self.d58_idxl_inv << 3) + ( self.d58_idl_inv << 4) d_inv = d58_inv + (d14_inv << 5) addr_data = self.clk_dis + (d_inv << 16) #self.ext_clk_reg_wr_femb( femb_addr, 21, addr_data) self.femb.write_reg(21, addr_data) addr_data = self.d58_rst_oft + (self.d14_rst_oft << 16) #self.ext_clk_reg_wr_femb( femb_addr, 22, addr_data) self.femb.write_reg(22, addr_data) addr_data = self.d58_rst_wdt + (self.d14_rst_wdt << 16) #self.ext_clk_reg_wr_femb( femb_addr, 23, addr_data) self.femb.write_reg(23, addr_data) addr_data = self.d58_read_oft + (self.d14_read_oft << 16) #self.ext_clk_reg_wr_femb( femb_addr, 24, addr_data) self.femb.write_reg(24, addr_data) addr_data = self.d58_read_wdt + (self.d14_read_wdt << 16) #self.ext_clk_reg_wr_femb( femb_addr, 25, addr_data) self.femb.write_reg(25, addr_data) addr_data = self.d58_idxm_oft + (self.d14_idxm_oft << 16) #self.ext_clk_reg_wr_femb( femb_addr, 26, addr_data) self.femb.write_reg(26, addr_data) addr_data = self.d58_idxm_wdt + (self.d14_idxm_wdt << 16) #self.ext_clk_reg_wr_femb( femb_addr, 27, addr_data) self.femb.write_reg(27, addr_data) addr_data = self.d58_idxl_oft + (self.d14_idxl_oft << 16) #self.ext_clk_reg_wr_femb( femb_addr, 28, addr_data) self.femb.write_reg(28, addr_data) addr_data = self.d58_idxl_wdt + (self.d14_idxl_wdt << 16) #self.ext_clk_reg_wr_femb( femb_addr, 29, addr_data) self.femb.write_reg(29, addr_data) addr_data = self.d58_idl0_oft + (self.d14_idl0_oft << 16) #self.ext_clk_reg_wr_femb( femb_addr, 30, addr_data) self.femb.write_reg(30, addr_data) addr_data = self.d58_idl0_wdt + (self.d14_idl0_wdt << 16) #self.ext_clk_reg_wr_femb( femb_addr, 31, addr_data) self.femb.write_reg(31, addr_data) addr_data = self.d58_idl1_oft + (self.d14_idl1_oft << 16) #self.ext_clk_reg_wr_femb( femb_addr, 32, addr_data) self.femb.write_reg(32, addr_data) addr_data = self.d58_idl1_wdt + (self.d14_idl1_wdt << 16) #self.ext_clk_reg_wr_femb( femb_addr, 33, addr_data) self.femb.write_reg(33, addr_data) #config phase for i in range(4): addr_data = self.d14_read_step + (self.d14_idxm_step << 16) #self.ext_clk_reg_wr_femb( femb_addr, 35, addr_data) self.femb.write_reg(35, addr_data) addr_data = self.d14_idxl_step + (self.d14_idl0_step << 16) #self.ext_clk_reg_wr_femb( femb_addr, 36, addr_data) self.femb.write_reg(36, addr_data) self.d14_phase_en = self.d14_phase_en ^ 1 d14_ud = self.d14_read_ud + (self.d14_idxm_ud << 1) + ( self.d14_idxl_ud << 2) + (self.d14_idl0_ud << 3) + ( self.d14_idl1_ud << 4) + (self.d14_phase_en << 15) addr_data = self.d14_idl1_step + (d14_ud << 16) #self.ext_clk_reg_wr_femb( femb_addr, 37, addr_data) self.femb.write_reg(37, addr_data) addr_data = self.d58_read_step + (self.d58_idxm_step << 16) #self.ext_clk_reg_wr_femb( femb_addr, 38, addr_data) self.femb.write_reg(38, addr_data) addr_data = self.d58_idxl_step + (self.d58_idl0_step << 16) #self.ext_clk_reg_wr_femb( femb_addr, 39, addr_data) self.femb.write_reg(39, addr_data) self.d58_phase_en = self.d58_phase_en ^ 1 d58_ud = self.d58_read_ud + (self.d58_idxm_ud << 1) + ( self.d58_idxl_ud << 2) + (self.d58_idl0_ud << 3) + ( self.d58_idl1_ud << 4) + (self.d58_phase_en << 15) addr_data = self.d58_idl1_step + (d58_ud << 16) #self.ext_clk_reg_wr_femb( femb_addr, 40, addr_data) self.femb.write_reg(40, addr_data)
class FEMB_CONFIG(FEMB_CONFIG_BASE): #__INIT__# def __init__(self): #declare basic system parameters self.NFEMBS = 4 self.NASICS = 8 self.NASICCH = 16 #declare board specific registers self.FEMB_VER = "WIB_SBND" self.REG_RESET = 0 self.REG_ASIC_RESET = 1 self.REG_ASIC_SPIPROG = 2 self.REG_SOFT_ADC_RESET = 1 self.REG_LATCHLOC_3_TO_0 = 4 self.REG_LATCHLOC_7_TO_4 = 14 self.REG_FPGA_TP_EN = 16 self.REG_ASIC_TP_EN = 16 self.REG_DAC_SELECT = 16 self.REG_TP = 5 self.CLK_SELECT = 6 self.CLK_SELECT2 = 15 self.REG_SEL_ASIC = 7 self.REG_SEL_ASIC_LSB = 8 self.REG_WIB_MODE = 8 self.REG_ADC_DISABLE = 8 self.REG_HS_DATA = 9 self.REG_HS = 17 self.INT_TP_EN = 18 self.EXT_TP_EN = 18 self.REG_SPI_BASE = 0x200 self.REG_SPI_RDBACK_BASE = 0x250 self.REG_TEST_PAT = 3 self.REG_TEST_PAT_DATA = 0x01230000 #internal variables self.fembNum = 0 self.wibNum = 0 self.useExtAdcClock = True self.isRoomTemp = False self.doReSync = True self.spiStatus = 0x0 self.syncStatus = 0x0 self.CLKSELECT_val_RT = 0xFF self.CLKSELECT2_val_RT = 0xFF self.CLKSELECT_val_CT = 0xEF self.CLKSELECT2_val_CT = 0xEF self.REG_LATCHLOC_3_TO_0_val = 0x04040404 self.REG_LATCHLOC_7_TO_4_val = 0x04040404 self.fe_regs = [0x00000000]*(16+2)*8*8 self.fe_REGS = [0x00000000]*(8+1)*4 self.useLArIATmap = False #True #COTS shifts self.fe1_sft_RT = 0x00000000 self.fe2_sft_RT = 0x00000000 self.fe3_sft_RT = 0x00000000 self.fe4_sft_RT = 0x00000000 self.fe5_sft_RT = 0x00000000 self.fe6_sft_RT = 0x00000000 self.fe7_sft_RT = 0x00000000 self.fe8_sft_RT = 0x00000000 self.fe1_sft_CT = 0x00000000 self.fe2_sft_CT = 0x00000000 self.fe3_sft_CT = 0x00000000 self.fe4_sft_CT = 0x00000000 self.fe5_sft_CT = 0x00000000 self.fe6_sft_CT = 0x00000000 self.fe7_sft_CT = 0x00000000 self.fe8_sft_CT = 0x00000000 #COTS phases self.fe1_pha_RT = 0x00000000 self.fe2_pha_RT = 0x00000000 self.fe3_pha_RT = 0x00000000 self.fe4_pha_RT = 0x00000000 self.fe5_pha_RT = 0x00000000 self.fe6_pha_RT = 0x00000000 self.fe7_pha_RT = 0x00000000 self.fe8_pha_RT = 0x00000000 self.fe1_pha_CT = 0x00000000 self.fe2_pha_CT = 0x00000000 self.fe3_pha_CT = 0x00000000 self.fe4_pha_CT = 0x00000000 self.fe5_pha_CT = 0x00000000 self.fe6_pha_CT = 0x00000000 self.fe7_pha_CT = 0x00000000 self.fe8_pha_CT = 0x00000000 #initialize FEMB UDP object self.femb = FEMB_UDP() self.femb.UDP_PORT_WREG = 32000 #WIB PORTS self.femb.UDP_PORT_RREG = 32001 self.femb.UDP_PORT_RREGRESP = 32002 self.femb.doReadBack = False #WIB register interface is unreliable #ASIC config variables self.feasicLeakage = 0 #0 = 500pA, 1 = 100pA self.feasicLeakagex10 = 0 #0 = pA, 1 = pA*10 self.feasicAcdc = 0 #AC = 0, DC = 1 self.feasicBaseline = 0 #0 = 900mV, 1 = 200mV self.feasicEnableTestInput = 0 #0 = disabled, 1 = enabled self.feasicGain = 2 #4.7,7.8,14,25 self.feasicShape = 1 #0.5,1,2,3 self.feasicBuf = 1 #0 = OFF, 1 = ON #Read in LArIAT mapping if desired if self.useLArIATmap: self.cppfr = CPP_FILE_RUNNER() with open(self.cppfr.filename('configuration/configs/LArIAT_pin_mapping.map'), "rb") as fp: self.lariatMap = pickle.load(fp) #APA Mapping va = self.lariatMap va_femb = [] for vb in va: if int(vb[9]) in (0,1,2,3,4) : va_femb.append(vb) apa_femb_loc = [] for chn in range(128): for vb in va_femb: if int(vb[8]) == chn: if (vb[1].find("Co")) >= 0 :#collection wire chninfo = [ "X" + vb[0], vb[8], int(vb[6]), int(vb[7]), int(vb[9]), int(vb[10])] elif (vb[1].find("In")) >= 0 : #induction wire chninfo = [ "U" + vb[0], vb[8], int(vb[6]), int(vb[7]), int(vb[9]), int(vb[10])] apa_femb_loc.append(chninfo) for chn in range(128): fl_w = True fl_i = 0 for tmp in apa_femb_loc: if int(tmp[1]) == chn: fl_w = False break if (fl_w): chninfo = [ "V" + format(fl_i, "03d"), format(chn, "03d"), chn//16 , format(chn%15, "02d"), apa_femb_loc[0][4], apa_femb_loc[0][5]] apa_femb_loc.append(chninfo) fl_i = fl_i + 1 self.All_sort = [] self.X_sort = [] self.V_sort = [] self.U_sort = [] for i in range(128): for chn in apa_femb_loc: if int(chn[1][0:3]) == i : self.All_sort.append(chn) for chn in apa_femb_loc: if chn[0][0] == "X" and int(chn[0][1:3]) == i : self.X_sort.append(chn) for chn in apa_femb_loc: if chn[0][0] == "V" and int(chn[0][1:3]) == i : self.V_sort.append(chn) for chn in apa_femb_loc: if chn[0][0] == "U" and int(chn[0][1:3]) == i : self.U_sort.append(chn) self.WireDict = {} for line in self.All_sort: key = "wib{:d}_femb{:d}_chip{:d}_chan{:02d}".format(line[5],line[4],line[2],line[3]) self.WireDict[key] = line[0] def printParameters(self): print("FEMB # \t",self.fembNum) print("Room temperature \t",self.isRoomTemp) print("Do resync \t",self.doReSync) print("FE-ASIC leakage \t",self.feasicLeakage) print("FE-ASIC leakage x10\t",self.feasicLeakagex10) print("FE-ASIC AD/DC \t",self.feasicAcdc) print("FE-ASIC test input \t",self.feasicEnableTestInput) print("FE-ASIC baseline \t",self.feasicBaseline) print("FE-ASIC gain \t",self.feasicGain) print("FE-ASIC shape \t",self.feasicShape) print("FE-ASIC buffer \t",self.feasicBuf) print("FE-ASIC config") for regNum in range(self.REG_SPI_BASE,self.REG_SPI_BASE+72,1): regVal = self.femb.read_reg( regNum) if regVal == None: continue print( str(regNum) + "\t" + str(hex(regVal)) ) def resetBoard(self): print("Reset") def initBoard(self): self.initWib() for femb in range(0,4,1): self.selectFemb(femb) self.initFemb() def initWib(self): #WIB initialization self.wib_switch() #set UDP ports to WIB registers self.wib_reg_enable() #register 2, LED #self.femb.write_reg_bits(2 , 0, 0xFF, 0 ) #set jumbo size #self.femb.write_reg(0x1F,0xEFB) #set external clock self.femb.write_reg(0x4, 8) self.femb.write_reg(16,0x7F00) self.femb.write_reg(15,0) #sync timestamp /WIB self.femb.write_reg(1,0) self.femb.write_reg(1,0) self.femb.write_reg(1,2) self.femb.write_reg(1,2) self.femb.write_reg(1,0) self.femb.write_reg(1,0) #Reset error /WIB self.femb.write_reg(18, 0x8000) self.femb.write_reg(18, 0x8000) #return register interface to FEMB self.selectFemb(self.fembNum) def initFemb(self): fembVal = self.fembNum - 4*(self.wibNum) if (fembVal < 0) or (fembVal >= self.NFEMBS ): return print("Initialize FEMB",fembVal) #FEMB power enable on WIB self.powerOnFemb(fembVal) #Make sure register interface is for correct FEMB self.selectFemb(fembVal) #check if FEMB register interface is working print("Checking register interface") regVal = self.femb.read_reg(6) if (regVal == None) or (regVal == -1): # try again self.powerOffFemb(fembVal) time.sleep(10) self.powerOnFemb(fembVal) newregVal = self.femb.read_reg(6) if (newregVal == None) or (newregVal == -1): print("Error - FEMB register interface is not working.") print(" Will not initialize FEMB.") return checkFirmware = self.checkFirmwareVersion() if checkFirmware == False: # try again self.powerOffFemb(fembVal) time.sleep(10) self.powerOnFemb(fembVal) newcheckFirmware = self.checkFirmwareVersion() if newcheckFirmware == False: print("Error - invalid firmware, will not attempt to initialize board") return #turn off pulser self.femb.write_reg_bits( self.REG_FPGA_TP_EN, 0,0x1,0) #test pulse enable self.femb.write_reg_bits( self.REG_ASIC_TP_EN, 1,0x1,0) #test pulse enable self.femb.write_reg_bits( self.REG_DAC_SELECT, 8,0x1,0) #test pulse enable self.femb.write_reg_bits( self.REG_TP, 0,0x1F,0x00) #test pulse amplitude self.femb.write_reg_bits( self.REG_TP, 16,0xFFFF,0x100) #test pulse frequency self.femb.write_reg_bits( self.REG_TP, 8,0xFF,0x00) #test pulse delay #Timestamp reset self.femb.write_reg(0, 4) self.femb.write_reg(0, 4) #Reset SPI self.femb.write_reg(self.REG_ASIC_RESET,1) self.femb.write_reg(self.REG_ASIC_RESET,1) self.femb.write_reg(self.REG_ASIC_RESET,2) self.femb.write_reg(self.REG_ASIC_RESET,2) self.femb.write_reg(self.REG_TEST_PAT, self.REG_TEST_PAT_DATA) #Turn off readback checking for ASIC config self.femb.doReadBack = False #ADC Setup self.set_cots_shift() #Set ASIC SPI configuration registers self.configFeAsic() #check ASIC SPI self.checkFembSpi() print("SPI STATUS","\t",self.spiStatus) #Enable Streaming self.femb.write_reg(9,9) self.femb.write_reg(9,9) time.sleep(0.1) # write to WIB self.wib_reg_enable() # check link status retry_links = False link_status = self.femb.read_reg(0x21) if (fembVal == 0): femb_link = link_status & 0xFF elif (fembVal == 1): femb_link = (link_status & 0xFF00)>>8 elif (fembVal == 2): femb_link = (link_status & 0xFF0000)>>16 elif (fembVal == 3): femb_link = (link_status & 0xFF000000)>>24 if (not femb_link): retry_links = True else: print("HS links enabled") if (retry_links): #Enable Streaming self.selectFemb(fembVal) self.femb.write_reg(9,9) self.femb.write_reg(9,9) time.sleep(2) self.wib_reg_enable() print("linkstatus",hex(link_status)) if (fembVal == 0): femb_link = link_status & 0xFF elif (fembVal == 1): femb_link = (link_status & 0xFF00)>>8 elif (fembVal == 2): femb_link = (link_status & 0xFF0000)>>16 elif (fembVal == 3): femb_link = (link_status & 0xFF000000)>>24 if (not femb_link): print("HS link error, LINK STATUS:",hex(femb_link)) return else: print("HS links enabled on retry") #reset the error counters self.femb.write_reg(20,3) self.femb.write_reg(20,3) time.sleep(0.001) self.femb.write_reg(20,0) self.femb.write_reg(20,0) time.sleep(0.001) # start streaming data from ASIC 0 in initialization self.femb.write_reg(7, 0x80000000) self.femb.write_reg(7, 0x80000000) femb_asic = 0 & 0x0F wib_asic = (((fembVal << 16)&0x000F0000) + ((femb_asic << 8) &0xFF00)) self.femb.write_reg(7, wib_asic | 0x80000000) self.femb.write_reg(7, wib_asic | 0x80000000) self.femb.write_reg(7, wib_asic) self.femb.write_reg(7, wib_asic) # return to FEMB control self.selectFemb(fembVal) #Print some happy messages for shifters print("Finished initializing ASICs for WIB{:d} FEMB{:d}".format(self.wibNum,fembVal)) #Test FEMB SPI working def checkFembSpi(self): print("Check ASIC SPI") self.spiStatus = 0 for k in range(2): #Disable streaming self.femb.write_reg(9, 0x0) time.sleep(0.01) i = 0 for regNum in range(self.REG_SPI_BASE,self.REG_SPI_BASE+len(self.fe_REGS),1): self.femb.write_reg( regNum, self.fe_REGS[i]) i += 1 time.sleep(0.01) self.femb.write_reg( self.REG_ASIC_SPIPROG, 1) if (k==1): for j in range(3): self.spiStatus = 0 time.sleep(0.01) readvals = [] for regNum in range(self.REG_SPI_RDBACK_BASE,self.REG_SPI_RDBACK_BASE+len(self.fe_REGS),1): rdbckVal = self.femb.read_reg( regNum) if rdbckVal == None : print("Error - FEMB register interface is not working.") return else: readvals.append(rdbckVal) time.sleep(0.001) for i in range(len(self.fe_REGS)): if self.fe_REGS[i] != readvals[i] : print(hex(self.fe_REGS[i]),"\t",hex(readvals[i])) print("SPI readback failed.") self.spiStatus = 1 if self.spiStatus == 1: return self.femb.write_reg(9, 9) self.femb.write_reg(9, 9) time.sleep(0.1) def checkSync(self): print("Check ASIC SYNC") regVal = self.femb.read_reg(6) if regVal == None: print("doAsicConfigcheckFembSpi: Could not check SYNC status, bad") return syncVal = ((regVal >> 16) & 0xFFFF) self.syncStatus = syncVal #Setup talking to WIB def wib_switch(self): #Set IP addresses based in wib number: #For SBND-LArIAT #iplist = ["131.225.150.203","131.225.150.206"] #For BNL testing iplist = ["192.168.121.1"] self.femb.UDP_IP = iplist[self.wibNum] def wib_reg_enable(self): self.femb.UDP_PORT_WREG = 32000 self.femb.UDP_PORT_RREG = 32001 self.femb.UDP_PORT_RREGRESP = 32002 self.femb.REG_SLEEP = 0.001 #COTS Shift and Phase Settings def set_cots_shift(self): if self.isRoomTemp: print("Setting COTS Shifts for RT") self.femb.write_reg(21,self.fe1_sft_RT) self.femb.write_reg(29,self.fe1_pha_RT) self.femb.write_reg(22,self.fe2_sft_RT) self.femb.write_reg(30,self.fe2_pha_RT) self.femb.write_reg(23,self.fe3_sft_RT) self.femb.write_reg(31,self.fe3_pha_RT) self.femb.write_reg(24,self.fe4_sft_RT) self.femb.write_reg(32,self.fe4_pha_RT) self.femb.write_reg(25,self.fe5_sft_RT) self.femb.write_reg(33,self.fe5_pha_RT) self.femb.write_reg(26,self.fe6_sft_RT) self.femb.write_reg(34,self.fe6_pha_RT) self.femb.write_reg(27,self.fe7_sft_RT) self.femb.write_reg(35,self.fe7_pha_RT) self.femb.write_reg(28,self.fe8_sft_RT) self.femb.write_reg(36,self.fe8_pha_RT) else: print("Setting COTS Shifts for CT") self.femb.write_reg(21,self.fe1_sft_CT) self.femb.write_reg(29,self.fe1_pha_CT) self.femb.write_reg(22,self.fe2_sft_CT) self.femb.write_reg(30,self.fe2_pha_CT) self.femb.write_reg(23,self.fe3_sft_CT) self.femb.write_reg(31,self.fe3_pha_CT) self.femb.write_reg(24,self.fe4_sft_CT) self.femb.write_reg(32,self.fe4_pha_CT) self.femb.write_reg(25,self.fe5_sft_CT) self.femb.write_reg(33,self.fe5_pha_CT) self.femb.write_reg(26,self.fe6_sft_CT) self.femb.write_reg(34,self.fe6_pha_CT) self.femb.write_reg(27,self.fe7_sft_CT) self.femb.write_reg(35,self.fe7_pha_CT) self.femb.write_reg(28,self.fe8_sft_CT) self.femb.write_reg(36,self.fe8_pha_CT) self.femb.write_reg(8,0) self.femb.write_reg(8,0) time.sleep(0.02) self.femb.write_reg(8,0x10) self.femb.write_reg(8,0x10) #FEMB power enable on WIB def powerOnFemb(self,femb): fembVal = int(femb) if (fembVal < 0) or (fembVal > 3 ): return #set UDP ports to WIB registers self.wib_reg_enable() # read back existing power setting oldVal = self.femb.read_reg(8) #print("oldVal",oldVal) #FEMB power enable if(fembVal == 0): regVal = 0x31000F if(fembVal == 1): regVal = 0x5200F0 if(fembVal == 2): regVal = 0x940F00 if(fembVal == 3): regVal = 0x118F000 pwrVal = regVal | oldVal self.femb.write_reg(8,0) time.sleep(1) self.femb.write_reg(8, pwrVal) time.sleep(2) regVal = self.femb.read_reg(8) if regVal == None: return print("FEMB Power on: ", hex(regVal)) #set UDP ports back to normal self.selectFemb(self.fembNum) def powerOffFemb(self,femb): fembVal = int(femb) if (fembVal < 0) or (fembVal > 3 ): return #set UDP ports to WIB registers self.wib_reg_enable() # read back existing power setting oldVal = self.femb.read_reg(8) regVal = 0 #FEMB power disable if(fembVal == 0 and (oldVal & 0xF) != 0): regVal = 0x31000F if(fembVal == 1 and (oldVal & 0xF0)>>4 != 0): regVal = 0x5200F0 if(fembVal == 2 and (oldVal & 0xF00)>>8 != 0): regVal = 0x940F00 if(fembVal == 3 and (oldVal & 0xF000)>>16 != 0): regVal = 0x118F000 pwrVal = 0x100000 | (regVal ^ oldVal) self.femb.write_reg(8, pwrVal) regVal = self.femb.read_reg(8) if regVal == None: return print("FEMB Power off: ", hex(regVal)) #set UDP ports back to normal self.selectFemb(self.fembNum) def selectChannel(self,asic,chan): #print("Select channel") asicVal = int(asic) if (asicVal < 0 ) or (asicVal > self.NASICS): return #print("asicVal",asicVal) fembVal = self.fembNum #print("fembVal",fembVal) #set UDP ports to WIB self.wib_reg_enable() # start streaming data from ASIC 0 in initialization self.femb.write_reg(7, 0x80000000) self.femb.write_reg(7, 0x80000000) femb_asic = asicVal & 0x0F wib_asic = (((fembVal << 16)&0x000F0000) + ((femb_asic << 8) &0xFF00)) self.femb.write_reg(7, wib_asic | 0x80000000) self.femb.write_reg(7, wib_asic | 0x80000000) self.femb.write_reg(7, wib_asic) self.femb.write_reg(7, wib_asic) #select ASIC #print("Selecting ASIC " + str(asicVal) ) self.femb.write_reg_bits(self.REG_SEL_ASIC , self.REG_SEL_ASIC_LSB, 0xF, asicVal ) #Note: WIB data format streams all 16 channels, don't need to select specific channel # return to FEMB control self.selectFemb(fembVal) #Enable Streaming self.femb.write_reg(9,9) self.femb.write_reg(9,9) time.sleep(0.1) def configFeAsic(self): print("CONFIG ASICs") # #global config varibles feasicLeakageVal = int( self.feasicLeakage ) #0 = 500pA, 1 = 100pA feasicLeakagex10Val = int( self.feasicLeakagex10 ) #0 = x1, 1 = x10 acdcVal = int( self.feasicAcdc ) #DC = 0, AC = 1 #channel specific variables testVal = int( self.feasicEnableTestInput ) baseVal = int( self.feasicBaseline ) #0 = 900mV, 1 = 200mV gainVal = int( self.feasicGain ) shapeVal = int( self.feasicShape ) bufVal = int( self.feasicBuf ) #0 = OFF, 1 = ON if (testVal < 0 ) or (testVal > 1): return if (baseVal < 0 ) or (baseVal > 1): return if (gainVal < 0 ) or (gainVal > 3): return if (shapeVal < 0 ) or (shapeVal > 3): return if (acdcVal < 0 ) or (acdcVal > 1): return if (bufVal < 0 ) or (bufVal > 1): return if (feasicLeakageVal < 0 ) or (feasicLeakageVal > 1 ): return if (feasicLeakagex10Val < 0) or (feasicLeakagex10Val > 1): return #gain gainArray = [0,2,1,3] #00=4.7, 10=7.8, 01=14, 11=25 gainValCorrect = gainArray[gainVal] #shape shapeArray = [2,0,3,1] #00=1.0, 10=0.5, 01=3.0, 11=2.0 shapeValCorrect = shapeArray[shapeVal] #datashift if self.isRoomTemp == True: self.femb.write_reg_bits(self.CLK_SELECT , 0, 0xFF, self.CLKSELECT_val_RT ) #clock select self.femb.write_reg_bits(self.CLK_SELECT2 , 0, 0xFF, self.CLKSELECT2_val_RT ) #clock select 2 else: self.femb.write_reg_bits(self.CLK_SELECT , 0, 0xFF, self.CLKSELECT_val_CT ) #clock select self.femb.write_reg_bits(self.CLK_SELECT2 , 0, 0xFF, self.CLKSELECT2_val_CT ) #clock select 2 self.femb.write_reg_bits(self.REG_LATCHLOC_3_TO_0 , 0, 0xFFFFFFFF, self.REG_LATCHLOC_3_TO_0_val ) self.femb.write_reg_bits(self.REG_LATCHLOC_7_TO_4 , 0, 0xFFFFFFFF, self.REG_LATCHLOC_7_TO_4_val ) #COTS Register Settings sts = testVal snc = baseVal sg = gainValCorrect st = shapeValCorrect smn = 0 #Output monitor enabled: not currently an option in femb_python so keep at 0 for now sdf = bufVal chn_reg = ((sts&0x01)<<7) + ((snc&0x01)<<6) + ((sg&0x03)<<4) + ((st&0x03)<<2) + ((smn&0x01)<<1) + ((sdf&0x01)<<0) #COTS Global Register Settings slk0 = feasicLeakageVal stb1 = 0 #Monitors not currently used in femb_python stb = 0 #Monitors not currently used in femb_python s16 = 0 #High filter in channel 16 disabled slk1 = feasicLeakagex10Val sdc = acdcVal swdac = 0 #For pulser, set elsewhere dac = 0 #For pulser, set elsewhere global_reg = ((slk0&0x01)<<0) + ((stb1&0x01)<<1) + ((stb&0x01)<<2)+ ((s16&0x01)<<3) + ((slk1&0x01)<<4) + ((sdc&0x01)<<5) +((00&0x03)<<6) dac_reg = (((dac&0x01)//0x01)<<7)+(((dac&0x02)//0x02)<<6)+\ (((dac&0x04)//0x04)<<5)+(((dac&0x08)//0x08)<<4)+\ (((dac&0x10)//0x10)<<3)+(((dac&0x20)//0x20)<<2)+\ (((swdac&0x03))<<0) for chip in range(self.NASICS): for chn in range(self.NASICCH): if self.useLArIATmap: key = "wib{:d}_femb{:d}_chip{:d}_chan{:02d}".format(self.wibNum,self.fembNum,chip+1,chn) #Note map has chips 1-8, not 0-7 if self.WireDict[key][0] == "X": snc = 0 #set baseline for collection elif self.WireDict[key][0] == "U": snc = 1 #set baseline for induction chn_reg = ((sts&0x01)<<7) + ((snc&0x01)<<6) + ((sg&0x03)<<4) + ((st&0x03)<<2) + ((smn&0x01)<<1) + ((sdf&0x01)<<0) #print("chip",chip,"channel",chn,"chn_reg",hex(chn_reg)) chn_reg_bool = [] for j in range(8): chn_reg_bool.append ( bool( (chn_reg>>j)%2 )) start_pos = (8*16+16)*chip + (16-chn)*8 self.fe_regs[start_pos-8 : start_pos] = chn_reg_bool global_reg_bool = [] for j in range(8): global_reg_bool.append ( bool( (global_reg>>j)%2 ) ) for j in range(8): global_reg_bool.append ( bool( (dac_reg>>j)%2 ) ) start_pos = (8*16+16)*chip + 16*8 self.fe_regs[start_pos : start_pos+16] = global_reg_bool #Convert bits to 36 32-bit register words for chip in [0,2,4,6]: chip_bits_len = 8*(16+2) chip_fe_regs0 = self.fe_regs[ chip*chip_bits_len: (chip+1)* chip_bits_len] chip_fe_regs1 = self.fe_regs[ (chip+1)*chip_bits_len: (chip+2)* chip_bits_len] chip_regs = [] for onebit in chip_fe_regs0: chip_regs.append(onebit) for onebit in chip_fe_regs1: chip_regs.append(onebit) len32 = len(chip_regs)//32 if (len32 != 9): print("ERROR FE register mapping") else: for i in range(len32): if ( i*32 <= len(chip_regs) ): bits32 = chip_regs[i*32: (i+1)*32] self.fe_REGS[int(chip/2*len32 + i) ] = (sum(v<<j for j, v in enumerate(bits32))) #turn off HS data before register writes self.femb.write_reg_bits(9 , 0, 0x1, 0 ) print("HS link turned off") time.sleep(1) #run the SPI programming self.doAsicConfig() #turn HS link back on print("HS link turned back on") self.femb.write_reg_bits(9 , 0, 0x1, 1 ) time.sleep(1) def doAsicConfig(self): print("Program ASIC SPI") for k in range(2): #Disable streaming self.femb.write_reg(9, 0x0) time.sleep(0.01) i = 0 for regNum in range(self.REG_SPI_BASE,self.REG_SPI_BASE+len(self.fe_REGS),1): self.femb.write_reg( regNum, self.fe_REGS[i]) self.femb.write_reg( regNum+36, self.fe_REGS[i]) i += 1 time.sleep(0.01) self.femb.write_reg( self.REG_ASIC_SPIPROG, 1) #self.printParameters() #Enable streaming self.femb.write_reg(9, 9) self.femb.write_reg(9, 9) time.sleep(0.1) def selectFemb(self, fembIn): fembVal = int( fembIn) if (fembVal < 0) or (fembVal > self.NFEMBS ): print("Invalid FEMB # requested") return self.fembNum = fembVal #print("selecting FEMB",fembVal) #set read/write ports if fembVal == 0: self.femb.UDP_PORT_WREG = 32016 self.femb.UDP_PORT_RREG = 32017 self.femb.UDP_PORT_RREGRESP = 32018 if fembVal == 1: self.femb.UDP_PORT_WREG = 32032 self.femb.UDP_PORT_RREG = 32033 self.femb.UDP_PORT_RREGRESP = 32034 if fembVal == 2: self.femb.UDP_PORT_WREG = 32048 self.femb.UDP_PORT_RREG = 32049 self.femb.UDP_PORT_RREGRESP = 32050 if fembVal == 3: self.femb.UDP_PORT_WREG = 32064 self.femb.UDP_PORT_RREG = 32065 self.femb.UDP_PORT_RREGRESP = 32066 #self.femb.write_reg(0, femb_asic) self.femb.write_reg(self.REG_HS,1) #slow down register interface for FEMBs self.femb.REG_SLEEP = 0.05 time.sleep(0.1) def setFpgaPulser(self,enable,dac): enableVal = int(enable) print("set FPGA pulser",enableVal) if (enableVal < 0 ) or (enableVal > 1 ) : print( "femb_config_femb : setFpgaPulser - invalid enable value") return dacVal = int(dac) if ( dacVal < 0 ) or ( dacVal > 0x3F ) : print( "femb_config_femb : setFpgaPulser - invalid dac value") return self.femb.write_reg_bits( self.REG_FPGA_TP_EN, 0,0x3,enableVal) #test pulse enable self.femb.write_reg_bits( self.REG_FPGA_TP_EN, 8,0x1,enableVal) #test pulse enable self.femb.write_reg_bits( self.REG_TP , 0, 0x3F, dacVal ) #TP Amplitude self.femb.write_reg_bits( self.REG_TP , 8, 0xFF, 219 ) #DLY self.femb.write_reg_bits( self.REG_TP , 16, 0xFFFF, 497 ) #FREQ #set pulser enable bit if enableVal == 1 : self.femb.write_reg( self.EXT_TP_EN, 0x2) #this register is confusing, check else : self.femb.write_reg( self.EXT_TP_EN, 0x3) #pulser disabled #connect channel test input to external pin firstfourasics = int(self.NASICS/2) for asic in range(0,firstfourasics,1): baseReg = int(asic)*9 self.fe_REGS[baseReg+4] = self.fe_REGS[baseReg+4] & 0xFFFF0000 self.fe_REGS[baseReg+8] = self.fe_REGS[baseReg+8] & 0x0000FFFF if enableVal == 1: self.fe_REGS[baseReg+4] = self.fe_REGS[baseReg+4] | 0x2<<8 self.fe_REGS[baseReg+8] = self.fe_REGS[baseReg+8] | 0x2<<24 self.doAsicConfig() def setInternalPulser(self,enable,dac): enableVal = int(enable) print("set ASIC pulser",enableVal) if (enableVal < 0 ) or (enableVal > 1 ) : print( "femb_config_femb : setInternalPulser - invalid enable value") return dacVal = int(dac) if ( dacVal < 0 ) or ( dacVal > 0x3F ) : print( "femb_config_femb : setInternalPulser - invalid dac value") return self.femb.write_reg_bits( self.REG_DAC_SELECT, 8, 0x1, 0) #test pulse enable self.femb.write_reg_bits( self.REG_TP , 0, 0x3F, 0 ) #TP Amplitude self.femb.write_reg_bits( self.REG_TP , 8, 0xFF, 219 ) #DLY self.femb.write_reg_bits( self.REG_TP , 16, 0xFFFF, 497 ) #FREQ #set pulser enable bit if enableVal == 1 : self.femb.write_reg( self.INT_TP_EN, 0x2) #this register is confusing, check else : self.femb.write_reg( self.INT_TP_EN, 0x3) #pulser disabled dacVal = (dacVal & 0x3F) newDacVal = int('{:08b}'.format(dacVal)[::-1], 2) asicWord = ((newDacVal << 8 ) & 0xFFFF) if enableVal == 1 : asicWord = asicWord + (0x1 << 8) #print(hex(asicWord)) #connect channel test input to external pin firstfourasics = int(self.NASICS/2) for asic in range(0,firstfourasics,1): baseReg = int(asic)*9 self.fe_REGS[baseReg+4] = self.fe_REGS[baseReg+4] & 0xFFFF0000 self.fe_REGS[baseReg+8] = self.fe_REGS[baseReg+8] & 0x0000FFFF if enableVal == 1: self.fe_REGS[baseReg+4] = self.fe_REGS[baseReg+4] | asicWord self.fe_REGS[baseReg+8] = self.fe_REGS[baseReg+8] | asicWord<<16 self.doAsicConfig() if enableVal == 1: self.femb.write_reg_bits( self.REG_ASIC_TP_EN , 0, 0x3, 0x2 ) #NOTE, also disabling FPGA pulser here else: self.femb.write_reg_bits( self.REG_ASIC_TP_EN , 0, 0x3, 0x0 ) def checkFirmwareVersion(self): #set UDP ports to WIB self.wib_reg_enable() #check WIB fw version reg wibVerReg = self.femb.read_reg(255) if wibVerReg == None : return False wibVerReg = (wibVerReg & 0xFFF) #set UDP ports back to normal self.selectFemb(self.fembNum) fembVerReg = self.femb.read_reg(257) if fembVerReg == None : return False fembVerReg = (fembVerReg & 0xFFF) if wibVerReg != 0x122 and wibVerReg != 0x111: print("Invalid WIB firmware version detected",hex(wibVerReg),"this configuration requires version 0x108 or 0x111") return False if fembVerReg != 0x501 : print("Invalid FEMB firmware version detected",hex(fembVerReg),"this configuration requires version 0x501") return False print( "WIB Firmware Version: " + str(hex(wibVerReg)) ) print( "FEMB Firmware Version: " + str(hex(fembVerReg)) ) #good firmware id return True def readCurrent(self): self.femb.UDP_PORT_WREG = 32000 #WIB PORTS self.femb.UDP_PORT_RREG = 32001 self.femb.UDP_PORT_RREGRESP = 32002 for j in range(0,100): self.femb.write_reg(5,0) self.femb.write_reg(5,0x10000) self.femb.write_reg(5,0) time.sleep(0.01) results = [] for pwrSel in range(1,25): self.femb.write_reg(5,pwrSel) time.sleep(0.1) regVal = self.femb.read_reg(6) if regVal == None: results.append(0) continue #return None val = regVal & 0xFFFFFFFF results.append(val) self.selectFemb(0) return results
class FEMB_CONFIG(FEMB_CONFIG_BASE): #__INIT__# def __init__(self): #set up UDP interface self.femb = FEMB_UDP() def initBoard(self): print("\nInitializing board and checking register interface\n") #check if FEMB register interface is working regVal = self.femb.read_reg(257) if regVal == None: print( "Error!! FEMB register interface is not working, will not initialize FEMB." ) print("Is the power supply turned on?\n") sys.exit(1) #check WIB fw version reg firmwareVerReg = (regVal & 0xFFF) if firmwareVerReg != 0x102: print( 'Error initializing board!! Invalid firmware and/or register read error.\n' ) sys.exit(1) def readStatus(self, epcsNum=0): #EPCS OP Code op_reg = 1 + 3 * epcsNum #EPCS Status status_reg = 3 + 3 * epcsNum #set status op code self.femb.write_reg(op_reg, 0x5) #start EPCS operation self.femb.write_reg(op_reg, 0x105) time.sleep(0.1) #stop EPCS operation self.femb.write_reg(op_reg, 0x5) #read status bit statusVal = self.femb.read_reg(status_reg) if statusVal == None: print("Error!! Status is None.") return return statusVal def readFlash(self, epcsNum=0, pageNum=0): #EPCS OP Code op_reg = 1 + 3 * epcsNum #EPCS address addr_reg = 2 + 3 * epcsNum read_base = 512 + 256 * epcsNum #set page to read self.femb.write_reg(addr_reg, 256 * pageNum) #1 page = 256 byte #read bytes op code self.femb.write_reg(op_reg, 0x3) #start EPCS operation self.femb.write_reg(op_reg, 0x103) time.sleep(0.1) self.femb.write_reg(op_reg, 0x3) #read the value outputData = [] for reg in range(read_base + 64, read_base + 64 + 64, 1): regVal = self.femb.read_reg(reg) if regVal == None: print("Error!! Read value is None, will continue") continue outputData.append(regVal) return outputData def eraseFlash(self, epcsNum=0): print("Erasing flash %s" % (epcsNum)) #EPCS OP Code op_reg = 1 + 3 * epcsNum #write enable self.femb.write_reg(op_reg, 0x6) self.femb.write_reg(op_reg, 0x106) time.sleep(0.1) self.femb.write_reg(op_reg, 0x6) #erase bulk self.femb.write_reg(op_reg, 0xC7) self.femb.write_reg(op_reg, 0x1C7) time.sleep(0.1) self.femb.write_reg(op_reg, 0xC7) def programFlash(self, epcsNum=0, pageNum=0, inputData=None): #EPCS OP Code op_reg = 1 + 3 * epcsNum #EPCS address addr_reg = 2 + 3 * epcsNum #EPCS Status status_reg = 3 + 3 * epcsNum write_base = 512 + 256 * epcsNum count = 0 for reg in range(write_base, write_base + 64, 1): self.femb.write_reg(reg, inputData[count]) count += 1 #Set write enable self.femb.write_reg(op_reg, 0x6) self.femb.write_reg(op_reg, 0x106) time.sleep(0.1) self.femb.write_reg(op_reg, 0x6) #set page to write self.femb.write_reg(addr_reg, 256 * pageNum) #write bytes self.femb.write_reg(op_reg, 0x2) self.femb.write_reg(op_reg, 0x102) time.sleep(0.1) self.femb.write_reg(op_reg, 0x2)
class FEMB_CONFIG(FEMB_CONFIG_BASE): def __init__(self): super().__init__() #declare board specific registers self.FEMB_VER = "adctest" self.REG_RESET = 0 self.REG_ASIC_RESET = 1 self.REG_ASIC_SPIPROG = 2 self.REG_SEL_ASIC = 7 self.REG_SEL_CH = 7 self.REG_FESPI_BASE = 592 self.REG_ADCSPI_BASE = 512 self.REG_FESPI_RDBACK_BASE = 632 self.REG_ADCSPI_RDBACK_BASE = 552 self.REG_HS = 17 self.REG_LATCHLOC = 4 self.REG_CLKPHASE = 6 #Latch latency 0x6666666f Phase 0xffff0055 self.ADC_TESTPATTERN = [ 0x12, 0x345, 0x678, 0xf1f, 0xad, 0xc01, 0x234, 0x567, 0x89d, 0xeca, 0xff0, 0x123, 0x456, 0x789, 0xabc, 0xdef ] self.NASICS = 1 self.FUNCGENINTER = RigolDG4000("/dev/usbtmc1", 1) self.POWERSUPPLYINTER = RigolDP800("/dev/usbtmc0", ["CH1"]) self.F2DEFAULT = 0 self.CLKDEFAULT = "fifo" #initialize FEMB UDP object self.femb = FEMB_UDP() self.adc_reg = ADC_ASIC_REG_MAPPING() def resetBoard(self): #Reset system self.femb.write_reg(self.REG_RESET, 1) time.sleep(5.) #Reset registers self.femb.write_reg(self.REG_RESET, 2) time.sleep(1.) #Time stamp reset #femb.write_reg( 0, 4) #time.sleep(0.5) #Reset ADC ASICs self.femb.write_reg(self.REG_ASIC_RESET, 1) time.sleep(0.5) def initBoard(self): nRetries = 5 for iRetry in range(nRetries): #set up default registers #Reset ADC ASICs self.femb.write_reg(self.REG_ASIC_RESET, 1) time.sleep(0.5) #Set ADC test pattern register self.femb.write_reg(3, 0x01230000) # test pattern off #self.femb.write_reg( 3, 0x81230000) # test pattern on #Set ADC latch_loc self.femb.write_reg(self.REG_LATCHLOC, 0x66666667) #Set ADC clock phase self.femb.write_reg(self.REG_CLKPHASE, 0xfffc0054) #internal test pulser control self.femb.write_reg(5, 0x00000000) self.femb.write_reg(13, 0x0) #enable #Set test and readout mode register self.femb.write_reg( 7, 0x0000) #11-8 = channel select, 3-0 = ASIC select #Set number events per header self.femb.write_reg(8, 0x0) #ADC ASIC SPI registers print("Config ADC ASIC SPI") print("ADCADC") ## Corresponds to f0=f1=0, clk=0,clk1=1, pcsr=pdsr=frqc=1, tstin=1 ## en_gr=0, slp=0 ## Clocks from digital generator of FIFO regs = [ 0xC0C0C0C, 0xC0C0C0C, 0xC0C0C0C, 0xC0C0C0C, 0xC0C0C0C, 0xC0C0C0C, 0xC0C0C0C, 0xC0C0C0C, 0x18321832, 0x18181819, 0x18181818, 0x18181818, 0x18181818, 0x18181818, 0x18181818, 0x18181818, 0x64186418, 0x30303030, 0x30303030, 0x30303030, 0x30303030, 0x30303030, 0x30303030, 0x30303030, 0x30303030, 0x60c868c8, 0x60606868, 0x60606868, 0x60606868, 0x60606868, 0x60606868, 0x60606868, 0x60606868, 0x9060A868, 0x10001, ] self.adc_reg.set_sbnd_board(frqc=1, pdsr=1, pcsr=1, clk0=0, clk1=1, f1=0, f2=0, tstin=1) regs = self.adc_reg.REGS for iReg, val in enumerate(regs): #print("{:032b}".format(val)) print("{:08x}".format(val)) self.femb.write_reg(self.REG_ADCSPI_BASE + iReg, val) #ADC ASIC sync self.femb.write_reg(17, 0x1) # controls HS link, 0 for on, 1 for off self.femb.write_reg(17, 0x0) # controls HS link, 0 for on, 1 for off #Write ADC ASIC SPI print("Program ADC ASIC SPI") self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) time.sleep(0.1) self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) time.sleep(0.1) print("Check ADC ASIC SPI") for regNum in range(self.REG_ADCSPI_RDBACK_BASE, self.REG_ADCSPI_RDBACK_BASE + 34, 1): val = self.femb.read_reg(regNum) #print("{:08x}".format(val)) #enable streaming #self.femb.write_reg( 9, 0x8) #LBNE_ADC_MODE self.femb.write_reg(16, 0x1) # Check that board streams data data = self.femb.get_data(1) if data == None: print("Board not streaming data, retrying initialization...") continue # try initializing again print("FEMB_CONFIG--> Reset FEMB is DONE") return print( "Error: Board not streaming data after trying to initialize {} times. Exiting." .format(nRetries)) sys.exit(1) def configAdcAsic_regs(self, Adcasic_regs): #ADC ASIC SPI registers print("FEMB_CONFIG--> Config ADC ASIC SPI") for k in range(10): i = 0 for regNum in range(self.REG_ADCSPI_BASE, self.REG_ADCSPI_BASE + len(Adcasic_regs), 1): #print("{:032b}".format(Adcasic_regs[i])) print("{:08x}".format(Adcasic_regs[i])) self.femb.write_reg(regNum, Adcasic_regs[i]) time.sleep(0.05) i = i + 1 #print(" ADC ASIC write : ",Adcasic_regs) #ADC ASIC sync self.femb.write_reg(17, 0x1) # controls HS link, 0 for on, 1 for off self.femb.write_reg(17, 0x0) # controls HS link, 0 for on, 1 for off #Write ADC ASIC SPI print("FEMB_CONFIG--> Program ADC ASIC SPI") self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) time.sleep(0.1) self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) time.sleep(0.1) #self.femb.write_reg ( 18, 0x0) #time.sleep(0.1) #LBNE_ADC_MODE self.femb.write_reg(16, 0x1) print("FEMB_CONFIG--> Check ADC ASIC SPI") adcasic_rb_regs = [] for regNum in range( self.REG_ADCSPI_RDBACK_BASE, self.REG_ADCSPI_RDBACK_BASE + len(Adcasic_regs), 1): val = self.femb.read_reg(regNum) #print("{:08x}".format(val)) adcasic_rb_regs.append(val) #print(" ADC ASIC read back: ",adcasic_rb_regs) #if (adcasic_rb_regs !=Adcasic_regs ) : # #if ( k == 1 ): # # sys.exit("femb_config : Wrong readback. ADC SPI failed") # # return # print("FEMB_CONFIG--> ADC ASIC Readback didn't match, retrying...") #else: if True: print("FEMB_CONFIG--> ADC ASIC SPI is OK") break #enable streaming #self.femb.write_reg ( 9, 0x8) #LBNE_ADC_MODE def configAdcAsic(self, enableOffsetCurrent=None, offsetCurrent=None, testInput=None, freqInternal=None, sleep=None, pdsr=None, pcsr=None, clockMonostable=None, clockExternal=None, clockFromFIFO=None, sLSB=None, f0=0, f1=0, f2=0, f3=None, f4=None, f5=None): """ Configure ADCs enableOffsetCurrent: 0 disable offset current, 1 enable offset current offsetCurrent: 0-15, amount of current to draw from sample and hold testInput: 0 digitize normal input, 1 digitize test input freqInternal: internal clock frequency: 0 1MHz, 1 2MHz sleep: 0 disable sleep mode, 1 enable sleep mode pdsr: if pcsr=0: 0 PD is low, 1 PD is high pcsr: 0 power down controlled by pdsr, 1 power down controlled externally Only one of these can be enabled: clockMonostable: True ADC uses monostable clock clockExternal: True ADC uses external clock clockFromFIFO: True ADC uses digital generator FIFO clock sLSB: LSB current steering mode. 0 for full, 1 for partial (ADC7 P1) f0, f1, f2, f3, f4, f5: version specific """ FEMB_CONFIG_BASE.configAdcAsic(self, clockMonostable=clockMonostable, clockExternal=clockExternal, clockFromFIFO=clockFromFIFO) if enableOffsetCurrent is None: enableOffsetCurrent = 0 if offsetCurrent is None: offsetCurrent = 0 else: offsetCurrent = int( "{:04b}".format(offsetCurrent)[::-1], 2) # need to reverse bits, use string/list tricks if testInput is None: testInput = 1 if freqInternal is None: freqInternal = 1 if sleep is None: sleep = 0 if pdsr is None: pdsr = 1 if pcsr is None: pcsr = 1 if not (clockMonostable or clockExternal or clockFromFIFO): clockFromFIFO = True clk0 = 0 clk1 = 0 if clockExternal: clk0 = 1 clk1 = 0 elif clockFromFIFO: clk0 = 0 clk1 = 1 self.adc_reg.set_sbnd_board(en_gr=enableOffsetCurrent, d=offsetCurrent, tstin=testInput, frqc=freqInternal, slp=sleep, pdsr=pdsr, pcsr=pcsr, clk0=clk0, clk1=clk1, f1=f1, f2=f2, res2=0, res1=1, res0=1) self.configAdcAsic_regs(self.adc_reg.REGS) #regs = [ # 0xC0C0C0C, # 0xC0C0C0C, # 0xC0C0C0C, # 0xC0C0C0C, # 0xC0C0C0C, # 0xC0C0C0C, # 0xC0C0C0C, # 0xC0C0C0C, # 0x18321832, # 0x18181818, # 0x18181818, # 0x18181818, # 0x18181818, # 0x18181818, # 0x18181818, # 0x18181818, # 0x64186418, # 0x30303030, # 0x30303030, # 0x30303030, # 0x30303030, # 0x30303030, # 0x30303030, # 0x30303030, # 0x30303030, # 0x60c868c8, # 0x60606868, # 0x60606868, # 0x60606868, # 0x60606868, # 0x60606868, # 0x60606868, # 0x60606868, # 0x9060A868, # 0x10001, #] #self.configAdcAsic_regs(regs) def selectChannel(self, asic, chan, hsmode=None): asicVal = int(asic) if (asicVal < 0) or (asicVal >= self.NASICS): print( "femb_config_femb : selectChan - invalid ASIC number, only 0 to {} allowed" .format(self.NASICS - 1)) return chVal = int(chan) if (chVal < 0) or (chVal > 15): print( "femb_config_femb : selectChan - invalid channel number, only 0 to 15 allowed" ) return #print( "Selecting ASIC " + str(asicVal) + ", channel " + str(chVal)) regVal = (chVal << 8) + asicVal self.femb.write_reg(self.REG_SEL_CH, regVal) def syncADC(self): #turn on ADC test mode print("Start sync ADC") reg3 = self.femb.read_reg(3) newReg3 = (reg3 | 0x80000000) self.femb.write_reg(3, newReg3) #31 - enable ADC test pattern alreadySynced = True for a in range(0, self.NASICS, 1): print("Test ADC " + str(a)) unsync = self.testUnsync(a) if unsync != 0: alreadySynced = False print("ADC not synced, try to fix") self.fixUnsync(a) LATCH = self.femb.read_reg(self.REG_LATCHLOC) PHASE = self.femb.read_reg(self.REG_CLKPHASE) self.femb.write_reg(3, reg3) # turn off adc test pattern self.femb.write_reg(3, reg3) # turn off adc test pattern print("Latch latency {:#010x} Phase: {:#010x}".format(LATCH, PHASE)) print("End sync ADC") return not alreadySynced, LATCH, None, PHASE def testUnsync(self, adc): adcNum = int(adc) if (adcNum < 0) or (adcNum >= self.NASICS): print("femb_config_femb : testLink - invalid asic number") return #loop through channels, check test pattern against data badSync = 0 for ch in range(0, 16, 1): self.selectChannel(adcNum, ch) time.sleep(0.1) for test in range(0, 1000, 1): data = self.femb.get_data(1) for samp in data: chNum = ((samp >> 12) & 0xF) sampVal = (samp & 0xFFF) if sampVal != self.ADC_TESTPATTERN[ch]: badSync = 1 if badSync == 1: break if badSync == 1: break if badSync == 1: break return badSync def fixUnsync(self, adc): adcNum = int(adc) if (adcNum < 0) or (adcNum >= self.NASICS): print("femb_config_femb : testLink - invalid asic number") return initLATCH = self.femb.read_reg(self.REG_LATCHLOC) initPHASE = self.femb.read_reg(self.REG_CLKPHASE) #loop through sync parameters for phase in range(0, 2, 1): clkMask = (0x1 << adcNum) testPhase = ((initPHASE & ~(clkMask)) | (phase << adcNum)) self.femb.write_reg(self.REG_CLKPHASE, testPhase) for shift in range(0, 16, 1): shiftMask = (0xF << 4 * adcNum) testShift = ((initLATCH & ~(shiftMask)) | (shift << 4 * adcNum)) self.femb.write_reg(self.REG_LATCHLOC, testShift) #reset ADC ASIC self.femb.write_reg(self.REG_ASIC_RESET, 1) time.sleep(0.1) self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) time.sleep(0.1) self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) time.sleep(0.1) #test link unsync = self.testUnsync(adcNum) if unsync == 0: print("ADC synchronized") return #if program reaches here, sync has failed print("ADC SYNC process failed for ADC # " + str(adc))
class FEMB_CONFIG(FEMB_CONFIG_BASE): def __init__(self,exitOnError=True): super().__init__(exitOnError=exitOnError) #declare board specific registers self.FEMB_VER = "adctestP1single" self.REG_RESET = 0 self.REG_ASIC_RESET = 1 self.REG_ASIC_SPIPROG = 2 self.REG_SEL_CH = 7 self.REG_HS = 17 self.REG_FESPI_BASE = 0x250 # 592 in decimal self.REG_ADCSPI_BASE = 0x200 # 512 in decimal self.REG_FESPI_RDBACK_BASE = 0x278 # 632 in decimal self.REG_ADCSPI_RDBACK_BASE = 0x228 # 552 in decimal self.REG_LATCHLOC1_4 = 4 self.REG_LATCHLOC5_8 = 14 self.REG_CLKPHASE = 6 self.REG_LATCHLOC1_4_data = 0x6 self.REG_LATCHLOC5_8_data = 0x0 self.REG_CLKPHASE_data = 0xfffc0000 self.REG_LATCHLOC1_4_data_1MHz = 0x5 self.REG_LATCHLOC5_8_data_1MHz = 0x0 self.REG_CLKPHASE_data_1MHz = 0xffff0000 self.REG_LATCHLOC1_4_data_cold = 0x6 self.REG_LATCHLOC5_8_data_cold = 0x0 self.REG_CLKPHASE_data_cold = 0xfffc0000 self.REG_LATCHLOC1_4_data_1MHz_cold = 0x4 self.REG_LATCHLOC5_8_data_1MHz_cold = 0x0 self.REG_CLKPHASE_data_1MHz_cold = 0xfffc0001 self.ADC_TESTPATTERN = [0x12, 0x345, 0x678, 0xf1f, 0xad, 0xc01, 0x234, 0x567, 0x89d, 0xeca, 0xff0, 0x123, 0x456, 0x789, 0xabc, 0xdef] ################################## # external clock control registers ################################## self.FPGA_FREQ_MHZ = 200 # frequency of FPGA clock in MHz self.REG_EXTCLK_RD_EN_OFF = 23 self.REG_EXTCLK_ADC_OFF = 21 self.REG_EXTCLK_ADC_WID = 22 self.REG_EXTCLK_MSB_OFF = 25 self.REG_EXTCLK_MSB_WID = 26 self.REG_EXTCLK_PERIOD = 20 self.REG_EXTCLK_LSB_FC_WID2 = 32 self.REG_EXTCLK_LSB_FC_OFF1 = 29 self.REG_EXTCLK_RD_EN_WID = 24 self.REG_EXTCLK_LSB_FC_WID1 = 30 self.REG_EXTCLK_LSB_FC_OFF2 = 31 self.REG_EXTCLK_LSB_S_WID = 28 self.REG_EXTCLK_LSB_S_OFF = 27 self.REG_EXTCLK_INV = 33 ################################## ################################## self.NASICS = 1 self.FUNCGENINTER = Keysight_33600A("/dev/usbtmc1",1) self.POWERSUPPLYINTER = RigolDP800("/dev/usbtmc0",["CH2","CH3","CH1"]) # turn on CH2 first self.F2DEFAULT = 0 self.CLKDEFAULT = "fifo" ## Firmware update related variables self.FIRMWAREPATH2MHZ = "/home/oper/Documents/CarlosForkedRepo/femb_python/femb_python/test_measurements/adc_clock_test/code/S_SKT_ADC_CHP_TST.sof" #self.FIRMWAREPATH1MHZ = "/opt/sw/releases/femb_firmware-0.1.0/adc_tester/S7_1M_SBND_FPGA.sof" self.FIRMWAREPROGEXE = "/opt/sw/intelFPGA/17.0/qprogrammer/bin/quartus_pgm" #self.FIRMWAREPROGCABLE = "USB-Blaster" self.FIRMWAREPROGCABLE = "USB-BlasterII" self.SAMPLERATE = 2e6 #initialize FEMB UDP object self.femb = FEMB_UDP() self.adc_reg = ADC_ASIC_REG_MAPPING() def resetFEMBBoard(self): #cp 1/17/18 # # resetFEMBBoard() # sends a 1 to register 1 for "instantaneous" ASIC reset. # sends a 0 to register 1 to ensure reset is not locked in. # # procedure: # line 29: FPGA to ASIC reset # line 30: wait 5 ms # line 31: FPGA to ASIC disable reset # print (" FEMB_CONFIG--> Reset FEMB (10 seconds) --") #Reset FEMB system self.femb.write_reg ( self.REG_RESET, 1) time.sleep(5.) self.femb.write_reg ( self.REG_RESET, 0) time.sleep(2.) print (" FEMB_CONFIG--> Reset FEMB is DONE\n") def initBoard(self): """ % initBoard() % set up default registers. % first wave in setting clock settings. """ print ("FEMB_CONFIG--> initBoard() -> Initialize FEMB --") # Frame size is multiple of 13, so 0xFACE is consistently the first 2 bytes. frame_size = settings.frame_size if (frame_size%13 != 0): frame_size = 13 * (frame_size//13) self.femb.write_reg(10, frame_size) time.sleep(0.1) if (self.femb.read_reg(10) != frame_size): sys.exit("FEMB_CONFIG--> initBoard() -> Frame Size not set correctly, something wrong with FPGA communication") print ("FEMB_CONFIG--> initBoard() -> Chip tester version {}".format(hex(self.femb.read_reg(0x101)))) # Set to WIB Mode and start by reading out chip 1 # Channel Setting is irrelevant in WIB mode self.femb.write_reg(8, 0x80000001) # WIB_MODE <= reg8_p(0) self.femb.write_reg(7, 0x80000000) # CHN_select <= reg7_p(7 downto 0) """ SHIFT DATA BUS """ # LATCH_LOC_0 <= reg4_p(7 downto 0) self.femb.write_reg(settings.LATCHLOC_reg, settings.LATCHLOC_data) """ SHIFT DATA BUS """ # CLK_selectx <= reg6_p(7 downto 0) self.femb.write_reg(settings.CLKPHASE_reg, settings.CLKPHASE_data) # self.femb.write_reg( 9, 0) # Write Coarse Clock Control self.femb.write_reg(21, settings.reg21_value[0]) self.femb.write_reg(21, settings.reg21_value[1]) self.femb.write_reg(21, settings.reg21_value[2]) self.femb.write_reg(21, settings.reg21_value[3]) self.femb.write_reg(21, settings.reg21_value[4]) self.femb.write_reg(21, settings.reg21_value[5]) self.femb.write_reg(22, settings.reg22_value[0]) # RESET Offset self.femb.write_reg(23, settings.reg23_value[0]) # RESET Width self.femb.write_reg(24, settings.reg24_value[0]) # READ Offset self.femb.write_reg(25, settings.reg25_value[0]) # READ Width self.femb.write_reg(26, settings.reg26_value[0]) # IDXM Offset self.femb.write_reg(27, settings.reg27_value[0]) # IDXM Width self.femb.write_reg(28, settings.reg28_value[0]) # IDXL Offset self.femb.write_reg(29, settings.reg29_value[0]) # IDXL Width self.femb.write_reg(30, settings.reg30_value[0]) # IDL1 Offset self.femb.write_reg(31, settings.reg31_value[0]) # IDL1 Width self.femb.write_reg(32, settings.reg32_value[0]) # IDL2 Offset self.femb.write_reg(33, settings.reg33_value[0]) # IDL2 Width #Fine Control self.femb.write_reg(34, settings.reg34_value[0]) # C0 & C1 fine clock settings self.femb.write_reg(35, settings.reg35_value[0]) # C2 & C3 fine clock settings self.femb.write_reg(36, settings.reg36_value[0]) # C2 & C3 fine clock settings #set default value to FEMB ADCs #clk = 2 is external #clk = 0 is internal self.adc_reg.set_adc_board( d=0, pcsr=0, pdsr=0, slp=0, tstin=1, clk = 0, frqc = 1, en_gr = 0, f0 = 0, f1 = 0, f2 = 0, f3 = 0, f4 = 0, f5 = 1, slsb = 0) # set to internal 1/31/18 cp self.femb.write_reg ( self.REG_ASIC_SPIPROG, 0x30) self.femb.write_reg ( self.REG_ASIC_SPIPROG, 0) self.configAdcAsic() print (" FEMB_CONFIG--> initBOARD() -> Initialize FEMB is DONE\n") """ def syncADC(self): # syncADC() # # procedures: # 1. set channel/global registers ensure F5=1, so # test data is selected and pipelined. Just as # in labview. # 2. configure ADC ASIC # 3. print ("\n FEMB_CONFIG--> Start sync ADC--") self.select_chn(1) # channel 0 & write clocks self.select_chn(3) # channel 0 & write clocks self.select_chn(1) # channel 0 & write clocks self.adc_reg.set_adc_global(chip = settings.chip_num, f5 = 1) # Test DATA self.configAdcAsic() print (" FEMB_CONFIG --> syncADC() -> Test ADC {}".format(settings.chip_num)) print (" FEMB_CONFIG --> syncADC() -> self.adc_reg.set_adc_global() \n") # for i in range(10,20,1): # print ("Register {} {}".format(i, hex(self.femb.read_reg(i)))) unsync = self.testUnsyncNew(settings.chip_num) if unsync != True: print (" FEMB_CONFIG --> ADC {} not synced, try to fix".format(settings.chip_num)) response = self.fixUnsyncNew(a) if (response != True): sys.exit (" FEMB_CONFIG --> ADC {} could not sync".format(settings.chip_num)) elif (unsync == True): print ("FEMB_CONFIG--> ADC {} synced!".format(settings.chip_num)) self.adc_reg.set_adc_global(chip = settings.chip_num, f5 = 1) self.configAdcAsic() self.REG_LATCHLOC1_4_data = self.femb.read_reg( settings.LATCHLOC_reg) self.REG_CLKPHASE_data = self.femb.read_reg( settings.CLKPHASE_reg) print ("FEMB_CONFIG--> Final Latch latency " + str(hex(self.REG_LATCHLOC1_4_data))) print ("FEMB_CONFIG--> Final Phase Shift " + str(hex(self.REG_CLKPHASE_data))) self.FinalSyncCheck() print ("FEMB_CONFIG--> ADC passed Sync Test!") """ def syncADC(self,iASIC=None): #turn on ADC test mode print("FEMB_CONFIG--> Start sync ADC") reg3 = self.femb.read_reg (3) newReg3 = ( reg3 | 0x80000000 ) self.femb.write_reg ( 3, newReg3 ) #31 - enable ADC test pattern time.sleep(0.1) alreadySynced = True for a in range(0,self.NASICS,1): print("FEMB_CONFIG--> Test ADC " + str(a)) unsync, syncDicts = self.testUnsync(a) if unsync != 0: alreadySynced = False print("FEMB_CONFIG--> ADC not synced, try to fix") self.fixUnsync(a) latchloc1_4 = self.femb.read_reg ( self.REG_LATCHLOC1_4 ) latchloc5_8 = self.femb.read_reg ( self.REG_LATCHLOC5_8 ) clkphase = self.femb.read_reg ( self.REG_CLKPHASE ) if self.SAMPLERATE == 1e6: if self.COLD: self.REG_LATCHLOC1_4_data_1MHz_cold = latchloc1_4 self.REG_LATCHLOC5_8_data_1MHz_cold = latchloc5_8 self.REG_CLKPHASE_data_1MHz_cold = clkphase else: self.REG_LATCHLOC1_4_data_1MHz = latchloc1_4 self.REG_LATCHLOC5_8_data_1MHz = latchloc5_8 self.REG_CLKPHASE_data_1MHz = clkphase else: # 2 MHz if self.COLD: self.REG_LATCHLOC1_4_data_cold = latchloc1_4 self.REG_LATCHLOC5_8_data_cold = latchloc5_8 self.REG_CLKPHASE_data_cold = clkphase else: self.REG_LATCHLOC1_4_data = latchloc1_4 self.REG_LATCHLOC5_8_data = latchloc5_8 self.REG_CLKPHASE_data = clkphase print("FEMB_CONFIG--> Latch latency {:#010x} {:#010x} Phase: {:#010x}".format(latchloc1_4, latchloc5_8, clkphase)) self.femb.write_reg ( 3, (reg3&0x7fffffff) ) self.femb.write_reg ( 3, (reg3&0x7fffffff) ) print("FEMB_CONFIG--> End sync ADC") return not alreadySynced,latchloc1_4,latchloc5_8 ,clkphase def testUnsync(self, adc, npackets=10): print("Starting testUnsync adc: ",adc) adcNum = int(adc) if (adcNum < 0 ) or (adcNum > 7 ): print("FEMB_CONFIG--> femb_config_femb : testLink - invalid asic number") return #loop through channels, check test pattern against data syncDataCounts = [{} for i in range(16)] #dict for each channel for ch in range(0,16,1): self.selectChannel(adcNum,ch, 1) time.sleep(0.05) data = self.femb.get_data(npackets) if data == None: continue for samp in data: if samp == None: continue #chNum = ((samp >> 12 ) & 0xF) sampVal = (samp & 0xFFF) if sampVal in syncDataCounts[ch]: syncDataCounts[ch][sampVal] += 1 else: syncDataCounts[ch][sampVal] = 1 # check jitter badSync = 0 maxCodes = [None]*16 syncDicts = [{}]*16 for ch in range(0,16,1): sampSum = 0 maxCode = None nMaxCode = 0 for code in syncDataCounts[ch]: nThisCode = syncDataCounts[ch][code] sampSum += nThisCode if nThisCode > nMaxCode: nMaxCode = nThisCode maxCode = code maxCodes[ch] = maxCode syncDicts[ch]["maxCode"] = maxCode syncDicts[ch]["nSamplesMaxCode"] = nMaxCode syncDicts[ch]["nSamples"] = sampSum syncDicts[ch]["zeroJitter"] = True if len(syncDataCounts[ch]) > 1: syncDicts[ch]["zeroJitter"] = False badSync = 1 diff = sampSum-nMaxCode frac = diff / float(sampSum) print("Sync Error: Jitter for Ch {:2}: {:8.4%} ({:5}/{:5})".format(ch,frac,diff,sampSum)) for ch in range(0,16,1): maxCode = maxCodes[ch] correctCode = self.ADC_TESTPATTERN[ch] syncDicts[ch]["data"] = True syncDicts[ch]["maxCodeMatchesExpected"] = True if maxCode is None: syncDicts[ch]["data"] = False badSync = 1 print("Sync Error: no data for ch {:2}".format(ch)) elif maxCode != correctCode: syncDicts[ch]["maxCodeMatchesExpected"] = True badSync = 1 print("Sync Error: mismatch for ch {:2}: expected {:#03x} observed {:#03x}".format(ch,correctCode,maxCode)) return badSync, syncDicts def selectChannel(self,asic,chan,hsmode=1,singlechannelmode=None): """ asic is chip number 0 to 7 chan is channel within asic from 0 to 15 hsmode: if 0 then streams all channels of a chip, if 1 only te selected channel. defaults to 1 singlechannelmode: not implemented """ hsmodeVal = int(hsmode) & 1; asicVal = int(asic) if (asicVal < 0 ) or (asicVal >= self.NASICS ) : print( "femb_config_femb : selectChan - invalid ASIC number, only 0 to {} allowed".format(self.NASICS-1)) return chVal = int(chan) if (chVal < 0 ) or (chVal > 15 ) : print("femb_config_femb : selectChan - invalid channel number, only 0 to 15 allowed") return #print( "Selecting ASIC " + str(asicVal) + ", channel " + str(chVal)) self.femb.write_reg ( self.REG_HS, hsmodeVal) regVal = (chVal << 8 ) + asicVal self.femb.write_reg( self.REG_SEL_CH, regVal) """ def testUnsyncNew(self, chip): print("\n FEMB_CONFIG --> testUnsyncNew() -> chip = {} --".format(chip)) adcNum = int(chip) if (adcNum < 0 ) or (adcNum > 3 ): print (" FEMB_CONFIG --> testUnsyncNew() -> Invalid asic number, must be between 0 and 3") return for j in range(100): #reset sync error self.femb.write_reg(11, 1) # ERROR_RESET <= reg11_p(0) time.sleep(0.01) self.femb.write_reg(11, 0) # ERROR_RESET <= reg11_p(0) time.sleep(0.01) if (chip == 0): conv_error = self.femb.read_reg(12) # reg12_i => x"" & CONV_ERROR header_error = self.femb.read_reg(13) # reg13_i => HDR2_ERROR & HDR1_ERROR # elif (chip == 1): # conv_error = self.femb.read_reg(50) # reg50_i => x"0000" & CONV_ERROR_1 # header_error = self.femb.read_reg(51) # reg51_i => HDR2_ERROR_2 & HDR1_ERROR_2 # elif (chip == 2): # conv_error = self.femb.read_reg(52) # header_error = self.femb.read_reg(53) # elif (chip == 3): # conv_error = self.femb.read_reg(54) # header_error = self.femb.read_reg(55) error = False if (conv_error != 0): # CONV_ERROR exists print (" FEMB_CONFIG --> testUnsyncNew() -> Convert error({})! Trial {}".format(hex(conv_error),j)) error = True else: print (" FEMB_CONFIG --> testUnsyncNew() -> No Convert Error ({}) Trial {}!".format(hex(conv_error),j)) #convert = 0 if (header_error != 0): # HEADER_ERROR exists print (" FEMB_CONFIG --> testUnsyncNew() -> Header error ({})!".format(hex(header_error))) error = True else: print (" FEMB_CONFIG --> testUnsyncNew() -> No Header Error({})! Trial {}".format(hex(header_error),j)) #not finding header if (error == False): #break loop if no error found print (" FEMB_CONFIG --> testUnsyncNew() -> Correct on Loop {} Trial {}".format(j,j)) break #return True elif (j > 30): print (" FEMB_CONFIG --> testUnsyncNew() -> Convert error({})! Trial {}".format(hex(conv_error),j)) print (" FEMB_CONFIG --> testUnsyncNew() -> Header error ({})! Trial {}".format(hex(header_error),j)) #sync_status = self.femb.read_reg(self.REG_ASIC_SPIPROG) >> 24 #print ("FEMB_CONFIG--> Register 2 Sync status is {}".format(hex(sync_status))) return False else: self.configAdcAsic(False) #print ("Loop {}".format(j)) for ch in range(0,16,1): for test in range(0,200,1): data = self.get_data_chipXchnX(chip = adcNum, chn = ch, packets = 1)#issue here? #print("unsyncNew data -> {}".format(data)) if (len(data) == 0): print (" FEMB_CONFIG--> testUnsyncNew() -> Sync response didn't come in") return False for samp in data[0:len(data)]: if samp != self.ADC_TESTPATTERN[ch]: print (" FEMB_CONFIG --> testUnsyncNew() -> Chip {} chn {} looking for {} but found {}".format( adcNum, ch, hex(self.ADC_TESTPATTERN[ch]), hex(samp))) return False return True """ def initFunctionGenerator(self): """ rm = visa.ResourceManager() try: #keysight = rm.open_resource('USB0::0x0957::0x5707::MY53802435::0::INSTR') keysight = rm.open_resource(u'USB0::2391::22279::MY53802422::0::INSTR') print ("Keysight Initialize--> Instrument Connected") except VisaIOError: print ("Keysight Initialize--> Exact system name not found") keysight = rm.open_resource(rm.list_resources()[0]) #Sets the self.instrument object in "GPIB_FUNCTIONS" to the #connected instrument, this makes it very easy to reference later time.sleep(0.1) keysight.write("Source1:Apply:Triangle {},{},{}".format(settings.frequency,settings.amplitude,settings.offset)) keysight.write("Output1:Load 50") #keysight.write("Output1:Load INFINITY") keysight.write("Source1:Burst:Mode Triggered") keysight.write("Source1:Burst:Ncycles 1") keysight.write("Source1:Burst:Phase {}".format(settings.phase_start)) keysight.write("Source1:Burst:State ON") keysight.write("Initiate1:Continuous OFF") return keysight """ def configAdcAsic(self): #cp 1/29/18 #helper """ config() """ print("FEMB_CONFIG -> configAdcAsic() --") Adcasic_regs = self.adc_reg.REGS #ADC ASIC SPI registers self.femb.write_reg ( self.REG_ASIC_SPIPROG, 0x40) self.femb.write_reg ( self.REG_ASIC_SPIPROG, 0) time.sleep(0.01) self.femb.write_reg ( self.REG_ASIC_SPIPROG, 0x20) self.femb.write_reg ( self.REG_ASIC_SPIPROG, 0) time.sleep(0.01) self.femb.write_reg ( self.REG_ASIC_SPIPROG, 0x40) self.femb.write_reg ( self.REG_ASIC_SPIPROG, 0) time.sleep(0.01) self.select_chn(1) # channel 1 & write clocks self.select_chn(3) # channel 3 & write clocks self.select_chn(1) # channel 1 & write clocks for k in range(10): i = 0 for regNum in range(self.REG_ADCSPI_BASE,self.REG_ADCSPI_BASE+len(Adcasic_regs),1): self.femb.write_reg( regNum, Adcasic_regs[i]) i = i + 1 # Program ADC ASIC SPI self.femb.write_reg ( self.REG_ASIC_SPIPROG, 0) time.sleep(.05) self.femb.write_reg ( self.REG_ASIC_SPIPROG, 1) time.sleep(.05) self.femb.write_reg ( self.REG_ASIC_SPIPROG, 1) time.sleep(.05) #self.femb.write_reg ( self.REG_ASIC_SPIPROG, 0) # Check ADC ASIC SPI readback_regs = [] i = 0 for regNum in range(self.REG_ADCSPI_RDBACK_BASE,self.REG_ADCSPI_RDBACK_BASE+len(Adcasic_regs),1): readback_regs.append(self.femb.read_reg(regNum)) #print ( "femb_config_sbnd.py -> configAdcAsic() -> readback reg: " + str(hex(regNum)) + " from base: " + str(hex(Adcasic_regs[i]))) i = i + 1 i=0 for i in range (0,len(readback_regs),1): #Why is this reading out extra adc asic registers? if (Adcasic_regs[i] != readback_regs[i]): print ("\t FEMB_CONFIG --> CONFIG() ERROR -> configAdcAsic() -> Sent Adcasic_reg not correct = " + str(hex(Adcasic_regs[i])) + " , rb_reg = " + str(hex(readback_regs[i])) ) else: continue #print ("femb_config_sbnd.py -> configAdcAsic() -> Adcasic_reg correct = " + str(hex(Adcasic_regs[i])) + " , rb_reg = " + str(hex(readback_regs[i])) ) # val = self.femb.read_reg ( self.REG_ASIC_SPIPROG ) wrong = False # # if (((val & 0x10000) >> 16) != 1): # #print ("FEMB_CONFIG--> Something went wrong when programming ADC 1") # wrong = True # if (((val & 0x40000) >> 18) != 1): # #print ("FEMB_CONFIG--> Something went wrong when programming ADC 2") # wrong = True # if (((val & 0x100000) >> 20) != 1): # #print ("FEMB_CONFIG--> Something went wrong when programming ADC 3") # wrong = True # if (((val & 0x400000) >> 22) != 1): # #print ("FEMB_CONFIG--> Something went wrong when programming ADC 4") # wrong = True if (wrong == True and k == 9): print ("\tFEMB_CONFIG--> CONFIG() -> SPI_Status") print (hex(val)) sys.exit("\tFEMB_CONFIG--> CONFIG() -> femb_config_femb : Wrong readback. ADC SPI failed") return elif (wrong == 0): print ("\tFEMB_CONFIG--> CONFIG() -> ADC ASIC SPI is OK") break #else: #print ("FEMB_CONFIG--> Try {}, since SPI response was {}".format(k + 2, hex(val))) def FinalSyncCheck(self): # # FinalSyncCheck() # # procedures: # line 337: set chip [determine which chip is being sync'd] # line 339: set global register [send test data from PC to FPGA (where is this data going?) F5=1 # line 340: write SPI (wtf is SPI?) print ("FEMB_CONFIG--> Final sync check to make sure") for a in settings.chips_to_use: self.adc_reg.set_adc_global(chip = a, f5 = 1) self.configAdcAsic() self.select_chn(1) # channel 0 & write clocks self.select_chn(3) # channel 0 & write clocks self.select_chn(1) # channel 0 & write clocks # quad board settings: #self.select_chip(chip = a) # single board settings: #select_chip is not necessary badSync = 0 for ch in range(0,16,1): for test in range(0,100,1): data = self.get_data_chipXchnX(chip = a, chn = ch, packets = 1) if (len(data) == 0): print ("FEMB_CONFIG--> Sync response bad. Exiting...") return 1 for samp in data[0:len(data)]: if samp != self.ADC_TESTPATTERN[ch]: badSync = 1 print ("FEMB_CONFIG--> Chip {} chn {} looking for {} but found {}".format( a, ch, hex(self.ADC_TESTPATTERN[ch]), hex(samp))) if badSync == 1: break #print("time after checking the sample {}".format(time.time())) if badSync == 1: break #print("time after checking 100 samples {}".format(time.time())) if badSync == 1: self.femb.write_reg( 9, 1) sys.exit("FEMB_CONFIG--> Failed final check looking at channel test values") self.configAdcAsic() print ("FEMB_CONFIG--> Chip {} recieved the correct test values!".format(a)) resp = self.testUnsyncNew(a) if (resp == False): self.femb.write_reg(9, 1) sys.exit("FEMB_CONFIG--> Sync failed in the final check") self.adc_reg.set_adc_global(chip = a, f5 = 0) # for i in range (100): # sync_status = self.femb.read_reg(self.REG_ASIC_SPIPROG) >> 24 # if ((sync_status & 0x3F) != 0): # # if (i == 99): # print ("FEMB_CONFIG--> Register 2 giving back a sync error") # print ("Sync status is {}".format(hex(sync_status))) # sys.exit("Done with trying") # # self.configAdcAsic(False) # # else: # print ("FEMB_CONFIG--> No Sync error through Register 2 check: ({})!".format(hex(sync_status))) # break def fixUnsyncNew(self, adc): print("\n femb_config_sbnd.py -> fixUnsyncNew() -> adc = " + str(adc) + "\n") adcNum = int(adc) if (adcNum < 0) or (adcNum > 3): print ("FEMB_CONFIG--> femb_config_femb : testLink - invalid asic number") return initLATCH1_4 = self.femb.read_reg( settings.LATCHLOC_reg) initPHASE = self.femb.read_reg( settings.CLKPHASE_reg) #loop through sync parameters shiftMask = (0xFF << 8*adcNum) initSetting = (initLATCH1_4 & shiftMask) >> (8*adcNum) print ("FEMB_CONFIG--> First testing around default value of {}".format(initSetting)) for phase in range(0,4,1): clkMask = (0x3 << (adcNum * 2)) testPhase = ( (initPHASE & ~(clkMask)) | (phase << (adcNum * 2)) ) self.femb.write_reg( settings.CLKPHASE_reg, testPhase) #print ("Init Setting is {}".format(hex(initSetting))) #print ("Will test {}, {}, and {}".format(initSetting - 1, initSetting, initSetting + 1)) for shift in range(initSetting - 1,initSetting + 2,1): print ("\n\tfemb_config_sbnd.py -> fixUnsyncNew -> This time, we're testing {}\n".format(shift)) testShift = ( (initLATCH1_4 & ~(shiftMask)) | (shift << 8*adcNum) ) self.femb.write_reg( settings.LATCHLOC_reg, testShift) print ("FEMB_CONFIG--> Trying to sync Chip {} with Latch Lock:{} and Phase:{}".format(adcNum, hex(testShift), hex(testPhase))) #test link unsync = self.testUnsyncNew(adcNum) if unsync == True : print ("FEMB_CONFIG--> ADC {} synchronized".format(adc)) self.REG_LATCHLOC1_4_data = testShift self.REG_CLKPHASE_data = testPhase return True #Then try all settings print ("FEMB_CONFIG--> Now testing the rest of them") for phase in range(0,4,1): clkMask = (0x3 << (adcNum * 2)) testPhase = ( (initPHASE & ~(clkMask)) | (phase << (adcNum * 2)) ) self.femb.write_reg( settings.CLKPHASE_reg, testPhase) #First test latch lock settings close to default values shiftMask = (0xFF << 8*adcNum) initSetting = initLATCH1_4 & shiftMask for shift in range(0,16,1): testShift = ( (initLATCH1_4 & ~(shiftMask)) | (shift << 8*adcNum) ) self.femb.write_reg( settings.LATCHLOC_reg, testShift) print ("FEMB_CONFIG--> Trying to sync Chip {} with Latch Lock:{} and Phase:{}".format(adcNum, hex(testShift), hex(testPhase))) #test link unsync = self.testUnsyncNew(adcNum) if unsync == True : print ("FEMB_CONFIG--> ADC {} synchronized".format(adc)) self.REG_LATCHLOC1_4_data = testShift self.REG_CLKPHASE_data = testPhase return True #if program reaches here, sync has failed print ("FEMB_CONFIG--> ADC SYNC process failed for ADC # " + str(adc)) return False def select_chn(self, chn): """ % select_chn() % This function is used in sending instructions to fpga to select chip. % There is not an option to select a chip for single socket boards. % This function is mostly relevent for using on quad board. % This function is used to output the desired clock settings correlated to the % 'selected chip' % Assume 16 channels % % [quad board:] % clock reg values [10-43] % % [single board:] % clock reg values [21-33] """ print("\t FEMB_CONFIG//select_chn()") if (chn < 0 ) or (chn > settings.chn_num): print ("\t FEMB_CONFIG//select_chn()//Error: Chn must be between 0 and {}".format(self.chn_num)) return """ quad board remains... self.femb.write_reg(9, 1) # STOP_ADC <= reg9_p (quad board) time.sleep(0.01) # WAIT self.femb.write_reg(3, 0x80000001 + chip) # CHP_SELECT <= reg3_p(7 downto 0) (quad board) time.sleep(0.01) # WAIT self.femb.write_reg(9, 0) # STOP_ADC <= reg9_p (quad board) time.sleep(0.01) # WAIT self.femb.write_reg(47, 1) # ERROR_RESET <= reg47_p (quad board) time.sleep(0.01) # WAIT self.femb.write_reg(47, 0) # ERROR_RESET <= reg47_p (quad board) """ # STOP ADC: TRUE ??? time.sleep(0.01) # WAIT self.femb.write_reg(7, 0x00000001 + chn) # CHN_SELECT <= reg7(7 downto 0) time.sleep(0.01) # WAIT # STOP ADC: FALSE ??? # WAIT self.femb.write_reg(11, 1) # CHN_SELECT <= reg11(0) time.sleep(0.01) # WAIT self.femb.write_reg(11, 0) # CHN_SELECT <= reg11(0) self.selected_chn = chn # originally self.selected_chip?? what is it used for? if (self.femb.read_reg(7) != 0x00000001 + chn): print ("\t FEMB CONFIG --> select_chn() -> Error - chip not chosen correctly!") print ("\t Should be ".format(hex(0x00000001 + chn))) print ("\t It is {}".format(hex(self.femb.read_reg(7)))) to_add = 0 """ quad board remains... if (settings.extended == True): to_add = 4 self.femb.write_reg(10, settings.reg10_value[chip + to_add]) #INV_RST_ADC1 <= reg10_p(0) #INV_READ_ADC1<= reg10_p(1) #Course Control Quad Board self.femb.write_reg(11, settings.reg11_value[chip + to_add]) self.femb.write_reg(12, settings.reg12_value[chip + to_add]) self.femb.write_reg(13, settings.reg13_value[chip + to_add]) self.femb.write_reg(14, settings.reg14_value[chip + to_add]) self.femb.write_reg(15, settings.reg15_value[chip + to_add]) self.femb.write_reg(16, settings.reg16_value[chip + to_add]) #Fine Control Quad Board self.femb.write_reg(17, settings.reg17_value[chip + to_add]) self.femb.write_reg(18, settings.reg18_value[chip + to_add]) self.femb.write_reg(19, settings.reg19_value[chip + to_add]) self.femb.write_reg(19, settings.reg19_value[chip + to_add]) self.femb.write_reg(19, 0x80000000 + settings.reg19_value[chip + to_add]) """ self.femb.write_reg( settings.CLKPHASE_reg, 0xFF) self.femb.write_reg( settings.CLKPHASE_reg, self.REG_CLKPHASE_data) time.sleep(0.01) def get_data_chipXchnX(self, chip, chn, packets = 1): if (chn < -1 ) or (chn > settings.chn_num ): print ("FEMB CONFIG --> get_data_chipXchnX() -> Error: Channel must be between 0 and 15, or -1 for all channels") return if (chip < 0 ) or (chip > settings.chip_num ): print ("FEMB CONFIG --> get_data_chipXchnX() -> Error: Chip must be between 0 and {}".format(self.chip_num)) return k = 0 for i in range(10): data = self.femb.get_data_packets(data_type = "int", num = packets, header = False) try: if (k > 0): print ("FEMB CONFIG --> Now doing another test") print (hex(data[0])) print (data[0] == 0xFACE) print (data[0] != 0xFACE) if (data[0] != 0xFACE): #If FACE isn't the first 2 bytes, turn WIB mode off and then on and try again self.femb.write_reg(8,0) # Turn WIB Mode Off time.sleep(0.01) self.femb.write_reg(8,1) # Turn WIB Mode On time.sleep(0.01) # quad board settings: # self.select_chip(chip) #tells fpga which chip information to provide # self.femb.write_reg(3, chip+1) # CHP_Select <= reg_3p(7-0) # # CHN_Select <= reg_3p(15-0) # # WIB_Mode <= reg_3p(31) # single board settings: self.femb.write_reg(7, chn) # CHN_select <= reg7_p(7-0) time.sleep(0.001) if (k > 8): print ("FEMB CONFIG --> Error in get_data_chipXchnX: Packet format error") #print (hex(data[0])) #print (data) return None else: print ("FEMB CONFIG --> Error in get_data_chipXchnX: Packet format error, trying again...") print ("k = {}".format(k)) print (data[0:13]) print (hex(data[0])) print ("FEMB CONFIG --> Hey: {}".format(data[0] == 0xFACE)) k += 1 else: break except IndexError: print ("FEMB CONFIG --> Something was wrong with the incoming data") print (data) test_length = len(data) # if ((test_length % self.BPS) != 0): # print ("FEMB CONFIG -> Error in get_data_chipXchnX: Irregular packet size") # print (data) # return None full_samples = test_length // self.BPS chn_data = [] for i in range (full_samples): if (chn == 7): chn_data.append(data[(self.BPS*i)+1] & 0x0FFF) if (chn == 6): chn_data.append(((data[(self.BPS*i)+2] & 0x00FF) << 4) + ((data[(self.BPS*i)+1] & 0xF000) >> 12)) if (chn == 5): chn_data.append(((data[(self.BPS*i)+3] & 0x000F) << 8) + ((data[(self.BPS*i)+2] & 0xFF00) >> 8)) if (chn == 4): chn_data.append(((data[(self.BPS*i)+3] & 0xFFF0) >> 4)) if (chn == 3): chn_data.append(data[(self.BPS*i)+4] & 0x0FFF) if (chn == 2): chn_data.append(((data[(self.BPS*i)+5] & 0x00FF) << 4) + ((data[(self.BPS*i)+4] & 0xF000) >> 12)) if (chn == 1): chn_data.append(((data[(self.BPS*i)+6] & 0x000F) << 8) + ((data[(self.BPS*i)+5] & 0xFF00) >> 8)) if (chn == 0): chn_data.append(((data[(self.BPS*i)+6] & 0xFFF0) >> 4)) if (chn == 15): chn_data.append(data[(self.BPS*i)+7] & 0x0FFF) if (chn == 14): chn_data.append(((data[(self.BPS*i)+8] & 0x00FF) << 4) + ((data[(self.BPS*i)+7] & 0xF000) >> 12)) if (chn == 13): chn_data.append(((data[(self.BPS*i)+9] & 0x000F) << 8) + ((data[(self.BPS*i)+8] & 0xFF00) >> 8)) if (chn == 12): chn_data.append(((data[(self.BPS*i)+9] & 0xFFF0) >> 4)) if (chn == 11): chn_data.append(data[(self.BPS*i)+10] & 0x0FFF) if (chn == 10): chn_data.append(((data[(self.BPS*i)+11] & 0x00FF) << 4) + ((data[(self.BPS*i)+10] & 0xF000) >> 12)) if (chn == 9): chn_data.append(((data[(self.BPS*i)+12] & 0x000F) << 8) + ((data[(self.BPS*i)+11] & 0xFF00) >> 8)) if (chn == 8): chn_data.append(((data[(self.BPS*i)+12] & 0xFFF0) >> 4)) if (chn == -1): return (data) return chn_data
class FEMB_CONFIG(FEMB_CONFIG_BASE): def __init__(self, exitOnError=True): super().__init__(exitOnError=exitOnError) #declare board specific registers self.FEMB_VER = "adctestP1quad" self.REG_RESET = 0 # bit 0 system, 1 reg, 2 alg, 3 udp self.REG_PWR_CTRL = 1 # bit 0-3 pwr, 8-15 blue LEDs near buttons self.REG_ASIC_SPIPROG_RESET = 2 # bit 0 FE SPI, 1 ADC SPI, 4 FE ASIC RESET, 5 ADC ASIC RESET, 6 SOFT ADC RESET & SPI readback check # I zero out REG_ASIC_SPIPROG_RESET a lot because only transitions from 0 to 1 do anything self.REG_SEL_CH = 3 # bit 0-7 chip, 8-15 channel, 31 WIB mode self.REG_DAC1 = 4 # bit 0-15 DAC val, 16-19 tp mode select, 31 set dac self.REG_DAC2 = 5 # bit 0-15 tp period, 16-31 tp shift self.REG_FPGA_TST_PATT = 6 # bit 0-11 tst patt, 16 enable self.REG_ADC_CLK = 7 # bit 0-3 clk phase, 8 clk speed sel self.REG_LATCHLOC = 8 # bit 0-7 ADC1, 8-15 ADC2, 16-23 ADC3, 24-31 ADC4 self.REG_STOP_ADC = 9 # bit 0 stops sending convert, read ADC HEADER redundant with reg 2 self.REG_UDP_FRAME_SIZE = 63 # bits 0-11 self.REG_FIRMWARE_VERSION = 0xFF # 255 in decimal self.CONFIG_FIRMWARE_VERSION = 259 # this file is written for this self.REG_LATCHLOC_data_2MHz = 0x02020202 self.REG_LATCHLOC_data_1MHz = 0x0 self.REG_LATCHLOC_data_2MHz_cold = 0x02020202 self.REG_LATCHLOC_data_1MHz_cold = 0x0 self.REG_CLKPHASE_data_2MHz = 0x4 self.REG_CLKPHASE_data_1MHz = 0x0 self.REG_CLKPHASE_data_2MHz_cold = 0x4 self.REG_CLKPHASE_data_1MHz_cold = 0x0 self.DEFAULT_FPGA_TST_PATTERN = 0x12 self.ADC_TESTPATTERN = [ 0x12, 0x345, 0x678, 0xf1f, 0xad, 0xc01, 0x234, 0x567, 0x89d, 0xeca, 0xff0, 0x123, 0x456, 0x789, 0xabc, 0xdef ] # registers 64-88 are SPI to ASICs # 88 is last register besides 255 which is firmware version self.REG_FESPI_BASE = 84 # this configures all FE ASICs self.REG_ADCSPI_BASES = [64, 69, 74, 79] # for each chip self.REG_EXTCLK_INV = 10 self.REG_EXTCLK_BASES = [11, 20, 29, 38] # for each chip self.FPGA_FREQ_MHZ = 200 # frequency of FPGA clock in MHz self.REG_PLL_BASES = [17, 26, 35, 44] # for each chip self.NASICS = 4 #self.FUNCGENINTER = DummyFuncGen("","") self.FUNCGENINTER = Keysight_33600A("/dev/usbtmc0", 1) self.POWERSUPPLYINTER = DummyPowerSupply("", "") self.F2DEFAULT = 0 self.CLKDEFAULT = "fifo" self.SAMPLERATE = 2e6 #initialize FEMB UDP object self.femb = FEMB_UDP() self.adc_regs = [] for i in range(self.NASICS): self.adc_regs.append(ADC_ASIC_REG_MAPPING()) #self.defaultConfigFunc = lambda: self.configAdcAsic() self.defaultConfigFunc = lambda: self.configAdcAsic(clockMonostable= True) #self.defaultConfigFunc = lambda: self.configAdcAsic(clockMonostable=True,freqInternal=0) # 1 MHz def resetBoard(self): """ Reset registers and state machines NOT udp Make sure to set reg 0 back to zero or there will be much sadness! """ #Reset registers self.femb.write_reg(self.REG_RESET, 2) time.sleep(1.) #Reset state machines self.femb.write_reg(self.REG_RESET, 4) time.sleep(1.) #Reset reset register to 0 self.femb.write_reg(self.REG_RESET, 0) time.sleep(0.2) def initBoard(self): #set up default registers # test readback readback = self.femb.read_reg(1) if readback is None: if self.exitOnError: print("FEMB_CONFIG: Error reading register 0, Exiting.") sys.exit(1) else: raise ReadRegError("Couldn't read register 0") ##### Start Top-level Labview stacked sequence struct 0 firmwareVersion = self.femb.read_reg( self.REG_FIRMWARE_VERSION) & 0xFFFF if firmwareVersion != self.CONFIG_FIRMWARE_VERSION: raise FEMBConfigError( "Board firmware version {} doesn't match configuration firmware version {}" .format(firmwareVersion, self.CONFIG_FIRMWARE_VERSION)) print("Firmware Version: ", firmwareVersion) self.femb.write_reg(self.REG_UDP_FRAME_SIZE, 0x1FB) time.sleep(0.05) self.setFPGADac(0, 0, 0, 0) # write regs 4 and 5 self.femb.write_reg(1, 0) # pwr ctrl self.femb.write_reg(3, (5 << 8)) # chn sel self.femb.write_reg(6, self.DEFAULT_FPGA_TST_PATTERN) #tst pattern self.femb.write_reg(7, 13) #adc clk self.femb.write_reg(8, 0) #latchloc ##### End Top-level Labview stacked sequence struct 0 self.turnOnAsics() nRetries = 1 for iRetry in range(nRetries): #Reset ASICs self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 0x0) # zero out reg self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 0x30) # reset FE and ADC self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 0x0) # zero out reg time.sleep(0.1) #Set FPGA test pattern register self.femb.write_reg( self.REG_FPGA_TST_PATT, self.DEFAULT_FPGA_TST_PATTERN) # test pattern off #self.femb.write_reg(self.REG_FPGA_TST_PATT, self.DEFAULT_FPGA_TST_PATTERN+(1 << 16)) # test pattern on #Set ADC latch_loc and clock phase and sample rate if self.SAMPLERATE == 1e6: if self.COLD: self.femb.write_reg(self.REG_LATCHLOC, self.REG_LATCHLOC_data_1MHz_cold) self.femb.write_reg( self.REG_ADC_CLK, (self.REG_CLKPHASE_data_1MHz_cold & 0xF) | (1 << 8)) else: self.femb.write_reg(self.REG_LATCHLOC, self.REG_LATCHLOC_data_1MHz) self.femb.write_reg(self.REG_ADC_CLK, (self.REG_CLKPHASE_data_1MHz & 0xF) | (1 << 8)) else: # use 2 MHz values if self.COLD: self.femb.write_reg(self.REG_LATCHLOC, self.REG_LATCHLOC_data_2MHz_cold) self.femb.write_reg( self.REG_ADC_CLK, (self.REG_CLKPHASE_data_2MHz_cold & 0xF)) else: self.femb.write_reg(self.REG_LATCHLOC, self.REG_LATCHLOC_data_2MHz) self.femb.write_reg(self.REG_ADC_CLK, (self.REG_CLKPHASE_data_2MHz & 0xF)) self.writePLLs(0, 0x20001, 0) self.setFPGADac(0, 1, 0, 0) #Configure ADC (and external clock inside) try: #self.femb.write_reg(self.REG_FESPI_BASE,1) ##self.adc_regs[0].set_chip(frqc=1) #regsListOfLists = [] #for chipRegConfig in self.adc_regs: # chipRegConfig.set_chip(frqc=1) # regsListOfLists.append(chipRegConfig.REGS) #self.configAdcAsic_regs(regsListOfLists) self.defaultConfigFunc() except ReadRegError: continue print("ADC Soft Reset...") self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 1 << 6) # ADC soft reset time.sleep(0.1) self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 0x0) # zero out reg time.sleep(0.1) # self.printSyncRegister() # self.syncADC() self.printSyncRegister() self.selectChannel(0, 0) # not packed many channels #print("Stop ADC...") #self.femb.write_reg(self.REG_STOP_ADC,1) #time.sleep(0.1) #print("Start ADC...") #self.femb.write_reg(self.REG_STOP_ADC,0) #time.sleep(0.1) #self.printSyncRegister() # Check that board streams data data = self.femb.get_data(1) if data == None: print("Board not streaming data, retrying initialization...") continue # try initializing again print("FEMB_CONFIG--> Reset FEMB is DONE") return print( "Error: Board not streaming data after trying to initialize {} times." .format(nRetries)) if self.exitOnError: print("Exiting.") sys.exit(1) else: raise InitBoardError def configAdcAsic_regs(self, Adcasic_regs): """ Takes a list NASICS long, each a list of 5 32 bit registers. """ #ADC ASIC SPI registers assert (type(Adcasic_regs) == list) assert (len(Adcasic_regs) == self.NASICS) print("FEMB_CONFIG--> Config ADC ASIC SPI") for iTry in range(2): #print(" Try at writing SPI: ",iTry+1) self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 0) for iChip, chipRegs in enumerate(Adcasic_regs): assert (len(chipRegs) == 5) for iReg in range(5): self.femb.write_reg(self.REG_ADCSPI_BASES[iChip] + iReg, chipRegs[iReg]) #print("{:3} {:#010x}".format(self.REG_ADCSPI_BASES[iChip]+iReg, chipRegs[iReg])) time.sleep(0.05) self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 3) time.sleep(0.1) self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 2) time.sleep(0.1) self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 0) time.sleep(0.1) self.femb.write_reg(self.REG_RESET, 0) time.sleep(0.1) self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 1 << 6) # soft reset self.printSyncRegister() def getSyncStatus(self): syncBits = None adc0 = None fe0 = None adc1 = None fe1 = None adc2 = None fe2 = None adc3 = None fe3 = None reg = self.femb.read_reg(self.REG_ASIC_SPIPROG_RESET) if reg is None: print("Error: can't read back sync register") if self.exitOnError: return else: raise ReadRegError else: print("Register 2: {:#010x}".format(reg)) syncBits = reg >> 24 reg = reg >> 16 adc0 = ((reg >> 0) & 1) == 1 fe0 = ((reg >> 1) & 1) == 1 adc1 = ((reg >> 2) & 1) == 1 fe1 = ((reg >> 3) & 1) == 1 adc2 = ((reg >> 4) & 1) == 1 fe2 = ((reg >> 5) & 1) == 1 adc3 = ((reg >> 6) & 1) == 1 fe3 = ((reg >> 7) & 1) == 1 return (fe0, fe1, fe2, fe3), (adc0, adc1, adc2, adc3), syncBits def printSyncRegister(self): (fe0, fe1, fe2, fe3), (adc0, adc1, adc2, adc3), syncBits = self.getSyncStatus() reg = self.femb.read_reg(self.REG_ASIC_SPIPROG_RESET) print("ASIC Readback Status:") print(" ADC 0:", adc0, "FE 0:", fe0) print(" ADC 1:", adc1, "FE 1:", fe1) print(" ADC 2:", adc2, "FE 2:", fe2) print(" ADC 3:", adc3, "FE 3:", fe3) print("ADC Sync Bits: {:#010b} (0 is good)".format(syncBits)) def configAdcAsic(self, enableOffsetCurrent=None, offsetCurrent=None, testInput=None, freqInternal=None, sleep=None, pdsr=None, pcsr=None, clockMonostable=None, clockExternal=None, clockFromFIFO=None, sLSB=None, f0=None, f1=None, f2=None, f3=None, f4=None, f5=None): """ Configure ADCs enableOffsetCurrent: 0 disable offset current, 1 enable offset current offsetCurrent: 0-15, amount of current to draw from sample and hold testInput: 0 digitize normal input, 1 digitize test input freqInternal: internal clock frequency: 0 1MHz, 1 2MHz sleep: 0 disable sleep mode, 1 enable sleep mode pdsr: if pcsr=0: 0 PD is low, 1 PD is high pcsr: 0 power down controlled by pdsr, 1 power down controlled externally Only one of these can be enabled: clockMonostable: True ADC uses monostable clock clockExternal: True ADC uses external clock clockFromFIFO: True ADC uses digital generator FIFO clock sLSB: LSB current steering mode. 0 for full, 1 for partial (ADC7 P1) f0, f1, f2, f3, f4, f5: version specific """ FEMB_CONFIG_BASE.configAdcAsic(self, clockMonostable=clockMonostable, clockExternal=clockExternal, clockFromFIFO=clockFromFIFO) if enableOffsetCurrent is None: enableOffsetCurrent = 0 if offsetCurrent is None: offsetCurrent = 0 else: offsetCurrent = int( "{:04b}".format(offsetCurrent)[::-1], 2) # need to reverse bits, use string/list tricks if testInput is None: testInput = 1 if freqInternal is None: freqInternal = 1 if sleep is None: sleep = 0 if pdsr is None: pdsr = 0 if pcsr is None: pcsr = 0 if sLSB is None: sLSB = 0 if f1 is None: f1 = 0 if f2 is None: f2 = 0 if f3 is None: f3 = 0 if f4 is None: f4 = 1 if f5 is None: f5 = 0 if not (clockMonostable or clockExternal or clockFromFIFO): clockExternal = True # a bunch of things depend on the clock choice clk0 = 0 clk1 = 0 if clockExternal: clk0 = 1 clk1 = 0 elif clockFromFIFO: clk0 = 0 clk1 = 1 if f0 is None: if clockExternal: f0 = 1 else: f0 = 0 if clockExternal: self.extClock(enable=True) else: self.extClock(enable=False) regsListOfLists = [] for chipRegConfig in self.adc_regs: chipRegConfig.set_chip(en_gr=enableOffsetCurrent, d=offsetCurrent, tstin=testInput, frqc=freqInternal, slp=sleep, pdsr=pdsr, pcsr=pcsr, clk0=clk0, clk1=clk1, f0=f0, f1=f1, f2=f2, f3=f3, f4=f4, f5=f5, slsb=sLSB) regsListOfLists.append(chipRegConfig.REGS) self.configAdcAsic_regs(regsListOfLists) def selectChannel(self, asic, chan, hsmode=1, singlechannelmode=0): """ asic is chip number 0 to 7 chan is channel within asic from 0 to 15 hsmode: if 0 then WIB streaming mode, if 1 then sends ch then adc, defaults to 1 singlechannelmode: if 1 and hsmode = 0, then only send a single channel of data instead of 16 in a row """ hsmodeVal = int(hsmode) & 1 # only 1 bit hsmodeVal = (~hsmodeVal) & 1 # flip bit singlechannelmode = int(singlechannelmode) & 1 asicVal = int(asic) if (asicVal < 0) or (asicVal >= self.NASICS): print( "femb_config_femb : selectChan - invalid ASIC number, only 0 to {} allowed" .format(self.NASICS - 1)) return chVal = int(chan) if (chVal < 0) or (chVal > 15): print( "femb_config_femb : selectChan - invalid channel number, only 0 to 15 allowed" ) return #print( "Selecting ASIC " + str(asicVal) + ", channel " + str(chVal)) self.femb.write_reg(self.REG_STOP_ADC, 1) time.sleep(0.05) # bit 4 of chVal is the single channel mode bit chVal += (singlechannelmode << 4) # in this firmware asic = 0 disables readout, so asics are 1,2,3,4 regVal = (asicVal + 1) + (chVal << 8) + (hsmodeVal << 31) self.femb.write_reg(self.REG_SEL_CH, regVal) time.sleep(0.05) self.femb.write_reg(self.REG_STOP_ADC, 0) def syncADC(self, iASIC=None): #return True, 0, 0 #turn on ADC test mode print("FEMB_CONFIG--> Start sync ADC") self.configAdcAsic(clockMonostable=True, f4=0, f5=1) time.sleep(0.1) alreadySynced = True asicsToSync = [iASIC] if iASIC is None: # not actually getting for sync just for properly configured ADC chips feSPI, adcSPI, syncBits = self.getSyncStatus() asicsToSync = [i for i in range(self.NASICS) if adcSPI[i]] for a in asicsToSync: print("FEMB_CONFIG--> Test ADC " + str(a)) unsync, syncDicts = self.testUnsync(a) if unsync != 0: alreadySynced = False print("FEMB_CONFIG--> ADC not synced, try to fix") self.fixUnsync(a) latchloc = None phase = None latchloc = self.femb.read_reg(self.REG_LATCHLOC) clkphase = self.femb.read_reg(self.REG_ADC_CLK) & 0b1111 if self.SAMPLERATE == 1e6: if self.COLD: self.REG_LATCHLOC_data_1MHz_cold = latchloc self.REG_CLKPHASE_data_1MHz_cold = clkphase else: self.REG_LATCHLOC_data_1MHz = latchloc self.REG_CLKPHASE_data_1MHz = clkphase else: # 2 MHz if self.COLD: self.REG_LATCHLOC_data_2MHZ_cold = latchloc self.REG_CLKPHASE_data_2MHZ_cold = clkphase else: self.REG_LATCHLOC_data_2MHZ = latchloc self.REG_CLKPHASE_data_2MHZ = clkphase print("FEMB_CONFIG--> Latch latency {:#010x} Phase: {:#010x}".format( latchloc, clkphase)) self.defaultConfigFunc() print("FEMB_CONFIG--> End sync ADC") return not alreadySynced, latchloc, None, clkphase def testUnsync(self, adc, npackets=10): #return 0, [] print("Starting testUnsync adc: ", adc) adcNum = int(adc) if (adcNum < 0) or (adcNum > 7): print( "FEMB_CONFIG--> femb_config_femb : testLink - invalid asic number" ) return # syncBits = self.femb.read_reg(2) >> 24 # theseSyncBits = (syncBits >> (2*adc)) & 0b11 # if theseSyncBits == 0: # return 0, [] # else: # return 1, [] #loop through channels, check test pattern against data syncDataCounts = [{} for i in range(16)] #dict for each channel self.selectChannel(adcNum, 0, singlechannelmode=0) time.sleep(0.05) data = self.femb.get_data(npackets) if data == None: print("Error: Couldn't read data in testUnsync") if self.exitOnError: print("Exiting.") sys.exit(1) else: raise SyncADCError for samp in data: if samp == None: continue ch = ((samp >> 12) & 0xF) sampVal = (samp & 0xFFF) if sampVal in syncDataCounts[ch]: syncDataCounts[ch][sampVal] += 1 else: syncDataCounts[ch][sampVal] = 1 # check jitter print("Channel 0:") for key in sorted(syncDataCounts[0]): print(" {0:#06x} = {0:#018b} count: {1}".format( key, syncDataCounts[0][key])) badSync = 0 maxCodes = [None] * 16 syncDicts = [{}] * 16 for ch in range(0, 16, 1): sampSum = 0 maxCode = None nMaxCode = 0 for code in syncDataCounts[ch]: nThisCode = syncDataCounts[ch][code] sampSum += nThisCode if nThisCode > nMaxCode: nMaxCode = nThisCode maxCode = code maxCodes[ch] = maxCode syncDicts[ch]["maxCode"] = maxCode syncDicts[ch]["nSamplesMaxCode"] = nMaxCode syncDicts[ch]["nSamples"] = sampSum syncDicts[ch]["zeroJitter"] = True if len(syncDataCounts[ch]) > 1: syncDicts[ch]["zeroJitter"] = False badSync = 1 diff = sampSum - nMaxCode frac = diff / float(sampSum) print("Sync Error: Jitter for Ch {:2}: {:8.4%} ({:5}/{:5})". format(ch, frac, diff, sampSum)) for ch in range(0, 16, 1): maxCode = maxCodes[ch] correctCode = self.ADC_TESTPATTERN[ch] syncDicts[ch]["data"] = True syncDicts[ch]["maxCodeMatchesExpected"] = True if maxCode is None: syncDicts[ch]["data"] = False badSync = 1 print("Sync Error: no data for ch {:2}".format(ch)) elif maxCode != correctCode: syncDicts[ch]["maxCodeMatchesExpected"] = True badSync = 1 print( "Sync Error: mismatch for ch {:2}: expected {:#03x} observed {:#03x}" .format(ch, correctCode, maxCode)) return badSync, syncDicts def fixUnsync(self, adc): adcNum = int(adc) if (adcNum < 0) or (adcNum > 7): print( "FEMB_CONFIG--> femb_config_femb : testLink - invalid asic number" ) return initLATCH = self.femb.read_reg(self.REG_LATCHLOC) initPHASE = self.femb.read_reg( self.REG_ADC_CLK) # remember bit 16 sample rate phases = [0, 1] if self.COLD: phases = [0, 1, 0, 1, 0] #loop through sync parameters for shift in range(0, 16, 1): shiftMask = (0xFF << 8 * adcNum) testShift = ((initLATCH & ~(shiftMask)) | (shift << 8 * adcNum)) self.femb.write_reg(self.REG_LATCHLOC, testShift) time.sleep(0.01) for phase in phases: clkMask = (0x1 << adcNum) testPhase = ((initPHASE & ~(clkMask)) | (phase << adcNum)) self.femb.write_reg(self.REG_ADC_CLK, testPhase) time.sleep(0.01) print("try shift: {} phase: {} testingUnsync...".format( shift, phase)) #reset ADC ASIC self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 1 << 6) # ADC soft reset time.sleep(0.1) self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 0x0) # zero out reg time.sleep(0.1) #test link unsync, syncDicts = self.testUnsync(adcNum) if unsync == 0: print("FEMB_CONFIG--> ADC synchronized") return #if program reaches here, sync has failed print("Error: FEMB_CONFIG--> ADC SYNC process failed for ADC # " + str(adc)) print( "Setting back to original values: LATCHLOC: {:#010x}, PHASE: {:#010x}" .format(initLATCH, initPHASE & 0xF)) self.femb.write_reg(self.REG_LATCHLOC, initLATCH) self.femb.write_reg(self.REG_ADC_CLK, initPHASE) if self.exitOnError: sys.exit(1) else: raise SyncADCError def extClock(self, enable=False, period=500, mult=1, offset_rst=0, offset_read=480, offset_msb=230, offset_lsb=480, width_rst=50, width_read=20, width_msb=270, width_lsb=20, offset_lsb_1st_1=50, width_lsb_1st_1=190, offset_lsb_1st_2=480, width_lsb_1st_2=20, inv_rst=True, inv_read=True, inv_msb=False, inv_lsb=False, inv_lsb_1st=False): """ Programs external clock. All non-boolean arguments except mult are in nanoseconds IDXM = msb IDXL = lsb IDL = lsb_1st """ rd_off = 0 rst_off = 0 rst_wid = 0 msb_off = 0 msb_wid = 0 lsb_fc_wid2 = 0 lsb_fc_off1 = 0 rd_wid = 0 lsb_fc_wid1 = 0 lsb_fc_off2 = 0 lsb_wid = 0 lsb_off = 0 inv = 0 if enable: clock = 1. / self.FPGA_FREQ_MHZ * 1000. # clock now in ns denominator = clock / mult period_val = period // denominator #print("FPGA Clock freq: {} MHz period: {} ns".format(self.FPGA_FREQ_MHZ,clock)) #print("ExtClock option mult: {}".format(mult)) #print("ExtClock option period: {} ns".format(period)) #print("ExtClock option offset_read: {} ns".format(offset_read)) #print("ExtClock option offset_rst: {} ns".format(offset_rst)) #print("ExtClock option offset_msb: {} ns".format(offset_msb)) #print("ExtClock option offset_lsb: {} ns".format(offset_lsb)) #print("ExtClock option offset_lsb_1st_1: {} ns".format(offset_lsb_1st_1)) #print("ExtClock option offset_lsb_1st_2: {} ns".format(offset_lsb_1st_2)) #print("ExtClock option width_read: {} ns".format(width_read)) #print("ExtClock option width_rst: {} ns".format(width_rst)) #print("ExtClock option width_msb: {} ns".format(width_msb)) #print("ExtClock option width_lsb: {} ns".format(width_lsb)) #print("ExtClock option width_lsb_1st_1: {} ns".format(width_lsb_1st_1)) #print("ExtClock option width_lsb_1st_2: {} ns".format(width_lsb_1st_2)) #print("ExtClock option inv_rst: {}".format(inv_rst)) #print("ExtClock option inv_read: {}".format(inv_read)) #print("ExtClock option inv_msb: {}".format(inv_msb)) #print("ExtClock option inv_lsb: {}".format(inv_lsb)) #print("ExtClock option inv_lsb_1st: {}".format(inv_lsb_1st)) #print("ExtClock denominator: {} ns".format(denominator)) #print("ExtClock period: {} ns".format(period_val)) rd_off = int(offset_read // denominator) & 0xFFFF rst_off = int(offset_rst // denominator) & 0xFFFF rst_wid = int(width_rst // denominator) & 0xFFFF msb_off = int(offset_msb // denominator) & 0xFFFF msb_wid = int(width_msb // denominator) & 0xFFFF lsb_fc_wid2 = int(width_lsb_1st_2 // denominator) & 0xFFFF lsb_fc_off1 = int(offset_lsb_1st_1 // denominator) & 0xFFFF rd_wid = int(width_read // denominator) & 0xFFFF lsb_fc_wid1 = int(width_lsb_1st_1 // denominator) & 0xFFFF lsb_fc_off2 = int(offset_lsb_1st_2 // denominator) & 0xFFFF lsb_wid = int(width_lsb // denominator) & 0xFFFF lsb_off = int(offset_lsb // denominator) & 0xFFFF if inv_rst: inv += 1 << 0 if inv_read: inv += 1 << 1 if inv_msb: inv += 1 << 2 if inv_lsb: inv += 1 << 3 if inv_lsb_1st: inv += 1 << 4 def writeRegAndPrint(name, reg, val): #print("ExtClock Register {0:15} number {1:3} set to {2:10} = {2:#010x}".format(name,reg,val)) #print("ExtClock Register {0:15} number {1:3} set to {2:#034b}".format(name,reg,val)) self.femb.write_reg(reg, val) writeRegAndPrint("inv", self.REG_EXTCLK_INV, inv), for iChip, regBase in enumerate(self.REG_EXTCLK_BASES): iStr = str(iChip) asicRegs = [ ("RST_ADC" + iStr, (rst_wid << 16) | rst_off), ("READ_ADC" + iStr, (rd_wid << 16) | rd_off), ("IDXM_ADC" + iStr, (msb_wid << 16) | msb_off), # msb ("IDXL_ADC" + iStr, (lsb_wid << 16) | lsb_off), # lsb ("IDL1_ADC" + iStr, (lsb_fc_wid1 << 16) | lsb_fc_off1), # lsb_fc_1 ("IDL2_ADC" + iStr, (lsb_fc_wid2 << 16) | lsb_fc_off2), # lsb_fc_1 ] for iReg, tup in enumerate(asicRegs): name = tup[0] val = tup[1] writeRegAndPrint(name, regBase + iReg, val) def turnOffAsics(self): oldReg = self.femb.read_reg(self.REG_PWR_CTRL) newReg = oldReg & 0xFFFFFFF0 self.femb.write_reg(self.REG_PWR_CTRL, newReg) #pause after turning off ASICs time.sleep(2) #self.femb.write_reg(self.REG_RESET, 4) # bit 2 is ASIC reset as far as I can see def turnOnAsic(self, asic): asicVal = int(asic) if (asicVal < 0) or (asicVal >= self.NASICS): print( "femb_config_femb : turnOnAsics - invalid ASIC number, only 0 to {} allowed" .format(self.NASICS - 1)) return print("turnOnAsic " + str(asicVal)) oldReg = self.femb.read_reg(self.REG_PWR_CTRL) newReg = oldReg | (1 << asic) self.femb.write_reg(self.REG_PWR_CTRL, newReg) time.sleep(2) #pause after turn on #self.femb.write_reg(self.REG_RESET, 4) # bit 2 is ASIC reset as far as I can see def turnOnAsics(self): print("turnOnAsics 0-{}".format(int(self.NASICS - 1))) reg = self.femb.read_reg(self.REG_PWR_CTRL) for iAsic in reversed(range(self.NASICS)): print("iAsic", iAsic) reg = reg | (1 << iAsic) self.femb.write_reg(self.REG_PWR_CTRL, reg) if iAsic > 0: print("sleeping...") time.sleep(5.) #pause after turning on ASICs time.sleep(5) def setFPGADac(self, amp, mode, freq, delay): """ mode: 0 DAC only, 1 ext tp, 2 gnd, 3 1.8V, 4 test pulse, 5 1.8V FE, 6 ASIC TP DAC """ ampRegVal = ((mode & 0xFFFF) << 16) | (amp & 0xFFFF) freqRegVal = ((delay & 0xFFFF) << 16) | (freq & 0xFFFF) self.femb.write_reg(self.REG_DAC2, freqRegVal) time.sleep(0.05) self.femb.write_reg(self.REG_DAC1, ampRegVal) time.sleep(0.05) self.femb.write_reg(self.REG_DAC1, ampRegVal & 0x80000000) time.sleep(0.05) self.femb.write_reg(self.REG_DAC1, ampRegVal) def writePLLs(self, step0, step1, step2): for iChip in range(3): self.writePLL(iChip, step0, step1, step2) def writePLL(self, iChip, step0, step1, step2): def writeRegAndPrint(name, reg, val): self.femb.write_reg(reg, val) time.sleep(0.05) readback = self.femb.read_reg(reg) #print("PLL Register {0:15} number {1:3} set to {2:10} = {2:#010x}".format(name,reg,val)) #print("PLL Register {0:15} number {1:3} set to {2:#034b}".format(name,reg,val)) if readback == val: pass #print(" Readback match") else: print( "PLL Register {0:15} number {1:3} set to {2:10} = {2:#010x}" .format(name, reg, val)) print( " READBACK DOESN'T MATCH! write: {:#010x} read: {:#010x}". format(val, readback)) regBase = self.REG_PLL_BASES[iChip] iStr = str(iChip) asicRegs = [ ("pll_STEP0_ADC" + iStr, step0), ("pll_STEP1_ADC" + iStr, step1), ("pll_STEP2_ADC" + iStr, step2), ] for iReg, tup in enumerate(asicRegs): name = tup[0] val = tup[1] writeRegAndPrint(name, regBase + iReg, val) def syncPLLs(self): for iChip in range(1): syncd, detail = self.testUnsync(iChip) def programFirmware(self, firmware): """ Programs the FPGA using the firmware file given. """ pass def checkFirmwareProgrammerStatus(self): """ Prints a debug message for the firmware programmer """ pass def programFirmware1Mhz(self): pass def programFirmware2Mhz(self): pass def getClockStr(self): latchloc = self.femb.read_reg(self.REG_LATCHLOC) clkphase = self.femb.read_reg(self.REG_ADC_CLK) if latchloc is None: return "Register Read Error" if clkphase is None: return "Register Read Error" return "Latch Loc: {:#010x} Clock Phase: {:#010x}".format( latchloc, clkphase & 0xF)
class FEMB_CONFIG(FEMB_CONFIG_BASE): #__INIT__# def __init__(self): #declare basic system parameters self.NFEMBS = 4 self.NASICS = 8 self.NASICCH = 16 #declare board specific registers self.FEMB_VER = "WIB_SBND" self.REG_RESET = 0 self.REG_ASIC_RESET = 1 self.REG_ASIC_SPIPROG = 2 self.REG_LATCHLOC_3_TO_0 = 4 self.REG_LATCHLOC_7_TO_4 = 14 self.REG_FPGA_TP_EN = 16 self.REG_ASIC_TP_EN = 16 self.REG_DAC_SELECT = 16 self.REG_TP = 5 self.CLK_SELECT = 6 self.CLK_SELECT2 = 15 self.REG_SEL_ASIC = 7 self.REG_SEL_ASIC_LSB = 8 self.REG_WIB_MODE = 8 self.REG_ADC_DISABLE = 8 self.REG_HS_DATA = 9 self.INT_TP_EN = 18 self.EXT_TP_EN = 18 #EXTERNAL CLOCK STUFF HERE self.REG_SPI_BASE = 512 self.REG_SPI_RDBACK_BASE = 592 self.fembNum = 0 #initialize FEMB UDP object self.femb = FEMB_UDP() self.femb.UDP_PORT_WREG = 32000 #WIB PORTS self.femb.UDP_PORT_RREG = 32001 self.femb.UDP_PORT_RREGRESP = 32002 #ASIC config variables self.feasicLeakage = 0 #0 = 500pA, 1 = 100pA self.feasicLeakagex10 = 0 #0 = pA, 1 = pA*10 self.feasicAcdc = 0 #AC = 0, DC = 1 self.feasicEnableTestInput = 1 #0 = disabled, 1 = enabled self.feasicBaseline = 0 #0 = 200mV, 1 = 900mV self.feasicGain = 1 #4.7,7.8,14,25 self.feasicShape = 3 #0.5,1,2,3 self.feasicBuf = 0 #0 = OFF, 1 = ON def resetBoard(self): print("Reset") def initBoard(self): self.initWib() for femb in range(0, 4, 1): self.initFemb(femb) def initWib(self): #WIB initialization #set UDP ports to WIB registers self.femb.UDP_PORT_WREG = 32000 self.femb.UDP_PORT_RREG = 32001 self.femb.UDP_PORT_RREGRESP = 32002 self.femb.REG_SLEEP = 0.001 #register 2, LED self.femb.write_reg_bits(2, 0, 0xFF, 0) #clock select (firmware version dependent) #self.femb.write_reg_bits(4 , 2, 0x3, 2 ) #initialize clock self.initSI5338() #return register interface to FEMB self.selectFemb(self.fembNum) def initFemb(self, femb): fembVal = int(femb) if (fembVal < 0) or (fembVal >= self.NFEMBS): return #FEMB power enable on WIB self.powerOnFemb(fembVal) #Make sure register interface is for correct FEMB self.selectFemb(fembVal) #check if FEMB register interface is working self.selectFemb(fembVal) print("Checking register interface") regVal = self.femb.read_reg(6) if (regVal == None) or (regVal == -1): print("Error - FEMB register interface is not working.") print(" Will not initialize FEMB.") return #turn off pulser self.femb.write_reg_bits(self.REG_FPGA_TP_EN, 0, 0x1, 0) #test pulse enable self.femb.write_reg_bits(self.REG_ASIC_TP_EN, 1, 0x1, 0) #test pulse enable self.femb.write_reg_bits(self.REG_DAC_SELECT, 8, 0x1, 0) #test pulse enable self.femb.write_reg_bits(self.REG_TP, 0, 0x1F, 0x00) #test pulse amplitude self.femb.write_reg_bits(self.REG_TP, 16, 0xFFFF, 0x100) #test pulse frequency self.femb.write_reg_bits(self.REG_TP, 8, 0xFF, 0x00) #test pulse delay #phase control self.femb.write_reg_bits(self.CLK_SELECT, 0, 0xFF, 0x0) #clock select self.femb.write_reg_bits(self.CLK_SELECT2, 0, 0xFF, 0xF0) #clock select 2 self.femb.write_reg_bits(self.REG_LATCHLOC_3_TO_0, 0, 0xFFFFFFFF, 0x00000000) #datashift self.femb.write_reg_bits(self.REG_LATCHLOC_7_TO_4, 0, 0xFFFFFFFF, 0x00000000) #datashift #enable streaming self.femb.write_reg_bits(self.REG_HS_DATA, 0, 0x1, 1) #Enable streaming self.femb.write_reg_bits(self.REG_HS_DATA, 3, 0x1, 1) #Enable ADC data #Set FE ASIC SPI configuration registers self.configFeAsic() #Set ADC SPI configuration registers #EXTERNAL CLOCK STUFF #Test FEMB SPI working def checkFembSpi(self, femb): fembVal = int(femb) print("About to check SPI:", self.femb.read_reg(8)) print("Check ASIC SPI") for regNum in range(self.REG_SPI_BASE, self.REG_SPI_BASE + 72, 1): val = self.femb.read_reg(regNum) if (val == None) or (val == -1): print("Error - FEMB register interface is not working.") continue # print( str(hex(val)) ) print("Check ASIC SPI Readback") for regNum in range(self.REG_SPI_RDBACK_BASE, self.REG_SPI_RDBACK_BASE + 72, 1): val = self.femb.read_reg(regNum) if (val == None) or (val == -1): print("Error - FEMB register interface is not working.") continue # print( str(hex(val)) ) #Compare input to output #FEMB power enable on WIB def powerOnFemb(self, femb): fembVal = int(femb) if (fembVal < 0) or (fembVal > 3): return #set UDP ports to WIB registers self.femb.UDP_PORT_WREG = 32000 self.femb.UDP_PORT_RREG = 32001 self.femb.UDP_PORT_RREGRESP = 32002 regBase = int(fembVal * 4) #FEMB power enable self.femb.write_reg_bits(8, regBase + 0, 0x1, 1) #3.6V self.femb.write_reg_bits(8, regBase + 1, 0x1, 1) #2.8V self.femb.write_reg_bits(8, regBase + 2, 0x1, 1) #2.5V self.femb.write_reg_bits(8, regBase + 3, 0x1, 1) #1.5V self.femb.write_reg_bits(8, 16 + fembVal, 0x1, 1) #BIAS enable print("FEMB Power on: ", hex(self.femb.read_reg(8))) #return register interface to FEMB self.selectFemb(self.fembNum) def powerOffFemb(self, femb): fembVal = int(femb) if (fembVal < 0) or (fembVal > 3): return #set UDP ports to WIB registers self.femb.UDP_PORT_WREG = 32000 self.femb.UDP_PORT_RREG = 32001 self.femb.UDP_PORT_RREGRESP = 32002 regBase = int(fembVal * 4) #FEMB power disable self.femb.write_reg_bits(8, 16 + fembVal, 0x1, 0) #BIAS self.femb.write_reg_bits(8, regBase + 0, 0x1, 0) #3.6V self.femb.write_reg_bits(8, regBase + 1, 0x1, 0) #2.8V self.femb.write_reg_bits(8, regBase + 2, 0x1, 0) #2.5V self.femb.write_reg_bits(8, regBase + 3, 0x1, 0) #1.5V print("FEMB Power off: ", hex(self.femb.read_reg(8))) #return register interface to FEMB self.selectFemb(self.fembNum) def selectChannel(self, asic, chan): #print("Select channel") asicVal = int(asic) if (asicVal < 0) or (asicVal > self.NASICS): return #set UDP ports to WIB self.femb.UDP_PORT_WREG = 32000 self.femb.UDP_PORT_RREG = 32001 self.femb.UDP_PORT_RREGRESP = 32002 #select ASIC #print("Selecting ASIC " + str(asicVal) ) self.femb.write_reg_bits(self.REG_SEL_ASIC, self.REG_SEL_ASIC_LSB, 0xF, asicVal) #Note: WIB data format streams all 16 channels, don't need to select specific channel #set UDP ports back to normal self.selectFemb(self.fembNum) def configFeAsic(self): print("CONFIG ASICs") #configure ASICs to default #global config varibles feasicLeakageVal = int(self.feasicLeakage) #0 = 500pA, 1 = 100pA feasicLeakagex10Val = int(self.feasicLeakagex10) #0 = x1, 1 = x10 acdcVal = int(self.feasicAcdc) #DC = 0, AC = 1 #channel specific variables testVal = int(self.feasicEnableTestInput) baseVal = int(self.feasicBaseline) #0 = 900mV, 1 = 200mV gainVal = int(self.feasicGain) shapeVal = int(self.feasicShape) bufVal = int(self.feasicBuf) #0 = OFF, 1 = ON if (testVal < 0) or (testVal > 1): return if (baseVal < 0) or (baseVal > 1): return if (gainVal < 0) or (gainVal > 3): return if (shapeVal < 0) or (shapeVal > 3): return if (acdcVal < 0) or (acdcVal > 1): return if (bufVal < 0) or (bufVal > 1): return if (feasicLeakageVal < 0) or (feasicLeakageVal > 1): return if (feasicLeakagex10Val < 0) or (feasicLeakagex10Val > 1): return chReg = 0 #test capacitor, bit 7 chReg = chReg + ((testVal & 0x01) << 7) #baseline control, bit 6 baseVal = 1 - baseVal #assign 0 = 200mV, 1 = 900mV chReg = chReg + ((baseVal & 0x01) << 6) #gain control, bits 4-5 gainArray = [0, 2, 1, 3] chReg = chReg + ((gainArray[gainVal] & 0x03) << 4) #shape control, bits 2-3 shapeArray = [2, 0, 3, 1] #I don't know why chReg = chReg + ((shapeArray[shapeVal] & 0x03) << 2) #buffer control, bit 0 chReg = chReg + ((bufVal & 0x01) << 0) #construct the channel word chWord = (chReg << 24) + (chReg << 16) + (chReg << 8) + chReg asicReg = int(0) #asicReg = int(0x0A00) #leakage control 1, bit 0 asicReg = asicReg + ((feasicLeakageVal & 0x01) << 0) #leakage control 2, bit 4 asicReg = asicReg + ((feasicLeakagex10Val & 0x01) << 4) #AC/DC control #monitor control, bits 1-2 #internal DAC enable, bit 8 #external DAC enable, bit 9 #DAC OUTPUT bits 8-9 , 0xA00 = external DAC #turn off HS data before register writes self.femb.write_reg_bits(9, 0, 0x1, 0) print("HS link turned off") time.sleep(2) #write SPI regs - very rough version chWord = (chReg << 24) + (chReg << 16) + (chReg << 8) + chReg for asic in range(0, self.NASICS, 1): baseReg = self.REG_SPI_BASE + int(asic) * 9 self.femb.write_reg_bits(baseReg + 4, 16, 0xFF, chReg) #ch0 self.femb.write_reg_bits(baseReg + 4, 24, 0xFF, chReg) #ch1 self.femb.write_reg(baseReg + 5, chWord) #ch2-5 self.femb.write_reg(baseReg + 6, chWord) #ch6-9 self.femb.write_reg(baseReg + 7, chWord) #ch10-13 self.femb.write_reg_bits(baseReg + 8, 0, 0xFF, chReg) #ch14 self.femb.write_reg_bits(baseReg + 8, 8, 0xFF, chReg) #ch15 self.femb.write_reg_bits(baseReg + 8, 16, 0xFFFF, asicReg) #ASIC gen reg #run the SPI programming self.doAsicConfig() #turn HS link back on print("HS link turned back on") time.sleep(2) self.femb.write_reg_bits(9, 0, 0x1, 1) def doAsicConfig(self): #for regNum in range(self.REG_SPI_BASE,self.REG_SPI_BASE+72,1): # regVal = self.femb.read_reg( regNum) # print( str(regNum) + "\t" + str(hex(regVal)) ) #Write ADC ASIC SPI print("Program ASIC SPI") self.femb.write_reg(self.REG_ASIC_RESET, 1) time.sleep(0.1) self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) time.sleep(0.1) self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) time.sleep(0.1) #for regNum in range(self.REG_SPI_RDBACK_BASE,self.REG_SPI_RDBACK_BASE+72,1): # regVal = self.femb.read_reg( regNum) # print( str(regNum) + "\t" + str(hex(regVal)) ) def setInternalPulser(self, pulserEnable, pulseHeight): print("Set Pulser") def syncADC(self): print("Sync") def selectFemb(self, fembIn): fembVal = int(fembIn) if (fembVal < 0) or (fembVal > self.NFEMBS): print("Invalid FEMB # requested") return self.fembNum = fembVal #set data streaming for requested FEMB #set UDP ports to WIB self.femb.UDP_PORT_WREG = 32000 self.femb.UDP_PORT_RREG = 32001 self.femb.UDP_PORT_RREGRESP = 32002 self.femb.write_reg_bits(7, 16, 0x3, self.fembNum) #set read/write ports if fembVal == 0: self.femb.UDP_PORT_WREG = 32016 self.femb.UDP_PORT_RREG = 32017 self.femb.UDP_PORT_RREGRESP = 32018 if fembVal == 1: self.femb.UDP_PORT_WREG = 32032 self.femb.UDP_PORT_RREG = 32033 self.femb.UDP_PORT_RREGRESP = 32034 if fembVal == 2: self.femb.UDP_PORT_WREG = 32048 self.femb.UDP_PORT_RREG = 32049 self.femb.UDP_PORT_RREGRESP = 32050 if fembVal == 3: self.femb.UDP_PORT_WREG = 32064 self.femb.UDP_PORT_RREG = 32065 self.femb.UDP_PORT_RREGRESP = 32066 #slow down register interface for FEMBs self.femb.REG_SLEEP = 0.05 def initSI5338(self): #set UDP ports to WIB self.femb.UDP_PORT_WREG = 32000 self.femb.UDP_PORT_RREG = 32001 self.femb.UDP_PORT_RREGRESP = 32002 self.femb.REG_SLEEP = 0.001 #disable all outputs #i2c_reg_wr(i2c_bus_base_addr, si5338_i2c_addr, 230, 0x10); self.write_reg_SI5338(230, 0x10) #pause lol #i2c_reg_wr(i2c_bus_base_addr, si5338_i2c_addr, 241, 0xE5); self.write_reg_SI5338(241, 0xE5) import femb_python.configuration.femb_config_wib_sbnd_si5338_data for word in range(0, 349, 1): wordNum = int(word) addr = int(femb_python.configuration. femb_config_wib_sbnd_si5338_data.data[3 * wordNum + 0]) val = int(femb_python.configuration. femb_config_wib_sbnd_si5338_data.data[3 * wordNum + 1]) mask = int(femb_python.configuration. femb_config_wib_sbnd_si5338_data.data[3 * wordNum + 2]) if wordNum % 10 == 0: print("Writing SI5338 register # " + str(wordNum) + " out of 349") if mask == 0: continue writeVal = val if mask != 0xFF: curr_val = self.read_reg_SI5338(addr) clear_curr_val = curr_val & (~mask) clear_new_val = val & mask writeVal = clear_curr_val | clear_new_val self.write_reg_SI5338(addr, writeVal) #print(str(addr) + "\t" + str(writeVal)) #validate input clock status #i2c_reg_rd(i2c_bus_base_addr, si5338_i2c_addr, 218); clkStatus = (self.read_reg_SI5338(218) & 0x04) count = 0 while count < 100: clkStatus = (self.read_reg_SI5338(218) & 0x04) if clkStatus != 0x04: break count = count + 1 if clkStatus == 0x04: print("Did not finish clock initialization") return #configure pll pllWord = int( femb_python.configuration.femb_config_wib_sbnd_si5338_data.data[ 3 * 49 + 1]) self.write_reg_SI5338(49, (0x7F & pllWord)) #reset the chip self.write_reg_SI5338(246, 0x02) time.sleep(0.1) #restart lol self.write_reg_SI5338(241, 0x65) #validate pll pllStatus = self.read_reg_SI5338(218) count = 0 while count < 100: pllStatus = self.read_reg_SI5338(218) if pllStatus == 0: break count = count + 1 if pllStatus != 0: print("Did not finish clock initialization") return #copy FCAL values to active registers fcalVal = self.read_reg_SI5338(235) self.write_reg_SI5338(45, fcalVal) fcalVal = self.read_reg_SI5338(236) self.write_reg_SI5338(46, fcalVal) fcalVal = self.read_reg_SI5338(237) fcalVal = (0x14 | (fcalVal & 0x3)) self.write_reg_SI5338(47, fcalVal) #set pll to use FCAL values #i2c_reg_wr(i2c_bus_base_addr, si5338_i2c_addr, 49, 0x80|SI5338Reg[49*3+1]); setPllWord = (0x80 | pllWord) self.write_reg_SI5338(49, setPllWord) #enable outputs self.write_reg_SI5338(230, 0x00) print("Done initalizing Si5338 clock") def read_reg_SI5338(self, addr): addrVal = int(addr) if (addrVal < 0) or (addrVal > 255): return self.femb.write_reg(11, 0) self.femb.write_reg(12, addrVal) self.femb.write_reg(15, 0xE0) self.femb.write_reg(10, 1) self.femb.write_reg(10, 0) self.femb.write_reg(11, 1) self.femb.write_reg(10, 2) self.femb.write_reg(10, 0) regVal = self.femb.read_reg(14) return regVal def write_reg_SI5338(self, addr, val): addrVal = int(addr) if (addrVal < 0) or (addrVal > 255): return regVal = int(val) if (regVal < 0) or (regVal > 255): return self.femb.write_reg(11, 1) self.femb.write_reg(12, addrVal) self.femb.write_reg(13, regVal) self.femb.write_reg(10, 1) self.femb.write_reg(10, 0) def setFpgaPulser(self, enable, dac): enableVal = int(enable) if (enableVal < 0) or (enableVal > 1): print("femb_config_femb : setFpgaPulser - invalid enable value") return dacVal = int(dac) if (dacVal < 0) or (dacVal > 0x3F): print("femb_config_femb : setFpgaPulser - invalid dac value") return #set pulser enable bit if enableVal == 1: self.femb.write_reg( self.EXT_TP_EN, 0x2) #pulser enabled, bit 0 is FPGA pulser NOT enabled else: self.femb.write_reg(self.EXT_TP_EN, 0x3) #pulser disabled #connect channel test input to external pin for asic in range(0, self.NASICS, 1): baseReg = self.REG_SPI_BASE + int(asic) * 9 if enableVal == 1: self.femb.write_reg_bits(baseReg + 8, 24, 0x3, 0x2) #ASIC gen reg else: self.femb.write_reg_bits(baseReg + 8, 24, 0x3, 0x0) #ASIC gen reg self.doAsicConfig() self.femb.write_reg_bits(self.REG_FPGA_TP_EN, 0, 0x3, 0x1) #test pulse enable self.femb.write_reg_bits(self.REG_FPGA_TP_EN, 8, 0x1, 1) #test pulse enable self.femb.write_reg_bits(self.REG_TP, 0, 0x3F, dacVal) #TP Amplitude self.femb.write_reg_bits(self.REG_TP, 8, 0xFF, 219) #DLY self.femb.write_reg_bits(self.REG_TP, 16, 0xFFFF, 197) #FREQ def setInternalPulser(self, enable, dac): enableVal = int(enable) if (enableVal < 0) or (enableVal > 1): print( "femb_config_femb : setInternalPulser - invalid enable value") return dacVal = int(dac) if (dacVal < 0) or (dacVal > 0x3F): print("femb_config_femb : setInternalPulser - invalid dac value") return #set pulser enable bit if enableVal == 1: self.femb.write_reg(self.INT_TP_EN, 0x1) #pulser enabled else: self.femb.write_reg(self.INT_TP_EN, 0x3) #pulser disabled dacVal = (dacVal & 0x3F) newDacVal = int('{:08b}'.format(dacVal)[::-1], 2) asicWord = ((newDacVal << 8) & 0xFFFF) if enableVal == 1: asicWord = asicWord + (0x1 << 8) #connect channel test input to external pin for asic in range(0, self.NASICS, 1): baseReg = self.REG_SPI_BASE + int(asic) * 9 if enableVal == 1: self.femb.write_reg_bits(baseReg + 8, 24, 0xFF, newDacVal) self.femb.write_reg_bits(baseReg + 8, 24, 0x3, 0x1) #ASIC gen reg else: self.femb.write_reg_bits(baseReg + 8, 24, 0xFF, 0x0) #ASIC gen reg self.doAsicConfig() self.femb.write_reg_bits(self.REG_ASIC_TP_EN, 0, 0x3, 0x2) self.femb.write_reg_bits(self.REG_DAC_SELECT, 8, 0x1, 0) #test pulse enable self.femb.write_reg_bits(self.REG_TP, 0, 0x3F, dacVal) #TP Amplitude self.femb.write_reg_bits(self.REG_TP, 8, 0xFF, 219) #DLY self.femb.write_reg_bits(self.REG_TP, 16, 0xFFFF, 197) #FREQ
class FEMB_CONFIG(FEMB_CONFIG_BASE): def __init__(self, exitOnError=True): super().__init__(exitOnError=exitOnError) #declare board specific registers self.FEMB_VER = "adctestP1single" self.REG_RESET = 0 self.REG_ASIC_RESET = 1 self.REG_ASIC_SPIPROG = 2 self.REG_SEL_CH = 7 self.REG_HS = 17 self.REG_FESPI_BASE = 0x250 # 592 in decimal self.REG_ADCSPI_BASE = 0x200 # 512 in decimal self.REG_FESPI_RDBACK_BASE = 0x278 # 632 in decimal self.REG_ADCSPI_RDBACK_BASE = 0x228 # 552 in decimal self.REG_LATCHLOC1_4 = 4 self.REG_LATCHLOC5_8 = 14 self.REG_CLKPHASE = 6 self.REG_LATCHLOC1_4_data = 0x6 self.REG_LATCHLOC5_8_data = 0x0 self.REG_CLKPHASE_data = 0xfffc0000 self.REG_LATCHLOC1_4_data_1MHz = 0x5 self.REG_LATCHLOC5_8_data_1MHz = 0x0 self.REG_CLKPHASE_data_1MHz = 0xffff0000 self.REG_LATCHLOC1_4_data_cold = 0x6 self.REG_LATCHLOC5_8_data_cold = 0x0 self.REG_CLKPHASE_data_cold = 0xfffc0000 self.REG_LATCHLOC1_4_data_1MHz_cold = 0x4 self.REG_LATCHLOC5_8_data_1MHz_cold = 0x0 self.REG_CLKPHASE_data_1MHz_cold = 0xfffc0001 self.ADC_TESTPATTERN = [ 0x12, 0x345, 0x678, 0xf1f, 0xad, 0xc01, 0x234, 0x567, 0x89d, 0xeca, 0xff0, 0x123, 0x456, 0x789, 0xabc, 0xdef ] ################################## # external clock control registers ################################## self.FPGA_FREQ_MHZ = 200 # frequency of FPGA clock in MHz self.REG_EXTCLK_RD_EN_OFF = 23 self.REG_EXTCLK_ADC_OFF = 21 self.REG_EXTCLK_ADC_WID = 22 self.REG_EXTCLK_MSB_OFF = 25 self.REG_EXTCLK_MSB_WID = 26 self.REG_EXTCLK_PERIOD = 20 self.REG_EXTCLK_LSB_FC_WID2 = 32 self.REG_EXTCLK_LSB_FC_OFF1 = 29 self.REG_EXTCLK_RD_EN_WID = 24 self.REG_EXTCLK_LSB_FC_WID1 = 30 self.REG_EXTCLK_LSB_FC_OFF2 = 31 self.REG_EXTCLK_LSB_S_WID = 28 self.REG_EXTCLK_LSB_S_OFF = 27 self.REG_EXTCLK_INV = 33 ################################## ################################## self.NASICS = 1 self.FUNCGENINTER = Keysight_33600A("/dev/usbtmc1", 1) self.POWERSUPPLYINTER = RigolDP800( "/dev/usbtmc0", ["CH2", "CH3", "CH1"]) # turn on CH2 first self.F2DEFAULT = 0 self.CLKDEFAULT = "fifo" ## Firmware update related variables self.FIRMWAREPATH2MHZ = "/opt/sw/releases/femb_firmware-0.1.0/adc_tester/S7_2M_SBND_FPGA.sof" self.FIRMWAREPATH1MHZ = "/opt/sw/releases/femb_firmware-0.1.0/adc_tester/S7_1M_SBND_FPGA.sof" self.FIRMWAREPROGEXE = "/opt/sw/intelFPGA/17.0/qprogrammer/bin/quartus_pgm" #self.FIRMWAREPROGCABLE = "USB-Blaster" self.FIRMWAREPROGCABLE = "USB-BlasterII" self.SAMPLERATE = 2e6 #initialize FEMB UDP object self.femb = FEMB_UDP() self.adc_reg = ADC_ASIC_REG_MAPPING() def resetBoard(self): #Reset system self.femb.write_reg(self.REG_RESET, 1) time.sleep(5.) #Reset registers self.femb.write_reg(self.REG_RESET, 2) time.sleep(1.) #Time stamp reset #femb.write_reg( 0, 4) #time.sleep(0.5) #Reset ADC ASICs self.femb.write_reg(self.REG_ASIC_RESET, 1) time.sleep(0.5) def initBoard(self): nRetries = 5 for iRetry in range(nRetries): #set up default registers #Reset ADC ASICs self.femb.write_reg(self.REG_ASIC_RESET, 1) time.sleep(0.5) readback = self.femb.read_reg(0) if readback is None: if self.exitOnError: print("FEMB_CONFIG: Error reading register 0, Exiting.") sys.exit(1) else: raise ReadRegError("Couldn't read register 0") #Set ADC test pattern register self.femb.write_reg(3, 0x01170000) # test pattern off #self.femb.write_reg( 3, 0x81170000) # test pattern on #Set ADC latch_loc and clock phase latchloc1 = None latchloc5 = None clockphase = None if self.SAMPLERATE == 1e6: if self.COLD: print("Using 1 MHz cold latchloc/clockphase") latchloc1 = self.REG_LATCHLOC1_4_data_1MHz_cold latchloc5 = self.REG_LATCHLOC5_8_data_1MHz_cold clockphase = self.REG_CLKPHASE_data_1MHz_cold else: print("Using 1 MHz warm latchloc/clockphase") latchloc1 = self.REG_LATCHLOC1_4_data_1MHz latchloc5 = self.REG_LATCHLOC5_8_data_1MHz clockphase = self.REG_CLKPHASE_data_1MHz else: # use 2 MHz values if self.COLD: print("Using 2 MHz cold latchloc/clockphase") latchloc1 = self.REG_LATCHLOC1_4_data_cold latchloc5 = self.REG_LATCHLOC5_8_data_cold clockphase = self.REG_CLKPHASE_data_cold else: print("Using 2 MHz warm latchloc/clockphase") latchloc1 = self.REG_LATCHLOC1_4_data latchloc5 = self.REG_LATCHLOC5_8_data clockphase = self.REG_CLKPHASE_data print( "Initializing with Latch Loc: {:#010x} {:#010x} Clock Phase: {:#010x}" .format(latchloc1, latchloc5, clockphase)) self.femb.write_reg(self.REG_LATCHLOC1_4, latchloc1) self.femb.write_reg(self.REG_LATCHLOC5_8, latchloc5) for iTry in range(5): self.femb.write_reg(self.REG_CLKPHASE, ~clockphase) time.sleep(0.05) self.femb.write_reg(self.REG_CLKPHASE, ~clockphase) time.sleep(0.05) self.femb.write_reg(self.REG_CLKPHASE, clockphase) time.sleep(0.05) self.femb.write_reg(self.REG_CLKPHASE, clockphase) time.sleep(0.05) print("Readback: ", self.getClockStr()) #internal test pulser control self.femb.write_reg(5, 0x00000000) self.femb.write_reg(13, 0x0) #enable #Set test and readout mode register self.femb.write_reg( self.REG_HS, 0x0) # 0 readout all 15 channels, 1 readout only selected one self.femb.write_reg( self.REG_SEL_CH, 0x0000) #11-8 = channel select, 3-0 = ASIC select #Set number events per header self.femb.write_reg(8, 0x0) #Configure ADC (and external clock inside) try: self.configAdcAsic() #self.configAdcAsic(clockMonostable=True) except ReadRegError: continue # Check that board streams data data = self.femb.get_data(1) if data == None: print("Board not streaming data, retrying initialization...") continue # try initializing again print("FEMB_CONFIG--> Reset FEMB is DONE") return print( "Error: Board not streaming data after trying to initialize {} times." .format(nRetries)) if self.exitOnError: print("Exiting.") sys.exit(1) else: raise InitBoardError def configAdcAsic_regs(self, Adcasic_regs): #ADC ASIC SPI registers assert (len(Adcasic_regs) == 36) print("FEMB_CONFIG--> Config ADC ASIC SPI") for k in range(10): i = 0 for regNum in range(self.REG_ADCSPI_BASE, self.REG_ADCSPI_BASE + len(Adcasic_regs), 1): self.femb.write_reg(regNum, Adcasic_regs[i]) time.sleep(0.05) i = i + 1 #print(" ADC ASIC write : ",Adcasic_regs) #ADC ASIC sync -- Justin: I don't think this exists anymore #self.femb.write_reg ( 17, 0x1) # controls HS link, 0 for on, 1 for off #self.femb.write_reg ( 17, 0x0) # controls HS link, 0 for on, 1 for off #Write ADC ASIC SPI print("FEMB_CONFIG--> Program ADC ASIC SPI") self.femb.write_reg(self.REG_ASIC_RESET, 1) time.sleep(0.1) self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) time.sleep(0.1) self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) time.sleep(0.1) #enable streaming #self.femb.write_reg( 9, 0x1) #LBNE_ADC_MODE self.femb.write_reg(18, 0x1) print("FEMB_CONFIG--> Check ADC ASIC SPI") adcasic_rb_regs = [] for regNum in range( self.REG_ADCSPI_RDBACK_BASE, self.REG_ADCSPI_RDBACK_BASE + len(Adcasic_regs), 1): val = self.femb.read_reg(regNum) if val is None: message = "Error in FEMB_CONFIG.configAdcAsic_regs: read from board failed" print(message) if self.exitOnError: return else: raise ReadRegError adcasic_rb_regs.append(val) #print("{:32} {:32}".format("Write","Readback")) #print("{:8} {:8}".format("Write","Readback")) # we only get 15 LSBs back so miss D0 for a channel and CLK0 readbackMatch = True for regNum in range(36): write_val = Adcasic_regs[regNum] #& 0x7FFF readback_val = adcasic_rb_regs[(regNum + 9) % 36] >> 1 # we only get the 15 LSBs back if readback_val != (Adcasic_regs[regNum] & 0x7FFF): readbackMatch = False #print("{:032b} {:032b}".format(write_val,readback_val)) #print("{:08X} {:08X}".format(write_val,readback_val)) if readbackMatch: print("FEMB_CONFIG--> ADC ASIC SPI is OK") return else: print( "FEMB_CONFIG--> ADC ASIC Readback didn't match, retrying..." ) print("Error: Wrong ADC SPI readback.") if self.exitOnError: print("Exiting.") sys.exit(1) else: raise ConfigADCError def configAdcAsic(self, enableOffsetCurrent=None, offsetCurrent=None, testInput=None, freqInternal=None, sleep=None, pdsr=None, pcsr=None, clockMonostable=None, clockExternal=None, clockFromFIFO=None, sLSB=None, f0=None, f1=None, f2=None, f3=None, f4=None, f5=None): """ Configure ADCs enableOffsetCurrent: 0 disable offset current, 1 enable offset current offsetCurrent: 0-15, amount of current to draw from sample and hold testInput: 0 digitize normal input, 1 digitize test input freqInternal: internal clock frequency: 0 1MHz, 1 2MHz sleep: 0 disable sleep mode, 1 enable sleep mode pdsr: if pcsr=0: 0 PD is low, 1 PD is high pcsr: 0 power down controlled by pdsr, 1 power down controlled externally Only one of these can be enabled: clockMonostable: True ADC uses monostable clock clockExternal: True ADC uses external clock clockFromFIFO: True ADC uses digital generator FIFO clock sLSB: LSB current steering mode. 0 for full, 1 for partial (ADC7 P1) f0, f1, f2, f3, f4, f5: version specific """ FEMB_CONFIG_BASE.configAdcAsic(self, clockMonostable=clockMonostable, clockExternal=clockExternal, clockFromFIFO=clockFromFIFO) if enableOffsetCurrent is None: enableOffsetCurrent = 0 if offsetCurrent is None: offsetCurrent = 0 else: offsetCurrent = int( "{:04b}".format(offsetCurrent)[::-1], 2) # need to reverse bits, use string/list tricks if testInput is None: testInput = 1 if freqInternal is None: freqInternal = 1 if sleep is None: sleep = 0 if pdsr is None: pdsr = 0 if pcsr is None: pcsr = 0 if sLSB is None: sLSB = 0 if f1 is None: f1 = 0 if f2 is None: f2 = 0 if f3 is None: f3 = 0 if f4 is None: f4 = 1 if f5 is None: f5 = 0 if not (clockMonostable or clockExternal or clockFromFIFO): clockExternal = True # a bunch of things depend on the clock choice clk0 = 0 clk1 = 0 if clockExternal: clk0 = 1 clk1 = 0 elif clockFromFIFO: clk0 = 0 clk1 = 1 if f0 is None: if clockExternal: f0 = 1 else: f0 = 0 if clockExternal: self.extClock(enable=True) else: self.extClock(enable=False) self.adc_reg.set_sbnd_board(en_gr=enableOffsetCurrent, d=offsetCurrent, tstin=testInput, frqc=freqInternal, slp=sleep, pdsr=pdsr, pcsr=pcsr, clk0=clk0, clk1=clk1, f0=f0, f1=f1, f2=f2, f3=f3, f4=f4, f5=f5, slsb=sLSB) self.configAdcAsic_regs(self.adc_reg.REGS) def selectChannel(self, asic, chan, hsmode=1, singlechannelmode=None): """ asic is chip number 0 to 7 chan is channel within asic from 0 to 15 hsmode: if 0 then streams all channels of a chip, if 1 only te selected channel. defaults to 1 singlechannelmode: not implemented """ hsmodeVal = int(hsmode) & 1 asicVal = int(asic) if (asicVal < 0) or (asicVal >= self.NASICS): print( "femb_config_femb : selectChan - invalid ASIC number, only 0 to {} allowed" .format(self.NASICS - 1)) return chVal = int(chan) if (chVal < 0) or (chVal > 15): print( "femb_config_femb : selectChan - invalid channel number, only 0 to 15 allowed" ) return #print( "Selecting ASIC " + str(asicVal) + ", channel " + str(chVal)) self.femb.write_reg(self.REG_HS, hsmodeVal) regVal = (chVal << 8) + asicVal self.femb.write_reg(self.REG_SEL_CH, regVal) def syncADC(self, iASIC=None): #turn on ADC test mode print("FEMB_CONFIG--> Start sync ADC") reg3 = self.femb.read_reg(3) newReg3 = (reg3 | 0x80000000) self.femb.write_reg(3, newReg3) #31 - enable ADC test pattern time.sleep(0.1) alreadySynced = True for a in range(0, self.NASICS, 1): print("FEMB_CONFIG--> Test ADC " + str(a)) unsync, syncDicts = self.testUnsync(a) if unsync != 0: alreadySynced = False print("FEMB_CONFIG--> ADC not synced, try to fix") self.fixUnsync(a) latchloc1_4 = self.femb.read_reg(self.REG_LATCHLOC1_4) latchloc5_8 = self.femb.read_reg(self.REG_LATCHLOC5_8) clkphase = self.femb.read_reg(self.REG_CLKPHASE) if self.SAMPLERATE == 1e6: if self.COLD: self.REG_LATCHLOC1_4_data_1MHz_cold = latchloc1_4 self.REG_LATCHLOC5_8_data_1MHz_cold = latchloc5_8 self.REG_CLKPHASE_data_1MHz_cold = clkphase else: self.REG_LATCHLOC1_4_data_1MHz = latchloc1_4 self.REG_LATCHLOC5_8_data_1MHz = latchloc5_8 self.REG_CLKPHASE_data_1MHz = clkphase else: # 2 MHz if self.COLD: self.REG_LATCHLOC1_4_data_cold = latchloc1_4 self.REG_LATCHLOC5_8_data_cold = latchloc5_8 self.REG_CLKPHASE_data_cold = clkphase else: self.REG_LATCHLOC1_4_data = latchloc1_4 self.REG_LATCHLOC5_8_data = latchloc5_8 self.REG_CLKPHASE_data = clkphase print("FEMB_CONFIG--> Latch latency {:#010x} {:#010x} Phase: {:#010x}". format(latchloc1_4, latchloc5_8, clkphase)) self.femb.write_reg(3, (reg3 & 0x7fffffff)) self.femb.write_reg(3, (reg3 & 0x7fffffff)) print("FEMB_CONFIG--> End sync ADC") return not alreadySynced, latchloc1_4, latchloc5_8, clkphase def testUnsync(self, adc, npackets=10): print("Starting testUnsync adc: ", adc) adcNum = int(adc) if (adcNum < 0) or (adcNum > 7): print( "FEMB_CONFIG--> femb_config_femb : testLink - invalid asic number" ) return #loop through channels, check test pattern against data syncDataCounts = [{} for i in range(16)] #dict for each channel for ch in range(0, 16, 1): self.selectChannel(adcNum, ch, 1) time.sleep(0.05) data = self.femb.get_data(npackets) if data == None: continue for samp in data: if samp == None: continue #chNum = ((samp >> 12 ) & 0xF) sampVal = (samp & 0xFFF) if sampVal in syncDataCounts[ch]: syncDataCounts[ch][sampVal] += 1 else: syncDataCounts[ch][sampVal] = 1 # check jitter badSync = 0 maxCodes = [None] * 16 syncDicts = [{}] * 16 for ch in range(0, 16, 1): sampSum = 0 maxCode = None nMaxCode = 0 for code in syncDataCounts[ch]: nThisCode = syncDataCounts[ch][code] sampSum += nThisCode if nThisCode > nMaxCode: nMaxCode = nThisCode maxCode = code maxCodes[ch] = maxCode syncDicts[ch]["maxCode"] = maxCode syncDicts[ch]["nSamplesMaxCode"] = nMaxCode syncDicts[ch]["nSamples"] = sampSum syncDicts[ch]["zeroJitter"] = True if len(syncDataCounts[ch]) > 1: syncDicts[ch]["zeroJitter"] = False badSync = 1 diff = sampSum - nMaxCode frac = diff / float(sampSum) print("Sync Error: Jitter for Ch {:2}: {:8.4%} ({:5}/{:5})". format(ch, frac, diff, sampSum)) for ch in range(0, 16, 1): maxCode = maxCodes[ch] correctCode = self.ADC_TESTPATTERN[ch] syncDicts[ch]["data"] = True syncDicts[ch]["maxCodeMatchesExpected"] = True if maxCode is None: syncDicts[ch]["data"] = False badSync = 1 print("Sync Error: no data for ch {:2}".format(ch)) elif maxCode != correctCode: syncDicts[ch]["maxCodeMatchesExpected"] = True badSync = 1 print( "Sync Error: mismatch for ch {:2}: expected {:#03x} observed {:#03x}" .format(ch, correctCode, maxCode)) return badSync, syncDicts def fixUnsync(self, adc): adcNum = int(adc) if (adcNum < 0) or (adcNum > 7): print( "FEMB_CONFIG--> femb_config_femb : testLink - invalid asic number" ) return initLATCH1_4 = self.femb.read_reg(self.REG_LATCHLOC1_4) initLATCH5_8 = self.femb.read_reg(self.REG_LATCHLOC5_8) initPHASE = self.femb.read_reg(self.REG_CLKPHASE) phases = [0, 1] if self.COLD: phases = [0, 1, 0, 1, 0] #loop through sync parameters for shift in range(0, 16, 1): shiftMask = (0x3F << 8 * adcNum) if (adcNum < 4): testShift = ((initLATCH1_4 & ~(shiftMask)) | (shift << 8 * adcNum)) self.femb.write_reg(self.REG_LATCHLOC1_4, testShift) time.sleep(0.01) else: testShift = ((initLATCH5_8 & ~(shiftMask)) | (shift << 8 * adcNum)) self.femb.write_reg(self.REG_LATCHLOC5_8, testShift) time.sleep(0.01) for phase in phases: clkMask = (0x1 << adcNum) testPhase = ((initPHASE & ~(clkMask)) | (phase << adcNum)) self.femb.write_reg(self.REG_CLKPHASE, testPhase) time.sleep(0.01) print("try shift: {} phase: {} testingUnsync...".format( shift, phase)) print( " initPHASE: {:#010x}, phase: {:#010x}, testPhase: {:#010x}" .format(initPHASE, phase, testPhase)) #reset ADC ASIC self.femb.write_reg(self.REG_ASIC_RESET, 1) time.sleep(0.01) self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) time.sleep(0.01) self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) time.sleep(0.01) #test link unsync, syncDicts = self.testUnsync(adcNum) if unsync == 0: print("FEMB_CONFIG--> ADC synchronized") return #if program reaches here, sync has failed print("Error: FEMB_CONFIG--> ADC SYNC process failed for ADC # " + str(adc)) print( "Setting back to original values: LATCHLOC1_4: {:#010x}, LATCHLOC5_8: {:#010x}, PHASE: {:#010x}" .format, initLATCH1_4, initLATCH5_8, initPHASE) self.femb.write_reg(self.REG_LATCHLOC1_4, initLATCH1_4) self.femb.write_reg(self.REG_LATCHLOC5_8, initLATCH5_8) self.femb.write_reg(self.REG_CLKPHASE, initPHASE) if self.exitOnError: sys.exit(1) else: raise SyncADCError def extClock(self, enable=False, period=500, mult=1, offset_rst=0, offset_read=480, offset_msb=230, offset_lsb=480, width_rst=50, width_read=20, width_msb=270, width_lsb=20, offset_lsb_1st_1=50, width_lsb_1st_1=190, offset_lsb_1st_2=480, width_lsb_1st_2=20, inv_rst=True, inv_read=True, inv_msb=False, inv_lsb=False, inv_lsb_1st=False): """ Programs external clock. All non-boolean arguments except mult are in nanoseconds """ rd_en_off = 0 adc_off = 0 adc_wid = 0 msb_off = 0 msb_wid = 0 period_val = 0 lsb_fc_wid2 = 0 lsb_fc_off1 = 0 rd_en_wid = 0 lsb_fc_wid1 = 0 lsb_fc_off2 = 0 lsb_s_wid = 0 lsb_s_off = 0 inv = 0 if enable: clock = 1. / self.FPGA_FREQ_MHZ * 1000. # clock now in ns #print("FPGA Clock freq: {} MHz period: {} ns".format(self.FPGA_FREQ_MHZ,clock)) #print("ExtClock option mult: {}".format(mult)) #print("ExtClock option period: {} ns".format(period)) #print("ExtClock option offset_read: {} ns".format(offset_read)) #print("ExtClock option offset_rst: {} ns".format(offset_rst)) #print("ExtClock option offset_msb: {} ns".format(offset_msb)) #print("ExtClock option offset_lsb: {} ns".format(offset_lsb)) #print("ExtClock option offset_lsb_1st_1: {} ns".format(offset_lsb_1st_1)) #print("ExtClock option offset_lsb_1st_2: {} ns".format(offset_lsb_1st_2)) #print("ExtClock option width_read: {} ns".format(width_read)) #print("ExtClock option width_rst: {} ns".format(width_rst)) #print("ExtClock option width_msb: {} ns".format(width_msb)) #print("ExtClock option width_lsb: {} ns".format(width_lsb)) #print("ExtClock option width_lsb_1st_1: {} ns".format(width_lsb_1st_1)) #print("ExtClock option width_lsb_1st_2: {} ns".format(width_lsb_1st_2)) #print("ExtClock option inv_rst: {}".format(inv_rst)) #print("ExtClock option inv_read: {}".format(inv_read)) #print("ExtClock option inv_msb: {}".format(inv_msb)) #print("ExtClock option inv_lsb: {}".format(inv_lsb)) #print("ExtClock option inv_lsb_1st: {}".format(inv_lsb_1st)) denominator = clock / mult #print("ExtClock denominator: {} ns".format(denominator)) period_val = period // denominator rd_en_off = offset_read // denominator adc_off = offset_rst // denominator adc_wid = width_rst // denominator msb_off = offset_msb // denominator msb_wid = width_msb // denominator lsb_fc_wid2 = width_lsb_1st_2 // denominator lsb_fc_off1 = offset_lsb_1st_1 // denominator rd_en_wid = width_read // denominator lsb_fc_wid1 = width_lsb_1st_1 // denominator lsb_fc_off2 = offset_lsb_1st_2 // denominator lsb_s_wid = width_lsb // denominator lsb_s_off = offset_lsb // denominator if inv_rst: inv += 1 << 0 if inv_read: inv += 1 << 1 if inv_msb: inv += 1 << 2 if inv_lsb: inv += 1 << 3 if inv_lsb_1st: inv += 1 << 4 regsValsToWrite = [ ("rd_en_off", self.REG_EXTCLK_RD_EN_OFF, rd_en_off), ("adc_off", self.REG_EXTCLK_ADC_OFF, adc_off), ("adc_wid", self.REG_EXTCLK_ADC_WID, adc_wid), ("msb_off", self.REG_EXTCLK_MSB_OFF, msb_off), ("msb_wid", self.REG_EXTCLK_MSB_WID, msb_wid), ("period", self.REG_EXTCLK_PERIOD, period_val), ("lsb_fc_wid2", self.REG_EXTCLK_LSB_FC_WID2, lsb_fc_wid2), ("lsb_fc_off1", self.REG_EXTCLK_LSB_FC_OFF1, lsb_fc_off1), ("rd_en_wid", self.REG_EXTCLK_RD_EN_WID, rd_en_wid), ("lsb_fc_wid1", self.REG_EXTCLK_LSB_FC_WID1, lsb_fc_wid1), ("lsb_fc_off2", self.REG_EXTCLK_LSB_FC_OFF2, lsb_fc_off2), ("lsb_s_wid", self.REG_EXTCLK_LSB_S_WID, lsb_s_wid), ("lsb_s_off", self.REG_EXTCLK_LSB_S_OFF, lsb_s_off), ("inv", self.REG_EXTCLK_INV, inv), ] for name, reg, val in regsValsToWrite: val = int(val) & 0xFFFF # only 16 bits for some reason #print("ExtClock Register {0:12} number {1:3} set to {2:5} = {2:#06x}".format(name,reg,val)) self.femb.write_reg(reg, val) def programFirmware(self, firmware): """ Programs the FPGA using the firmware file given. """ if self.FIRMWAREPROGCABLE == "USB-BlasterII": # this programmer is too fast for our board # (or linux or something) so we have to slow it down jtagconfig_commandline = os.path.dirname(self.FIRMWAREPROGEXE) jtagconfig_commandline = os.path.join(jtagconfig_commandline, "jtagconfig") jtagconfig_commandline += " --setparam 1 JtagClock 6M" print(jtagconfig_commandline) subprocess.run(jtagconfig_commandline.split(), check=True) commandline = "{} -c {} -m jtag -o p;{}".format( self.FIRMWAREPROGEXE, self.FIRMWAREPROGCABLE, firmware) commandlinelist = commandline.split() print(commandline) print(commandlinelist) subprocess.run(commandlinelist, check=True) def checkFirmwareProgrammerStatus(self): """ Prints a debug message for the firmware programmer """ jtagconfig_commandline = os.path.dirname(self.FIRMWAREPROGEXE) jtagconfig_commandline = os.path.join(jtagconfig_commandline, "jtagconfig") if self.FIRMWAREPROGCABLE == "USB-BlasterII": # this programmer is too fast for our board # (or linux or something) so we have to slow it down jtagconfig_commandline_speed = jtagconfig_commandline + " --setparam 1 JtagClock 6M" print(jtagconfig_commandline_speed) subprocess.run(jtagconfig_commandline_speed.split()) subprocess.run(jtagconfig_commandline.split()) def programFirmware1Mhz(self): self.programFirmware(self.FIRMWAREPATH1MHZ) self.SAMPLERATE = 1e6 def programFirmware2Mhz(self): self.programFirmware(self.FIRMWAREPATH2MHZ) self.SAMPLERATE = 2e6 def getClockStr(self): latchloc1 = self.femb.read_reg(self.REG_LATCHLOC1_4) latchloc5 = self.femb.read_reg(self.REG_LATCHLOC5_8) clkphase = self.femb.read_reg(self.REG_CLKPHASE) if latchloc1 is None: return "Register Read Error" if latchloc5 is None: return "Register Read Error" if clkphase is None: return "Register Read Error" return "Latch Loc: {:#010x} {:#010x} Clock Phase: {:#010x}".format( latchloc1, latchloc5, clkphase) def getSyncStatus(self): return [None], [True], None
class FEMB_CONFIG(FEMB_CONFIG_BASE): def __init__(self): super().__init__() #declare board specific registers self.FEMB_VER = "35t" self.REG_RESET = 0 self.REG_ASIC_RESET = 1 self.REG_ASIC_SPIPROG = 2 self.REG_SEL_ASIC = 7 self.REG_SEL_CH = 7 self.REG_FESPI_BASE = 592 self.REG_ADCSPI_BASE = 512 self.REG_FESPI_RDBACK_BASE = 632 self.REG_ADCSPI_RDBACK_BASE = 552 self.REG_HS = 17 self.REG_LATCHLOC = 4 self.REG_CLKPHASE = 6 self.ADC_TESTPATTERN = [ 0x12, 0x345, 0x678, 0xf1f, 0xad, 0xc01, 0x234, 0x567, 0x89d, 0xeca, 0xff0, 0x123, 0x456, 0x789, 0xabc, 0xdef ] self.NASICS = 8 #initialize FEMB UDP object self.femb = FEMB_UDP() #initialiuze ASIC ch objects, specify SPI register number (firmware specific!!!) self.feasic_ch_list = [] for ch in range(0, 128, 1): chVal = int(ch) if (chVal < 0) or (chVal > 127): continue #seriously messy mapping between ch # and register bits regGrp = int((chVal % 64) / 16) regGrpLine = 7 - int((chVal % 16) / 2) regGrpBase = [27, 18, 9, 0] regNum = self.REG_FESPI_BASE + regGrpBase[regGrp] + regGrpLine regPos = (1 - chVal % 2) * 8 + int(chVal / 64) * 16 feasic_ch = FEASIC_CH_CONFIG(ch, regNum, regPos) self.feasic_ch_list.append(feasic_ch) def resetBoard(self): #Reset system self.femb.write_reg(self.REG_RESET, 1) time.sleep(5.) #Reset registers self.femb.write_reg(self.REG_RESET, 2) time.sleep(1.) #Time stamp reset #femb.write_reg( 0, 4) #time.sleep(0.5) #Reset ADC ASICs self.femb.write_reg(self.REG_ASIC_RESET, 1) time.sleep(0.5) #Reset FE ASICs self.femb.write_reg(self.REG_ASIC_RESET, 2) time.sleep(0.5) def initBoard(self): nRetries = 5 for iRetry in range(nRetries): #set up default registers #Reset ADC ASICs self.femb.write_reg(self.REG_ASIC_RESET, 1) time.sleep(0.5) #Reset FE ASICs self.femb.write_reg(self.REG_ASIC_RESET, 2) time.sleep(0.5) #Set ADC test pattern register self.femb.write_reg(3, 0x01230000) #31 - enable ADC test pattern, #Set ADC latch_loc self.femb.write_reg(self.REG_LATCHLOC, 0x77777677) #Set ADC clock phase self.femb.write_reg(self.REG_CLKPHASE, 0x1e) #internal test pulser control self.femb.write_reg(5, 0x02000001) self.femb.write_reg(13, 0x0) #enable #Set test and readout mode register self.femb.write_reg( 7, 0x0000) #11-8 = channel select, 3-0 = ASIC select #Set number events per header self.femb.write_reg(8, 0x0) #FE ASIC SPI registers print("Config FE ASIC SPI") for regNum in range(self.REG_FESPI_BASE, self.REG_FESPI_BASE + 34, 1): self.femb.write_reg(regNum, 0xC4C4C4C4) self.femb.write_reg(self.REG_FESPI_BASE + 8, 0xC400C400) self.femb.write_reg(self.REG_FESPI_BASE + 16, 0x00C400C4) self.femb.write_reg(self.REG_FESPI_BASE + 25, 0xC400C400) self.femb.write_reg(self.REG_FESPI_BASE + 33, 0x00C400C4) #ADC ASIC SPI registers print("Config ADC ASIC SPI") self.femb.write_reg(self.REG_ADCSPI_BASE + 0, 0xc0c0c0c) self.femb.write_reg(self.REG_ADCSPI_BASE + 1, 0xc0c0c0c) self.femb.write_reg(self.REG_ADCSPI_BASE + 2, 0xc0c0c0c) self.femb.write_reg(self.REG_ADCSPI_BASE + 3, 0xc0c0c0c) self.femb.write_reg(self.REG_ADCSPI_BASE + 4, 0xc0c0c0c) self.femb.write_reg(self.REG_ADCSPI_BASE + 5, 0xc0c0c0c) self.femb.write_reg(self.REG_ADCSPI_BASE + 6, 0xc0c0c0c) self.femb.write_reg(self.REG_ADCSPI_BASE + 7, 0xc0c0c0c) self.femb.write_reg(self.REG_ADCSPI_BASE + 8, 0x18321832) self.femb.write_reg(self.REG_ADCSPI_BASE + 9, 0x18181818) self.femb.write_reg(self.REG_ADCSPI_BASE + 10, 0x18181818) self.femb.write_reg(self.REG_ADCSPI_BASE + 11, 0x18181818) self.femb.write_reg(self.REG_ADCSPI_BASE + 12, 0x18181818) self.femb.write_reg(self.REG_ADCSPI_BASE + 13, 0x18181818) self.femb.write_reg(self.REG_ADCSPI_BASE + 14, 0x18181818) self.femb.write_reg(self.REG_ADCSPI_BASE + 15, 0x18181818) self.femb.write_reg(self.REG_ADCSPI_BASE + 16, 0x64186418) self.femb.write_reg(self.REG_ADCSPI_BASE + 17, 0x30303030) self.femb.write_reg(self.REG_ADCSPI_BASE + 18, 0x30303030) self.femb.write_reg(self.REG_ADCSPI_BASE + 19, 0x30303030) self.femb.write_reg(self.REG_ADCSPI_BASE + 20, 0x30303030) self.femb.write_reg(self.REG_ADCSPI_BASE + 21, 0x30303030) self.femb.write_reg(self.REG_ADCSPI_BASE + 22, 0x30303030) self.femb.write_reg(self.REG_ADCSPI_BASE + 23, 0x30303030) self.femb.write_reg(self.REG_ADCSPI_BASE + 24, 0x30303030) self.femb.write_reg(self.REG_ADCSPI_BASE + 25, 0x60c860c8) self.femb.write_reg(self.REG_ADCSPI_BASE + 26, 0x60606060) self.femb.write_reg(self.REG_ADCSPI_BASE + 27, 0x60606060) self.femb.write_reg(self.REG_ADCSPI_BASE + 28, 0x60606060) self.femb.write_reg(self.REG_ADCSPI_BASE + 29, 0x60606060) self.femb.write_reg(self.REG_ADCSPI_BASE + 30, 0x60606060) self.femb.write_reg(self.REG_ADCSPI_BASE + 31, 0x60606060) self.femb.write_reg(self.REG_ADCSPI_BASE + 32, 0x60606060) self.femb.write_reg(self.REG_ADCSPI_BASE + 33, 0x90609060) self.femb.write_reg(self.REG_ADCSPI_BASE + 34, 0x10001) #ADC ASIC sync self.femb.write_reg(17, 0x1) # controls HS link, 0 for on, 1 for off self.femb.write_reg(17, 0x0) # controls HS link, 0 for on, 1 for off #Write FE ASIC SPI print("Program FE ASIC SPI") self.femb.write_reg(self.REG_ASIC_SPIPROG, 2) time.sleep(0.1) self.femb.write_reg(self.REG_ASIC_SPIPROG, 2) time.sleep(0.1) #Write ADC ASIC SPI print("Program ADC ASIC SPI") self.femb.write_reg(self.REG_ASIC_RESET, 1) time.sleep(0.1) self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) time.sleep(0.1) self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) time.sleep(0.1) #35t ONLY, check if sync is ok, try redoing ADC reprogramming if not for test in range(0, 5, 1): regVal = self.femb.read_reg(6) isSync = ((regVal & 0xFFFF0000) >> 16) if isSync == 0: print("Synced ADCs") break self.femb.write_reg(self.REG_ASIC_RESET, 1) time.sleep(0.1) self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) time.sleep(0.1) self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) time.sleep(0.1) """ print("Check ADC ASIC SPI") for regNum in range(self.REG_ADCSPI_RDBACK_BASE,self.REG_ADCSPI_RDBACK_BASE+34,1): val = self.femb.read_reg( regNum ) print(hex(val)) print("Check FE ASIC SPI") for regNum in range(self.REG_FESPI_RDBACK_BASE,self.REG_FESPI_RDBACK_BASE+34,1): val = self.femb.read_reg( regNum) print(hex(val)) """ # Check that board streams data data = self.femb.get_data(1) if data == None: print("Board not streaming data, retrying initialization...") continue # try initializing again print("FEMB_CONFIG--> Reset FEMB is DONE") return print( "Error: Board not streaming data after trying to initialize {} times. Exiting." .format(nRetries)) sys.exit(1) def configFeAsic(self, gain, shape, base): gainVal = int(gain) if (gainVal < 0) or (gainVal > 3): return shapeVal = int(shape) if (shapeVal < 0) or (shapeVal > 3): return baseVal = int(base) if (baseVal < 0) or (baseVal > 1): return #get ASIC channel config register SPI values chReg = 0x0 gainArray = [0, 2, 1, 3] shapeArray = [2, 0, 3, 1] #I don't know why chReg = (gainArray[gainVal] << 4) + (shapeArray[shapeVal] << 2) if (baseVal == 0): chReg = chReg + 0x40 #enable test capacitor here chReg = chReg + 0x80 #enabled #chReg = chReg + 0x0 #disabled #need better organization of SPI, just store in words for now word1 = chReg + (chReg << 8) + (chReg << 16) + (chReg << 24) word2 = (chReg << 8) + (chReg << 24) word3 = chReg + (chReg << 16) #turn off HS data before register writes self.femb.write_reg_bits(9, 0, 0x1, 0) print("HS link turned off") time.sleep(1) print("Config FE ASIC SPI") for regNum in range(self.REG_FESPI_BASE, self.REG_FESPI_BASE + 34, 1): self.femb.write_reg(regNum, word1) self.femb.write_reg(self.REG_FESPI_BASE + 8, word2) self.femb.write_reg(self.REG_FESPI_BASE + 16, word3) self.femb.write_reg(self.REG_FESPI_BASE + 25, word2) self.femb.write_reg(self.REG_FESPI_BASE + 33, word3) #Write FE ASIC SPI print("Program FE ASIC SPI") self.femb.write_reg(self.REG_ASIC_SPIPROG, 2) time.sleep(0.1) self.femb.write_reg(self.REG_ASIC_SPIPROG, 2) time.sleep(0.1) #print "Check FE ASIC SPI" #for regNum in range(self.REG_FESPI_RDBACK_BASE,self.REG_FESPI_RDBACK_BASE+34,1): # val = self.femb.read_reg( regNum) # print hex(val) #turn HS link back on print("HS link turned back on") time.sleep(1) self.femb.write_reg_bits(9, 0, 0x1, 1) def selectChannel(self, asic, chan, hsmode=None): asicVal = int(asic) if (asicVal < 0) or (asicVal > 7): print("femb_config_femb : selectChan - invalid ASIC number") return chVal = int(chan) if (chVal < 0) or (chVal > 15): print("femb_config_femb : selectChan - invalid channel number") return #print "Selecting ASIC " + str(asicVal) + ", channel " + str(chVal) regVal = (chVal << 8) + asicVal self.femb.write_reg(self.REG_SEL_CH, regVal) def setInternalPulser(self, pulserEnable, pulseHeight): pulserEnable = int(pulserEnable) if (pulserEnable < 0) or (pulserEnable > 1): return pulserEnableVal = int(pulserEnable) if (pulseHeight < 0) or (pulseHeight > 32): return pulseHeightVal = int(pulseHeight) self.femb.write_reg_bits(5, 0, 0x1F, pulseHeightVal) #self.femb.write_reg_bits( 16, 8,0x1,0) self.femb.write_reg_bits(13, 1, 0x1, pulserEnableVal) def syncADC(self): #turn on ADC test mode print("Start sync ADC") reg3 = self.femb.read_reg(3) newReg3 = (reg3 | 0x80000000) self.femb.write_reg(3, newReg3) #31 - enable ADC test pattern alreadySynced = True for a in range(0, 8, 1): print("Test ADC " + str(a)) unsync = self.testUnsync(a) if unsync != 0: print("ADC not synced, try to fix") alreadySynced = False self.fixUnsync(a) LATCH = self.femb.read_reg(self.REG_LATCHLOC) PHASE = self.femb.read_reg(self.REG_CLKPHASE) print("Latch latency " + str(hex(LATCH)) + "\tPhase " + str(hex(PHASE))) print("End sync ADC") return not alreadySynced, LATCH, None, PHASE def testUnsync(self, adc): adcNum = int(adc) if (adcNum < 0) or (adcNum > 7): print("femb_config_femb : testLink - invalid asic number") return #loop through channels, check test pattern against data badSync = 0 for ch in range(0, 16, 1): self.selectChannel(adcNum, ch) time.sleep(0.1) for test in range(0, 10, 1): data = self.femb.get_data(1) if data == None: continue for samp in data: if samp == None: continue chNum = ((samp >> 12) & 0xF) sampVal = (samp & 0xFFF) if sampVal != self.ADC_TESTPATTERN[ch]: badSync = 1 if badSync == 1: break if badSync == 1: break if badSync == 1: break return badSync def fixUnsync(self, adc): adcNum = int(adc) if (adcNum < 0) or (adcNum > 7): print("femb_config_femb : testLink - invalid asic number") return initLATCH = self.femb.read_reg(self.REG_LATCHLOC) initPHASE = self.femb.read_reg(self.REG_CLKPHASE) #loop through sync parameters for phase in range(0, 2, 1): clkMask = (0x1 << adcNum) testPhase = ((initPHASE & ~(clkMask)) | (phase << adcNum)) self.femb.write_reg(self.REG_CLKPHASE, testPhase) for shift in range(0, 16, 1): shiftMask = (0xF << 4 * adcNum) testShift = ((initLATCH & ~(shiftMask)) | (shift << 4 * adcNum)) self.femb.write_reg(self.REG_LATCHLOC, testShift) #reset ADC ASIC self.femb.write_reg(self.REG_ASIC_RESET, 1) time.sleep(0.1) self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) time.sleep(0.1) self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) time.sleep(0.1) #test link unsync = self.testUnsync(adcNum) if unsync == 0: print("ADC synchronized") return #if program reaches here, sync has failed print("ADC SYNC process failed for ADC # " + str(adc))
class FEMB_CONFIG(FEMB_CONFIG_BASE): def __init__(self): super().__init__() #declare board specific registers self.FEMB_VER = "SBND(FE-ASIC with internal DAC)" self.REG_RESET = 0 self.REG_ASIC_RESET = 1 self.REG_ASIC_SPIPROG = 2 self.REG_SEL_ASIC = 7 self.REG_SEL_CH = 7 self.REG_FESPI_BASE = 0x250 self.REG_ADCSPI_BASE = 0x200 self.REG_FESPI_RDBACK_BASE = 0x278 self.REG_ADCSPI_RDBACK_BASE = 0x228 self.REG_HS = 17 self.REG_LATCHLOC1_4 = 4 self.REG_LATCHLOC1_4_data = 0x07060707 self.REG_LATCHLOC5_8 = 14 self.REG_LATCHLOC5_8_data = 0x06060606 self.REG_CLKPHASE = 6 self.REG_CLKPHASE_data = 0xe1 self.REG_EN_CALI = 16 self.ADC_TESTPATTERN = [ 0x12, 0x345, 0x678, 0xf1f, 0xad, 0xc01, 0x234, 0x567, 0x89d, 0xeca, 0xff0, 0x123, 0x456, 0x789, 0xabc, 0xdef ] self.NASICS = 8 #initialize FEMB UDP object self.femb = FEMB_UDP() self.adc_reg = ADC_ASIC_REG_MAPPING() self.fe_reg = FE_ASIC_REG_MAPPING() def resetBoard(self): #Reset system self.femb.write_reg(self.REG_RESET, 1) #Reset registers self.femb.write_reg(self.REG_RESET, 2) #Time stamp reset #femb.write_reg ( 0, 4) #Reset ADC ASICs self.femb.write_reg(self.REG_ASIC_RESET, 1) def initBoard(self): nRetries = 5 for iRetry in range(nRetries): print("FEMB_CONFIG--> Reset FEMB") #set up default registers #Reset ADC ASICs self.femb.write_reg(self.REG_ASIC_RESET, 1) #Set ADC test pattern register self.femb.write_reg(3, 0x01170000) #31 - enable ADC test pattern, #Set ADC latch_loc self.femb.write_reg(self.REG_LATCHLOC1_4, self.REG_LATCHLOC1_4_data) self.femb.write_reg(self.REG_LATCHLOC5_8, self.REG_LATCHLOC5_8_data) #Set ADC clock phase self.femb.write_reg(self.REG_CLKPHASE, self.REG_CLKPHASE_data) #internal test pulser control freq = 500 dly = 80 ampl = 0 % 32 int_dac = 0 # or 0xA1 dac_meas = int_dac # or 60 reg_5_value = ((freq << 16) & 0xFFFF0000) + ( (dly << 8) & 0xFF00) + ((dac_meas | ampl) & 0xFF) self.femb.write_reg(5, reg_5_value) self.femb.write_reg(16, 0x0) self.femb.write_reg(13, 0x0) #enable #Set test and readout mode register self.femb.write_reg( 7, 0x0000) #11-8 = channel select, 3-0 = ASIC select self.femb.write_reg(17, 1) #11-8 = channel select, 3-0 = ASIC select #for iReg in range(len(self.fe_reg.REGS)): # self.fe_reg.REGS[iReg] = 0xFFFFFFFF #set default value to FEMB ADCs and FEs #self.configAdcAsic(pdsr=1,pcsr=1,clockFromFIFO=True,freqInternal=1,f2=1) self.configAdcAsic_regs(self.adc_reg.REGS) self.configFeAsic_regs(self.fe_reg.REGS) #Set number events per header -- no use #self.femb.write_reg ( 8, 0x0) # Check that board streams data data = self.femb.get_data(1) if data == None: print("Board not streaming data, retrying initialization...") continue # try initializing again print("FEMB_CONFIG--> Reset FEMB is DONE") return print( "Error: Board not streaming data after trying to initialize {} times. Exiting." .format(nRetries)) sys.exit(1) def configAdcAsic_regs(self, Adcasic_regs): #ADC ASIC SPI registers print("FEMB_CONFIG--> Config ADC ASIC SPI") for k in range(10): i = 0 for regNum in range(self.REG_ADCSPI_BASE, self.REG_ADCSPI_BASE + len(Adcasic_regs), 1): #print("{:032b}".format(Adcasic_regs[i])) #print("{:08x}".format(Adcasic_regs[i])) self.femb.write_reg(regNum, Adcasic_regs[i]) time.sleep(0.05) i = i + 1 #print(" ADC ASIC write : ",Adcasic_regs) #ADC ASIC sync #self.femb.write_reg ( 17, 0x1) # controls HS link, 0 for on, 1 for off #self.femb.write_reg ( 17, 0x0) # controls HS link, 0 for on, 1 for off #Write ADC ASIC SPI print("FEMB_CONFIG--> Program ADC ASIC SPI") self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) time.sleep(0.1) self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) time.sleep(0.1) self.femb.write_reg(18, 0x0) time.sleep(0.1) print("FEMB_CONFIG--> Check ADC ASIC SPI") adcasic_rb_regs = [] for regNum in range( self.REG_ADCSPI_RDBACK_BASE, self.REG_ADCSPI_RDBACK_BASE + len(Adcasic_regs), 1): val = self.femb.read_reg(regNum) adcasic_rb_regs.append(val) #print(" ADC ASIC read back: ",adcasic_rb_regs) if (adcasic_rb_regs != Adcasic_regs): if (k == 1): sys.exit("femb_config : Wrong readback. ADC SPI failed") return print( "FEMB_CONFIG--> ADC ASIC Readback didn't match, retrying..." ) else: print("FEMB_CONFIG--> ADC ASIC SPI is OK") break #enable streaming #self.femb.write_reg ( 9, 0x8) #LBNE_ADC_MODE def configFeAsic_regs(self, feasic_regs): print("FEMB_CONFIG--> Config FE ASIC SPI") assert (len(feasic_regs) == 34) for k in range(10): i = 0 for regNum in range(self.REG_FESPI_BASE, self.REG_FESPI_BASE + len(feasic_regs), 1): self.femb.write_reg(regNum, feasic_regs[i]) i = i + 1 #Write FE ASIC SPI print("FEMB_CONFIG--> Program FE ASIC SPI") self.femb.write_reg(self.REG_ASIC_SPIPROG, 2) self.femb.write_reg(self.REG_ASIC_SPIPROG, 2) print("FEMB_CONFIG--> Check FE ASIC SPI") feasic_rb_regs = [] for regNum in range(self.REG_FESPI_RDBACK_BASE, self.REG_FESPI_RDBACK_BASE + len(feasic_regs), 1): val = self.femb.read_reg(regNum) feasic_rb_regs.append(val) if (feasic_rb_regs != feasic_regs): if (k == 9): sys.exit( "femb_config_femb : Wrong readback. FE SPI failed") return print( "FEMB_CONFIG--> FE ASIC Readback didn't match, retrying..." ) if len(feasic_rb_regs) == len(feasic_regs): print("{:15} {:15}".format("feasic_rb_regs", "feasic_regs")) for iReg in range(len(feasic_rb_regs)): print("{:#010x} {:#010x}".format( feasic_rb_regs[iReg], feasic_regs[iReg])) else: print("lens don't match: {} != {}".format( len(feasic_rb_regs), len(feasic_regs))) else: print("FEMB_CONFIG--> FE ASIC SPI is OK") #print("{:15} {:15}".format("feasic_rb_regs","feasic_regs")) #for iReg in range(len(feasic_rb_regs)): # print("{:#010x} {:#010x}".format(feasic_rb_regs[iReg],feasic_regs[iReg])) break def configFeAsic(self, gain, shape, base, slk=None, slkh=None, monitorBandgap=None, monitorTemp=None): """ Configure FEs with given gain/shape/base values. Also, configure leakage current slk = 0 for 500 pA, 1 for 100 pA and slkh = 0 for 1x leakage current, 1 for 10x leakage current if monitorBandgap is True: monitor bandgap instead of signal if monitorTemp is True: monitor temperature instead of signal """ gain = int("{:02b}".format(gain)[::-1], 2) # need to reverse bits, use string/list tricks shape = int("{:02b}".format(shape)[::-1], 2) # need to reverse bits, use string/list tricks if slk is None: slk = 0 if slkh is None: slkh = 0 if monitorBandgap and monitorTemp: raise Exception( "You can't monitor bandgap and temperature at the same time. Set either monitorBandgap or monitorTemp False" ) stb = 0 if monitorBandgap: stb = 0b11 if monitorTemp: stb = 0b10 self.fe_reg.set_fe_sbnd_board(snc=base, sg=gain, st=shape, slk0=slk, stb=stb) self.configFeAsic_regs(self.fe_reg.REGS) def configAdcAsic(self, enableOffsetCurrent=None, offsetCurrent=None, testInput=None, freqInternal=None, sleep=None, pdsr=None, pcsr=None, clockMonostable=None, clockExternal=None, clockFromFIFO=None, sLSB=None, f0=None, f1=None, f2=None, f3=None, f4=None, f5=None): """ Configure ADCs enableOffsetCurrent: 0 disable offset current, 1 enable offset current offsetCurrent: 0-15, amount of current to draw from sample and hold testInput: 0 digitize normal input, 1 digitize test input freqInternal: internal clock frequency: 0 1MHz, 1 2MHz sleep: 0 disable sleep mode, 1 enable sleep mode pdsr: if pcsr=0: 0 PD is low, 1 PD is high pcsr: 0 power down controlled by pdsr, 1 power down controlled externally Only one of these can be enabled: clockMonostable: True ADC uses monostable clock clockExternal: True ADC uses external clock clockFromFIFO: True ADC uses digital generator FIFO clock sLSB: LSB current steering mode. 0 for full, 1 for partial (ADC7 P1) f0, f1, f2, f3, f4, f5: version specific """ FEMB_CONFIG_BASE.configAdcAsic(self, clockMonostable=clockMonostable, clockExternal=clockExternal, clockFromFIFO=clockFromFIFO) if enableOffsetCurrent is None: enableOffsetCurrent = 0 if offsetCurrent is None: offsetCurrent = 0 else: offsetCurrent = int( "{:04b}".format(offsetCurrent)[::-1], 2) # need to reverse bits, use string/list tricks if testInput is None: testInput = 0 if freqInternal is None: freqInternal = 0 if sleep is None: sleep = 0 if pdsr is None: pdsr = 0 if pcsr is None: pcsr = 0 clk0 = 0 clk1 = 0 if clockExternal: clk0 = 1 clk1 = 0 elif clockFromFIFO: clk0 = 0 clk1 = 1 self.adc_reg.set_sbnd_board(en_gr=enableOffsetCurrent, d=offsetCurrent, tstin=testInput, frqc=freqInternal, slp=sleep, pdsr=pdsr, pcsr=pcsr, clk0=clk0, clk1=clk1, f1=f1, f2=f2) self.configAdcAsic_regs(self.adc_reg.REGS) def selectChannel(self, asic, chan, hsmode=1): asicVal = int(asic) if (asicVal < 0) or (asicVal >= self.NASICS): print( "femb_config_femb : selectChan - invalid ASIC number, only 0 to {} allowed" .format(self.NASICS - 1)) return chVal = int(chan) if (chVal < 0) or (chVal > 15): print( "femb_config_femb : selectChan - invalid channel number, only 0 to 15 allowed" ) return hsmodeVal = int(hsmode) if (hsmodeVal != 0) and (hsmodeVal != 1): print( "FEMB_CONFIG--> femb_config_femb : selectChan - invalid HS mode" ) return print("FEMB_CONFIG--> Selecting ASIC " + str(asicVal) + ", channel " + str(chVal)) self.femb.write_reg(self.REG_HS, hsmodeVal) self.femb.write_reg(self.REG_HS, hsmodeVal) regVal = (chVal << 8) + asicVal self.femb.write_reg(self.REG_SEL_CH, regVal) self.femb.write_reg(self.REG_SEL_CH, regVal) def setInternalPulser(self, pulserEnable, pulseHeight): if pulserEnable: print("Enabling internal FPGA DAC") # turn on test capacitor on all FE ASIC channels fe_reg = copy.deepcopy(self.fe_reg.REGS) self.fe_reg.set_fe_sbnd_board(sts=1) for i in range(len(fe_reg)): self.fe_reg.REGS[i] = fe_reg[i] | self.fe_reg.REGS[i] print(hex(self.fe_reg.REGS[i])) self.configFeAsic_regs(self.fe_reg.REGS) # internal FPGA DAC settings freq = 20 # number of samples between pulses dly = 80 # dly*5ns sets inteval between where FPGA starts pulse and ADC samples ampl = pulseHeight % 32 # mV injected int_dac = 0 # or 0xA1 dac_meas = int_dac # or 60 reg_5_value = ((freq << 16) & 0xFFFF0000) + ( (dly << 8) & 0xFF00) + ((dac_meas | ampl) & 0xFF) self.femb.write_reg(5, reg_5_value) # set to pulser mode (0x01) and enable FPGA DAC (0x01xx) self.femb.write_reg(16, 0x0101) print(self.femb.read_reg(16)) else: print("Disabling pulser (still testing may not work)") # disable test capacitor fe_reg = copy.deepcopy(self.fe_reg.REGS) self.fe_reg.set_fe_sbnd_board(sts=0) for i in range(len(fe_reg)): self.fe_reg.REGS[i] = fe_reg[i] | self.fe_reg.REGS[i] print(hex(self.fe_reg.REGS[i])) self.configFeAsic_regs(self.fe_reg.REGS) # disable pulser mode self.femb.write_reg(16, 0x0) print(self.femb.read_reg(16)) def syncADC(self): #turn on ADC test mode print("FEMB_CONFIG--> Start sync ADC") reg3 = self.femb.read_reg(3) newReg3 = (reg3 | 0x80000000) self.femb.write_reg(3, newReg3) #31 - enable ADC test pattern time.sleep(0.1) alreadySynced = True for a in range(0, self.NASICS, 1): print("FEMB_CONFIG--> Test ADC " + str(a)) unsync = self.testUnsync(a) if unsync != 0: alreadySynced = False print("FEMB_CONFIG--> ADC not synced, try to fix") self.fixUnsync(a) self.REG_LATCHLOC1_4_data = self.femb.read_reg(self.REG_LATCHLOC1_4) self.REG_LATCHLOC5_8_data = self.femb.read_reg(self.REG_LATCHLOC5_8) self.REG_CLKPHASE_data = self.femb.read_reg(self.REG_CLKPHASE) print("FEMB_CONFIG--> Latch latency " + str(hex(self.REG_LATCHLOC1_4_data)) \ + str(hex(self.REG_LATCHLOC5_8_data )) + \ "\tPhase " + str(hex(self.REG_CLKPHASE_data))) self.femb.write_reg(3, (reg3 & 0x7fffffff)) self.femb.write_reg(3, (reg3 & 0x7fffffff)) print("FEMB_CONFIG--> End sync ADC") return not alreadySynced, self.REG_LATCHLOC1_4_data, self.REG_LATCHLOC5_8_data, self.REG_CLKPHASE_data def testUnsync(self, adc): print("Starting testUnsync adc: ", adc) adcNum = int(adc) if (adcNum < 0) or (adcNum > 7): print( "FEMB_CONFIG--> femb_config_femb : testLink - invalid asic number" ) return #loop through channels, check test pattern against data badSync = 0 for ch in range(0, 16, 1): self.selectChannel(adcNum, ch, 1) time.sleep(0.05) for test in range(0, 10, 1): data = self.femb.get_data(1) #print("test: ",test," data: ",data) if data == None: continue for samp in data[0:(16 * 1024 + 1023)]: if samp == None: continue chNum = ((samp >> 12) & 0xF) sampVal = (samp & 0xFFF) if sampVal != self.ADC_TESTPATTERN[ch]: badSync = 1 if badSync == 1: break if badSync == 1: break if badSync == 1: break return badSync def fixUnsync(self, adc): adcNum = int(adc) if (adcNum < 0) or (adcNum > 7): print( "FEMB_CONFIG--> femb_config_femb : testLink - invalid asic number" ) return initLATCH1_4 = self.femb.read_reg(self.REG_LATCHLOC1_4) initLATCH5_8 = self.femb.read_reg(self.REG_LATCHLOC5_8) initPHASE = self.femb.read_reg(self.REG_CLKPHASE) #loop through sync parameters for phase in range(0, 2, 1): clkMask = (0x1 << adcNum) testPhase = ((initPHASE & ~(clkMask)) | (phase << adcNum)) self.femb.write_reg(self.REG_CLKPHASE, testPhase) time.sleep(0.01) for shift in range(0, 16, 1): shiftMask = (0x3F << 8 * adcNum) if (adcNum < 4): testShift = ((initLATCH1_4 & ~(shiftMask)) | (shift << 8 * adcNum)) self.femb.write_reg(self.REG_LATCHLOC1_4, testShift) time.sleep(0.01) else: testShift = ((initLATCH5_8 & ~(shiftMask)) | (shift << 8 * adcNum)) self.femb.write_reg(self.REG_LATCHLOC5_8, testShift) time.sleep(0.01) print("trying phase: ", phase, " shift: ", shift, " testingUnsync...") #reset ADC ASIC self.femb.write_reg(self.REG_ASIC_RESET, 1) time.sleep(0.01) self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) time.sleep(0.01) self.femb.write_reg(self.REG_ASIC_SPIPROG, 1) time.sleep(0.01) #test link unsync = self.testUnsync(adcNum) if unsync == 0: print("FEMB_CONFIG--> ADC synchronized") return #if program reaches here, sync has failed print("FEMB_CONFIG--> ADC SYNC process failed for ADC # " + str(adc)) def get_rawdata_chipXchnX(self, chip=0, chn=0): i = 0 while (1): i = i + 1 self.selectChannel(chip, chn, 1) data = self.femb.get_rawdata() #make sure the data belong to chipXchnX data0 = struct.unpack_from(">1H", data[0:2]) if (len(data) > 2): if ((data0[0] >> 12) == chn): if (i > 1): print( "FEMB_CONFIG--> get_rawdata_chipXchnX--> cycle%d to get right data" % i) break return data def get_rawdata_packets_chipXchnX(self, chip=0, chn=0, val=10): i = 0 while (1): self.selectChannel(chip, chn, 1) data = self.femb.get_rawdata_packets(val) #make sure the data belong to chnX if (len(data) > 2): data0 = struct.unpack_from(">1H", data[0:2]) if ((data0[0] >> 12) == chn): if (i > 1): print( "FEMB_CONFIG--> get_rawdata_chipXchnX--> cycle%d to get right data" % i) break return data def enablePulseMode(self, srcflag): #Configures board in test pulse mode #srcflag = 0 means external input is enabled #srcflag = 1 means internal FPGA DAC is enabled with default settings #srcflag = 99 means turn it off #ETW just playing around with the internal DAC settings not sure this works srcflag = int(srcflag) if (srcflag == 1): print("Enabling internal FPGA DAC") # turn on test capacitor on all FE ASIC channels fe_reg = copy.deepcopy(self.fe_reg.REGS) self.fe_reg.set_fe_sbnd_board(sts=1) for i in range(len(fe_reg)): self.fe_reg.REGS[i] = fe_reg[i] | self.fe_reg.REGS[i] print(hex(self.fe_reg.REGS[i])) self.configFeAsic_regs(self.fe_reg.REGS) # internal FPGA DAC settings freq = 20 # number of samples between pulses dly = 80 # dly*5ns sets inteval between where FPGA starts pulse and ADC samples ampl = 20 % 32 # mV injected int_dac = 0 # or 0xA1 dac_meas = int_dac # or 60 reg_5_value = ((freq << 16) & 0xFFFF0000) + ( (dly << 8) & 0xFF00) + ((dac_meas | ampl) & 0xFF) self.femb.write_reg(5, reg_5_value) # set to pulser mode (0x01) and enable FPGA DAC (0x01xx) self.femb.write_reg(16, 0x0101) print(self.femb.read_reg(16)) elif (srcflag == 0): print("Enabling external pulse (still testing may not work)") # turn on test capacitor on all FE ASIC channels fe_reg = copy.deepcopy(self.fe_reg.REGS) self.fe_reg.set_fe_sbnd_board(sts=1) for i in range(len(fe_reg)): self.fe_reg.REGS[i] = fe_reg[i] | self.fe_reg.REGS[i] print(hex(self.fe_reg.REGS[i])) self.configFeAsic_regs(self.fe_reg.REGS) # set to pulser mode (0x01) and enable external input (0x00xx) self.femb.write_reg(16, 0x0001) print(self.femb.read_reg(16)) elif (srcflag == 99): print("Disabling pulser (still testing may not work)") # disable test capacitor fe_reg = copy.deepcopy(self.fe_reg.REGS) self.fe_reg.set_fe_sbnd_board(sts=0) for i in range(len(fe_reg)): self.fe_reg.REGS[i] = fe_reg[i] | self.fe_reg.REGS[i] print(hex(self.fe_reg.REGS[i])) self.configFeAsic_regs(self.fe_reg.REGS) # disable pulser mode self.femb.write_reg(16, 0x0) print(self.femb.read_reg(16)) else: print("Source flag must be 0 (ext), 1 (dac), or 99 (disable)")