print "\t",' adc_reg $addr $val',"\t write to register of all ADCs, arguments are oct()'ed\n";
print "\t",' adc_testio $id',"\t enable testio of all ADCs, id=0 disables\n";
print "\t",' adc_phase $phase [ADCs]',"\t set the clock-data output phase\n";
- print "\t",' adc_testall',"\t test all ADC channels with patterns\n";
+ print "\t",' adc_testall',"\t test ADC LVDS communication with pattern\n";
exit;
}
# init stuff
&lmk_init;
&adc_init;
-
- # set the ADC phase to 0x0
- # this is mandatory in order to get
- # working communication!
- #sendcmd_adc(0x16, 0b0);
- #sendcmd_adc(0xFF, 0x1);
- #print ">>> Phase set to 0°, your board should be working now...\n";
+ while(1) {
+ print ">>> Optimizing ADC phases...\n";
+ &set_optimal_phases;
+ print ">>> Check ADCs again...\n";
+ my @good = &adc_testall;
+ #print Dumper(\@good);
+ # check if all ADCs are good
+ if(@good == grep { $_ } @good) {
+ last;
+ }
+ else {
+ print ">>> Some ADCs are not working, retrying...\n";
+ #exit;
+ }
+ }
+ print ">>> Your board should be working now...\n";
}
-# sub read_channels {
-# my @result;
-# my $ctrlreg = 0xa081;
-# trb_register_write($board,$ctrlreg,0);
-# usleep(100000);
-# trb_register_write($board,$ctrlreg,2);
-# for (my $ch=0;$ch<48;$ch++) {
-# my $r = trb_register_read_mem($board,0xa000+$ch,1,300);
-# push(@result, $r->{$board});
-# #print Dumper($r);
-# }
-# trb_register_write($board,$ctrlreg,0);
-
-# return @result;
-# }
-
-
-
sub read_rates {
my $addr=shift;
my $size=shift;
my $mask = 0;
$mask |= (1<<$_) for ($start..$start+$bits-1);
- my $us = 1000000;
+ my $us = 100000;
# read it
my $r1 = trb_register_read_mem($board,$addr,0,$size);
usleep($us);
my $val2 = ($r2->[$i] & $mask) >> $start;
# detect overflow
if($val2<$val1) {
- print "Overflow\n";
+ #print "Overflow\n";
$val2 += 1<<$bits;
}
my $t1 = 0; #$r1->{time}->[$i];
my $t2 = $us/1e6; # $r2->{time}->[$i];
my $rate = ($val2-$val1)/($t2-$t1);
#print $r2->{value}->[$i]-$r1->{value}->[$i],"\n";
- print $val2-$val1," ",$rate,"\n";
+ #print $val2-$val1," ",$rate,"\n";
+ push(@rates,$rate);
}
- #print
- #print $bits,"\n";
- #print 36 & vec($mask, 0, 32),"\n";
- return \@rates;
+ return @rates;
}
if ($ARGV[1] eq "adc_testall") {
$verbose=0;
- @adcs=(0);
+ my @good = &adc_testall;
+ for my $adc (0..11) {
+ printf("ADC %02d: %s\n",$adc,
+ $good[$adc] ? "Working" : "NOT WORKING!!!");
+ }
+}
+
+sub adc_testall {
+ my @phases = @{(shift || [-1])}; # by default dont change phases
+
+ # checkerboard, sends 0x2aa and 0x155 as ADC words
+ adc_testio(0b0100);
+ trb_register_write($board, 0xa019, 0x015502aa);
+ # midscale short
+ #adc_testio(0b0001);
+ #trb_register_write($board, 0xa019, 0x02000200);
+
+ my @good_ranges;
+ for my $phase (@phases) {
+ #print "Setting phase to ",$phase*60,"\n";
+ adc_phase($phase) if $phase>=0;
+ # word counts per ADC (12 items) at 0xa030 (upper 28bits)
+ my @word_rates = read_rates(0xa030, 12, 4, 28);
+
+ # invalid words per channel (4x12=48 items) at 0xa8c0
+ # use only upper 31 bits to account for overflow
+ my @invalid_rates = read_rates(0xa8c0, 48, 1, 31);
+
+ for my $adc (0..11) {
+ my $word_rate = $word_rates[$adc];
+ my $MS = 4e7; # assume 40MS ADC...
+ my $good = $word_rate > 0.98*$MS;
+ for my $i (0..3) {
+ my $ch = $adc*4+$i;
+ my $invalid_rate = $invalid_rates[$ch];
+ $good &= $invalid_rate==0 ? 1 : 0;
+ }
+ #printf("%02d %.0f %d\n", $adc, $word_rate, $good);
+ if($phase<0) {
+ $good_ranges[$adc] = $good;
+ }
+ else {
+ $good_ranges[$adc]->[$phase] = $good;
+ $good_ranges[$adc]->[$phase+@phases] = $good; # another copy to account for cyclic phase
+ }
+ }
+ }
- # word counts per ADC (12 items) at 0xa030 (upper 28bits)
- my $word_counts = read_rates(0xa030,12,4,28);
+ # disable testio again
+ adc_testio(0);
+ trb_register_write($board, 0xa019, 0x0);
- print Dumper($word_counts);
+ return @good_ranges;
}
-# if ($ARGV[1] eq "adc_testall") {
-# $verbose=0;
-
-# # set pattern to checkerboard,
-# # should give alternating 0x155, 0x2aa, 0x155, 0x2aa ...
-# my $ok_checkerboard = 1;
-# adc_testio(0b0100);
-# my @r = read_channels();
-# #print Dumper(\@r);
-# for(my $ch=0;$ch<@r;$ch++) {
-# my @vals = map { $_ & 0x3ff } @{$r[$ch]};
-# # look at first value
+sub set_optimal_phases {
+ $verbose=0;
+
+ my $max_phase = 0b1011;
+
+ my @good_ranges = adc_testall([0..$max_phase]);
-# my @checkerboard;
-# my $firstval = $vals[0];
-# if($firstval == 0x2aa) {
-# @checkerboard = (0x2aa, 0x155);
-# }
-# elsif($firstval == 0x155) {
-# @checkerboard = (0x155, 0x2aa);
-# }
-# else {
-# printf("ERROR: First value 0x%x from checkerboard not recognized, ch=$ch\n",$firstval);
-# $ok_checkerboard = 0;
-# next;
-# }
-
-
-# # compare the remaining values
-# for(my $i=1;$i<@vals;$i++) {
-# if($vals[$i] != $checkerboard[$i % 2]) {
-# printf("ERROR: Value 0x%x (idx=$i) from checkerboard not recognized, ch=$ch\n",$vals[$i]);
-# $ok_checkerboard = 0;
-# last;
-# }
-# }
-# }
-# if($ok_checkerboard) {
-# print ">>> Tested all channels with checkerboard pattern successfully\n";
-# }
-# else {
-# print ">>> Test with checkerboard failed, see above.\n";
-# }
-
-# # set testmode to mixed frequency,
-# # should give 0b1001100011
-# adc_testio(0b1100);
-# my $ok_mixed = 1;
-# @r = read_channels();
-# for(my $ch=0;$ch<@r;$ch++) {
-# my @vals = map { $_ & 0x3ff } @{$r[$ch]};
-
-# for(my $i=0;$i<@vals;$i++) {
-# if ($vals[$i] != 0b1001100011) {
-# printf("ERROR: Value 0x%x (idx=$i) from mixed-frequency not recognized, ch=$ch\n", $vals[$i]);
-# $ok_mixed = 0;
-# last;
-# }
-# }
-# }
-# if($ok_checkerboard) {
-# print ">>> Tested all channels with mixed frequency pattern successfully\n";
-# }
-# else {
-# print ">>> Test with mixed-frequency pattern failed\n";
-# }
-# # disable testio
-# adc_testio(0);
-
-# if($ok_checkerboard && $ok_mixed) {
-# print ">>> All ADC channels seem to be nicely working with testpatterns!\n";
-# }
-# else {
-# print ">>> Test of ADC channels failed :(((\n";
-# }
-#}
+ # find the optimal phases as largest
+ # consecutive range of good state
+ # then set the phases for each ADC individually
+ my @old_adcs = @adcs;
+ for my $adc (0..11) {
+ my @good = @{$good_ranges[$adc]};
+ #printf("%02d %s\n", $adc, join(' ',@good));
+ # search for largest consecutive ones in @good
+ my $start = -1;
+ my $max_length = 0;
+ my $opt_phase = -1;
+ #my $end = -1;
+ for(my $i=0;$i<@good;$i++) {
+ if($start<0) {
+ if($good[$i]) {
+ #print "Found start at $i\n";
+ $start=$i;
+ }
+ }
+ else {
+ if(!$good[$i] || $i==@good-1) {
+ my $length = $i - $start + ($i==@good-1);
+ #print "Found stop at $i with length $length\n";
+ if($length>$max_length) {
+ $max_length=$length;
+ $opt_phase = int($start+$length/2) % ($max_phase+1);
+ }
+ $start = -1;
+ }
+ }
+ }
+ if($opt_phase<0) {
+ print "Warning: No optimal phase found for ADC $adc, guessing 0\n";
+ $opt_phase=0;
+ }
+ #print "Opt phase: $opt_phase Max length $max_length\n";
+
+ # now set them for each ADC
+ @adcs = ($adc); # used by adc_phase
+ adc_phase($opt_phase);
+ #printf("Set ADC %02d to optimal phase of %03d degrees\n", $adc, $opt_phase*60);
+ }
+
+ @adcs = @old_adcs;
+}
+