Digitaltester

Wenn ihr Ideen zu neuen Entwicklungen habt, dann diskutiert sie bitte hier.
Antworten
Benutzeravatar
Bart
kann c't-Lab-Bausätze löten
kann c't-Lab-Bausätze löten
Beiträge: 45
Registriert: 11.01.2014, 10:44

Digitaltester

Beitrag von Bart » 20.06.2014, 10:29

Hallo Forum!

Hiermit möchte ich meine kleine Erweiterung für das c't-Lab vorstellen.
Mit dieser Erweiterung können digitale Logik-Schaltkreise getestet werden.
Digitaltester_Uebersicht.jpg
Digitaltester mit c't-Lab
Es wird mindestens ein ADA-IO Modul benötigt. Außerdem habe auch mein DCG verwendet, es aber würde theoretisch auch ohne gehen.

Es können digitale Logikschaltkreise mit 14 bzw. 16 Pins auf ihre Funktion hin getestet werden.
Digitaltester_Detail.jpg
Detail
Der Testvorgang verläuft in drei Schritten:
1. Ermittelung der Datenrichtung der Pins (Ein-/Ausgänge)
2. Erfassen, welche Eingänge auf welche Ausgänge wirken
3. Bestimmung der Logik-Funktion(en)

Als kleine Beigabe wird noch der Stromverbrauch pro Gatter bestimmt und die eingesetzte Technologie (TTL, CMOS) erraten.

Hier ist die Ausgabe für den im Bild gezeigten D204:
Initialisation: ok
Power: U (5.00 V) * I (32.59 mA) = P (161.8 mW)
14-pin device
check DUT pin directions
Testing pin 1 low: 1.07 V hi: 5.03 V hiZ: 5.01 V --> direction: Input
Testing pin 2 low: 0.10 V hi: 0.15 V hiZ: 0.11 V --> direction: Output
Testing pin 3 low: 0.97 V hi: 4.94 V hiZ: 4.92 V --> direction: Input
Testing pin 4 low: 0.11 V hi: 0.15 V hiZ: 0.11 V --> direction: Output
Testing pin 5 low: 0.97 V hi: 4.94 V hiZ: 4.92 V --> direction: Input
Testing pin 6 low: 0.09 V hi: 0.13 V hiZ: 0.10 V --> direction: Output
Testing pin 8 low: 0.08 V hi: 0.12 V hiZ: 0.08 V --> direction: Output
Testing pin 9 low: 0.98 V hi: 4.96 V hiZ: 4.30 V --> direction: Input
Testing pin 10 low: 0.09 V hi: 0.13 V hiZ: 0.09 V --> direction: Output
Testing pin 11 low: 0.99 V hi: 4.96 V hiZ: 4.35 V --> direction: Input
Testing pin 12 low: 0.09 V hi: 0.13 V hiZ: 0.09 V --> direction: Output
Testing pin 13 low: 1.00 V hi: 4.96 V hiZ: 4.26 V --> direction: Input
6 input pins: [1, 3, 5, 9, 11, 13]
6 output pins: [2, 4, 6, 8, 10, 12]
check 64 logic combinations
[################################################################################] 100% Done...
found following equations:
input(s): [1], output: 2 --> 10 (NOT)
input(s): [3], output: 4 --> 10 (NOT)
input(s): [5], output: 6 --> 10 (NOT)
input(s): [9], output: 8 --> 10 (NOT)
input(s): [11], output: 10 --> 10 (NOT)
input(s): [13], output: 12 --> 10 (NOT)
Power per gate: P_gate = 27.0 mW
Technology : High Speed TTL
Cleanup
Done
ctLab_Digitaltester_schematic.pdf
Schaltplan
(40.11 KiB) 157-mal heruntergeladen
Zum Schaltplan ist nicht wirklich viel zu sagen. Die Pins hängen über 1kOhm-Widerstände an den digitalen IOs. Zusätzlich können die AD-Wandler direkt an den Pins messen.

Falls das jemand nachbauen möchte, hier noch ein paar Tipps:
- besorgt den Textool-Sockel vorher, damit genug Platz auf der Platine eingeplant wird und der Footprint passt,
- es gibt einige Chips (z.B. HEF4049), die Vcc an Pin 1 haben, dazu müsste noch ein Jumper vorgesehen werden,
- ein Stützkondensator kann bei diesen langen Zuleitungen auch nicht schaden


Der Quellcode ist nicht wirklich schön, sollte - Dank Python - aber verständlich sein.
Die Python-Bibliothek ctlab.py ist sicher auch für eigene Projekte verwendbar und natürlich erweiterbar.


Perspektivisch könnte man noch folgende Funktionen einbauen:
- Auswahl eines Chips aus einer Liste und Test ob er seine Funktion erfüllt,
- Unterstützung für Speicherchips bzw. Flip/Flops.
Wobei ich für letzteres noch keine Idee habe, wie man das Automatisieren könnte.

Falls man das Timing der Signale berücksichtigen möchte, bräuchte man ein komplett anderes Konzept.

Viele Grüße
Bart

Anhang: Quellcode

Code: Alles auswählen

#! /usr/bin/env python
# ctlab.py

import serial
import re


class ctlab( object):

    def __init__( self, serialport):

        self.ada = None
        self.dcg = None
        self.edl = None
        self.dds = None
        self.div = None

        self.ser = serial.Serial( serialport, 38400, timeout = 0.1)
        self.ser.parity   = 'N'
        self.ser.bytesize = 8
        self.ser.stopbits = 1


    def send_command_only( self, device, command):
        
        def xorstr( s):
            result = 0
            for c in s:
                result = result ^ ord( c)
            return result

        if self.ser.inWaiting() != 0:
            print "ERROR: obsolete buffer content:", self.ser.readline().strip() 
        self.ser.flushInput()
        cmdstr = "%i:%s!" % ( device, command)
        self.ser.write( "%s$%02x\r" % ( cmdstr, xorstr( cmdstr)))
        #print( "%s$%02x" % ( cmdstr, xorstr( cmdstr)))
        return cmdstr


    def send_command( self, device, command):

        while True:
            scmd = self.send_command_only( device, command)
            # wait for result
            while self.ser.inWaiting() == 0:
                None
            answer = self.ser.readline().strip()
            resdev = re.search( r"#(.*?):", answer)
            if resdev != None:
                resdev = resdev.group( 1)
            rescode = re.search( r"\[(.*?)\]", answer)
            if rescode != None:
                rescode = rescode.group( 1)

            if rescode == "OK":
                return
            
            print "ERROR: command (%s) answer: %s (device: %s, code %s)" % ( scmd, answer, resdev, rescode)


    def send_command_result( self, device, command):
        while True:
            cmdstr = self.send_command_only( device, command)
            while self.ser.inWaiting() == 0:
                None
            result = self.ser.readline().strip()
            if result.find( "7 [CHKSUM]") == -1:
                if result == cmdstr:
                    return None
                return result


    def read_value( self, device, commnad):
        result = None
        while result == None:
            value = self.send_command_result( device, commnad)
            #print "command %s   result %s" % ( commnad, value)
            result = re.search( r"=(.*?)$", value)
        return float( result.group( 1).strip())



    def get_device_type( self, value):
        result = re.search( r"\[(.*?)\s", value)
        if result != None:
            return result.group( 1).strip()
        return result

    def get_device_options( self, value):
        result = re.search( r"\[.*;(.*?)\]", value)
        if result != None:
            return result.group( 1).strip()
        return result
        

    def check_devices( self, verbose = True):

        if verbose:
            print "Scan for devices:"
        for index in range( 8):
            result = self.send_command_result( index, "idn?")
            if result != None:
                devicetype = self.get_device_type( result)
                if verbose:
                    print "Index %d: Device: %3s" % ( index, devicetype),
                options = self.get_device_options( result)
                if verbose:
                    if options != None:
                        print "    Options: %s" % options
                    else:
                        print

                # search for device indices
                if ( devicetype == "ADA") and ( self.ada < 0):
                    self.ada = index
                if ( devicetype == "DCG") and ( self.dcg < 0):
                    self.dcg = index
                if ( devicetype == "DDS") and ( self.dds < 0):
                    self.dds = index
                if ( devicetype == "EDL") and ( self.edl < 0):
                    self.edl = index



    def dcg_measure_power( self):
        return self.read_value( self.dcg, "msw?")

    def dcg_measure_voltage( self):
        return self.read_value( self.dcg, "msv?")

    def dcg_set_voltage( self, voltage):
        self.send_command( self.dcg, "dcv=%.3f" % voltage)
    
    
    def dcg_measure_current_ma( self):
        return self.read_value( self.dcg, "msa 1?")

    def dcg_set_current( self, current):
        self.send_command( self.dcg, "dca=%.3f" % ( current))

    def dcg_set_current_ma( self, current):
        self.send_command( self.dcg, "dca 1=%.3f" % ( current))



    def dds_set_frequency( self, frequency):
        self.send_command( self.dds, "frq=%.1f" % frequency)

    def dds_set_amplitude( self, amplitude):
        self.send_command( self.dds, "lvl=%.1f" % amplitude)


    def ada_set_da_voltage( self, pin, voltage):
        self.send_command( self.ada, "val%d=%.4f" % ( 20 + pin, frequency))

    def ada_measure_adcint( self, pin):
        return self.read_value( self.ada, "val %d?" % ( 0 + pin))
    
    def ada_measure_adc( self, pin):
        return self.read_value( self.ada, "val %d?" % ( 10 + pin))

    def ada_set_direction( self, port, value):
        self.send_command( self.ada, "dir%d=%d" % ( port, value))

    def ada_set_port( self, port, value):
        self.send_command( self.ada, "pio%d=%d" % ( port, value))
    
    def ada_get_port( self, port):
        return int( self.read_value( self.ada, "pio %d?" % port))

Code: Alles auswählen

#! /usr/bin/env python
# graycode.py

def bin(s):
    return str(s) if s<=1 else bin(s>>1) + str(s&1)

import math
def log2(x):
    """ Return log base 2 of x. """ 
    #return math.log(x) / math.log(2)
    return int( math.log( x, 2))

""" http://www.barricane.com/python-grey-code-algorithm """
def gray(i): 
    """ This function returns the i'th Gray Code. It is recursive and operates in O(log n) time. """ 
    if i == 0: 
        return 0 
    if i == 1: 
        return 1

    ln2 = int(log2(i))
    # the grey code of index i is the same as the gray code of an index an 
    # equal distance on the other side of ln2-0.5, but with bit ln2 set
    pivot = 2**(ln2) - 0.5 # TODO: double everything so that we use no floats
    delta = i - pivot
    mirror = int(pivot - delta)
    x = gray(mirror)    # get the grey code of the 'mirror' value
    x = x + 2**(ln2)    # set the high bit
    return x

def main():
    for i in range( 256):
        print i, bin( 256 + gray( i))[1:]

if __name__ == "__main__":
    main()

Code: Alles auswählen

#! /usr/bin/env python
# digitaltester.py

serialport = '/dev/ttyUSB0'

import ctlab
import graycode
import sys


############################################################
## helper stuff
## progress bar
############################################################

## found here:
# http://stackoverflow.com/questions/3160699/python-progress-bar/15860757#15860757

# update_progress() : Displays or updates a console progress bar
## Accepts a float between 0 and 1. Any int will be converted to a float.
## A value under 0 represents a 'halt'.
## A value at 1 or bigger represents 100%
def update_progress( progress, barLength = 10):
    #barLength = 10 # Modify this to change the length of the progress bar
    status = ""
    if isinstance(progress, int):
        progress = float(progress)
    if not isinstance(progress, float):
        progress = 0
        status = "error: progress var must be float\r\n"
    if progress < 0:
        progress = 0
        status = "Halt...\r\n"
    if progress >= 1:
        progress = 1
        status = "Done...\r\n"
    block = int(round(barLength*progress))
    text = "\r[{0}] {1}% {2}".format( "#"*block + "-"*(barLength-block), "%2.0f" % (progress*100), status)
    sys.stdout.write(text)
    sys.stdout.flush()


############################################################
## helper stuff
## functions for bit testing
############################################################

# testBit() returns a nonzero result, 2**offset, if the bit at 'offset' is one.
def testBit(int_type, offset):
    mask = 1 << offset
    return(int_type & mask)

def testBit01(int_type, offset):
    if testBit(int_type, offset) == 0:
        return 0
    return 1


############################################################
## helper stuff
## bit manipulation stuff
############################################################

# setBit() returns an integer with the bit at 'offset' set to 1.
def setBit(int_type, offset):
    mask = 1 << offset
    return(int_type | mask)

# clearBit() returns an integer with the bit at 'offset' cleared.
def clearBit(int_type, offset):
    mask = ~(1 << offset)
    return(int_type & mask)

# toggleBit() returns an integer with the bit at 'offset' inverted, 0 -> 1 and 1 -> 0.
def toggleBit(int_type, offset):
    mask = 1 << offset
    return(int_type ^ mask)

def xor( a, b):
    return (a and not b) or (not a and b)



############################################################
## helper stuff
## list manipulation
############################################################

def deldoub1(liste):
    res = []
    tmp = []
    for item in liste:
        if not item[0] in tmp:
            tmp.append(item[0])
            res.append(item)
    return res



############################################################
##  main stuff
############################################################

class digitaltester( object):

    def __init__( self, serialport, verbose = True):
        self.lab = ctlab.ctlab( serialport)
        self.lab.check_devices( verbose)

        if self.lab.dcg == None:
            print "Error: missing DCG"
            raise StandardError

        if self.lab.ada == None:
            print "Error: missing ADA"
            raise StandardError
        
        # 100 mV
        self.tolerance = 0.1
       
        self.inputs = []
        self.outputs = []

        
        # switch power on
        self.lab.dcg_set_voltage( 5.0)
        self.lab.dcg_set_current_ma( 50)

        # init digital ports
        self.set_all_pin_voltage_none()


    def set_all_pin_voltage_none( self):
        self.port2 = 0
        self.port3 = 0
        self.dir2 = 0
        self.dir3 = 0
        self.update_pins()


    def check_number_of_pins( self):
        if self.test_pin( 7) == 'GND':
            self.pinrange = range( 1, 7) + range( 10, 16)
            self.pins = 14
        else:
            self.pinrange = range( 1, 8) + range( 9, 16)
            self.pins = 16
        return self.pins

    def correct_pin_number( self, pin):
        # only for 14 pin devices
        if ( self.pins == 14) and ( pin > 7):
            return pin - 2
        else:
            return pin


    def set_pin_voltage( self, pin, value):
        
        if value == None:
            if ( pin >= 1) and ( pin <= 7):
                self.dir2  = clearBit( self.dir2,  pin - 1) 
            if ( pin >= 9) and ( pin <= 15):
                self.dir3  = clearBit( self.dir3,  pin - 9) 
        elif value == 0:
            if ( pin >= 1) and ( pin <= 7):
                self.dir2  = setBit(   self.dir2,  pin - 1) 
                self.port2 = clearBit( self.port2, pin - 1) 
            if ( pin >= 9) and ( pin <= 15):
                self.dir3  = setBit(   self.dir3,  pin - 9) 
                self.port3 = clearBit( self.port3, pin - 9)

        else:
            if ( pin >= 1) and ( pin <= 7):
                self.dir2  = setBit( self.dir2,  pin - 1) 
                self.port2 = setBit( self.port2, pin - 1) 
            if ( pin >= 9) and ( pin <= 15):
                self.dir3  = setBit( self.dir3,  pin - 9) 
                self.port3 = setBit( self.port3, pin - 9)


    def update_pins( self):
            self.lab.ada_set_direction( 2, self.dir2)
            self.lab.ada_set_direction( 3, self.dir3)
            self.lab.ada_set_port(      2, self.port2)
            self.lab.ada_set_port(      3, self.port3)


    def get_pin_voltage( self, pin):
        if ( pin >= 1) and ( pin <= 6):
            return self.lab.ada_measure_adcint( 1 + pin)
        if pin == 7:
            return self.lab.ada_measure_adc( 7)
        if pin == 8:
            return 0.0
        if (pin >= 9) and ( pin <= 15):
            return self.lab.ada_measure_adc( pin - 9)
        if pin == 16:
            return self.lab.dcg_measure_voltage()


    def get_pin_voltage_digital( self, pin):
        if ( pin >= 1) and ( pin <= 7):
            return testBit01( self.port2_in, pin - 1)
        if pin == 8:
            return 0
        if (pin >= 9) and ( pin <= 15):
            return testBit01( self.port3_in,  pin - 9)
        if pin == 16:
            return 1


    def read_pin_pattern( self):
        result = ""
        for pin in self.pinrange:
            result += self.voltage_to_digital( self.get_pin_voltage( pin), self.tolerance)
        return result


    def voltage_to_digital( self, voltage, tolerance):
        if ( voltage >= -tolerance) and ( voltage <= tolerance):
            return '0'
        elif ( voltage >= 5 - tolerance) and ( voltage <= 5 + tolerance):
            return '1'
        else:
            return 'X'
        return result


    def selftest( self):
        expected_pin_pattern = "10000000000000"
        error_count = 0
        for pin in range( 1, 8) + range( 9, 16):
            # show activity in display
            if pin == 1:
                self.lab.send_command( self.lab.ada, "DSP=32")
            if pin == 9:
                self.lab.send_command( self.lab.ada, "DSP=33")
            print "Testing pin %2d" % ( pin, self.correct_pin_number( pin)), 

            self.set_pin_voltage( pin, 1)
            self.update_pins()
            pattern = self.read_pin_pattern()
            if pattern != expected_pin_pattern:
                error_count += 1
            print pattern, ( pattern == expected_pin_pattern)
            self.set_pin_voltage( pin, 0)
            self.update_pins()
            # 'rotate' pattern
            expected_pin_pattern = expected_pin_pattern[-1:] + expected_pin_pattern[:-1]
        return error_count


    def check_pin_directions( self):

        def current_ma( set_voltage, voltage):
            return ( set_voltage - voltage)

        self.set_all_pin_voltage_none()
        #print "Pinrange: ", self.pinrange
        
        for pin in self.pinrange:
        
            # show activity in display
            if pin == 1:
                self.lab.send_command( self.lab.ada, "DSP=32")
            if pin == 9:
                self.lab.send_command( self.lab.ada, "DSP=33")

            print "Testing pin %2d" % ( self.correct_pin_number( pin)), 
            self.set_pin_voltage( pin, 0)
            self.update_pins()
            low   = self.get_pin_voltage( pin)

            self.set_pin_voltage( pin, 1)
            self.update_pins()
            high  = self.get_pin_voltage( pin)
            
            self.set_pin_voltage( pin, None)
            self.update_pins()
            highZ = self.get_pin_voltage( pin)
            
            dir = self.guess_pin_direction( low, high, highZ)
            print "  low: %.2f V  hi: %.2f V  hiZ: %.2f V" % ( low, high, highZ),
            #print "  I_low: %.2f mA  I_hi: %-.2f mA  " % ( current_ma( 0.0, low), current_ma( highZ, high)),
            print "  --> direction: %s" % dir
            if dir == 'Input':
                self.inputs.append( pin) 
            if dir == 'Output':
                self.outputs.append( pin) 
        
        self.set_all_pin_voltage_none()
            
            
    def test_pin( self, pin):
        self.set_pin_voltage( pin, 0)
        self.update_pins()
        
        low   = self.get_pin_voltage( pin)
        self.set_pin_voltage( pin, 1)
        self.update_pins()

        high  = self.get_pin_voltage( pin)
        self.set_pin_voltage( pin, None)
        self.update_pins()
        
        highZ = self.get_pin_voltage( pin)
        return self.guess_pin_direction( low, high, highZ)


    def guess_pin_direction( self, low, high, highZ):
        tolerance = 2.0 # V 
        if ( low < 0.01) and ( high < 0.01) and ( highZ < 0.01):
            return "GND"
        elif ( low < tolerance) and ( high < 5 - tolerance):
            return "Output"
        elif ( low > tolerance) and ( high > 5 - tolerance):
            return "Output"
        elif ( low < tolerance) and ( high > 5 - tolerance):
            return "Input"
        else:
            return "Unknown"


    def check_logic( self):
        mapping = []
        count   = 2**len( self.inputs)
        print "check %d logic combinations" % count

        oldinputs = graycode.gray( count - 1)
        self.set_inputs( oldinputs)
        oldoutput = self.read_outputs_digital()
        
        for index in range( count):
            update_progress( 1.0 * index / count, barLength = 80)
            inputs = graycode.gray( index)
            self.set_inputs( inputs)
            output = self.read_outputs_digital()
            #print "get out ", bin( output)

            outdiff = output ^ oldoutput
            if outdiff > 0:
                inpin  = graycode.log2( inputs ^ oldinputs)
                outpin = graycode.log2( outdiff) 
                #pin = { "in" : inpin, "out": outpin}
                pin = [ inpin, outpin]
                if mapping.count( pin) == 0:
                    mapping.append( pin)

            oldinputs = inputs
            oldoutput = output

        update_progress( 1.0, barLength = 80)

        # sort mapping
        #mapping.sort()
        # uniq mapping
        #print "einfach"
        #print deldoub1( mapping)

        # replace 'virtual pins' by real pin numbers
        self.pinmap = []
        for element in mapping:
            self.pinmap.append([ self.inputs[ element[ 0]], self.outputs[ element[ 1]]])
        
        self.equations = []
        for o in self.outputs:
            equation = [ [el[ 0] for el in self.pinmap if el[ 1] == o], o]
            self.equations.append( equation)

        return self.equations


    # input: list with to elements
    #    element 0: list of input pins
    #    element 1: output pin
    def check_equation( self, equation):
        count   = 2**len( equation[ 0])

        shift = 0
        result = ''
        for index in range( count):
            for pin in equation[ 0]:
                self.set_pin_voltage( pin, testBit01( index, equation[ 0].index( pin)))
            self.update_pins()
            result += self.voltage_to_digital( self.get_pin_voltage( equation[ 1]), tolerance = 2)
            shift  += 1

        return result



    def set_inputs( self, value):
        index = 0
        for pin in self.inputs:
            self.set_pin_voltage( pin, testBit01( value, index))
            index += 1
        self.update_pins()


    def read_outputs( self):
        for index in self.outputs:
            print self.voltage_to_digital( self.get_pin_voltage( index), tolerance = 1.2), 
        print



    def read_outputs_digital( self):
        self.port2_in = self.lab.ada_get_port( 2)
        self.port3_in = self.lab.ada_get_port( 3)
        #print bin( self.port2_in), bin( self.port3_in),
        shift = 0
        result = 0
        for index in self.outputs:
            result += self.get_pin_voltage_digital( index) << shift
            shift  += 1
        return result


    def cleanup( self):
        self.set_all_pin_voltage_none()
        
        
        # switch (nearly) off
        self.lab.dcg_set_voltage( 0.1)
        self.lab.dcg_set_current_ma( 1)
    

    def logic_table_name( self, value):
        # no input
        if value == "0":
            return "logic low"
        if value == "1":
            return "logic high"

        # one input
        if value == "00":
            return "logic low"
        if value == "01":
            return "EQUAL"
        if value == "10":
            return "NOT"
        if value == "11":
            return "logic high"

        # two inputs
        if value == "0000":
            return "logic low"
        if value == "0001":
            return "AND"
        if value == "0110":
            return "XOR"
        if value == "0111":
            return "OR"
        if value == "1000":
            return "NOR"
        if value == "1001":
            return "XNOR"
        if value == "1110":
            return "NAND"
        if value == "1111":
            return "logic high"
        else:
            return "unknown"




def main():

    print "Initialisation:",
    digitest = digitaltester( serialport, verbose = False)

    # check configuration
    if digitest.lab.ada == None:
        print "missing ADA module"
        exit()
    if digitest.lab.dcg == None:
        print "missing DCG module"
        exit()
    print "ok"

    # make sure no DUT is connected
    #print "Selftest"
    #digitest.selftest()

    print "Power: ",
    voltage = digitest.lab.dcg_measure_voltage()
    current = digitest.lab.dcg_measure_current_ma()
    power   = digitest.lab.dcg_measure_power()
    print "U (%.2f V) * "  %  voltage,
    print "I (%.2f mA) = " %  current,
    print "P (%.1f mW)"  %  ( power * 1000)
    if ( power > 0.200) or ( voltage < 4.5):
        digitest.cleanup()
        print "power consumtion too high!"
        exit()


    try:
        # check number of pins
        # also set correct ranges
        print "%d-pin device" % digitest.check_number_of_pins()


        print "check DUT pin directions" 
        digitest.check_pin_directions()
        print "%d input  pins: %s" % ( len( digitest.inputs),  map( digitest.correct_pin_number, digitest.inputs))
        print "%d output pins: %s" % ( len( digitest.outputs), map( digitest.correct_pin_number, digitest.outputs))

        if len( digitest.inputs) == 0:
            print "error: no input pins found"
            raise StandardError
        if len( digitest.outputs) == 0:
            print "error: no output pins found"
            raise StandardError
        #( digitest.inputs, digitest.outputs ) = ( digitest.outputs, digitest.inputs)

        equations = digitest.check_logic()

        print "found following equations:"
        for equation in equations: 
            check = digitest.check_equation( equation)
            print "input(s): %25s, output: %2d --> %s (%s)" % ( map( digitest.correct_pin_number, equation[0]), digitest.correct_pin_number( equation[ 1]), check, digitest.logic_table_name( check))

        power_per_gate = power * 1000 / len( digitest.outputs)
        print "Power per gate: P_gate = %.1f mW" % power_per_gate

        print "guess Technology :",
        if power_per_gate < 0.5:
            print "CMOS"
        elif power_per_gate < 5:
            print "Low Power TTL"
        elif power_per_gate < 20:
            print "TTL"
        else:
            print "High Speed TTL"

    
    except KeyboardInterrupt, StandardError:
        None
    #except IndexError:
    #    print "program error"


    print "Cleanup"
    digitest.cleanup()
    
    print "Done"


main()

psclab38
kann c't-Lab-Konstrukteure konstruieren
kann c't-Lab-Konstrukteure konstruieren
Beiträge: 879
Registriert: 25.01.2008, 23:34

Re: Digitaltester

Beitrag von psclab38 » 20.06.2014, 18:31

Hallo Bart,

bin echt beeindruckt!
Vielleicht sollte man dazusagen, daß man zu python auch pyserial dazuinstallieren muß...

Du verwendest scheinbar die Pascal-Firmware-Versionen. Mit den C-Firmwaren gibt es insofern ein Problem, weil die Meldungen dazu ein wenig anders aussehen.
Initialisation: Scan for devices:
Index 0: Device: ADA-C Options: DA12 AD16 IO32 LCD
Index 1: Device: DDSp
Index 2: Device: DCG2d
Index 3: Device: DCG2d
Index 4: Device: None
Index 5: Device: FPGA-C
Index 6: Device: None
Index 7: Device: DIV
ok
Ich habe den Suchcode ein wenig angepaßt. (ich hoffe, das ist einigermaßen richtig, weil ich von python keine Ahnung habe)
statt in "ctlab.py"

Code: Alles auswählen

                # search for device indices
                if ( devicetype == "ADA") and ( self.ada < 0):
                    self.ada = index
                if ( devicetype == "DCG") and ( self.dcg < 0):
                    self.dcg = index
                if ( devicetype == "DDS") and ( self.dds < 0):
                    self.dds = index
                if ( devicetype == "EDL") and ( self.edl < 0):
                    self.edl = index

Code: Alles auswählen

                if devicetype != None:
                    # search for device indices
                    if ( devicetype[:3] == "ADA") and ( self.ada < 0):
                        self.ada = index
                    if ( devicetype[:3] == "DCG") and ( self.dcg < 0):
                        self.dcg = index
                    if ( devicetype[:3] == "DDS") and ( self.dds < 0):
                        self.dds = index
                    if ( devicetype[:3] == "EDL") and ( self.edl < 0):
                        self.edl = index
Da werden dann nur die jeweils wichtigen Buchstaben geprüft, wenn das Feld nicht leer (None) ist.

Ein wenig später schmiert die Sache dann aber ab, war ja auch nichts angeschlossen:
Power: U (5.00 V) * I (0.02 mA) = P (0.1 mW)
14-pin device
check DUT pin directions
Testing pin 1 low: 0.00 V hi: 0.00 V hiZ: 0.00 V --> direction: GND
Testing pin 2 low: 0.00 V hi: 0.00 V hiZ: 0.00 V --> direction: GND
Testing pin 3 low: 0.00 V hi: 0.00 V hiZ: 0.00 V --> direction: GND
Testing pin 4 low: 0.00 V hi: 0.00 V hiZ: 0.00 V --> direction: GND
Testing pin 5 low: 0.00 V hi: 0.00 V hiZ: 0.00 V --> direction: GND
Testing pin 6 low: 0.00 V hi: 0.00 V hiZ: 0.00 V --> direction: GND
Testing pin 8 low: -0.71 V hi: -0.71 V hiZ: -0.71 V --> direction: GND
Testing pin 9 low: -0.69 V hi: -0.68 V hiZ: -0.66 V --> direction: GND
Testing pin 10 low: -0.72 V hi: -0.71 V hiZ: -0.72 V --> direction: GND
Testing pin 11 low: -0.68 V hi: -0.74 V hiZ: -0.74 V --> direction: GND
Testing pin 12 low: -0.71 V hi: -0.71 V hiZ: -0.71 V --> direction: GND
Testing pin 13 low: -0.66 V hi: -0.66 V hiZ: -0.65 V --> direction: GND
0 input pins: []
0 output pins: []
error: no input pins found
Traceback (most recent call last):
File "F:\component\digitaltester.py", line 554, in <module>
main()
File "F:\component\digitaltester.py", line 515, in main
raise StandardError
UnboundLocalError: local variable 'StandardError' referenced before assignment
Wenn Du im Forum Code anhängst, dann am Besten als Zip. Das ist deutlich praktischer...

Viele Grüße
Paul

Antworten