Archive

Archive for September, 2015

Velleman PCSU1000 teardown and review

September 29th, 2015

I purchased Velleman PCSU1000 at "Electronics For You" shop when I had a sudden need resulted from the death of my 100 MHz Tektronix Oscilloscope. That was few years ago and the scope has been useful for debug of many of my digital problems. The scope is priced decent at $277 at amazon , and I think I purchased it for $300.

The Oscilloscope hooks to your computer on USB Port and you need to run a software to start acquiring the waveforms. It is advertised as a 60 MHz scope - but what is the reality ? Today, I took apart the scope to find the details.

Velleman_PCSU1000_compressed

A/D Converter ADC08L060

The ADC08L060 is an 8-bit 60 Mega Samples/sec A/D Converter from Texas Instruments and the scope uses two of these for each of these two channels. Now Velleman advertises its bandwidth as DC to 60 MHz +/3 dB. Even if we assume that the bandwidth of its front and is 60 Hz, can we accurately generate 60 MHz waveform by capturing at 60 Mega Samples per seconds ? Obviously not. So the first thing you need to keep in mind is that it is NOT and high frequency analog Oscilloscope. Yes - it may be ok to capture Digital 1 and 0 at high bit rate. That being said, I have used this scope to debug my analog sections of production boards ( like Microphone Audio etc). But I will not rely upon it for measurement of my power supply noise and Microphone noice etc.

ADC08L060

Xilinx Spartan XC3S50

When I looked at Spartan XC3S50 I remembered the P. Chug's FPGA Prototyping By Verilog Examples . It has the Spartan 3 FPGA - and is not even a BGA. A 50 MHz Oscillator clock the FPGA, but what surprised me was absence of any Memory hooked with the FPGA. Obviously, you can not sample faster without missing the data in the FIFO bus to USB transmission path.

Xilinx-Spartan-XC3S50

FTD FT245BL

The communication on the USB is through the FT245BL chip ( look at the top left in the picture above). It basically transfers the data from and to USB using 8 bit wide data bus.

PIC16F630

The FPGA sees to load its code through the PIC Microcontroller. But the Microcontroller could also be doing some other things in addition to loading and configuring the FPGA. Most designs have a dedicated Flash for this purpose.

PIC-microcontroller

In addition, there are a bunch of OP AMPs at the front end, some reed relays ( there are 7 of them for each channel), few buffers and of course power supply regulators. In overall, it is not bad design, considering that they have been able to come up with something that a hobby designer can use for his projects. But any serious scope ( even for 60 MHz), you will need faster A/D, and FPGA that has integrated memory - to make it useful. This is where the Sigilent's Entry level oscilloscopes come in picture .

By

Vikas Shukla

Uncategorized

Parts used in Siglent 1000 Series Oscilloscopes

September 28th, 2015

The Siglent 1000 series offer one of the best price performance and we have no hesitation to recommend it to any one looking for decent oscilloscopes at reasonable price. It comes is DL, CNL, CML CFL and X Series. The entry Level DL Series has sampling rate of 500 Mega Samples/sec that increases to 1 GSamples/ Second for CNL and CML Series and to 2 GS/sec for CFL Series. The CML Series has higher memory depth of 2 Million points. The X Series is an entirely new design and offer significantly higher memory depth.

Let us look at the different part numbers and corresponding features

Table : Siglent 1000 Series Oscilloscopes

Part Number Bandwidth Sampling rate Memory Depth
SDS1022DL 20 MHz 500 Mega Samples/sec 24K points
SDS1052DL 50 MHz 500 Mega Samples/sec 24K points
SDS1102DL 100 MHz 500 Mega Samples/sec 24K points
SDS1202DL 200 MHz 500 Mega Samples/sec 24K points
SDS1202CNL 200 MHz 2 Gs/sec ( 1 ch) 18K points
SDS1102CNL 100 MHz 1 Gs/sec 40K points
SDS1072CNL 70 MHz 1 Gs/sec 40K points
SDS1152CML 150 MHz 1Gs/s 2M points
SDS1102CML 200 MHz 1 Gs/sec ( 1 ch) 2M points
SDS1072CML 70 MHz 1 Gs/sec 2M Points
SDS1302CFL 300 MHz 2 Gs/sec 24K points
SDS1202CFL 200 MHz 2 Gs/sec 24K points
SDS1102CFL 100 MHz 2 Gs/sec 24K points
SDS1072CFL 70 MHz 2 Gs/sec 24K points

Besides that it also has 4 Channel variations of SDL000CFL Series

Table : 4 Channel SDL1000CPL Series

Part Number Bandwidth Sampling rate Memory Depth
SDS1304CFL 300 MHz 2 Gs/sec 24K points
SDS1204CFL 200 MHz 2 Gs/sec 24K points
SDS1104CFL 100 MHz 2 Gs/sec 24K points
SDS1074CFL 70 MHz 2 Gs/sec 24K points

The 1000X Series increases the memory depth to 14M. The Suffix S in part numbers add Waveform generation function to these Oscilloscopes ( and yes - an extra $200).

Table : SDS1000X Series

Part Number Bandwidth Sampling rate Memory Depth
SDS1202X-S 200 MHz 1 Gs/sec 2M points
SDS1202X 200 MHz 1 Gs/sec 2M points
SDS1102X-S 100 MHz 1 Gs/sec 2M points
SDS1102X 100 MHz 1 Gs/sec 2M points

Let us take a look at some to the parts used in its design. The parts used are based upon the SDS1202X part which is 200 MHz part with 14M depth. The parts used should apply to all of the SD1000X series. The other series may have similar but slightly different design.

A/D COnverter HAD 1511

Hitttite HADCAD1511 is used for A/D conversion. It gives out 1 Gig Samples /second @ 8 bits.

A_D_Converter-HAD

Memory Hooked to acquisition FPGA

Micron's 64 Mb part MT41J64M16JT-15E:G is attached to the acquisition FPGA.

DDR3-RAM-D9MNJ

1. Processor Analog Devices ADSP-BF526

The Analog Devices Blakfin DSP processor ADSP-BF526 is used, likely for the waveform processing and math function and other similar stuffs. It also connects a USB port and Ethernet port.

ADSP-BF526

2. Memory attached to Processor

Micron 48LC32M16A2 is attached to the Analog Devices processor.

Memory-48LC32M16A2

2. Lattice FPGA LCMX0640C used for Display

A separate Lattice FPGA is used for Display.

Lattice-LCMX0640C

The full video of the tear apart is posted by EEVblog - view it here

Uncategorized

Parts used in Picoscope 5000 USB Oscilloscope

September 28th, 2015

Picoscope 5000 Series is a 200 MHz, 1 Giga Samples per second USB Oscilloscope at not so affordable price of $1805 ( for its highest end model 5244A in this series). Let us take a look at some key components used in the design.

A/D Converter

Arctic Silicon Devices ASD5020 has been used for the A/D Converter. It has 4 Channels, but you will need to use only one channel and 8 bit mode ( It allows 12 bit mode at reduced sampling rate) to get maximum sampling rate of 1000 Mega Samples per second.

ASD5020

It takes in the 4 differential data as its input and then gives the converted digital output on 4 SPI Bus. This can then be sampled by the FPGA for further processing.

ASD5020_block_diagram

Arctic Silicon Devices has been bought by Hittite Microwave Corporation and the new part has a similar part numbering under the banner of Hittite.

Update 12/06/2015

Hittite Microwave Corporation has in turn been acquired by Analog Devices and the new part number for this part is HMCAD1520TR ( Digikey shows its price at 93.4656 in quantity of 500).

FPGA

Xilinx Spartan 6, BGA part XC6SLX25 has been used for communication between the Cypress microcontroller and the A/D Converter.

xilinx

DDR3 SDRAM

The part marking shows D9PXV with Micron Logo( using Micron's part decoder ). It is 256 Mega bit or 32 Megabyte part. I think that I could be good idea to explore multi chip parts that are 512 Megabits or 64 Megabits. They do need extra chip select pins.

DDR3_RAM

Microcontroller

The Cypress CY7C68013A-SG part will sit between the FPGA and the USB interface.

CY7C68013A-SG

Signal Generator AD9744

Analog Devices AD9744 is used for signal generator.

AD9744

A video of this Oscilloscope is posted here.

Uncategorized

Verilog Code for counter increment on button press

September 25th, 2015

We will present an important verilog code that will form the basis of some more important verilog topics. We will discuss how a push button press can increment counter and display it on a 7 segment display.

This is how it looks like..

There are two inputs to the circuit - a button_in and a n_reset. On pressing button_in the counter increments by 1. On pressing n_reset the counter resets to 0.

If you wish to understand the code, we strongly recommend that you go though the following posts ( in that order)

1. Binary to 7 Segment Display

2. Implementation of Key Debounce
- The key debounce code will ensure that we have a stable input, otherwise, our counter will increment several times on pressing key once.

3. Level Change detection in Verilog
- We monitor the level change of the debounced output of the key.

If you understand the above three, it will be easy for you to follow the code below.


module  counterdisplay 
    (
input   clk, n_reset, button_in,        // inputs
output leda,
output ledb,
output ledc,
output ledd,
output lede,
output ledf,
output ledg

	 
    );
	 reg DB_out;
	  reg [3:0] counter;
     reg [6:0] seg_data;
	  reg [3:0] counter_reg;
    /*
    Parameter N defines the debounce time. Assuming 50 KHz clock,
    the debounce time is 2^(11-1)/ 50 KHz = 20 ms
     
    For 50 MHz clock increase value of N accordingly to 21.
     
    */
    parameter N = 11 ;      
 
    reg  [N-1 : 0]  delaycount_reg;                     
    reg  [N-1 : 0]  delaycount_next;
     
    reg DFF1, DFF2;                                 
    wire q_add;                                     
    wire q_reset;
 

 reg  delay_reg ; // Registers for detecting level change of DB_out
 wire level_out;
 
        always @ ( posedge clk or negedge n_reset )
        begin
            if(n_reset ==  0) // At reset initialize FF and counter 
                begin
                    DFF1 <= 1'b0;
                    DFF2 <= 1'b0;
					// For level change detection
					delay_reg  <=  1'b0;

                    delaycount_reg <= { N {1'b0} };
                end
            else
                begin
                    DFF1 <= button_in;
                    DFF2 <= DFF1;
                    delaycount_reg <= delaycount_next;
						
					
					
					delay_reg  <=  DB_out;// to detect level change
                end
        end
     
     
    assign q_reset = (DFF1  ^ DFF2); // Ex OR button_in on conecutive clocks
                                     // to detect level change 
                                      
    assign  q_add = ~(delaycount_reg[N-1]); // Check count using MSB of counter         
     
 
    always @ ( q_reset, q_add, delaycount_reg)
        begin
            case( {q_reset , q_add})
                2'b00 :
                        delaycount_next <= delaycount_reg;
                2'b01 :
                        delaycount_next <= delaycount_reg + 1;
                default :
                // In this case q_reset = 1 => change in level. Reset the counter 
                        delaycount_next <= { N {1'b0} };
            endcase    
        end
     
     
    always @ ( posedge clk )
        begin
            if(delaycount_reg[N-1] == 1'b1)
                    DB_out <= DFF2;
            else
                    DB_out <= DB_out;
        end
         
	
	assign  level_out  =  (delay_reg)  &  (~DB_out);	 
   
			 

	
	always @(posedge  clk )
	
	if ( n_reset == 0)
	counter <= 0;

	else if ( level_out == 1'b1)
	begin
	if (counter  < 9)
	counter <= counter +1;
	else counter <= 0;
	end
	

	
always @(counter)
case (counter)
4'b0000:seg_data=7'b1111110;
4'b0001:seg_data=7'b0110000;
4'b0010:seg_data=7'b1101101;
4'b0011:seg_data=7'b1111001;
4'b0100:seg_data=7'b0110011;
4'b0101:seg_data=7'b1011011;
4'b0110:seg_data=7'b1011111;
4'b0111:seg_data=7'b1110000;
4'b1000:seg_data=7'b1111111;
4'b1001:seg_data=7'b1111011;
default:seg_data=7'b1111110;
endcase
 
assign leda=seg_data[6];
assign ledb=seg_data[5];
assign ledc=seg_data[4];
assign ledd=seg_data[3];
assign lede=seg_data[2];
assign ledf=seg_data[1];
assign ledg=seg_data[0];

		 
endmodule

The following test bench may be used.

`timescale 1 us / 1 us
 
module tb_counterdisplay();
    reg clk;
    reg n_reset;
    reg button_in;
    wire DB_out;
 
    counterdisplay UUT (
        .clk(clk), 
        .n_reset(n_reset), 
        .button_in(button_in)     
        );
  
    initial begin
            clk = 1'b0;
            n_reset = 1'b0;
            #20 n_reset = 1'b1;      // at time 20 release the reset
            button_in = 1'b1;
             
            // We need at least twice the counter value to stabilize value of DB_out
            // before we change the button in
            #50000 button_in = 1'b0; // We pressed the key here 
            #400 button_in = 1'b1; // Key debounce to 1 after 400 micro seconds             
            #800 button_in = 1'b0;    // Debounce after 800 ms
            #2000 button_in = 1'b1; // Decounce after 2 ms          
            #800 button_in = 1'b0;
            #40000 button_in = 1'b1;
            #4000 button_in = 1'b0;     
            #40000 button_in = 1'b1;
            #400 button_in = 1'b0;
            #800 button_in = 1'b1;      
            #800 button_in = 1'b0;
            #800 button_in = 1'b1;
            #40000 button_in = 1'b0;        
            #40000 button_in = 1'b0;
			   #400 button_in = 1'b1;
            #800 button_in = 1'b1;      
            #800 button_in = 1'b0;
            #800 button_in = 1'b1;
            #40000 button_in = 1'b0;
			#40000 button_in = 1'b0;			
            #4000 button_in = 1'b1;
            $finish;
    end
    always
            #10 clk = ~clk;  // 20 mirco seconds = 50 KHz Clock cycle   
 
initial
      begin
      $dumpfile ("debounce.vcd");
      $dumpvars (0,DeBounce_tf);
      end
endmodule

Uncategorized

Level change detection in Verilog

September 25th, 2015

A level detector detects the change is the level, either from high to low or from low to high and takes some action based upon the change in the level. We will develop a circuit that will detect a level change from high to low. It will give an output high for a duration of one clock cycle for every change from high to low.

The basic concept is simple. Consider the moment the Input has just changed from High to low. The diagram below shows the implementation of the high to low level change detector..

EdgeDetector_circuit

The present output level_out depends upon

1. The present input
2. The input one clock cycle earlier.

The level_out, when the present input is 1, is zero because it inverts the present input and ANDs with the input a clock cycle earlier. Now consider the moment the input level switched from high to low somewhere in the middle of clock at the point shown in the diagram below.

EdgeDetector1

In the diagram above, the delay_reg represents the output of the flip flop. When the input level goes 0, the output of the NOT gate turns high. This is ANDed with the level_in in previous clock cycle - which was one. The result is a logic high level_out. This logic high stays only till the next rising edge of the clock. At the next rising edge of clock

This is the verilog implementation of this scheme.

module  edgedetect 
	(
	input 	wire level_in, clk, n_reset,	// inputs
	output wire level_out
	);
	reg  delay_reg  ;
	always @(posedge  clk,  negedge  n_reset)
	if  ( n_reset == 0)
	delay_reg  <=  0;
	else
	delay_reg  <=  level_in;
	assign  level_out  =  (delay_reg)  &  (~level_in);
	endmodule

The following test bench can be used to verify the circuit.

`timescale 1 us / 1 us
 
module tb_edgedetect();
    reg clk;
    reg n_reset;
    reg level_in;
    wire level_out;
 
    edgedetect UUT (
        .clk(clk), 
        .n_reset(n_reset), 
        .level_in(level_in),
        .level_out(level_out)
        );
 
 
    initial begin
            clk = 1'b0;
            n_reset = 1'b1;
            #5 n_reset = 1'b0;  
			#10 n_reset = 1'b1;
            level_in = 1'b1;
            #25 level_in = 1'b0; 
            #40 level_in = 1'b1;            
            #80 level_in = 1'b0;   
            #20 level_in = 1'b1;       
            #80 level_in = 1'b0;
            #40 level_in = 1'b1;
            #40 level_in = 1'b0;     
            #40 level_in = 1'b1;
            $finish;
    end
    always
            #10 clk = ~clk;  // 20 mirco seconds = 50 KHz Clock cycle   
 
initial
      begin
      $dumpfile ("edgedetect.vcd");
      $dumpvars (0,tb_edgedetect);
      end
endmodule

EdgeDetector

Concern

The tick output may be smaller that one clock cycle period. Which makes it faster, but at the same time, less useful, you you wish to do some synchronous task based upon the tick. One way to fix it may be the insertion of two flip flops in place of one flip flop between level_in and level_out.

Some Exercise for readers

For a better understanding, do the following exercizes

1. What change will be required to implement a low to high in place of high to low level detection.
2. Change the code so that it generates a tick on both level changes high to low as well as low to high.
3. Develop the code for a Moore Machine.
4. Implement a 4 bit counter that counts from 0 to 9 and then to 0 on each high to low level change.

Uncategorized

Key Debounce implementation in Verilog

September 24th, 2015

The Circuit below show a simple push button implemented in design such as one in the Spartan 6 Evaluation board .

key-bounce1

The pin 1 of the Switch SW2 is normally high ( due to the pull up resistor R22). When the switch SW2 is pressed, the pin 1 of the switch makes connection with pin 3 of switch SW2, making Pin 1 of the Switch SW2 to make a transition from high to low.

However, this transition is rarely clean. More often than not the switch will make and break contacts several times before making a final transition from 1 o 0. Similarly, when the push button is released it will make and break several times before making a final stable transition from 0 to 1. The process is called key bouncing and the duration and number of the bounces depend upon the characteristic of the switch and typically lasts less than 20 ms. The figure shows the scheme of the key bounce.

key-bounce2

The pattern of the key bounce is not as regular as shown, but you get the idea. Getting rid of the small transitions when the key is pressed or released, is called debouncing. In this article we will show how to do it using Verilog code. It will help you in your understanding of the Verilog. But before we do that, here is an explanation of what how we implement it.

1. Use two flip flops to store the logic levels of button_in during two consecutive clock periods.

2. When these two levels are same ( by XOR gating the output of the two flip flops), we increment a counter. When this counter reaches a specified time, the button input value propagates to output.

3. When the button in changes value, the two flip flops change their values in subsequent clock cycles. In that case, the XOR values of the two counters turns high and the counter is cleared.

4. If the counter keeps incrementing, but the button_in changes the value before the counter reaches the 20 ms value, its value is cleared.

5. To keep the design simpler, the MSB of the counter is monitored.

module  DeBounce 
	(
	input 	clk, n_reset, button_in,		// inputs
	output reg DB_out
	);
	
	/*
	Parameter N defines the debounce time. Assuming 50 KHz clock,
	the debounce time is 2^(11-1)/ 50 KHz = 20 ms
	
	For 50 MHz clock increase value of N accordingly to 21.
	
	*/
	parameter N = 11 ;		

	reg  [N-1 : 0]	delaycount_reg;						
	reg  [N-1 : 0]	delaycount_next;
	
	reg DFF1, DFF2;									
	wire q_add;										
	wire q_reset;

		always @ ( posedge clk )
		begin
			if(n_reset ==  1'b0) // At reset initialize FF and counter 
				begin
					DFF1 <= 1'b0;
					DFF2 <= 1'b0;
					delaycount_reg <= { N {1'b0} };
				end
			else
				begin
					DFF1 <= button_in;
					DFF2 <= DFF1;
					delaycount_reg <= delaycount_next;
				end
		end
	
	
	assign q_reset = (DFF1  ^ DFF2); // Ex OR button_in on conecutive clocks
                                     // to detect level change 
									 
	assign  q_add = ~(delaycount_reg[N-1]); // Check count using MSB of counter			
	

	always @ ( q_reset, q_add, delaycount_reg)
		begin
			case( {q_reset , q_add})
				2'b00 :
						delaycount_next <= delaycount_reg;
				2'b01 :
						delaycount_next <= delaycount_reg + 1;
				default :
				// In this case q_reset = 1 => change in level. Reset the counter 
						delaycount_next <= { N {1'b0} };
			endcase 	
		end
	
	
	always @ ( posedge clk )
		begin
			if(delaycount_reg[N-1] == 1'b1)
					DB_out <= DFF2;
			else
					DB_out <= DB_out;
		end
		
endmodule

Code Explanation

1. At the time of reset, the two flip flops DFF1 and DFF2 are cleared. The counter register delaycount_reg is also cleared.

 always @ ( posedge clk )
        begin
            if(n_reset ==  1'b0) // At reset initialize FF and counter 
                begin
                    DFF1 <= 1'b0;
                    DFF2 <= 1'b0;
                    delaycount_reg <= { N {1'b0} };
                end
            else
                begin
                    DFF1 <= button_in;
                    DFF2 <= DFF1;
                    delaycount_reg <= delaycount_next;
                end
        end

2. At every clock cycle if there is no reset, the button_in propagates to flip flop DFF1. The DFF1 propagates to DFF2 serially. We also update the delaycount_reg. Whether, its value is incremented or becomes zero will depend upon next state logic that we will see later. Basically it will either
- Increment its value, or
- Will be cleared if the because button_in changes its value, or
- Will be cleared because counter reached certain value ( indicated by its MSB).

3. The Change is the button_in value is monitored using a variable q_reset, by XORing the two flip flops. We will later see how q_reset is used.

    assign q_reset = (DFF1  ^ DFF2); 

4. We use a variable q_add to find if the counter has reached its maximum value. This is done by monitoring the MSB of the register delaycount_reg. When the MSB of delaycount_reg is 1, q_add goes 0.

   assign  q_add = ~(delaycount_reg[N-1]); // Check count using MSB of counter

5. This is the most important piece of code. We monitor the change in the button_in value ( via variable q_reset which XORs DFF1 and DFF2, the counter reaching its max value ( via q_add which tracks its MSB) and the delaycount_reg.


always @ ( q_reset, q_add, delaycount_reg)
        begin
            case( {q_reset , q_add})
                2'b00 :
                        delaycount_next <= delaycount_reg;
                2'b01 :
                        delaycount_next <= delaycount_reg + 1;
                default :
                        delaycount_next <= { N {1'b0} };
            endcase    
        end

- If the button_in changes its value, q_reset becomes 1, and reset the delaycount_next to 0.

 default : 
 delaycount_next <= { N {1'b0} };  

- If the button_in stays same ( q_reset stats 0), and counter's MSB is still not 1 ( q_add is 1) , we increment the delaycount_next

     2'b01 :
                        delaycount_next <= delaycount_reg + 1; 

- If the button_in stays same ( q_reset stats 0), and counter's becomes 1 ( q_add is 0), delaycount_next is assigned the value of delaycount_reg;
( Question to readers - can we assign 0 to delacount_next ).

  2'b00 :
                        delaycount_next <= delaycount_reg;

6. Finally, the debounce output is assigned the value of DFF2 if the MSB of the counter becomes 1. Else, it retains its previous value.

always @ ( posedge clk )
        begin
            if(delaycount_reg[N-1] == 1'b1)
                    DB_out <= DFF2;
            else
                    DB_out <= DB_out;
        end

Here is the stimulus code for this

`timescale 1 us / 1 us

module DeBounce_tf();
    reg clk;
    reg n_reset;
    reg button_in;
    wire DB_out;

    DeBounce UUT (
        .clk(clk), 
        .n_reset(n_reset), 
        .button_in(button_in),
        .DB_out(DB_out)
        );


    initial begin
			clk = 1'b0;
            n_reset = 1'b0;
			#20 n_reset = 1'b1;      // at time 20 release the reset
            button_in = 1'b1;
			
			// We need at least twice the counter value to stabilize value of DB_out
			// before we change the button in
			#50000 button_in = 1'b0; // We pressed the key here 
			#400 button_in = 1'b1; // Key debounce to 1 after 400 micro seconds				
			#800 button_in = 1'b0;	  // Debounce after 800 ms
			#2000 button_in = 1'b1;	// Decounce after 2 ms			
			#800 button_in = 1'b0;
			#40000 button_in = 1'b1;
			#4000 button_in = 1'b0;		
			#40000 button_in = 1'b1;
			#400 button_in = 1'b0;
			#800 button_in = 1'b1;		
			#800 button_in = 1'b0;
			#800 button_in = 1'b1;
			#40000 button_in = 1'b0;		
			#4000 button_in = 1'b1;
			$finish;
    end
	always 
			#10 clk = ~clk;  // 20 mirco seconds = 50 KHz Clock cycle   

initial
      begin
      $dumpfile ("debounce.vcd");
      $dumpvars (0,DeBounce_tf);
      end
endmodule 

Let us see the waveform

key-debounce3

Uncategorized