Archive for the ‘Circuits’ Category

Chronovu USB LA-8 Logic Analyzer

Friday, August 13th, 2010 by lane

I am a fan of reducing cost and complexity of test equipment by pushing the UI to the PC to make the test equipment headless. In this vein, however, I was previously disappointed in the purchase an ELAN USB oscilloscope. It claimed Linux support, but after much hoop jumping, I never got their java app working on linux. I ended up running it in a virtual machine running windows, and even then the experience was not great. That is story for another post, though. For this post I am going to provide my initial feedback on the ChronoVu USB Logic Analyzer LA-8 that I purchased on Ebay for $189.00.

The primary reasons I picked the ChronoVu amongst the other several options (see Comments at this link from SparkFun.com for additional competitive products) was that it sampled at 100MHz and the app ran on Linux without java. I downloaded the app prior to purchasing to give it a test run and noticed that it used QT for widgets, so I was happy that the performance had a chance at being adequate on Linux.

Amazingly, the setup on Linux (or at least Fedora 13) was quite seemless. I am used to futzing with everything from udev rules to 64b/32b issues to compiling kernel modules to etc. when using these sort of fringe products that claim Linux support, but everything worked out of the box on my Fedora 13 Linux install. The lsusb output is shown at the end of this post for those interested. It basically enumerates as a serial device and on my Fedora 13 machine, it appears on device node ‘/dev/ttyUSBX’ with correct permissions so that I can use it without root access (in other words, udev rules exist and work without issue). The application seems to detect and find the correct ttyUSB devnode to use, so I am not sure how it would behave with multiple units plugged in, but I do have other usb-serial devs on ttyUSB nodes and it has never been confused or had issues with that. That was a refreshing experience that shows they are serious about linux and not just releasing crippled linux support for marketing reasons.

My initial experience was to debug an I2C problem I was having. I flipped into a precanned I2C setup on the application, hooked up my probes, and pressed play. It asked for a file to save the data to (which I now find a bit annoying). It then downloaded and processed the data. That takes more time than I would like, but the precanned I2C bus analysis worked well and performed a deserialization of the data correctly. All that worked without any issue. Kudos to ChronoVu. It was a better experience than I was expecting based on my previous experience with a piece of USB test equipment.

While the initial experience was positive, after using it, there are several user interface issues that still keep this device in a class below dedicated logic analyzers. The sad thing is that these are primarily software issues. I hope ChronoVu takes notice because if these are addressed, then it will be a happy day for me when I can replace a many tens of thousand dollar machine that is the size of a desktop PC and requires its own cart with a sub $200 pocket sized piece of equipment. They have already taken a major step to that end, but it is not quite there (yet).

User Interface Issues

  • You cannot setup triggering options beyond the simple state==0 or state==1. This makes it hard to sync to events of interest. This is my biggest complaint. Makes it hard to do more than just simple debugging.
  • The zoom level resets after every acquisition. Quite a pain given that events of interest can take a while to find again. This issue is also related to the lack of complex triggering options given that even if the view didn’t reset, I will still have to scroll around to find my event.
  • The UI is sluggish to zoom and pan. This is annoying and further exacerbates the view reseting issue previously mentioned. This is my second biggest complaint.
  • You cannot zoom in indefinitely, and even worse, you cannot zoom in adequately to see even 25ns clocks. This is quite annoying. I sampled a 25MHz clock at 100MHz and would like to see the clock up close. I realize that there will be some frequency beating between the 25MHz clock and 100MHz sampling rate, and I can live with that, but I still want to be able to zoom in and put some cursors down at the clock transition edges and make sure my clock is running as I expect. Instead I can only zoom in close enough to see a very high frequency signal, but nothing sufficient for what I want.
  • It asks to save a file everytime you press play to capture some data. 90% of the time I am taking setup data and I want it as quickly as possible. For the 10% of the time I take data I care about (after I have it setup and framed the way I want), then it would be nice to click a “Save As” button and save the raw data somewhere. Otherwise, I would prefer it save to a temp file that I don’t have to manage or know about. I would rather click to save the data permanently after I know the data is what I want. Don’t bother me a priori with a popup box.
  • Download and process time take too long. I count around 12 Mississippi’s (seconds). This is not a show a stopper, but annoying. They must not be using USB 2.0 high speed. I am not familiar with the Future Technologies USB-Serial chip they are using, but they would be well served by going with a chipset that supported high speed option as this would make it around 10 times faster and much more bearable.
  • This one is a nit-pick, but the application installer creates a new root menu in the GNOME “Applications” menu list. Perhaps it should install in the FEL “Electronics” menu or “Other”.
  • I don’t need a CD or a carrying case and would prefer not to pay for them.

Hardware Issues

  • There is crosstalk issue. I plugged in a low frequency signals into channel 0 (FV) and channel 1 (LV) and a 50MHz clock into channel 2 (CLK). The clock beats as expected against the 100MHz sampling rate, but it corrupts channel 0 and channel 1 as you can see in this screen shot.

    Disconnecting channel 2 probe from the clock and connecting it to ground solves the problem. The following is screen shot shows what channel 0 and channel 1 should look like in the previous capture.
  • If I had to guess, there is a significant inductance on the ground connection between the units and the ground bounce induced by the high frequency clock is causing this problem. It is hard to blame this one on them without some more futzing, so for now, I will only hook up to the clock when I slow everything down to debug.

    lsusb -v -s 001:080 output

    Bus 001 Device 080: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC
    Device Descriptor:
      bLength                18
      bDescriptorType         1
      bcdUSB               2.00
      bDeviceClass            0 (Defined at Interface level)
      bDeviceSubClass         0
      bDeviceProtocol         0
      bMaxPacketSize0         8
      idVendor           0x0403 Future Technology Devices International, Ltd
      idProduct          0x6001 FT232 USB-Serial (UART) IC
      bcdDevice            6.00
      iManufacturer           1 ChronoVu
      iProduct                2 ChronoVu LA8
      iSerial                 3 CV100528120813
      bNumConfigurations      1
      Configuration Descriptor:
        bLength                 9
        bDescriptorType         2
        wTotalLength           32
        bNumInterfaces          1
        bConfigurationValue     1
        iConfiguration          0
        bmAttributes         0x80
          (Bus Powered)
        MaxPower              200mA
        Interface Descriptor:
          bLength                 9
          bDescriptorType         4
          bInterfaceNumber        0
          bAlternateSetting       0
          bNumEndpoints           2
          bInterfaceClass       255 Vendor Specific Class
          bInterfaceSubClass    255 Vendor Specific Subclass
          bInterfaceProtocol    255 Vendor Specific Protocol
          iInterface              2 ChronoVu LA8
          Endpoint Descriptor:
            bLength                 7
            bDescriptorType         5
            bEndpointAddress     0x81  EP 1 IN
            bmAttributes            2
              Transfer Type            Bulk
              Synch Type               None
              Usage Type               Data
            wMaxPacketSize     0x0040  1x 64 bytes
            bInterval               0
          Endpoint Descriptor:
            bLength                 7
            bDescriptorType         5
            bEndpointAddress     0x02  EP 2 OUT
            bmAttributes            2
              Transfer Type            Bulk
              Synch Type               None
              Usage Type               Data
            wMaxPacketSize     0x0040  1x 64 bytes
            bInterval               0
    Device Status:     0x0000
      (Bus Powered)
    

    AC Transistor Noise Analysis in HSPICE

    Wednesday, February 18th, 2009 by lane

    Whenever I perform a noise analysis on a circuit, I like to verify the result with a simulation.  I have really enjoyed Eldo’s transient noise analysis in the past, but currently I only have access to HSPICE.  All the spice simulators have AC noise analysis features.  Here is a toy example that I use to verify basic functionality prior to getting more complicated. 

    Suppose you have a single NMOS transistor configured as follows where the drain is active loaded with an ideal current source and the gate is biased with an ideal voltage source.

    The goal here is to calculate the input referred noise of this amplifier and verify the result with an AC noise simulation in HSPICE. The HSPICE netlist I use to simulate with is:

    * HSPICE Netlist
    
    * Include models
    .lib '../../../pdk/hspicemm/cmn018_assp_v1d1.l' TT
    .lib '../../../pdk/hspicemm/cmn018_assp_v1d1.l' TT_3V
    .GLOBAL gnd!
    m0 vd vg gnd! gnd! nch3 w='0.42u' l='0.35u' nf=1 m=1 ad='0.2016p' as='0.2016p'
    + pd='1.38u' ps='1.38u' nrd=1.14286 nrs=1.14286 sa='0.48u' sb='0.48u' sd=0
    v4 vg gnd! dc=.9 ac=1
    i3 gnd! vd dc='3u'
    
    .options POST=1 parhier=local
    .TEMP 45
    
    .ac DEC 10 1000 100G
    .noise V(vd) V4
    .probe noise onoise onoise(m) onoise(db)
    .probe noise inoise inoise(m) inoise(db) 
    
    .probe GMO(M0)
    .probe GDSO(M0)
    .probe CDDBM(M0)
    .end
    

    Because the transistor models are proprietary to our manufacturer, I do not include them here. They are level=54 (BSIM 4) transistors, whose parameter descriptions can be found at this web address: http://www-device.eecs.berkeley.edu/~bsim3/bsim4_get.html. For the purposes of verifying these against hand calculations, I temporarily disabled flicker noise in the models by setting the NOIA, NOIB, NOIC parameters to 0. BSIM 4.0 models (see page 87-88 of BSIM manual) use a more complicated equation for thermal noise than the traditional thermal noise = 8/3kTgm equation appropriate for hand analysis, but as you will see, the hand analysis is pretty close.

    After running this simulation, I first look at the AC response and extract the gain and bandwidth from the gm, gds, and Cdd parameters that I probed in the simulation. As the plot below shows, calculating the gain as A=gm/gds and the single pole as tau=Cdd/gds gives a first order model that matches the simulated results quite well until the a zero from the Cgd hits above 10 GHz.

    From this first order model, I calculate the output referred noise spectral density as N=8/3kTgm/gds^2. This is then filtered by the same first order model (but without the gain) to produce a frequency response as shown below in green. The result from the HSPICE simulation matches to within 2dB. This discrepancy comes from the more complex noise model employed by HSPICE and BSIM 4. After integrating the PSD, spice reports the output noise as 18.2mV and I calculate 14.9mV. Not bad for a hand calculation. The input referred noise, on the other hand, is somewhat of a mystery to me. Rather than dividing by the DC gain of the circuit to input refer the noise, HSPICE divides the output PSD by the frequency response of the system, and the result is spice’s input referred noise becomes quite broadband—almost white (see red line in plot below). Integrating this to get the equivalent total input referred noise is useless. So I calculate the input referred noise by dividing the output RMS noise by the gain because the number reported by HSPICE for the input referred total noise is meaningless. Since the gain is 40 in this example, the input referred noise is 375uV.

    The code I wrote to generate these plots utilizes all open source software including Numerical Python and Matplotlib, which I highly recommend as an alternative to Matlab. I modified Mike Perrott’s HSPICE Matlab Toolbox code to read hspice sim data in as a numpy array. The code follows:

    from cad.sim import hspice, anal
    import pylab, numpy
    
    s,p = hspice.read("results/netlist.ac0")
    
    f=s["HERTZ"]
    gm = s["gmo(m0"][0]
    gds= s["gdso(m0"][0]
    C  = s["cddbm(m0"][0]
    
    A = gm/gds
    tau = C/gds
    F = 1/numpy.sqrt(1+(2*numpy.pi*f*tau)**2)
    H = A*F
    
    def dB(x):
        return 20*numpy.log10(numpy.abs(x))
    
    pylab.figure()
    pylab.semilogx(f, dB(s["vd"]), label="Simulation Result", lw=2)
    pylab.semilogx(f, dB(H), label="First Order Model", lw=2)
    pylab.grid(True)
    pylab.figtext(0.2,0.4,"A=%2.1f f=%2.1fMHz" % (A, 1/tau/2/numpy.pi/1e6), bbox=dict(edgecolor="k", facecolor="w"))
    pylab.xlabel("Frequency (Hz)")
    pylab.ylabel("Magnitude (dB)")
    pylab.title("Transfer function from 'vg' to 'vd'")
    pylab.legend(loc=3)
    pylab.savefig("transfer.png")
    
    kT = 1.38e-23 * 315; # Joules
    
    onoise = 8/3.* kT * gm / (gds**2)
    inoise = 8/3.* kT / gm
    nb = 1/4./tau
    
    sigma = numpy.sqrt(inoise * nb)
    
    pylab.figure()
    pylab.semilogx(f, s["onoise(db"], label="Simulated output noise (onoise)", lw=2)
    pylab.semilogx(f, dB(numpy.sqrt(onoise)*F), label="Hand calculated output noise", lw=2)
    pylab.semilogx(f, s["inoise(db"], label="Simulation input noise (inoise)", lw=2)
    pylab.grid(True)
    pylab.xlabel("Frequency (Hz)")
    pylab.ylabel("Noise (dB/sqrt(Hz))")
    pylab.title("Noise Power Spectral Density Plots")
    pylab.figtext(0.2,0.6,"""Spice Total Output Noise=18.2mV
    Hand Calculated Output Noise=%2.1fmV""" % (sigma*A*1e3,), bbox=dict(edgecolor="k", facecolor="w"))
    pylab.legend(loc=3)
    pylab.savefig("noise.png")
    

    Weak Inversion

    The previous example was for a transistor in strong inversion. When I change the operating to bias the above circuit in weak inversion, the spice generated output noise becomes= 27.6mV and my hand calculations now use the noise spectral density equation that 4*gamma*kT*gm where gamma=n/2 and where n is the subthreshold slope ideality factor. Using a ideality factor of 2, my hand calculations give the output referred noise as 26.5mV, which is within 4% of the spice result.

    Safe or Glitch-Free Clock Gating

    Sunday, August 10th, 2008 by lane

    Following is an example of a way to perform glitch-free clock gating. The clock is stalled in the high state one clock cycle after gate is asserted high. It is safe as long as the delay through the register is less than a half clock cycle.


    Gray Coding

    Friday, July 25th, 2008 by lane

    The schematic for gray coding and back to binary is shown in the figure below.

    Below are two verilog functions to implement this logic. They are made functions for ease of instancing.

       function [ADDR_WIDTH-1:0] bin2gray;
          input [ADDR_WIDTH-1:0] x;
          begin
             bin2gray = x ^ (x>>1);
          end
       endfunction
    
       function [ADDR_WIDTH-1:0] gray2bin;
          input [ADDR_WIDTH-1:0] x;
          integer                i;
          begin
             gray2bin[ADDR_WIDTH-1] = x[ADDR_WIDTH-1];
             for(i=ADDR_WIDTH-2; i>=0; i=i-1) begin
                gray2bin[i] =  gray2bin[i+1] ^ x[i];
             end
          end
       endfunction
    

    Following is a simple module for testing these functions:

    module graytest
       (input clk,
        input resetn
        );
       parameter ADDR_WIDTH=3;
    
       reg [ADDR_WIDTH-1:0] count;
    
       wire [ADDR_WIDTH-1:0] gcount = bin2gray(count);
       wire [ADDR_WIDTH-1:0] bcount = gray2bin(gcount);
    
       always @ (posedge clk or negedge resetn) begin
          if(~resetn) begin
    	 count <= 0;
          end else begin
    	 $display("0b%b -> 0b%b -> 0b%b", count, gcount, bcount);
    	 count <= count + 1;
          end
       end
    
       function [ADDR_WIDTH-1:0] bin2gray;
          input [ADDR_WIDTH-1:0] x;
          begin
             bin2gray = x ^ (x>>1);
          end
       endfunction
    
       function [ADDR_WIDTH-1:0] gray2bin;
          input [ADDR_WIDTH-1:0] x;
          integer                i;
          begin
             gray2bin[ADDR_WIDTH-1] = x[ADDR_WIDTH-1];
             for(i=ADDR_WIDTH-2; i>=0; i=i-1) begin
                gray2bin[i] =  gray2bin[i+1] ^ x[i];
             end
          end
       endfunction
    endmodule
    

    When I run this simulation (using verilator), I get the following output:

    0b000 -> 0b000 -> 0b000
    0b001 -> 0b001 -> 0b001
    0b010 -> 0b011 -> 0b010
    0b011 -> 0b010 -> 0b011
    0b100 -> 0b110 -> 0b100
    0b101 -> 0b111 -> 0b101
    0b110 -> 0b101 -> 0b110
    0b111 -> 0b100 -> 0b111
    

    The left-most column is a 3 bit number from a binary counter. The middle column is the gray encoded value of this counter, and the right column is the gray2bin output. This verifies that it works. Here is a picture of the simulation results: