def as_bytes(self):
        """Get a byte array representing this entry.

        :return: ndarray(dtype='u1') of bytes for this entry.
        :rtype: np.ndarray
        """
        data = np.zeros(8, dtype='u1')
        data[0:3] = littleEndian(self.from_addr, 3)
        data[3:6] = littleEndian(self.to_addr, 3)
        data[6:8] = self.operation.as_bytes()
        return data
Exemple #2
0
    def as_bytes(self):
        """Get a byte array representing this entry.

        :return: ndarray(dtype='u1') of bytes for this entry.
        :rtype: np.ndarray
        """
        data = np.zeros(8, dtype='u1')
        data[0:3] = littleEndian(self.from_addr, 3)
        data[3:6] = littleEndian(self.to_addr, 3)
        data[6:8] = self.operation.as_bytes()
        return data
Exemple #3
0
    def regRun(cls, mode, info, reps, startDelay=0):
        """
        Returns a numpy array of register bytes to run the board
        Register Write:
        These registers control the AD functions.  This card is always set in slave mode for daisychain initiation of AD functions (see GHzDAC board).  

        l(0)	length[15..8]		set to 0  ; ( length[15..0] = 59 )
        l(1)	length[7..0]		set to 59

        d(0)	start[7..0]     Output & command function
                                0 = off
                                1 = register readback
                                2 = average mode, auto start (use n=1)
                                3 = average mode, daisychain start
                                4 = demodulator mode, auto start (use n=1)
                                5 = demodulator mode, daisychain start
                                6 = set PLL of 1GHz clock with ser[23..0], no readback
                                7 = recalibrate AD converters, no readback
        d(1)	startdelay[7..0]	Start delay after daisychain signal, compensates for dchain delays 
        d(2)	startdelay[15..8]	  Note longer delays than for GHzDAC
        d(3) 	ser1[7..0]		8 lowest PLL bits of serial interface 
        d(4)	ser2[7..0]		8  middle PLL bits
        d(5)	ser3[7..0]		8 highest PLL bits
        d(6)	spare

        d(7)	n[7..0]			n = Number of averages in average mode
        d(8)	n[15..8]		n = Number of total events in demodulator mode
        d(9)	bitflip[7..0]		XOR mask for bit readout	
        d(10)	mon0[7..0] 		SMA mon0 and mon1 programming, like DAC board
        d(11)	mon1[7..0] 	
        ...
        d(58)	spare	
        
        """
        regs = np.zeros(cls.REG_PACKET_LEN, dtype='<u1')
        regs[0] = mode
        regs[1:3] = littleEndian(startDelay, 2)  #Daisychain delay
        regs[7:9] = littleEndian(reps, 2)  #Number of repetitions
        regs[9] = littleEndian(0, 1)[0]  #XOR bit flip mask

        mon0 = info.get('mon0', 'start')
        mon1 = info.get('mon1', 'don')

        if isinstance(mon0, str):
            mon0 = mondict.MONDICT[mon0]
        if isinstance(mon1, str):
            mon1 = mondict.MONDICT[mon1]

        regs[10] = mon0
        regs[11] = mon1

        return regs
Exemple #4
0
    def regRun(cls, mode, info, reps, startDelay=0):
        """
        Returns a numpy array of register bytes to run the board
        Register Write:
        These registers control the AD functions.  This card is always set in slave mode for daisychain initiation of AD functions (see GHzDAC board).  

        l(0)	length[15..8]		set to 0  ; ( length[15..0] = 59 )
        l(1)	length[7..0]		set to 59

        d(0)	start[7..0]     Output & command function
                                0 = off
                                1 = register readback
                                2 = average mode, auto start (use n=1)
                                3 = average mode, daisychain start
                                4 = demodulator mode, auto start (use n=1)
                                5 = demodulator mode, daisychain start
                                6 = set PLL of 1GHz clock with ser[23..0], no readback
                                7 = recalibrate AD converters, no readback
        d(1)	startdelay[7..0]	Start delay after daisychain signal, compensates for dchain delays 
        d(2)	startdelay[15..8]	  Note longer delays than for GHzDAC
        d(3) 	ser1[7..0]		8 lowest PLL bits of serial interface 
        d(4)	ser2[7..0]		8  middle PLL bits
        d(5)	ser3[7..0]		8 highest PLL bits
        d(6)	spare

        d(7)	n[7..0]			n = Number of averages in average mode
        d(8)	n[15..8]		n = Number of total events in demodulator mode
        d(9)	bitflip[7..0]		XOR mask for bit readout	
        d(10)	mon0[7..0] 		SMA mon0 and mon1 programming, like DAC board
        d(11)	mon1[7..0] 	
        ...
        d(58)	spare	
        
        """
        regs = np.zeros(cls.REG_PACKET_LEN, dtype='<u1')
        regs[0] = mode
        regs[1:3] = littleEndian(startDelay, 2) #Daisychain delay
        regs[7:9] = littleEndian(reps, 2)       #Number of repetitions
        regs[9] = littleEndian(0, 1)[0] #XOR bit flip mask

        mon0 = info.get('mon0', 'start')
        mon1 = info.get('mon1', 'don')

        if isinstance(mon0,str):
            mon0 = mondict.MONDICT[mon0]
        if isinstance(mon1,str):
            mon1 = mondict.MONDICT[mon1]

        regs[10] = mon0
        regs[11] = mon1
        
        return regs
Exemple #5
0
 def toString(self):
     """Serialize jump table to a byte string for the FPGA"""
     data = np.zeros(self.PACKET_LEN, dtype='<u1')
     # Set counter values. Each one is 4 bytes
     for i, c in enumerate(self.counters):
         data[i * 4:(i + 1) * 4] = littleEndian(c, 4)
     # Set start address
     data[16:19] = littleEndian(self.start_addr, 3)
     data[19:22] = littleEndian(self.start_addr, 3)
     # Start op code
     data[22] = 5
     data[23] = 0
     for i, jump in enumerate(self.jumps):
         ofs = 24 + i * 8
         data[ofs:ofs + 8] = jump.as_bytes()
     return data.tostring()
Exemple #6
0
    def as_bytes(self):
        """Get bytes for an END.

        The op code is
            xxxxxxxx xxxxx111
        """
        return littleEndian(7, 2)
Exemple #7
0
    def makeMixerTable(cls, demods, p):
        """
        Page 1-12 of SRAM has the mixer tables for demodulators 0-11 respectively.

        (2) For the multiplier lookup tables, adrstart is taken from the following table  
        adrstart[20..8]= channel n + 1.  This offsets by 1 from the above trigger page.

        The Ethernet packet for channel n is:

        l(1)	length[15..8]		set to 4; ( length[15..0]= 1024+2=1026 )
        l(2)	length[7..0]		set to 2

        d(1)	adrstart[15..8]		SRAM page for start address: middle bits = n+1 
        d(2)	adrstart[23..16]	upper bits; size of SRAM implies bits [23..19] = 0

        d(3)	sram(+0)[7..0]		multsin(0)		Multiplier time 0
        d(4)	sram(+1)[7..0]		multcos(0)
        d(5)	sram(+2)[7..0]		multsin(1)		Multiplier time 1 (1/2 clock, 2ns)
        d(6)	sram(+3)[7..0]		multcos(1)
        ...
        d(1025)sram(+1022)[7..0]	multsin(511)
        d(1026)sram(+1023)[7..0]	multcos(511)
        """

        for idx, demod in enumerate(demods):
            data = np.zeros(cls.SRAM_MIXER_PKT_LEN, dtype='<i1')
            # retrigger table is page 0, mixer tables are pages 1-13, factor of 4 from stripping least significant bits
            data[0:2] = littleEndian((idx + 1), 2)  # SRAM page address
            mixerTable = demod['mixerTable']
            for tidx, row in enumerate(mixerTable):
                I, Q = row
                data[(tidx * 2) + 2] = I
                data[(tidx * 2 + 1) + 2] = Q

            p.write(data.tostring())
 def toString(self):
     """Serialize jump table to a byte string for the FPGA"""
     data = np.zeros(self.PACKET_LEN, dtype='<u1')
     # Set counter values. Each one is 4 bytes
     for i, c in enumerate(self.counters):
         data[i * 4:(i + 1) * 4] = littleEndian(c, 4)
     # Set start address
     data[16:19] = littleEndian(self.start_addr, 3)
     data[19:22] = littleEndian(self.start_addr, 3)
     # Start op code
     data[22] = 5
     data[23] = 0
     for i, jump in enumerate(self.jumps):
         ofs = 24 + i * 8
         data[ofs:ofs+8] = jump.as_bytes()
     return data.tostring()
    def as_bytes(self):
        """Get bytes for an END.

        The op code is
            xxxxxxxx xxxxx111
        """
        return littleEndian(7, 2)
Exemple #10
0
 def regRun(cls, mode, reps, filterFunc, filterStretchAt,
               filterStretchLen, demods, startDelay=0):
     """Returns a numpy array of register bytes to run the board"""
     regs = np.zeros(cls.REG_PACKET_LEN, dtype='<u1')
     regs[0] = mode
     regs[1:3] = littleEndian(startDelay, 2) #Daisychain delay
     regs[7:9] = littleEndian(reps, 2)       #Number of repetitions
     
     if len(filterFunc)<=1:
         raise Exception('Filter function must be at least 2')
     #Filter function end address. -1 comes from 0 indexing.
     regs[9:11] = littleEndian(len(filterFunc)-1, 2)
     #Stretch address for filter
     regs[11:13] = littleEndian(filterStretchAt, 2)
     #Filter function stretch length
     regs[13:15] = littleEndian(filterStretchLen, 2)
     
     for i in range(cls.DEMOD_CHANNELS):
         if i not in demods:
             continue
         addr = 15 + 4*i
         #Lookup table step per sample
         regs[addr:addr+2] = littleEndian(demods[i]['dPhi'], 2)
         #Lookup table start address
         regs[addr+2:addr+4] = littleEndian(demods[i]['phi0'], 2)
     return regs
Exemple #11
0
    def regRun(cls,
               mode,
               reps,
               filterFunc,
               filterStretchAt,
               filterStretchLen,
               demods,
               startDelay=0):
        """Returns a numpy array of register bytes to run the board"""
        regs = np.zeros(cls.REG_PACKET_LEN, dtype='<u1')
        regs[0] = mode
        regs[1:3] = littleEndian(startDelay, 2)  #Daisychain delay
        regs[7:9] = littleEndian(reps, 2)  #Number of repetitions

        if len(filterFunc) <= 1:
            raise Exception('Filter function must be at least 2')
        #Filter function end address. -1 comes from 0 indexing.
        regs[9:11] = littleEndian(len(filterFunc) - 1, 2)
        #Stretch address for filter
        regs[11:13] = littleEndian(filterStretchAt, 2)
        #Filter function stretch length
        regs[13:15] = littleEndian(filterStretchLen, 2)

        for i in range(cls.DEMOD_CHANNELS):
            if i not in demods:
                continue
            addr = 15 + 4 * i
            #Lookup table step per sample
            regs[addr:addr + 2] = littleEndian(demods[i]['dPhi'], 2)
            #Lookup table start address
            regs[addr + 2:addr + 4] = littleEndian(demods[i]['phi0'], 2)
        return regs
Exemple #12
0
    def as_bytes(self):
        """Get bytes for a JUMP

        The op code is
            xxjjjjjj xxxx1101
        where
            jjjjjj is the jump index to set after the jump.
        """
        # binary 1101 = decimal 13
        val = (self.jump_index << 8) + 13
        return littleEndian(val, 2)
Exemple #13
0
    def as_bytes(self):
        """Get bytes for a JUMP

        The op code is
            xxjjjjjj xxxx1101
        where
            jjjjjj is the jump index to set after the jump.
        """
        # binary 1101 = decimal 13
        val = (self.jump_index << 8) + 13
        return littleEndian(val, 2)
Exemple #14
0
    def as_bytes(self):
        """Get bytes for an IDLE.

        The op code is
            dddddddd ddddddd0
        where d[14..0] is the number of FPGA cycles to idle.
        """
        if not (IDLE_MIN_CYCLES <= self.cycles <= IDLE_MAX_CYCLES):
            raise ValueError(
                "IDLE num cycles must fit in {} bits".format(IDLE_NUM_BITS))
        return littleEndian(self.cycles << 1, 2)
Exemple #15
0
    def as_bytes(self):
        """Get bytes for a CYCLE.

        The op code is
            xxjjjjjj xxccx011
        where
            jjjjjj is the jump index to set if the cycle is not done.
            cc is which counter to increment.
        """
        jump_index = self.jump_index << 8
        counter = self.counter << 4
        op = 3
        return littleEndian(jump_index + counter + op, 2)
Exemple #16
0
    def as_bytes(self):
        """Get bytes for a CYCLE.

        The op code is
            xxjjjjjj xxccx011
        where
            jjjjjj is the jump index to set if the cycle is not done.
            cc is which counter to increment.
        """
        jump_index = self.jump_index << 8
        counter = self.counter << 4
        op = 3
        return littleEndian(jump_index + counter + op, 2)
Exemple #17
0
    def as_bytes(self):
        """Get bytes for an IDLE.

        The op code is
            dddddddd ddddddd0
        where d[14..0] is the number of FPGA cycles to idle.
        """
        if not (IDLE_MIN_CYCLES <= self.cycles <= IDLE_MAX_CYCLES):
            raise ValueError(
                "IDLE num cycles must fit in {} bits".format(
                    IDLE_NUM_BITS
                )
            )
        return littleEndian(self.cycles << 1, 2)
Exemple #18
0
    def as_bytes(self):
        """Get bytes for a CHECK

        The op code is
            xxjjjjjj iiiin001
        where
            jjjjjj jump index to set when check is True
            iiii specifies which daisychain bit to check
            n selects whether we check for bit ON or OFF
        """
        jump_idx = self.jump_index << 8
        which_daisy_bit = self.which_daisy_bit << 4
        bit_state = int(self.bit_state) << 3
        op = 1
        val = jump_idx + which_daisy_bit + bit_state + op
        return littleEndian(val, 2)
Exemple #19
0
    def as_bytes(self):
        """Get bytes for a CHECK

        The op code is
            xxjjjjjj iiiin001
        where
            jjjjjj jump index to set when check is True
            iiii specifies which daisychain bit to check
            n selects whether we check for bit ON or OFF
        """
        jump_idx = self.jump_index << 8
        which_daisy_bit = self.which_daisy_bit << 4
        bit_state = int(self.bit_state) << 3
        op = 1
        val = jump_idx + which_daisy_bit + bit_state + op
        return littleEndian(val, 2)
Exemple #20
0
 def pktWriteSram(cls, derp, data):
     """
     Get a numpy array of bytes to write one derp of SRAM
     
     data - ndarray: numeric data to be written. This must be formatted such
            that .tostring will yield the proper byte string for the direct
            ethernet packet.
     """
     assert 0 <= derp < cls.SRAM_WRITE_DERPS, \
         'SRAM derp out of range: %d' % derp
     # Ensure data is a numpy array.
     # This should not be needed, as it should have happened already
     data = np.asarray(data)
     pkt = np.zeros(cls.SRAM_WRITE_PKT_LEN + 2, dtype='<u1')
     pkt[0:2] = littleEndian(derp, 2)
     pkt[2:2 + len(data)] = data
     return pkt
Exemple #21
0
 def pktWriteSram(cls, derp, data):
     """
     Get a numpy array of bytes to write one derp of SRAM
     
     data - ndarray: numeric data to be written. This must be formatted such
            that .tostring will yield the proper byte string for the direct
            ethernet packet.
     """
     assert 0 <= derp < cls.SRAM_WRITE_DERPS, \
         'SRAM derp out of range: %d' % derp 
     # Ensure data is a numpy array.
     # This should not be needed, as it should have happened already
     data = np.asarray(data)
     pkt = np.zeros(cls.SRAM_WRITE_PKT_LEN + 2, dtype='<u1')
     pkt[0:2] = littleEndian(derp, 2)
     pkt[2:2+len(data)] = data
     return pkt
Exemple #22
0
    def makeMixerTable(cls, demods, p):
    
        """
        Page 1-12 of SRAM has the mixer tables for demodulators 0-11 respectively.

        (2) For the multiplier lookup tables, adrstart is taken from the following table  
        adrstart[20..8]= channel n + 1.  This offsets by 1 from the above trigger page.

        The Ethernet packet for channel n is:

        l(1)	length[15..8]		set to 4; ( length[15..0]= 1024+2=1026 )
        l(2)	length[7..0]		set to 2

        d(1)	adrstart[15..8]		SRAM page for start address: middle bits = n+1 
        d(2)	adrstart[23..16]	upper bits; size of SRAM implies bits [23..19] = 0

        d(3)	sram(+0)[7..0]		multsin(0)		Multiplier time 0
        d(4)	sram(+1)[7..0]		multcos(0)
        d(5)	sram(+2)[7..0]		multsin(1)		Multiplier time 1 (1/2 clock, 2ns)
        d(6)	sram(+3)[7..0]		multcos(1)
        ...
        d(1025)sram(+1022)[7..0]	multsin(511)
        d(1026)sram(+1023)[7..0]	multcos(511)
        """

        for idx,demod in enumerate(demods):
            data = np.zeros(cls.SRAM_MIXER_PKT_LEN, dtype='<i1')
            # retrigger table is page 0, mixer tables are pages 1-13, factor of 4 from stripping least significant bits
            data[0:2] = littleEndian((idx+1),2) # SRAM page address
            mixerTable = demod['mixerTable']
            for tidx, row in enumerate(mixerTable):
                I, Q = row
                data[(tidx*2)+2] = I
                data[(tidx*2+1)+2] = Q
                
            p.write(data.tostring())
Exemple #23
0
    def as_bytes(self):
        """Get bytes for a NOP.

        The op code is xxxxxxxx xxxx0101
        """
        return littleEndian(5, 2)
Exemple #24
0
    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

        if len(triggerTable) > 128:  # no memory for more than 128 entries
            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 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
                pass
            else:
                raise Exception(
                    "rlen < 50 clock cycles (200 ns) can cause FIFO backup for 12 chans"
                )

        data = np.zeros(cls.SRAM_RETRIGGER_PKT_LEN, dtype='<u1')

        data[0] = 0  # SRAM page for start address: middle bits = 0,
        data[1] = 0  # upper bits; size of SRAM implies bits [23..19] = 0

        for idx, entry in enumerate(triggerTable):
            currCount, currDelay, currLength, currChans = entry

            # WARNING: currChans defined in a funny way
            # if you want a trigger to measure a subset of channels,
            # those channels must be the lowest channels.
            # i.e. you can only read out:
            # (0, 0-1, 0-2, ... 0-11)
            # you cannot cherry pick which channels to read out
            # as far as JK and TW understand it.
            # For now, we will not make use of currChans(rchan),
            # rather default it all channels always read out.

            # See documentation above
            currCount -= 1  # compensate for FPGA offsets
            currDelay -= 4  # compensate for FPGA offsets
            currLength -= 1  # compensate for FPGA offsets

            midx = idx * 8 + 2
            data[midx:midx + 2] = littleEndian(currCount, 2)
            data[midx + 2:midx + 4] = littleEndian(currDelay, 2)
            data[midx + 4] = currLength
            data[midx + 5] = currChans
            data[midx + 6:midx + 8] = littleEndian(0, 2)  # spare

        p.write(data.tostring())
Exemple #25
0
 def regSerial(cls, bits):
     """Returns a numpy array of register bytes to write to PLL"""
     regs = np.zeros(cls.REG_PACKET_LEN, dtype='<u1')
     regs[0] = 6
     regs[3:6] = littleEndian(bits, 3)
     return regs
Exemple #26
0
    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
        
        if len(triggerTable) > 128: # no memory for more than 128 entries
            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 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
                pass
            else:
                raise Exception("rlen < 50 clock cycles (200 ns) can cause FIFO backup for 12 chans")
        
        data = np.zeros(cls.SRAM_RETRIGGER_PKT_LEN, dtype='<u1')
        
        data[0] = 0 # SRAM page for start address: middle bits = 0,
        data[1] = 0 # upper bits; size of SRAM implies bits [23..19] = 0
        
        for idx,entry in enumerate(triggerTable):
            currCount, currDelay, currLength, currChans = entry
            
            # WARNING: currChans defined in a funny way
            # if you want a trigger to measure a subset of channels,
            # those channels must be the lowest channels.
            # i.e. you can only read out:
            # (0, 0-1, 0-2, ... 0-11)
            # you cannot cherry pick which channels to read out 
            # as far as JK and TW understand it.
            # For now, we will not make use of currChans(rchan),
            # rather default it all channels always read out.
            
            # See documentation above
            currCount -= 1 # compensate for FPGA offsets
            currDelay -= 4 # compensate for FPGA offsets
            currLength -=1 # compensate for FPGA offsets
            
            midx = idx * 8 + 2
            data[midx:midx+2] = littleEndian(currCount, 2)
            data[midx+2:midx+4] = littleEndian(currDelay, 2)
            data[midx+4] = currLength
            data[midx+5] = currChans
            data[midx+6:midx+8] = littleEndian(0, 2) # spare
        
        p.write(data.tostring())
Exemple #27
0
    def as_bytes(self):
        """Get bytes for a NOP.

        The op code is xxxxxxxx xxxx0101
        """
        return littleEndian(5, 2)
Exemple #28
0
 def regSerial(cls, bits):
     """Returns a numpy array of register bytes to write to PLL"""
     regs = np.zeros(cls.REG_PACKET_LEN, dtype='<u1')
     regs[0] = 6
     regs[3:6] = littleEndian(bits, 3)
     return regs