From 34b1fc4e45486c20a3940faebd9d42ba0801718f Mon Sep 17 00:00:00 2001 From: Daniel Sank Date: Tue, 12 Jan 2016 23:29:01 -0800 Subject: [PATCH 1/2] Clean up adc.py. --- fpgalib/adc.py | 459 ++++++++++++++++++------------------------------- 1 file changed, 165 insertions(+), 294 deletions(-) diff --git a/fpgalib/adc.py b/fpgalib/adc.py index d97812bb..2dd860fb 100644 --- a/fpgalib/adc.py +++ b/fpgalib/adc.py @@ -21,16 +21,16 @@ class ADC(fpga.FPGA): """ Base class for ADC builds - + Some functions are implemented here. I chose to do this in a few functions that I don't expect to change. Of course you can just override them in subclasses as necessary. """ - + MAC_PREFIX = '00:01:CA:AA:01:' REG_PACKET_LEN = 59 READBACK_LEN = 46 - + # Start modes RUN_MODE_REGISTER_READBACK = 1 RUN_MODE_AVERAGE_AUTO = 2 @@ -38,24 +38,24 @@ class ADC(fpga.FPGA): RUN_MODE_DEMOD_AUTO = 4 RUN_MODE_DEMOD_DAISY = 5 RUN_MODE_CALIBRATE = 7 - + @classmethod def macFor(cls, boardNumber): """Get the MAC address of an ADC board as a string.""" return cls.MAC_PREFIX + ('0'+hex(int(boardNumber))[2:])[-2:].upper() - + @classmethod def isMac(mac): """Return True if this mac is for an ADC, otherwise False""" return mac.startswith(cls.MAC_PREFIX) - + # Life cycle methods - + @inlineCallbacks def connect(self, name, group, de, port, board, build): """Establish a connection to the board.""" - print('connecting to ADC board: %s (build #%d)'\ - % (self.macFor(board), build)) + print('connecting to ADC board: {} (build #{})'.format( + (self.macFor(board), build)) self.boardGroup = group self.server = de @@ -84,29 +84,29 @@ def connect(self, name, group, de, port, board, build): p.timeout(self.timeout) p.listen() yield p.send() - + @inlineCallbacks def shutdown(self): """Called when this device is to be shutdown.""" yield self.cxn.manager.expire_context(self.server.ID, context=self.ctx) - + # Register byte methods - + @classmethod def regPing(cls): """Returns a numpy array of register bytes to ping ADC register""" regs = np.zeros(cls.REG_PACKET_LEN, dtype='> 4) & 0xF) # << 12 Qmin = twosComp((Qrng >> 0) & 0xF) # << 12 return Imax, Imin, Qmax, Qmin - + ranges = np.array([getRange(pkt) for pkt in packets]).T Imax = int(max(ranges[0])) Imin = int(min(ranges[1])) @@ -546,17 +546,17 @@ class AdcRunner_Build2(AdcRunner_Build1): class ADC_Build2(ADC_Build1): """ ADC build 2 - + This build adds ability to read back the parity of the PLL latch bits. This should allow us to """ - + RUNNER_CLASS = AdcRunner_Build2 - + @staticmethod def processReadback(resp): """Process byte string returned by ADC register readback - + Returns a dict with following keys build - int: the build number of the board firmware noPllLatch - bool: True is unlatch, False is latch (I think) @@ -579,7 +579,7 @@ class AdcRunner_Build3(AdcRunner_Build2): class ADC_Build3(ADC_Build2): RUNNER_CLASS = AdcRunner_Build3 - + fpga.REGISTRY[('ADC', 3)] = ADC_Build3 @@ -592,14 +592,14 @@ class ADC_Build6(ADC_Build2): This is the same as ADC_Build2 but has more demodulator channels. """ RUNNER_CLASS = AdcRunner_Build6 - + # Build-specific constants DEMOD_CHANNELS = 6 fpga.REGISTRY[('ADC', 6)] = ADC_Build6 class AdcRunner_Build7(AdcRunner_Build2): - + def __init__(self, dev, reps, runMode, startDelay, channels, info): self.dev = dev self.reps = reps @@ -607,7 +607,7 @@ def __init__(self, dev, reps, runMode, startDelay, channels, info): self.startDelay = startDelay self.channels = channels self.info = info - + if self.runMode == 'average': self.mode = self.dev.RUN_MODE_AVERAGE_DAISY self.nPackets = self.dev.AVERAGE_PACKETS @@ -626,7 +626,7 @@ def __init__(self, dev, reps, runMode, startDelay, channels, info): statTime = 4e-9*sum([count*(delay+rlen) for count, delay, rlen, chan in info['triggerTable']]) self.seqTime = fpga.TIMEOUT_FACTOR * (statTime * self.reps) + 1 # print "sequence time: %f, timeout: %f" % (statTime, self.seqTime) - + def loadPacket(self, page, isMaster): """Create pipelined load packet. For ADC this is the trigger table.""" # print "making ADC load packet" @@ -636,15 +636,15 @@ def loadPacket(self, page, isMaster): p = self.dev.load(self.info) # print("adc load packet: %s" % (str(p._packet))) return p - + def setupPacket(self): p = self.dev.setup(self.info) # print("ADC setup packet: %s" % (str(p[0]._packet),)) return p - + def runPacket(self, page, slave, delay, sync): """Create run packet. - + The unused arguments page, slave, and sync, in the call signature are there so that we could use the same call for DACs and ADCs. This is cheesey and ought to be fixed. @@ -653,7 +653,7 @@ def runPacket(self, page, slave, delay, sync): regs = self.dev.regRun(self.mode, self.info, self.reps, startDelay=startDelay) # print("ADC run packet: %s" % (regs,)) return regs - + def extract(self, packets): """Extract data coming back from a readPacket.""" if self.runMode == 'average': @@ -664,44 +664,12 @@ def extract(self, packets): class ADC_Branch2(ADC): """Superclass for second branch of ADC boards""" - + # Direct ethernet server packet update methods - + @classmethod def makeTriggerTable(cls, triggerTable, p): """ - Page 0 of SRAM has a table defining ADC trigger repetition counts and delays - - SRAM Write: - The controller must write to SRAM in the AD board to define two tables, a retrigger table to define multiple AD triggers for an experiment start, and a multiplier table for demodulation of the incoming signal for each demodulation channel. - - (1) The retrigger table defines multiple AD triggers per master start. The table starts at address 0, then increments up (to a maximum 127) after performing the functions of each table entry, until it reaches a table entry with rdelay[15..8]=0, at which time the retriggering stops. Note that an empty table with rdelay[15..9]=0 at the address 0 will not ever trigger the AD. In the table entry, rdelay[15..0]+ 3 is the number of 4 ns cycles between the AD start (or last end of ADon) and the AD trigger. After this delay, the AD is turned on for rlength[7..0]+1 cycles, during which ADon demultiplexer (don) is high. The value rcount[15..0]+1 is the number of AD triggers per table entry. An AD done signal pulses 3 cycles after the last ADon goes low. Note that there is approximately 7 clock cycle delay that needs to be measured and taken into account to get demodulation time correct. Channels 0 to rchan[3..0]-1 is read out; maximum rchan[3..0] is 11 for 12 channels. If rchan[3..0]=0, then save data in bit readout mode - see below. - - Note that you have multiple triggers, as for the DAC board. But for each trigger, you can have multiple retriggering to account for multiple AD demodulations during each sequence. - - (1) The retrigger table is stored in SRAM memory with adrstart[20..8] = 0. The Ethernet packet is given by - - l(0) length[15..8] set to 4; ( length[15..0]= 1024+2=1026 ) - l(1) length[7..0] set to 2 - - d(0) adrstart[15..8] SRAM page for start address: middle bits = 0, - d(1) adrstart[23..16] upper bits; size of SRAM implies bits [23..19] = 0 - - d(2) sram(+0)[7..0] rcount[7..0](0) +1 = number AD cycles - d(3) sram(+1)[7..0] rcount[15..8](0) - d(4) sram(+2)[7..0] rdelay[7..0](0) +3= clock delay before Multiplier on - d(5) sram(+3)[7..0] rdelay[15..8](0) (units of 4 ns) - d(6) sram(+4)[7..0] rlength(7..0](0) +1 = clock length of Multiplier on - d(7) sram(+5)[7..0] rchan[3..0](0) Number channels saved, 0=bit mode - d(8) sram(+6)[7..0] spare - d(9) sram(+7)[7..0] spare - - d(10) sram(+8)[7..0] rcount[7..0](1) - ... - d(1022)sram(+1022)[7..0] rcount[15..8](127) - ... - d(1025)sram(+1022)[7..0] spare - """ # takes trigger table and turns it into a packet for ADC @@ -709,26 +677,29 @@ def makeTriggerTable(cls, triggerTable, p): raise Exception("Trigger table max len = 128") if triggerTable[0][1] < 1: raise Exception("Trigger table row0 rdelay is 0") - + rlens = [row[1]<50 for row in triggerTable] - - # if there is a spacing of <50 clock cycles between demods then the FIFO gets backed up + + # if there is a spacing of <50 clock cycles between demods then the FIFO + # gets backed up if any(rlens): count0 = triggerTable[0][0] rlen0 = triggerTable[0][1] - if rlen0<50 and count0==1 and not any(rlens[1:]): # if its only the start delay, no exception + # if its only the start delay, no exception + if rlen0<50 and count0==1 and not any(rlens[1:]): pass else: - raise Exception("rlen < 50 clock cycles (200 ns) can cause FIFO backup for 12 chans") - + raise Exception("rlen < 50 clock cycles (200 ns) can cause FIFO" + "backup for 12 chans") + data = np.zeros(cls.SRAM_RETRIGGER_PKT_LEN, dtype=' Date: Tue, 12 Jan 2016 23:32:23 -0800 Subject: [PATCH 2/2] Typo. --- fpgalib/adc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fpgalib/adc.py b/fpgalib/adc.py index 2dd860fb..1b23806d 100644 --- a/fpgalib/adc.py +++ b/fpgalib/adc.py @@ -55,7 +55,7 @@ def isMac(mac): def connect(self, name, group, de, port, board, build): """Establish a connection to the board.""" print('connecting to ADC board: {} (build #{})'.format( - (self.macFor(board), build)) + self.macFor(board), build) self.boardGroup = group self.server = de