Bitcoin mining with FPGAs

On July 19, 2011, in News, by Jeff

Recently, what looks to be the first open source FPGA bitcoin miner was released on GitHub. The code is based on the Terasic DE2-115 development board featuring the Altera Cyclone IV, however the author says the design should be applicable to any other FPGA. Maybe we should make it work on a Xilinx FPGA? Here is what they say about its performance:

Project is fully functional and allows mining of Bitcoins both in a Pool and Solo. It also supports Namecoins.

Current Performance: 109 MHash/s On a Terasic DE2-115 Development Board

Note: The included default configuration file, and source files, are built for 50 MHash/s performance (downclocked). This is meant to prevent damage to your valuable chip if you don’t provide an appropriate cooling solution.

For more information about bitcoins: http://bitcoin.org/

I wonder what performance we could get on the ML505/XUPV5? If anyone has done it, let us know. More importantly, I wonder if anyone is making money with this…

 

Code templates: Generate for loop

On July 18, 2011, in Code templates, by Jeff

This is the first part of a series of posts I will write on various code structures and examples for HDL designs. Here I want to talk about the generate statement and particularly the for loop.

Most programmers think of a for loop as being a code segment that is repeated during execution of the program. The generate for loop is similar in concept however the difference is that the code segment is repeated on compilation time. For example, I could write the code:

for(i = 0; i < 8; i++)
  printf("hello world");

To achieve the same functional effect, I could have written the printf statement 8 times. Of course you wouldn’t do this because it’s not good coding practice and likewise you would not do this in HDL. But what does the compiler do with the for loop? In reality, the C compiler will not replace your for loop with 8 copies of the printf statement, but in the case of the generate for loop, the synthesis program will do that! That is precisely the point of the generate for loop: to save you writing the same code segment multiple times, preventing you from making errors and making for cleaner code.

The example below shows a generate for loop that generates 8 regional clock buffers (BUFR) using the same chip enable (CE) and clear (CLR) signals but with their own clock input and output signals. The separate clock input and output signals are referenced to different bits of a signal vector using the variable called index.

VHDL generate for loop:

gen_code_label:
  for index in 0 to 7 generate
    begin
      BUFR_inst : BUFR
      generic map (
        BUFR_DIVIDE => "BYPASS")
      port map (
        O => clk_o(index),
        CE => ce,
        CLR => clear,
        I => clk_i(index)
      );
  end generate;

Verilog generate for loop:

genvar index;
generate
for (index=0; index < 8; index=index+1)
  begin: gen_code_label
    BUFR BUFR_inst (
      .O(clk_o(index)), // Clock buffer ouptput
      .CE(ce), // Clock enable input
      .CLR(clear), // Clock buffer reset input
      .I(clk_i(index)) // Clock buffer input
    );
  end
endgenerate

Now you might ask why you would want to write the same code segment multiple times so here are a couple of examples where you would want to use the generate for loop:

  • Instantiating multiple RocketIO, HDL modules, buffers, etc. Using the generate for loop makes your code cleaner and is easier to check and debug later on. Going up a notch, when you have to instantiate hundreds of thousands of something, the generate loop becomes absolutely necessary, not just convenient.
  • Making a large number of connections between several signals. Writing out the connections for a hundred signal vectors can be made easier by grouping the vectors into an array and writing a generate for loop to make the connections.

So if you have written code that contains lots of repetitive stuff, try using the generate loop to clean it up. If you’ve got questions about the generate for loop, leave them in the comments below.

 

List and comparison of FPGA companies

On July 15, 2011, in General FPGA, by Jeff

With the top two FPGA companies taking up 89% of the FPGA market, you can be forgiven for thinking there was no one else out there. Xilinx and Altera have done a good job of defending the duopoly but a few companies are gradually winning market share by targeting specific applications and sub-markets. Here is a list of the top 5 FPGA companies by revenue.

 

Xilinx

 

Website: www.xilinx.com

Stock: NASDAQ:XLNX

Market share: 49% ($2,369.45 million) 12 months ending 2011-01-02

The leader in FPGAs for many years, Xilinx has a good range of FPGAs in terms of cost and performance. In recent years, the popular Spartan series has covered the low-to-mid-end market while the Virtex series has covered the high-end. Recently, Xilinx released the “7″ family of FPGAs which are built on 28-nm process and for the first time introduced the Artex-7 and Kintex-7 series which provide better coverage of the lower and mid-end applications previously covered by the Spartan series. The Kintex-7 recently won the “Highly Commended Prize” Semiconductor of the year award for 2011.

 

Altera

 

Website: www.altera.com

Stock: NASDAQ:ALTR

Market share: 40% ($1,954.43 million) 12 months ending 2011-01-02

The Altera FPGAs cover the low, mid and upper end markets with the Cyclone, Arria and Stratix series respectively. The most recent offering from Altera is the Cyclone-V, Arria-V and Stratix-V, all build on 28-nm process technology.

Larger than Xilinx in market value, Altera has made great progress in winning market share in recent years. Many people would say that their software tools are much better than those of Xilinx which has likely been an important factor in their success.

 

Lattice Semiconductor

 

Website: www.latticesemi.com

Stock: NASDAQ:LSCC

Market share: 6% ($297.77 million) 12 months ending 2011-01-02

Lattice Semiconductor tackles the low-power and low-cost market for FPGAs. They market their products as the “high-value FPGAs” of the industry, providing best performance per cost. With the explosion in portable electronics, this has been a good strategy for Lattice. Lattice claims to have the industry’s lowest power and price SERDES-capable FPGA: LatticeECP3. Obviously they didn’t follow the trend of naming FPGAs after greek mythology or meteorological phenomena (not saying its a bad move!).

 

Microsemi (was Actel)

 

Website: www.microsemi.com

Stock: NASDAQ:MSCC

Market share: 4% ($207.49 million) 12 months ending 2011-01-02

Microsemi specializes in low-power and mixed-signal FPGAs.  Here are some of Microsemi’s claims:

  • The industry’s lowest power FPGA: the IGLOO.
  • The industry’s only FPGA with hard 32-bit ARM Cortex-M3 microcontroller: the SmartFusion.

 

QuickLogic

 

Website: www.quicklogic.com

Stock: NASDAQ:QUIK

Market share: 1% ($26.20 million) 12 months ending 2011-01-02

QuickLogic’s focus is on the mobile devices industry meaning ultra-low power, small form factor packaging, and high design security. Rather than selling “FPGA”, they pitch “customizable semiconductors”. You will not find the word “FPGA” on the front page of their website.

“Our patented ViaLink® interconnect technology enables QuickLogic to deliver the lowest power, most routable FPGA in the industry,” Brian Faith, Quicklogic’s Manager of FPGA products.

I’m interested to hear from FPGA developers who have worked on Lattice, Microsemi and QuickLogic FPGAs. Share your experience with us in the comments below. What are their tools like? How do they compare in performance and price to Xilinx and Altera? Can anyone see them breaking the duopoly?

 

 

JP Morgan applies FPGA to risk management

On July 12, 2011, in News, by Jeff

You might already know I’m interested in the application of FPGAs in the financial markets, a field that has been growing over the last few years. JP Morgan has been working on this over the last 3 years and its paying off.

JP Morgan supercomputer offers risk analysis in near real-time

Prior to the implementation, JP Morgan would take eight hours to do a complete risk run, and an hour to run a present value, on its entire book. If anything went wrong with the analysis, there was no time to re-run it.

It has now reduced that to about 238 seconds, with an FPGA time of 12 seconds.

 

 

Tagged with:  

How to melt an FPGA

On July 11, 2011, in General FPGA, by Jeff

Recently I was asked this question by a reader: “Is it possible to make a design large enough to make the FPGA melt?”.

I don’t know why you would want to melt an FPGA, but the idea is interesting so its worth writing about. I’ve actually had people tell me rumors that if you made a design that utilized 90-100% of the resources in an FPGA that it would melt itself. Anyone who’s seen how hot FPGAs can get might think that’s feasible at first glance, but its not that simple.

Firstly, if you want to melt an FPGA, you should first understand what makes it heat up. Most of the heat generated by an FPGA is created when flip-flops transition from one-to-zero or zero-to-one. To maximize the heat generated, we need to maximize the number of flip-flops in the design and the frequency at which they transition. This can be done by chaining together a large number of flip-flops one after the other and feeding the chain with a toggling signal. The easy way to code this is with a for loop generate statement. Let me know in the comments if you want this code, and if enough people are interested, I’ll code it and post it.

The bad news is, most FPGAs are made with internal thermal switches that cut the power to the device when the temperature exceeds a certain level (typically 85 degrees). That temperature, if maintained for long periods is enough to cause damage to the device, but not to melt it. Secondly, you probably could come up with a design that uses close to 100% of the FPGA resources without actually melting or damaging it, because the amount of heat generated is not just proportional to the number of resources used, but also the toggle rate of your design. But even if you were to make a design that uses 100% of the resources, it would take hours and hours to build the bitstream, I challenge someone to give it a try.

 

Clocks, resets and wild goose chases

On July 7, 2011, in General FPGA, by Jeff

There’s a problem that I believe costs design companies billions of dollars a year whether they’re in hardware, software or FPGA design. The problem is hard to control, difficult to monitor and impossible to predict. The problem is bad design practice. Some people call everything “bugs”, but I prefer to call this problem poor design. It is what happens when you do those late-nighters and you’re too tired to see all the loose-ends you’re leaving in your code, or when you don’t have time to test every use case because the product release is yesterday.

Logic is the art of going wrong with confidence. -Joseph Wood Krutch

Here is the typical design and debugging sequence:

  1. Write code
  2. Test code: WORKS!
  3. Write more code
  4. Test code: WORKS!
  5. Write more code
  6. Test code: DOESN’T WORK!
  7. Check what was changed in step 5: FOUND BUG!
  8. Fix the stupid mistake
  9. Test code: WORKS!

The sequence above illustrates a point I want to make: When something stops working, we as designers typically blame the most recent changes we made to a design. But sometimes the real bug is not in the most recent changes, sometimes it was made earlier. Now you might be saying, that doesn’t make sense, the code “worked” before, it’s logical that the bug must be in your most recent changes. Wrong. These are the kind of bugs I’m talking about, the nasty bugs that lead us on wild goose chases. The bugs that slip through the cracks because they give us the impression that they don’t exist. The bugs that can allow a design to work by coincidence. Think about that, did you ever find yourself saying “it can’t be the ..bleep.. because it always worked fine”, the stupid assumption that cost you 1 week. Or what about “I’m sure the ..bleep.. is not working”, the assumption that just cost you 2 days testing something that works perfectly fine.

This week I was given the task of debugging a problem with an FPGA design that didn’t make sense to anyone, including myself. In hindsight the problem was so weird that it had to be one of these nasty wild-goose-chase problems, and the worst thing is I think I sensed that but I still went in with the “most recent changes” bias.

Think about this, you have a fairly straight forward design that works, you never had a problem with it. You tested the design thoroughly and you fixed all the bugs. You are ready to come out of development phase and go to release phase, so you remove your debugging tools from the design (ie. Chipscope): DOESN’T WORK!

What the?? You only removed the debug tools. You didn’t change the design. Like I said, I was biased from the start, so I went into this task with my sights set on what exactly removing Chipscope would do to the design. Well that’s easy, it changes the placement of your logic and primitives, surely this is a timing problem caused by poor placement. Bad assumption. Have you got an idea? It’s probably also a bad assumption. So I spent a good amount of time comparing the placement of the working design with the non-working design. Not surprisingly, and to my great satisfaction, I found that a lot of things were displaced! Doesn’t it feel nice when we find evidence to support our beliefs, even when those beliefs are false? Admittedly the placement didn’t appear to be that different as to cause the problem, but I was stuck on my theory and I had to have it disproved. After a few rounds of changing the placement and testing, and a good many hours, I had to give up on my theory. Beliefs shattered, ego dented, I was forced to look at the big picture and I could now actually do something useful.

Now I don’t want to go into details because that’s not the point of my post, but after looking deeper, I noticed a flaw in the design: we were not managing our clocks and resets correctly. This is a topic that I could write several posts about and I can’t stress enough how important it is. We had a configurable external clock which, after reset, defaulted to a certain frequency. We then configured the clock to another frequency, but we were forgetting to reset the core. When we were asking ourselves “why doesn’t it work anymore?” it just so happened that the right question we should have been asking was “why DID it work before?”.

The point I want to make here is not so much about the clocks and resets but the fact that very often we have to look at more than just the most recent changes that we make to a design when we are faced with strange behavior. As a logical human being we have a tendency to focus on what we just changed, but sometimes we have to open our minds to the possibility that our design was lucky to get as far as it did. Sometimes we don’t realize that our design is hanging on by a thread and that it shouldn’t actually be working at all. If that’s hard to understand, this great quote should make it clearer:

Logic: The art of thinking and reasoning in strict accordance with the limitations and incapacities of the human misunderstanding. -Ambrose Bierce

 

In a previous post I wrote about using SVN with HDL designs and how to do it most effectively. Here I want to write about having your peripheral cores automatically generate the netlists they use when the project is compiled, for example when you build the bitstream of an XPS project. Firstly I’ll give you an example where it would be useful.

Let’s say I have a peripheral that contains a FIFO. I generated that FIFO using Core Generator. So I have a netlist file that I place in the “netlist” folder of my peripheral, plus I have created a .bbd file in my “data” folder containing the name of the netlist file.

Now as discussed earlier, we don’t commit netlists, we only commit sources. The sources for my FIFO are the .xco and .cgp files that Coregen created. These are the files necessary to re-generate the netlist using Coregen so I should copy them to the “netlist” folder and commit them to my SVN.

Normally from this point, Jill starting from a clean slate, will need to generate the netlist by opening Coregen, opening the .cgp file, right-clicking the FIFO core and selecting “regenerate”.

In the case that our core uses multiple netlists, Jill’s job becomes tedious. It becomes even more tedious when she wants to use several other peripherals that have their own netlists to generate. Now we get to the point of this post: the automated way to regenerate your netlists using a TCL script. This is the basic idea:

  1. We create a .tcl file in the “data” folder that contains a function to execute Coregen and regenerate our netlist.
  2. We add a line into the .mpd file of the peripheral that calls the TCL function when the core is being compiled as part of a hardware project.

Here is an example .tcl file with the function that runs Coregen and generates our netlist file:

proc run_coregen {mhsinst} {
 set ngcfolder "./pcores/my_peripheral_v1_00_a/netlist"
 set ngcfile $ngcfolder/my_fifo.ngc
 set cgpfile $ngcfolder/coregen.cgp
 set xcofile $ngcfolder/my_fifo.xco
 set ngcexists [file exists $ngcfile]
 if {$ngcexists != 1} {
  puts "my_peripheral: Generating netlists using Coregen\n"
  set result [catch {exec coregen -p $cgpfile -b $xcofile -intstyle xflow}]
 }
}

 

Here is an example .mpd file with a line that calls the TCL function:

 

###################################################################
 ##
 ## Name     : my_peripheral
 ## Desc     : Microprocessor Peripheral Description
 ##          : Automatically generated by PsfUtility
 ##
 ###################################################################
 BEGIN my_peripheral

 ## Peripheral Options
 OPTION IPTYPE = PERIPHERAL
 OPTION IMP_NETLIST = TRUE
 OPTION RUN_NGCBUILD = TRUE
 OPTION STYLE = MIX

 OPTION PLATGEN_SYSLEVEL_UPDATE_PROC = run_coregen

 ## Bus Interfaces

 ## Generics for VHDL or Parameters for Verilog

 ## Ports
 PORT Clk     = "",   DIR = I
 PORT Rst     = "",   DIR = I
 PORT DataIn  = "",   DIR = I, VEC = [7:0]
 PORT DataOut = "",   DIR = O, VEC = [7:0]

END

Now when you build your XPS project containing my_peripheral, you will see the line “my_peripheral: Generating netlists using Coregen” appear at some point in the message console. If you have used Coregen before you would know that it can take some time to generate a netlist, so be patient!

To conclude all this, dont forget to commit all the sources of your peripheral. That includes:

  • \data\*.mpd
  • \data\*.pao
  • \data\*.tcl
  • \data\*.bbd
  • \netlist\*.cgp
  • \netlist\*.xco
  • \hdl\* (obviously all your sources .vhd and .v)

If you have questions please leave them in the comments below.

 

Is Xilinx losing to the competition?

On July 5, 2011, in General FPGA, by Jeff

I recently read an interesting article on Xilinx’s position with respect to its competitors: Is Xilinx Good Enough for You? As someone who works mainly with Xilinx FPGAs, I find it important to know how they are faring competitively. If one day a competitor manages to blow Xilinx out of the water, I would like to have seen it coming.

The image below was taken from Google Trends and shows Google search results for Xilinx and Altera. Clearly, search volume for Altera has overtaken that for Xilinx and the spread seems to be growing.

What about their relative financial positions? The image below comes from Google Finance and shows the stock price of Xilinx (XLNX) vs Altera (ALTR). Since the low at the end of the tech boom and bust, Altera stock has grown 300% while Xilinx has only managed a gain of 100%. Technical analysts would tell you that its a bad sign that Xilinx hasn’t returned to its 2004 high. Altera on the other hand destroyed that high. Market capital for Xilinx is 9.8 billion while Altera is 15 billion.

Is Xilinx a sinking ship? Let us know in the comments below.

 

In the previous tutorial on using the SDK, we exported our base project from EDK to SDK and then we ran a simple software application that printed “Hello World” in the terminal window. In this tutorial, we will do something more useful than saying hello, instead we will illustrate the concept of communicating with a peripheral from C code running on the Microblaze. More specifically, we will read the DIP switch settings and display them on the terminal screen using printfs. Our C code will poll the switches constantly so that any change will be reflected in the terminal window.

Requirements

To perform this tutorial, you will need:

  • Xilinx ISE Design Suite 13.1
  • ML50x or XUPV5 development board
  • Serial to USB converter

You will also need to go through the previous tutorial about using SDK. You can continue here once you have the base system EDK project exported to SDK and a workspace already defined.

Start SDK

  1. Open SDK by selecting “Xilinx ISE Design Suite 13.1->EDK->Xilinx Software Development Kit”.
  2. The first thing you will be asked by SDK is what workspace to open. Select “C:\ML509\Projects\base-system-v13-1\sdk” for your SDK workspace and click OK.
  3. When SDK opens you should see the hello_world C project in the Project Explorer. In SDK you can have multiple software projects (or applications) in the one workspace. In other words, one workspace can be used to manage several software applications for running on the same hardware platform. We want to create a new software application and write the code for it. Select “File->New->Xilinx C project”.
  4. The wizard that follows will allow us to create a template software application for our project. The default is the “hello world” example that we used in the previous tutorial. For this tutorial we want to use the “Empty Application” template, because we want to write our own code. Select “Empty Application” and click Next to accept the defaults as shown in the image below.
  5. Click Finish to accept the defaults of the second page.
  6. If you did everything correctly, you should have the SDK window looking like the image below.

Write the C code

  1. In the Project Explorer, if you open the tree “empty_application_0->src”, you will see that there are no .c source files for the application. We have to write our own .c source file with the main function.
  2. Select “File->New->Source File”.
  3. In the dialog box that opens, you must specify the name of the source file to create, and the folder in which to put it. Follow the screenshot below and click “Finish”.
  4. The readdip.c file should have been created and opened in SDK. Notice that SDK fills it with a comment showing the file name, the date it was created and the name of the author. Copy and paste the following code into the file, after the comment, and select “File->Save” to save the file. When you save, the C project will automatically be compiled.
#include "xparameters.h"
#include "xbasic_types.h"
#include "xgpio.h"
#include "xstatus.h"

XGpio GpioOutput;
XGpio GpioInput;

int main (void) {

  Xuint32 status;
  Xuint32 DataRead;
  Xuint32 OldData;

  // Clear the screen
  xil_printf("%c[2J",27);

  // Initialize the GPIO driver so that it's ready to use,
  status = XGpio_Initialize(&GpioOutput,
                                 XPAR_LEDS_8BIT_DEVICE_ID);
  if (status != XST_SUCCESS)
    return XST_FAILURE;
  // Set the direction for all signals to be outputs
  XGpio_SetDataDirection(&GpioOutput, 1, 0x0);

  // Initialize the GPIO driver so that it's ready to use,
  status = XGpio_Initialize(&GpioInput,
                         XPAR_DIP_SWITCHES_8BIT_DEVICE_ID);
  if (status != XST_SUCCESS)
    return XST_FAILURE;
  // Set the direction for all signals to be inputs
  XGpio_SetDataDirection(&GpioInput, 1, 0xFFFFFFFF);

  OldData = 0xFFFFFFFF;
  while(1){
    // Read the state of the DIP switches
    DataRead = XGpio_DiscreteRead(&GpioInput, 1);

    // Send the data to the UART if the settings change
    if(DataRead != OldData){
      xil_printf("DIP Switch settings: 0x%X\r\n", DataRead);
      // Set the GPIO outputs to the DIP switch values
      XGpio_DiscreteWrite(&GpioOutput, 1, DataRead);
      // Record the DIP switch settings
      OldData = DataRead;
    }
  }
  return 0;
}

Load the FPGA with the bitstream

  1. Turn on your hardware platform (ML50x or XUPV5 or whatever you have).
  2. Connect the Serial to USB device to your board’s RS232 port and your computer’s USB port.
  3. Open your terminal program (eg. Hyperterminal or Putty) and connect to the COM port that corresponds to your Serial to USB device.
  4. From the SDK menu, select “Xilinx Tools->Program FPGA”.
  5. In the “Program FPGA” dialog box, the defaults should already specify the correct bitstream for the hardware project. Make sure they correspond to the image above and click Program.

Run the Software Application

  1. In the Project Explorer, select the “empty_application_0” and from the menu, select “Run->Run”.
  2. In the “Run As” dialog box, select “Launch on Hardware”.
  3. SDK will build the software application, load it into the memory on the FPGA and trigger the Microblaze to run the code. You should see “DIP Switch settings: 0×0″ written in your terminal window. If you change the DIP switches by turning them on and off, you will see the terminal display change to reflect the new settings. The settings are displayed as a hexadecimal number, where 0×0 means zero (all switches are OFF) and 0xFF means all switches are ON. The least significant bit corresponds to switch 8 while the most significant bit corresponds to switch 1. In the screen shot below, I gradually turned all the switches ON.

Summary

Now you should have a good idea about the SDK and how to use it to write software applications and run them on your FPGA board. In future tutorials, I will show you different C applications and go into detail about what the application actually does, rather than going through every step covered in this tutorial.

 

The Virtex-6 based ML605

On July 1, 2011, in General FPGA, by Jeff

Forget about the ML505. The ML605 just made it obsolete. Not because of the Virtex-6 or the 8-lane PCIe or the DDR3… You need the ML605 because it has two FMC expansion connectors, one high-pin count and one low-pin count. You could do practically anything with this board. Why do I like it? Because for once we have a board that lets you interface real data at a high throughput to a beast of an FPGA.

Here are some of the FMCs you might want to plug into this board:

That’s the potential of the FMC standard that I tried to get across in a previous post FMC is a game-changer. With FMC, the FPGA/processing platform can be developed independently from the IO card which spreads the risk for the hardware developer and gives more choice and flexibility to the FPGA designer.

But of course that’s not the only thing that’s great about the ML605, checkout all the features as described on the Xilinx ML605 page:

  • FPGA: XC6VLX240T-1FFG1156
  • Configuration
    • Onboard configuration circuitry (USB to JTAG)
    • 16MB Platform Flash XL
    • 32MB Parallel (BPI) Flash
    • System ACE CF with 2GB Compact FLASH (CF) Card
  • Communications and Networking
    • 10/100/1000 Tri-Speed Ethernet (GMII, RGMII, SGMII, MII)
    • SFP transceiver connector
    • GTX port (TX, RX) with four SMA connectors
    • USB To UART Bridge
    • USB Host Port and USB Peripheral Port
    • PCI Express x8 Edge Connector (card supports up to x4 Gen2 with Virtex-6 LX240T-1 silicon)
  • Memory
    • DDR3 SO-DIMM (512 MB)
    • BPI Linear Flash (32 MB) (Also available for configuration)
    • IIC EEPROM (8 Kb)
  • Clocking
    • 200 MHz Oscillator (Differential)
    • 66 MHz Socketed Oscillator (Single-Ended)
    • SMA Connectors for external clock (Differential)
    • GTX Reference Clock port with 2 SMA connectors
  • Input/Output and Expansion Ports
    • 16×2 LCD character display
    • DVI Output
    • System Monitor
    • User Push buttons (5), DIP switches (3), LEDs (13)
    • User GPIO with two SMA connectors
    • Two FMC Expansion Ports
      • High Pin Count (HPC)
        • Eight GTX Transceivers
        • 160 SelectIOs
      • Low Pin Count (LPC)
        • One GTX Transceiver
        • 68 SelectIOs
  • Power
    • 12V wall adapter or ATX
    • Voltage and Current measurement capability of 2.5V, 1.5V, and 1.2V, 1.0V supplies

If you have an ML605, leave a comment and let us know what interesting things you’re doing with it.

 

Tagged with: