test17.py 8.12 KB
Newer Older
1 2 3 4 5 6 7 8
#!   /usr/bin/env   python
#    coding: utf8

# Copyright CERN, 2011
# Author: Matthieu Cattin <matthieu.cattin@cern.ch>
# Licence: GPL v2 or later.
# Website: http://www.ohwr.org

9 10

# Import system modules
11 12 13 14
import sys
import time
import os

15 16 17 18 19 20 21
# Add common modules and libraries location to path
sys.path.append('../../../')
sys.path.append('../../../gnurabbit/python/')
sys.path.append('../../../common/')

# Import common modules
import rr
22 23
from ptsexcept import *

24 25 26 27 28
# Import specific modules
from numpy import *
from pylab import *
from ctypes import *
import fmc_adc_spec
29 30
import fmc_adc
import calibr_box
31
import find_usb_tty
32 33 34 35 36
from PAGE.Agilent33250A import *
from PAGE.SineWaveform import *


"""
37
test17: Plot all channels
38 39 40 41 42 43

Note: Requires test00.py to run first to load the firmware!
"""

GN4124_CSR = 0x0

44 45 46 47 48 49
# Calibration box vendor and device IDs
BOX_USB_VENDOR_ID = 0x10c4 # Cygnal Integrated Products, Inc.
BOX_USB_DEVICE_ID = 0xea60 # CP210x Composite Device
# Agilent AWG serial access vendor and device IDs
AWG_USB_VENDOR_ID = 0x0403 # Future Technology Devices International, Ltd
AWG_USB_DEVICE_ID = 0x6001 # FT232 USB-Serial (UART) IC
50 51 52
RS232_BAUD = 57600
NB_CHANNELS = 4

53
AWG_SET_SLEEP = 0.3
54
SSR_SET_SLEEP = 0.05
55 56
BOX_SET_SLEEP = 0.01
DAC_SET_SLEEP = 0.01
57 58 59 60 61

ACQ_TIMEOUT = 10

MAX_FIRMWARE_RELOAD = 10

62
PRE_TRIG_SAMPLES = 2000
63
POST_TRIG_SAMPLES = 50000
64 65
NB_SHOTS = 1

66
ACQ_LENGTH = 50000 # in samples
67 68
DMA_LENGTH = 4096 # in bytes

Matthieu Cattin's avatar
Matthieu Cattin committed
69 70 71 72
ADC_NBITS = 16 # ADC chip is 14 bits, but shifted to 16 bits in the firmware
DAC_NBITS = 16
DAC_FS = 10 # DAC full scale range is 10V

73 74 75

def disconnect_channels(fmc):
    for i in range(1,NB_CHANNELS+1):
76
        fmc.set_ssr(i, 0x00)
77 78 79 80 81 82 83 84 85 86
        time.sleep(SSR_SET_SLEEP)


def fmc_adc_init(spec, fmc):
    print('Initialise FMC board.')
    fmc.__init__(spec)
    # Reset offset DACs
    fmc.dc_offset_reset()
    # Make sure all switches are OFF
    disconnect_channels(fmc)
87 88
    # Reset offset DACs
    fmc.dc_offset_reset()
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
    # Set trigger
    fmc.set_soft_trig()
    # Set acquisition
    fmc.set_pre_trig_samples(PRE_TRIG_SAMPLES)
    fmc.set_post_trig_samples(POST_TRIG_SAMPLES)
    fmc.set_shots(NB_SHOTS)
    # Print configuration
    #fmc.print_adc_core_config()


def set_awg_freq(gen, sine, freq):
    sine.frequency = freq
    gen.play(sine)
    print('Sine frequency:%3.3fMHz')%(sine.frequency/1E6)
    time.sleep(AWG_SET_SLEEP)


106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
def acquisition_all(fmc, spec_fmc):
    # Make sure no acquisition is running
    fmc.stop_acq()
    #print('Acquisition FSM state : %s') % fmc.get_acq_fsm_state()
    # Start acquisition
    fmc.start_acq()
    time.sleep(0.01)
    # Trigger
    fmc.sw_trig()
    # Wait end of acquisition
    timeout = 0
    while('IDLE' != fmc.get_acq_fsm_state()):
        #print fmc.get_acq_fsm_state()
        time.sleep(.1)
        timeout += 1
        if(ACQ_TIMEOUT < timeout):
            print('Acquisition timeout. Check that the AWG is switched ON and properly connected.')
            return 1
    # Retrieve data trough DMA
    trig_pos = fmc.get_trig_pos()
126
    print('Trigger position; 0x%X')%(trig_pos)
127
    channels_data = spec_fmc.get_data((trig_pos-(PRE_TRIG_SAMPLES*8)), (PRE_TRIG_SAMPLES+POST_TRIG_SAMPLES)*8)
128 129 130
    return channels_data


131

132 133 134 135 136 137 138 139 140 141 142 143
def plot_all(data, mean, ylimit):
    sample = arange(len(data)/4)
    clf()
    plot(sample, data[0::4], 'b', label='Channel 1')
    plot(sample, data[1::4], 'g', label='Channel 2')
    plot(sample, data[2::4], 'c', label='Channel 3')
    plot(sample, data[3::4], 'm', label='Channel 4')
    plot(sample, [mean[0]]*len(sample), 'r')
    plot(sample, [mean[1]]*len(sample), 'r')
    plot(sample, [mean[2]]*len(sample), 'r')
    plot(sample, [mean[3]]*len(sample), 'r')
    ylim(-ylimit-(ylimit/10.0), ylimit+(ylimit/10.0))
144
    xlim(0, len(sample))
145 146 147 148 149 150 151 152 153 154 155 156 157 158
    grid(which='both')
    legend()
    draw()
    show()
    return 0

# Converts two's complement hex to signed
def hex2signed(value):
    if(value & 0x8000):
        return -((~value & 0xFFFF) + 1)
    else:
        return value


159 160
# Converts digital value to volts
def digital2volt(value, full_scale, nb_bit):
161
    return float(value) * float(full_scale)/2**nb_bit
162 163


164
# Converts volts to digital value
165 166 167 168 169 170
def volt2digital(value, full_scale, nb_bit):
    digital = (value + full_scale/2) * 2**nb_bit/full_scale
    if(digital > 2**nb_bit - 1):
        digital = 2**nb_bit - 1
    if(digital < 0):
        digital = 0
Matthieu Cattin's avatar
Matthieu Cattin committed
171
    return int(digital)
172 173


174
def set_offset_dac(fmc, dac_fs, dac_nbits, channel, offset_volt):
175 176
    dac_v = offset_volt
    dac_d = volt2digital(dac_v,dac_fs,dac_nbits)
Matthieu Cattin's avatar
Matthieu Cattin committed
177
    #print('DAC value: 0x%X (%fV)')%(dac_d, dac_v)
178
    fmc.set_dc_offset(channel,dac_d)
179 180 181
    time.sleep(DAC_SET_SLEEP)


Matthieu Cattin's avatar
Matthieu Cattin committed
182 183 184 185 186 187 188 189
def get_mean_value(adc_fs, adc_nbits, acq):
    mean_d = []
    for channel in range(1,NB_CHANNELS+1):
        mean_d.append(mean(acq[channel-1::4]))
    mean_v = [digital2volt(item,adc_fs,adc_nbits) for item in mean_d]
    return mean_v


190 191
def main (default_directory = '.'):

192 193 194
    # Constants declaration
    TEST_NB = 19
    EXPECTED_BITSTREAM_TYPE = 0x1
195
    FMC_ADC_BITSTREAM = '../firmwares/spec_fmcadc100m14b4cha.bin'
196
    FMC_ADC_BITSTREAM = os.path.join(default_directory, FMC_ADC_BITSTREAM)
197 198 199

    # Objects declaration
    spec = rr.Gennum() # bind to the SPEC board
200 201

    print "Loading FMC ADC firmware: %s\n" % FMC_ADC_BITSTREAM
202 203 204 205 206
    if(os.path.isfile(FMC_ADC_BITSTREAM)):
        spec.load_firmware(FMC_ADC_BITSTREAM)
        time.sleep(2)
    else:
        raise PtsCritical("Firmware file \"%s\" is missing, test stopped." % FMC_ADC_BITSTREAM)
207 208 209

    carrier = fmc_adc_spec.CFmcAdc100mSpec(spec, EXPECTED_BITSTREAM_TYPE)
    fmc = fmc_adc.CFmcAdc100m(spec)
210 211 212 213
    usb_tty = find_usb_tty.CttyUSB()
    awg_tty = usb_tty.find_usb_tty(AWG_USB_VENDOR_ID, AWG_USB_DEVICE_ID)
    box_tty = usb_tty.find_usb_tty(BOX_USB_VENDOR_ID, BOX_USB_DEVICE_ID)
    gen = Agilent33250A(device=awg_tty[0], bauds=RS232_BAUD)
214
    sine = SineWaveform()
215
    box = calibr_box.CCalibr_box(box_tty[0])
216

217
    # Work-around to make dma work with sdb firmware
218 219
    #carrier.gnum.set_local_bus_freq(200)
    print "GN4124 local bus freq: ", carrier.gnum.get_local_bus_freq()
220

221
    # Enable "DMA finished" IRQ
222
    carrier.enable_dma_done_irq()
223 224 225 226

    # Initialise fmc adc
    fmc_adc_init(spec, fmc)

227
    # Use test data instead of data from ADC
228
    #fmc.test_data_en()
229 230 231 232

    # Use data pattern instead of ADC data
    #fmc.testpat_en(0x2000)

233
    # Connect to AWG
234
    #gen.connect()
235 236

    # Switch AWG output OFF
237
    #gen.output = False
238

239
    # Measure FMC and carrier temperature
240
    print('SPEC temperature: %3.3f°C') % carrier.get_temp()
241 242 243 244 245 246 247 248
    print('FMC temperature : %3.3f°C') % fmc.get_temp()

    # Open all switches, reset offset DAC to mid-scale (0V)
    for channel in range(1,NB_CHANNELS+1):
        fmc.set_input_range(channel, 'OPEN')
        fmc.set_input_term(channel, 'OFF')
    fmc.dc_offset_reset()

Matthieu Cattin's avatar
Matthieu Cattin committed
249 250

    # ADC full scale is 100mV
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
    select = raw_input('Select input range [1=10V, 2=1V, 3=100mV]:')
    if('1' == select):
        print('10V input range selected')
        ADC_FS = 10.0
        in_range = '10V'
    elif('2' == select):
        print('1V input range selected')
        ADC_FS = 1.0
        in_range = '1V'
    elif('3' == select):
        print('100mV input range selected')
        ADC_FS = 0.1
        in_range = '100mV'
    else:
        print('10V input range selected')
        ADC_FS = 10.0
        in_range = '10V'
Matthieu Cattin's avatar
Matthieu Cattin committed
268

269
    # Set calibration box to AWG
270
    box.select_output_ch(1)
271
    time.sleep(BOX_SET_SLEEP)
Matthieu Cattin's avatar
Matthieu Cattin committed
272

273
    # All offset DACs to 0V
Matthieu Cattin's avatar
Matthieu Cattin committed
274
    for channel in range(1,NB_CHANNELS+1):
275
        set_offset_dac(fmc, DAC_FS, DAC_NBITS, channel, 0.0)
276

277
    # Set channel input range
Matthieu Cattin's avatar
Matthieu Cattin committed
278
    for channel in range(1,NB_CHANNELS+1):
279 280
        fmc.set_input_range(channel, in_range)
        time.sleep(SSR_SET_SLEEP)
281

282
    # Measures value on each channel
283
    acq_d = acquisition_all(fmc, carrier)
284 285 286 287
    acq_d = [hex2signed(item) for item in acq_d]
    acq_v = [digital2volt(item,ADC_FS,ADC_NBITS) for item in acq_d]
    mean_v = get_mean_value(ADC_FS, ADC_NBITS, acq_d)
    plot_all(acq_v, mean_v, ADC_FS/2.0)
288 289


Matthieu Cattin's avatar
Matthieu Cattin committed
290
    # Close AWG
291
    #gen.close()
292 293 294 295 296 297 298 299

    # Check if an error occured during frequency response test
    #if(error != 0):
    #    raise PtsError('An error occured during frequency response test, check log for details.')


if __name__ == '__main__' :
    main()