]> jspc29.x-matter.uni-frankfurt.de Git - daqtools.git/commitdiff
adc.pl: improved phase optimization with newest FPGA firmware
authorAndreas Neiser <neiser@kph.uni-mainz.de>
Mon, 1 Dec 2014 12:36:41 +0000 (13:36 +0100)
committerAndreas Neiser <neiser@kph.uni-mainz.de>
Mon, 1 Dec 2014 12:37:04 +0000 (13:37 +0100)
tools/adc.pl

index 7242ddfb7312fa5f2b00c0d1cad4006252a5e846..227ee5b70b15a0fa338a5678b311241af4b91c82 100755 (executable)
@@ -25,7 +25,7 @@ unless(defined $ARGV[0] && defined $ARGV[1]) {
   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;
 }
 
@@ -272,33 +272,24 @@ if ($ARGV[1] eq "init") {
   # 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;
@@ -307,7 +298,7 @@ sub read_rates {
   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);
@@ -321,106 +312,128 @@ sub read_rates {
     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;
+}
+