class TRACE_ALLCHAN_WINDOW(Tk.Frame): """ This window displays a live ADC redout """ def __init__(self, master=None, packedHighSpeed=False): self.maxtraces = 5 self.selChan = 0 Tk.Frame.__init__(self, master) # hack to make work in python2 self.pack() self.figure = Figure(figsize=(15, 7), dpi=100, facecolor='white') self.canvas = FigureCanvas(self.figure, master=self) self.canvas.show() self.canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) self.toolbar = NaviationToolbar(self.canvas, self) self.toolbar.update() self.canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) self.pauseButton = Tk.Button(self, text="Pause", command=self.pause) self.pauseButton.pack(side=Tk.LEFT) self.playButton = Tk.Button(self, text="Play", command=self.play, state=Tk.DISABLED) self.playButton.pack(side=Tk.LEFT) self.prevButton = Tk.Button(self, text="Previous Trace", command=self.prevTrace, state=Tk.DISABLED) self.prevButton.pack(side=Tk.LEFT) self.nextButton = Tk.Button(self, text="Next Trace", command=self.nextTrace, state=Tk.DISABLED) self.nextButton.pack(side=Tk.LEFT) self.packedHighSpeed = packedHighSpeed self.femb = None self.iTrace = -1 self.traces = [] self.timestamps = [] self.reset() def reset(self, iTrace=None): self.femb = FEMB_UDP() self.figure.clf() self.subgs = [None] * 16 self.ax = [None] * 16 self.plot = [None] * 16 # 4x4 grid, one cell per channel self.gs = gridspec.GridSpec(4, 4) self.gs.update(wspace=0.2, hspace=0.2) # 1 plots per channel for row in range(4): for col in range(4): self.subgs[col + 4 * row] = gridspec.GridSpecFromSubplotSpec( 1, 1, subplot_spec=self.gs[col + 4 * row], hspace=0.0) self.ax[col + 4 * row] = self.figure.add_subplot( self.subgs[col + 4 * row][0]) self.ax[col + 4 * row].tick_params(axis='x', colors='black', labelsize='medium') self.ax[col + 4 * row].tick_params(axis='y', colors='black', labelsize='smaller') if iTrace is None: self.ani = animation.FuncAnimation(self.figure, self.plotData, interval=1000, blit=True) else: self.plotData(0, iTrace) self.canvas.draw() def pause(self): self.ani.event_source.stop() self.reset(self.iTrace) self.pauseButton['state'] = Tk.DISABLED self.playButton['state'] = Tk.NORMAL self.prevButton['state'] = Tk.NORMAL self.nextButton['state'] = Tk.DISABLED def play(self): self.ani.event_source.start() self.pauseButton['state'] = Tk.NORMAL self.playButton['state'] = Tk.DISABLED self.prevButton['state'] = Tk.DISABLED self.nextButton['state'] = Tk.DISABLED def prevTrace(self): self.iTrace -= 1 self.reset(self.iTrace) if self.iTrace < 1: self.prevButton['state'] = Tk.DISABLED else: self.prevButton['state'] = Tk.NORMAL if self.iTrace >= len(self.traces) - 1: self.nextButton['state'] = Tk.DISABLED else: self.nextButton['state'] = Tk.NORMAL def nextTrace(self): self.iTrace += 1 self.reset(self.iTrace) if self.iTrace < 1: self.prevButton['state'] = Tk.DISABLED else: self.prevButton['state'] = Tk.NORMAL if self.iTrace >= len(self.traces) - 1: self.nextButton['state'] = Tk.DISABLED else: self.nextButton['state'] = Tk.NORMAL def plotData(self, iFrame, iTrace=None): for a in self.ax: a.cla() a.locator_params(tight=True, nbins=3) # In case no data, return an empty plot self.plot[0] = self.ax[0].plot() for r in range(4): for c in range(4): t, adc, thistimestamp = self.getTraceAndFFT(iTrace=iTrace, chan=c + 4 * r) if not (t is None) and not (adc is None): self.plot[c + 4 * r] = self.ax[c + 4 * r].plot(t, adc) if c + 4 * r < 12: self.ax[c + 4 * r].set_xticklabels([]) self.figure.text(0.5, 0.02, 'Time [us]', ha='center', color='black', fontsize='25.0', weight='bold') self.figure.text(0.08, 0.5, 'ADC', ha='center', rotation=90, color='black', fontsize='25.0', weight='bold') if not (thistimestamp is None): self.figure.suptitle( thistimestamp.replace(microsecond=0).isoformat(" ")) self.canvas.draw() return self.plot[0] def getTraceAndFFT(self, iTrace=None, chan=0): """ Gets trace from FEMB and returns 4 1D arrays: times, ADC counts """ data = None timestamp = None if iTrace is None: data = self.femb.get_data(100) timestamp = datetime.datetime.now() self.traces.append(data) self.timestamps.append(timestamp) if len(self.traces) > self.maxtraces: self.traces.pop(0) self.timestamps.pop(0) self.iTrace = len(self.traces) - 1 else: data = self.traces[iTrace] timestamp = self.timestamps[iTrace] if data == None: return None, None, None, None, None if len(data) == 0: return None, None, None, None, None chSamples = None if self.packedHighSpeed: chSamples = WRITE_ROOT_TREE.convertHighSpeedPacked(None, data) else: chSamples = WRITE_ROOT_TREE.convertHighSpeedSimple(None, data) xpoint = [] ypoint = [] num = 0 for samp in chSamples[chan]: xpoint.append(num * 0.5) ypoint.append(samp) num = num + 1 xarr = np.array(xpoint) yarr = np.array(ypoint) return xarr, yarr, timestamp
class TRACE_ALLCHAN_WINDOW(Tk.Frame): """ This window displays a live ADC redout """ def __init__(self, master=None): self.maxtraces = 5 self.selChan = 0 Tk.Frame.__init__(self, master) # hack to make work in python2 self.pack() self.figure = Figure(figsize=(20, 8), dpi=100, facecolor='white') self.canvas = FigureCanvas(self.figure, master=self) self.canvas.show() self.canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) self.toolbar = NaviationToolbar(self.canvas, self) self.toolbar.update() self.canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) self.pauseButton = Tk.Button(self, text="Pause", command=self.pause) self.pauseButton.pack(side=Tk.LEFT) self.playButton = Tk.Button(self, text="Play", command=self.play, state=Tk.DISABLED) self.playButton.pack(side=Tk.LEFT) self.prevButton = Tk.Button(self, text="Previous Trace", command=self.prevTrace, state=Tk.DISABLED) self.prevButton.pack(side=Tk.LEFT) self.nextButton = Tk.Button(self, text="Next Trace", command=self.nextTrace, state=Tk.DISABLED) self.nextButton.pack(side=Tk.LEFT) self.femb = None self.iTrace = -1 self.traces = [] self.timestamps = [] self.reset() def reset(self, iTrace=None): self.femb = FEMB_UDP() self.femb_config = CONFIG() self.figure.clf() self.subgs = [None] * 16 * 4 self.ax = [None] * 16 * 4 self.plot = [None] * 16 * 4 # 4x4x4 grid, one cell per channel self.gs = gridspec.GridSpec(4, 16) self.gs.update(wspace=0.2, hspace=0.2) # 1 plots per channel for row in range(4): for col in range(16): self.subgs[col + 16 * row] = gridspec.GridSpecFromSubplotSpec( 1, 1, subplot_spec=self.gs[col + 16 * row], hspace=0.0) self.ax[col + 16 * row] = self.figure.add_subplot( self.subgs[col + 16 * row][0]) self.ax[col + 16 * row].tick_params(axis='x', colors='black', labelsize='medium') self.ax[col + 16 * row].tick_params(axis='y', colors='black', labelsize='smaller') if iTrace is None: self.ani = animation.FuncAnimation(self.figure, self.plotData, interval=100, blit=True) else: self.plotData(0, iTrace) self.canvas.draw() def pause(self): self.ani.event_source.stop() self.reset(self.iTrace) self.pauseButton['state'] = Tk.DISABLED self.playButton['state'] = Tk.NORMAL self.prevButton['state'] = Tk.NORMAL self.nextButton['state'] = Tk.DISABLED def play(self): self.ani.event_source.start() self.pauseButton['state'] = Tk.NORMAL self.playButton['state'] = Tk.DISABLED self.prevButton['state'] = Tk.DISABLED self.nextButton['state'] = Tk.DISABLED def prevTrace(self): self.iTrace -= 1 self.reset(self.iTrace) if self.iTrace < 1: self.prevButton['state'] = Tk.DISABLED else: self.prevButton['state'] = Tk.NORMAL if self.iTrace >= len(self.traces) - 1: self.nextButton['state'] = Tk.DISABLED else: self.nextButton['state'] = Tk.NORMAL def nextTrace(self): self.iTrace += 1 self.reset(self.iTrace) if self.iTrace < 1: self.prevButton['state'] = Tk.DISABLED else: self.prevButton['state'] = Tk.NORMAL if self.iTrace >= len(self.traces) - 1: self.nextButton['state'] = Tk.DISABLED else: self.nextButton['state'] = Tk.NORMAL def plotData(self, iFrame, iTrace=None): for a in self.ax: a.cla() a.locator_params(tight=True, nbins=3) # In case no data, return an empty plot self.plot[0] = self.ax[0].plot() for a in range(4): #for a in [2]: #if a != 0: # continue asicNum = a #asicNum = 2 self.femb_config.setExtClockRegs(asicNum) self.femb_config.selectAsic(asicNum) #self.femb_config.doAdcAsicConfig(a) #self.femb_config.initAsic(a) chPlots, thistimestamp = self.getTraceAndFFT(iTrace=iTrace) if chPlots == None: continue if thistimestamp == None: continue if len(chPlots) != 16: continue for chan in range(0, 16, 1): t = chPlots[chan][0] adc = chPlots[chan][1] if not (t is None) and not (adc is None): self.plot[chan + 16 * a] = self.ax[chan + 16 * a].plot( t, adc) #if c+4*r < 12: self.ax[c+4*r].set_xticklabels([]) self.figure.text(0.5, 0.02, 'Time [us]', ha='center', color='black', fontsize='25.0', weight='bold') self.figure.text(0.08, 0.5, 'ADC', ha='center', rotation=90, color='black', fontsize='25.0', weight='bold') if not (thistimestamp is None): self.figure.suptitle( thistimestamp.replace(microsecond=0).isoformat(" ")) self.canvas.draw() return self.plot[0] def getTraceAndFFT(self, iTrace=None): """ Gets trace from FEMB and returns 4 1D arrays: times, ADC counts """ data = None timestamp = None if iTrace is None: data = self.femb.get_data(5) timestamp = datetime.datetime.now() self.traces.append(data) self.timestamps.append(timestamp) if len(self.traces) > self.maxtraces: self.traces.pop(0) self.timestamps.pop(0) self.iTrace = len(self.traces) - 1 else: data = self.traces[iTrace] timestamp = self.timestamps[iTrace] if data == None: return None, None if len(data) == 0: return None, None chSamples = self.convertHighSpeedPacked(data) if len(chSamples) != 16: return None, None chPlots = [] for chan in range(0, 16, 1): xpoint = [] ypoint = [] num = 0 for samp in chSamples[chan]: xpoint.append(num * 0.5) ypoint.append(samp) num = num + 1 xarr = np.array(xpoint) yarr = np.array(ypoint) chPlots.append([xarr, yarr]) return chPlots, timestamp #taken from write_root_tree def convertHighSpeedPacked(self, data): packetNum = 0 wordArray = [] result = [[] for chan in range(16)] for word in data: if str(hex(word)) == "0xface": packetNum = 0 wordArray = [] if packetNum > 0 and packetNum < 13: wordArray.append(word) if packetNum == 12: result[0].append(((wordArray[5] & 0xFFF0) >> 4)) result[1].append(((wordArray[4] & 0xFF00) >> 8) | ((wordArray[5] & 0x000F) << 8)) result[2].append(((wordArray[4] & 0x00FF) << 4) | ((wordArray[3] & 0xF000) >> 12)) result[3].append(((wordArray[3] & 0x0FFF) >> 0)) result[4].append(((wordArray[2] & 0xFFF0) >> 4)) result[5].append(((wordArray[2] & 0x000F) << 8) | ((wordArray[1] & 0xFF00) >> 8)) result[6].append(((wordArray[1] & 0x00FF) << 4) | ((wordArray[0] & 0xF000) >> 12)) result[7].append(((wordArray[0] & 0x0FFF) >> 0)) result[8].append(((wordArray[11] & 0xFFF0) >> 4)) result[9].append(((wordArray[11] & 0x000F) << 8) | ((wordArray[10] & 0xFF00) >> 8)) result[10].append(((wordArray[10] & 0x00FF) << 4) | ((wordArray[9] & 0xF000) >> 12)) result[11].append(((wordArray[9] & 0x0FFF))) result[12].append(((wordArray[8] & 0xFFF0) >> 4)) result[13].append(((wordArray[8] & 0x000F) << 8) | ((wordArray[7] & 0xFF00) >> 8)) result[14].append(((wordArray[7] & 0x00FF) << 4) | ((wordArray[6] & 0xF000) >> 12)) result[15].append(((wordArray[6] & 0x0FFF))) packetNum = packetNum + 1 return result
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=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 TRACE_FFT_ALLCHAN_WINDOW(Tk.Frame): """ This window displays a live ADC redout and its FFT """ def __init__(self, master=None): self.maxtraces = 5 self.selChan = 0 Tk.Frame.__init__(self, master) # hack to make work in python2 self.pack() #self.figure = Figure(figsize=(14,9), dpi=100, facecolor='gray') self.figure = Figure(figsize=(14, 8), dpi=100, facecolor='gray') self.canvas = FigureCanvas(self.figure, master=self) self.canvas.show() self.canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) self.toolbar = NaviationToolbar(self.canvas, self) self.toolbar.update() self.canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) self.pauseButton = Tk.Button(self, text="Pause", command=self.pause) self.pauseButton.pack(side=Tk.LEFT) self.playButton = Tk.Button(self, text="Play", command=self.play, state=Tk.DISABLED) self.playButton.pack(side=Tk.LEFT) self.prevButton = Tk.Button(self, text="Previous Trace", command=self.prevTrace, state=Tk.DISABLED) self.prevButton.pack(side=Tk.LEFT) self.nextButton = Tk.Button(self, text="Next Trace", command=self.nextTrace, state=Tk.DISABLED) self.nextButton.pack(side=Tk.LEFT) self.femb = None self.iTrace = -1 self.traces = [] self.timestamps = [] self.reset() def reset(self, iTrace=None): self.femb = FEMB_UDP() self.figure.clf() self.subgs = [None] * 16 self.ax = [None] * 32 self.plot = [None] * 32 # 4x4 grid, one cell per channel self.gs = gridspec.GridSpec(4, 4) self.gs.update(wspace=0.2, hspace=0.2) # 2 plots per channel for row in range(4): for col in range(4): self.subgs[col + 4 * row] = gridspec.GridSpecFromSubplotSpec( 2, 1, subplot_spec=self.gs[col + 4 * row], hspace=0.0) self.ax[col + 8 * row] = self.figure.add_subplot( self.subgs[col + 4 * row][0]) self.ax[col + 8 * row].tick_params(axis='x', colors='blue') self.ax[col + 8 * row].tick_params(axis='y', colors='blue') self.ax[col + 8 * row].xaxis.tick_top() self.ax[col + 8 * row].yaxis.tick_right() self.ax[4 + col + 8 * row] = self.figure.add_subplot( self.subgs[col + 4 * row][1]) self.ax[4 + col + 8 * row].tick_params(axis='x', colors='red') self.ax[4 + col + 8 * row].tick_params(axis='y', colors='red') if iTrace is None: self.ani = animation.FuncAnimation(self.figure, self.plotData, interval=1000, blit=True) else: self.plotData(0, iTrace) self.canvas.draw() def pause(self): self.ani.event_source.stop() self.reset(self.iTrace) self.pauseButton['state'] = Tk.DISABLED self.playButton['state'] = Tk.NORMAL self.prevButton['state'] = Tk.NORMAL self.nextButton['state'] = Tk.DISABLED def play(self): self.ani.event_source.start() self.pauseButton['state'] = Tk.NORMAL self.playButton['state'] = Tk.DISABLED self.prevButton['state'] = Tk.DISABLED self.nextButton['state'] = Tk.DISABLED def prevTrace(self): self.iTrace -= 1 self.reset(self.iTrace) if self.iTrace < 1: self.prevButton['state'] = Tk.DISABLED else: self.prevButton['state'] = Tk.NORMAL if self.iTrace >= len(self.traces) - 1: self.nextButton['state'] = Tk.DISABLED else: self.nextButton['state'] = Tk.NORMAL def nextTrace(self): self.iTrace += 1 self.reset(self.iTrace) if self.iTrace < 1: self.prevButton['state'] = Tk.DISABLED else: self.prevButton['state'] = Tk.NORMAL if self.iTrace >= len(self.traces) - 1: self.nextButton['state'] = Tk.DISABLED else: self.nextButton['state'] = Tk.NORMAL def plotData(self, iFrame, iTrace=None): for a in self.ax: a.cla() a.locator_params(tight=True, nbins=3) # in case no data, return an empty plot self.plot[0] = self.ax[0].plot() for r in range(4): for c in range(4): t, adc, frq, amp, thistimestamp = self.getTraceAndFFT( iTrace=iTrace, chan=c + 4 * r) if not (t is None) and not (adc is None): self.plot[c + 8 * r] = self.ax[c + 8 * r].plot(t, adc) if c + 8 * r > 3: self.ax[c + 8 * r].set_xticklabels([]) if not (frq is None) and not (amp is None): self.plot[4 + c + 8 * r] = self.ax[4 + c + 8 * r].plot( frq, amp, 'r') if 4 + c + 8 * r < 28: self.ax[4 + c + 8 * r].set_xticklabels([]) self.figure.text(0.45, 0.04, 'Time [us]', ha='center', color='blue') self.figure.text(0.55, 0.04, 'Frequency [MHz]', ha='center', color='red') self.figure.text(0.042, 0.45, 'ADC', ha='center', rotation=90, color='blue') self.figure.text(0.04, 0.55, '|Y(freq)|', ha='center', rotation=90, color='red') if not (thistimestamp is None): self.figure.suptitle( thistimestamp.replace(microsecond=0).isoformat(" ")) self.canvas.draw() return self.plot[0] def getTraceAndFFT(self, iTrace=None, chan=0): """ Gets trace from FEMB and returns 4 1D arrays: times, ADC counts, frequencies, Amplitude """ Yfft_total = [] first = 1 data = None timestamp = None if iTrace is None: data = self.femb.get_data(100) timestamp = datetime.datetime.now() self.traces.append(data) self.timestamps.append(timestamp) if len(self.traces) > self.maxtraces: self.traces.pop(0) self.timestamps.pop(0) self.iTrace = len(self.traces) - 1 else: data = self.traces[iTrace] timestamp = self.timestamps[iTrace] if data == None: #time.sleep(1.) return None, None, None, None, None if len(data) == 0: #time.sleep(1.) return None, None, None, None, None xpoint = [] ypoint = [] num = 0 packetNum = 0 wordArray = [] for word in data: #print(str(packetNum) + "\t" + str(hex(word)) ) if str(hex(word)) == "0xface": packetNum = 0 wordArray = [] if packetNum > 0 and packetNum < 13: wordArray.append(word) if packetNum == 12: chSamp = [] for i in range(0, 16, 1): chSamp.append(0) chSamp[0] = ((wordArray[5] & 0xFFF0) >> 4) chSamp[1] = ((wordArray[4] & 0xFF00) >> 8) | ( (wordArray[5] & 0x000F) << 8) chSamp[2] = ((wordArray[4] & 0x00FF) << 4) | ( (wordArray[3] & 0xF000) >> 12) chSamp[3] = ((wordArray[3] & 0x0FFF) >> 0) chSamp[4] = ((wordArray[2] & 0xFFF0) >> 4) chSamp[5] = ((wordArray[2] & 0x000F) << 8) | ( (wordArray[1] & 0xFF00) >> 8) chSamp[6] = ((wordArray[1] & 0x00FF) << 4) | ( (wordArray[0] & 0xF000) >> 12) chSamp[7] = ((wordArray[0] & 0x0FFF) >> 0) chSamp[8] = ((wordArray[11] & 0xFFF0) >> 4) chSamp[9] = ((wordArray[11] & 0x000F) << 8) | ( (wordArray[10] & 0xFF00) >> 8) chSamp[10] = ((wordArray[10] & 0x00FF) << 4) | ( (wordArray[9] & 0xF000) >> 12) chSamp[11] = ((wordArray[9] & 0x0FFF)) chSamp[12] = ((wordArray[8] & 0xFFF0) >> 4) chSamp[13] = ((wordArray[8] & 0x000F) << 8) | ( (wordArray[7] & 0xFF00) >> 8) chSamp[14] = ((wordArray[7] & 0x00FF) << 4) | ( (wordArray[6] & 0xF000) >> 12) chSamp[15] = ((wordArray[6] & 0x0FFF)) xpoint.append(num * 0.5) ypoint.append(chSamp[int(chan)]) num = num + 1 packetNum = packetNum + 1 #return None, None, None, None, None #for samp in data: # chNum = ((samp >> 12 ) & 0xF) # sampVal = (samp & 0xFFF) # #print str(chNum) + "\t" + str(sampVal) + "\t" + str( hex(sampVal) ) # #if chNum == 0: # xpoint.append(num*0.5) # ypoint.append(sampVal) # num = num + 1 xarr = np.array(xpoint) yarr = np.array(ypoint) Fs = 2.0 # sampling rate Ts = 1.0 / Fs # sampling interval t = np.arange(0, 1, Ts) # time vector n = len(yarr) # length of the signal k = np.arange(n) T = n / Fs frq = k / T # two sides frequency range frq = frq[:n // 2] # one side frequency range Yfft = np.fft.fft(yarr) / n # fft computing and normalization Yfft = Yfft[:n // 2] frq = frq[1:] Yfft = Yfft[1:] #do averaging and normalization, very messy pos = 0 total = 0 for x in np.nditer(Yfft): #print abs(x) total = total + abs(x) if first == 1: Yfft_total.append(abs(x)) else: Yfft_total[pos] = Yfft_total[pos] + abs(x) pos = pos + 1 first = 0 if total < 0: #time.sleep(0.1) return None, None, None, None pos = 0 Yfft_norm = [] for bin in Yfft_total: Yfft_norm.append(bin / total) return xarr, yarr, frq, Yfft_norm, timestamp
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 = "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): 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)")