Commit b8629c15 authored by Matthieu Cattin's avatar Matthieu Cattin

Use new DMA acquisition function from spec_fmc, frequency response in dB, use calibration box v2.

parent 30f3d392
......@@ -15,284 +15,269 @@ from pylab import *
from ptsexcept import *
import gn4124
import spec_fmc_adc
import fmc_adc
import calibr_box
import find_usb_tty
from PAGE.Agilent33250A import *
from PAGE.SineWaveform import *
"""
test09: Test analogue front-end frequency response
test09: Test analogue front-end frequency response,
with limits check
Note: Requires test00.py to run first to load the firmware!
"""
GN4124_CSR = 0x0
# Calibration box vendor and product IDs
BOX_USB_VENDOR_ID = 0x10c4 # Cygnal Integrated Products, Inc.
BOX_USB_PRODUCT_ID = 0xea60 # CP210x Composite Device
# Agilent AWG serial access vendor and product IDs
AWG_USB_VENDOR_ID = 0x0403 # Future Technology Devices International, Ltd
AWG_USB_PRODUCT_ID = 0x6001 # FT232 USB-Serial (UART) IC
AWG_BAUD = 57600
USB_DEVICE = "/dev/ttyUSB0"
RS232_BAUD = 57600
NB_CHANNELS = 4
AWG_SET_SLEEP = 1
AWG_SET_SLEEP = 0.6
SSR_SET_SLEEP = 0.05
BOX_SET_SLEEP = 1
ACQ_TIMEOUT = 10
MAX_FIRMWARE_RELOAD = 10
PRE_TRIG_SAMPLES = 1000
POST_TRIG_SAMPLES = 1000
PRE_TRIG_SAMPLES = 10
POST_TRIG_SAMPLES = 10000
NB_SHOTS = 1
DMA_LENGTH = 4096 # DMA length in bytes
ACQ_LENGTH = 10000 # in samples
# col 0: freq
# col 1: expected amplitude (ADC raw data)
# col 2: tolerance on the amplitude
points = [[1E6, 33300, 4000],
[10E6, 21000, 4000],
[15E6, 16500, 4000],
[16E6, 15700, 4000],
[17E6, 15000, 4000],
[18E6, 14500, 4000],
[19E6, 14000, 4000],
[20E6, 12500, 4000],
[21E6, 12500, 4000],
[22E6, 12500, 4000],
[23E6, 12000, 4000],
[24E6, 11500, 4000],
[25E6, 10000, 4000],
[30E6, 9000, 4000],
[40E6, 4500, 4000],
[60E6, 1000, 700],
[80E6, 400, 300]]
# The following table is used to test the test
"""
points = [[1E6, 36300, 1000],
[10E6, 24000, 1000],
[15E6, 19500, 1000],
[16E6, 18700, 1000],
[17E6, 18000, 1000],
[18E6, 17500, 1000],
[19E6, 17000, 1000],
[20E6, 15500, 1000],
[21E6, 15500, 1000],
[22E6, 15500, 1000],
[23E6, 15000, 1000],
[24E6, 14500, 1000],
[25E6, 14000, 2000],
[30E6, 12000, 1000],
[40E6, 7500, 1000],
[60E6, 4000, 500],
[80E6, 3400, 200]]
"""
# col 1: expected attenuation (in dB)
# col 2: tolerance on attenuation (in dB)
points = [[10E3 , 0 , 1],
[100E3, 0 , 1],
[1E6 , 0 , 1],
[5E6 , 0 , 1],
[10E6 , 0 , 1],
[12E6 , 0 , 1],
[14E6 , 0 , 1],
[16E6 , 0 , 2],
[18E6 , 0 , 2],
[20E6 , 0 , 2],
[22E6 , 0 , 2],
[24E6 , -0.5, 2],
[26E6 , -1 , 2],
[28E6 , -2 , 2],
[30E6 , -3.5, 2],
[32E6 , -4.5, 2],
[34E6 , -6.5, 2],
[36E6 , -8.5, 2],
[38E6 , -10.5, 2],
[40E6 , -13.5, 2],
[42E6 , -15 , 2],
[44E6 , -17.5, 2],
[46E6 , -20 , 2],
[48E6 , -22.5, 2],
[60E6 , -38 , 3],
[80E6 , -66 , 3]]
def load_firmware(default_directory):
print('Load firmware to FPGA')
path_fpga_loader = '../../../gnurabbit/user/fpga_loader';
path_firmware = '../firmwares/spec_fmcadc100m14b4cha_test.bin';
firmware_loader = os.path.join(default_directory, path_fpga_loader)
bitstream = os.path.join(default_directory, path_firmware)
print firmware_loader + ' ' + bitstream
os.system( firmware_loader + ' ' + bitstream )
time.sleep(2);
def open_all_channels(fmc):
for i in range(1,NB_CHANNELS+1):
fmc.set_input_range(i, 'OPEN')
time.sleep(SSR_SET_SLEEP)
def fmc_adc_init(spec, fmc):
print('Initialise FMC board.')
fmc.__init__(spec)
print "Initialise FMC board."
# Reset offset DACs
fmc.dc_offset_reset()
# Make sure all switches are OFF
open_all_channels(fmc)
# Set trigger
# hw trig, rising edge, external, sw disable, no delay
fmc.set_trig_config(1, 0, 1, 1, 0, 0, 0)
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()
#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)
#print('Sine frequency:%3.3fMHz')%(sine.frequency/1E6)
time.sleep(AWG_SET_SLEEP)
# Converts two's complement hex to signed
def hex2signed(value):
if(value & 0x8000):
return -((~value & 0xFFFF) + 1)
else:
return value
def acquisition(gnum, pages, fmc, channel_nb, channel_data):
# Start acquisition
# Converts digital value to volts
def digital2volt(value, full_scale, nb_bit):
return float(value) * float(full_scale)/2**nb_bit
def acq_channels(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.')
print "Acquisition timeout. Missing trigger?."
print "Acq FSm state: %s"%fmc.get_acq_fsm_state()
return 1
#raise PtsError('Acquisition timeout. Check that the AWG is switched ON and properly connected.')
# Retrieve data trough DMA
page1_data_before_dma = gnum.get_memory_page(1)
gnum.add_dma_item(0x100, pages[1], DMA_LENGTH, 0, 0)
gnum.start_dma()
gnum.wait_irq()
page1_data = gnum.get_memory_page(1)
page_zeros = [0] * len(page1_data)
if((page1_data_before_dma == page1_data) or (page_zeros == page1_data)):
print('Previous page:')
print page1_data_before_dma[0:20]
print('Current page:')
print page1_data[0:20]
print('### Acquisition or DMA error. ###')
#raise PtsWarning('Acquisition or DMA error.')
return 1
for i in range(len(page1_data)):
channel_data.append(page1_data[i] & 0xFFFF)
channel_data.append(page1_data[i]>>16)
channel_data = channel_data[channel_nb-1::4]
return 0
def show_result_graph(points, ch_diff):
trig_pos = fmc.get_trig_pos()
# Enable "DMA done" iinterrupt
spec_fmc.set_irq_en_mask(0x1)
# Read ACQ_LENGTH samples after the trigger for all channels
channels_data = spec_fmc.get_data((trig_pos<<3), ACQ_LENGTH*8)
# Disable "DMA done" iinterrupt
spec_fmc.set_irq_en_mask(0x0)
channels_data = [hex2signed(item) for item in channels_data]
channels_data = [digital2volt(item,1.0,16) for item in channels_data]
return channels_data
def show_result_graph(points, ch_att):
pt = array(points)
freq = pt[:,0]
a_min = pt[:,1] - pt[:,2]
a_max = pt[:,1] + pt[:,2]
semilogx(freq, ch_diff[0::4], 'b', label='Channel 1')
semilogx(freq, ch_diff[1::4], 'g', label='Channel 2')
semilogx(freq, ch_diff[2::4], 'r', label='Channel 3')
semilogx(freq, ch_diff[3::4], 'c', label='Channel 4')
cutoff = [-3] * len(points)
semilogx(freq, ch_att[0], 'b', label='Channel 1')
semilogx(freq, ch_att[1], 'g', label='Channel 2')
semilogx(freq, ch_att[2], 'm', label='Channel 3')
semilogx(freq, ch_att[3], 'c', label='Channel 4')
semilogx(freq, a_min, 'r:', label='Lower limit')
semilogx(freq, a_max, 'r:', label='Upper limit')
legend()
semilogx(freq, cutoff, 'k', label='-3dB')
grid(color='k', linestyle='--', linewidth=1)
legend(loc='upper left')
show()
return 0
def main (default_directory='.'):
"""
# Load firmware to FPGA
path_fpga_loader = '../../../gnurabbit/user/fpga_loader';
path_firmware = '../firmwares/spec_fmcadc100m14b4cha.bin';
firmware_loader = os.path.join(default_directory, path_fpga_loader)
bitstream = os.path.join(default_directory, path_firmware)
print firmware_loader + ' ' + bitstream
os.system( firmware_loader + ' ' + bitstream )
time.sleep(2);
"""
# Load firmware
load_firmware(default_directory)
# Objects declaration
spec = rr.Gennum() # bind to the SPEC board
gnum = gn4124.CGN4124(spec, GN4124_CSR)
spec_fmc = spec_fmc_adc.CSpecFmcAdc100Ms(spec)
fmc = fmc_adc.CFmcAdc100Ms(spec)
gen = Agilent33250A(device=USB_DEVICE, bauds=RS232_BAUD)
usb_tty = find_usb_tty.CttyUSB()
awg_tty = usb_tty.find_usb_tty(AWG_USB_VENDOR_ID, AWG_USB_PRODUCT_ID)
box_tty = usb_tty.find_usb_tty(BOX_USB_VENDOR_ID, BOX_USB_PRODUCT_ID)
gen = Agilent33250A(device=awg_tty[0], bauds=AWG_BAUD)
sine = SineWaveform()
# Enable "DMA finished" IRQ
spec_fmc.set_irq_en_mask(0x1)
box = calibr_box.CCalibr_box(box_tty[0])
# Initialise fmc adc
fmc_adc_init(spec, fmc)
# Set sine params
sine.frequency = 1E6
sine.amplitude = 0.25
sine.amplitude = 0.8
sine.dc = 0
print('Sine frequency:%3.3fMHz amplitude:%2.3fVp offset:%2.3fV')%(sine.frequency/1E6, sine.amplitude, sine.dc)
#print('Sine frequency:%3.3fMHz amplitude:%2.3fVp offset:%2.3fV')%(sine.frequency/1E6, sine.amplitude, sine.dc)
# Set AWG
gen.connect()
gen.play(sine)
gen.output = True
# Get physical addresses of the pages for DMA transfer
pages = gnum.get_physical_addr()
# Test frequency response of all channels
ch_diff = []
j = 0
retry_cnt = 0
error = 0
while(j < len(points)):
#print('begin loop j=%d')%(j)
set_awg_freq(gen, sine, points[j][0])
for i in range(1,NB_CHANNELS+1):
fmc.set_input_range(i, '1V')
time.sleep(SSR_SET_SLEEP)
print "\nFrequency response measurement."
ch_ampl = [[],[],[],[]]
for i in range(1,NB_CHANNELS+1):
fmc.set_input_range(i, '1V')
fmc.set_input_term(i, 'ON')
time.sleep(SSR_SET_SLEEP)
box.select_output_ch(i) # connect AWG to current channel
time.sleep(BOX_SET_SLEEP)
for j in range(len(points)):
set_awg_freq(gen, sine, points[j][0])
channel_data = []
retry = acquisition(gnum, pages, fmc, i, channel_data)
if(retry != 0):
retry_cnt += 1
print('RETRY: %d')%(retry_cnt)
if(MAX_FIRMWARE_RELOAD < retry_cnt):
print('Maximium of %d retry exceeded (channel:%d, freq:%2.3fMHz)')%(MAX_FIRMWARE_RELOAD, i, points[j][0]/1E6)
error += 1
break
#raise PtsError('Maximium of %d retry exceeded (channel:%d, freq:%2.3fMHz)'%(MAX_FIRMWARE_RELOAD, i, points[j][0]/1E6))
load_firmware(default_directory)
fmc_adc_init(spec, fmc)
#time.sleep(2)
break
diff = max(channel_data)-min(channel_data)
print('CH%d amplitude:%d expected:%d +/-%d')%(i, diff, points[j][1], points[j][2])
ch_diff.append(diff)
fmc.set_input_range(i, 'OPEN')
if((diff < points[j][1]-points[j][2]) | (diff > points[j][1]+points[j][2])):
print('Channel %d frequency response is out of range at freq:%2.3fMHz')%(i, points[j][0]/1E6)
print('Current amplitude:%d, expected:%d +/-%d')%(diff, points[j][1], points[j][2])
channels_data = acq_channels(fmc, spec_fmc)
channel_data = channels_data[i-1::4]
ampl = max(channel_data)-min(channel_data)
print "CH%d frequency:%8.0f Hz amplitude:%f V"%(i, points[j][0], ampl)
ch_ampl[i-1].append(ampl)
fmc.set_input_range(i, 'OPEN')
fmc.set_input_term(i, 'OFF')
# Convert volts to dB
ch_att = [[],[],[],[]]
for ch in range(NB_CHANNELS):
vref = ch_ampl[ch][0]
print "Channel %d vref=%f"%(ch, vref)
ch_att[ch] = [(20*log(item/vref)) for item in ch_ampl[ch]]
# Check that frequency response is in the limits
print "\nFrequency response check."
error = 0
for i in range(len(points)):
for ch in range(NB_CHANNELS):
if((ch_att[ch][i] < points[j][1]-points[j][2]) | (ch_att[ch][i] > points[i][1]+points[i][2])):
print "Channel %d frequency response is out of range at freq:%2.3fMHz"%(ch+1, points[i][0]/1E6)
print "Attenuation:%3.3fdB, expected:%2.1f +/-%2.1fdB"%(ch_att[ch][i], points[i][1], points[i][2])
error += 1
#raise PtsError('Channel %d frequency response is out of range at freq:%2.3fMHz'%(i, points[j][0]/1E6))
if(retry == 0):
j += 1
retry_cnt = 0
#print('j++')
#print('end loop j=%d')%(j)
if error == 0:
print "OK!"
# print freqency response to log
print('Channels frequency response')
print('Frequency, Expected value, tolerance, CH1 value, CH2 value, CH3 value, CH4 value')
print('\nChannels frequency response in dB')
print('Frequency, Expected value, tolerance, CH1 attenuation, CH2 attenuation, CH3 attenuation, CH4 attenuation, Mean attenuation')
for i in range(len(points)):
print('%2.3f, %d, %d, %d, %d, %d, %d')%(points[i][0]/1E6, points[i][1], points[i][2], ch_diff[i*4], ch_diff[i*4+1], ch_diff[i*4+2], ch_diff[i*4+3])
# The following code is to show a graph of the test results
# !! Don't forget to import numpy and pylab !!
"""
pt = array(points)
freq = pt[:,0]
a_min = pt[:,1] - pt[:,2]
a_max = pt[:,1] + pt[:,2]
semilogx(freq, ch_diff[0::4], 'b', label='Channel 1')
semilogx(freq, ch_diff[1::4], 'g', label='Channel 2')
semilogx(freq, ch_diff[2::4], 'r', label='Channel 3')
semilogx(freq, ch_diff[3::4], 'c', label='Channel 4')
semilogx(freq, a_min, 'r:', label='Lower limit')
semilogx(freq, a_max, 'r:', label='Upper limit')
legend()
show()
"""
ch_att_mean = (ch_att[0][i]+ch_att[1][i]+ch_att[2][i]+ch_att[3][i])/4
print "%8.0f, %3d, %2d, % 3.3f, % 3.3f, % 3.3f, % 3.3f, %f"%(points[i][0],
points[i][1],
points[i][2],
ch_att[0][i],
ch_att[1][i],
ch_att[2][i],
ch_att[3][i],
ch_att_mean)
# print frequency response to a separate file
file_name = "test09_freq_resp.txt"
f = open(file_name, 'w')
for i in range(len(points)):
f.write('%8.0f, %2.1f, %2.1f, % 3.3f, % 3.3f, % 3.3f, % 3.3f\n'%(points[i][0],
points[i][1],
points[i][2],
ch_att[0][i],
ch_att[1][i],
ch_att[2][i],
ch_att[3][i]))
f.close()
# Plot results -> use test10.py to plot the results!
#show_result_graph(points, ch_att)
# Make sure all switches are OFF
open_all_channels(fmc)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment