Electronics

Getting started with CPLDs

Introduction & Disclaimer

I'm not an expert on CPLD's or FPGA's or any kind of programmable logic. This page, and any pages that follow in this series document my journey into this area. Any example code given should be treated with this in mind - in particular don't assume that any code or design here is an example of the best way to do something, although I will have checked that the code works to some degree or other on my development system.

Approach

Although it's not strictly necessary to have actual hardware to program, because you can write code in VHDL or Verilog and run it through a simulator, there's nothing quite like running your code on read hardware and seeing what happens to get an understanding; seeing actual LEDs flash!

Development hardware

cpld/cpld_red.png

You can pay pretty much as much or as little as you like for a CPLD board. I bought a £5 board from China (Pictured right - took a few weeks to arrive, but got here in the end!) which just consists of a regulator, crystal oscillator, the CPLD and some header pins. Other than that, there were no other peripherals. If you're thinking of going a long way with programmable logic, then an FPGA dev board like the DE0 Nano may be of interest, available for around £65. For the purposes of developing HDL skills, either will do, you'll just be able to do a lot more with FPGA's because they have many for facilities to use.

Of course, if like me you're just starting out and can't or don't want to spend a lot of money, then a CPLD is a much cheaper option, and if you are thinking about including programmable logic in your projects, then a CPLD is probably a better option. It will certainly give you the opportunity to get to grips with VHDL/Verilog and you can transfer your skills to the more complex and demanding FPGAs later.

I'd also recommend a dev board with at least switches and LED's on to get you started. I didn't bother because I had a "Gertboard" for my Raspberry Pi which I could use to provide these facilities. If you're handy with a soldering iron you could rig up something on Veroboard using buffer IC's to drive LEDs. Just dont forget CPLDs and FPGAs tend to work with 3.3v signals or lower, and don't usually respond well to being fed 5v signals. Consult the relevant datasheets for guidance.

One thing you will need is a compatible programming device. While most different makes of CPLD are all programmed with JTAG programmers, which is relatively standardised, the programmers themselves are not, and you'll need to get one that is compatible with the software supplied by the CPLD manufacturer. In my case I was lucky and managed to get a USB Blaster clone for ALtera devices for around £7! I got mine from Hobby Components but they are also available on eBay from suppliers worldwide. The clone devices seem to work well enough.

First step - Installing the Software.

This actually took me quite a while. For the Altera device I was using, Altera supply the Quartus 2 software free of charge (you need to register to download it but that was painless). I made things difficult for myself by downloading the Linux version, as I wanted to use an old laptop I had with no OS. I installed Centos 5 (the Linux distribution recommended for 32 bit Linux) with no problems. The first issue is that the download is a whopping 7Gb in size (!) and comes as an DVD ISO - except that I don't have a double layer DVD burner (mine is single layer, and maces out at 4.5Gb) however, so jiggery-pokery with mounting it with the loopback filesystem paid off. I had some security problems requiring me to change permissions which I only was able to find out about and discover by googling. There was a note on the Altera site - its a shame they didn't take note of it themselves and get the installer to set up permissions itself. There was alsp a problem with the version of a DLL supplied, and I had to move them out of the way and install the ones in the Centos repository. I'll write that up separately because right now I can't remember quite what I did!

Hopefully the rest of you will have an easier time of it.

Once you have the software running you realize that its overwhelmingly complex - largely due to a whole load of stuff that you don't really need at this stage. there is no "training wheels" version! Fortunately there seemed to be a lot of guides on the Internet provided by Universities for their Engineering students - none for exactly the version I was using but some where close enough to be useful:

Which HDL?

When embarking on my quest I had to decide how I was going to program my CPLD. There are schematic editors available that allow you to draw out the circuit you want and it translates that schematic into a bitstream for the device. Attractive as that is for simple use, I decided that it would be a little limiting, and being from a programming background I am more comfortable with code!

The options that remain come down to VHDL and Verilog. A cursory glance at various HDL forums found enthusiastic supporters of both, but in the end I plumped for Verilog because it looked like less typing and I'm lazy!

I found A good primer for Verilog called Verilog according to Tom with google that goes over the main points and got me started, and I would recommend looking at it for anyone new to Verilog.

The first thing I wanted to do was to try making a very simple circuit using Verilog and check that I could get it to compile, upload to the CPLD board and power it up & see it work! This brings us to the first project!

Full adder

This circuit is a very simple piece of combinatorial logic. Its not really what a CPLD is for, but its good to start. I found the code in a tutorial for a Tufts university lab course, which unfortunately used an older version of Quartus II than mine, so some of the menus etc had changed, but it did point me in the right direction.

The code for a full adder looks like this:

module fulladder(a, b, cin, sum, cout);
input a,b,cin;
output sum, cout;
reg sum, cout;

always @ (a or b or cin)
begin
  sum <= a ^^ b ^^ cin;
  cout <= (a && b) || (a && cin) || (b && cin);
end
endmodule

This first program creates an event block that sets the output registers whenever one of the inputs changes. This is an event-driven piece of logic. It is unclocked, so the compiler issues a warning, but it works. The compiler warning is because we have essentially produces asynchronous logic, and async logic can result in race conditions, so CPLD design is optimised towards sychronous (i.e. clocked) logic. Mote on this at a later date!

It's not the only way of doing it; another source on the internet has this code:

module fulladder(a,b,c,sum,carry);
input a,b,c;
output sum,carry;
wire sum,carry;
assign sum=a^b^c; // sum bit
assign carry=((a&b) | (b&c) | (a&c)); //carry bit
endmodule

This second example uses continuous assignment but is essentially the same. One question that did arise when I first saw this was why in the first example the logical "and" (&&) and "xor" (^^) operators, and in the second the bitwise ones are used. On further thought it becomes obvious that for single bit values the two are essentially the same, the difference only becomes significant when dealing with registers or buses of more than one bit.

Note also in this second example the outputs are of type "wire" while in the first they are of "reg". Some sources online that I looked at insisted that module outputs had to be of type "reg", but to me that made no sense - in particular, what if an output for your module is driven from a submodule?

The truth is that it is more detailed than that. Tom's guide gives a fuller explanation that:

The following are true of module interfaces:

  • An input or inout port is a wire within its module.
  • An output port must be a wire if it is generated by a submodule.
  • An output port must be a wire if it is generated declaratively.
  • An output port must be a reg if it is assigned to procedurally.

In the first fulladder, the output is assigned procedurally (i.e. within an event/begin..end block) and thus needs to be a "reg". In the second it is assigned in a "continuous assign" statement and can be a "wire". The clouds part!

First programming of the device

I'm not going to go over the steps to use the Altera software here, because the lab course is a pretty good guide I couldn't write better (other than to update it - perhaps another page!). You also may be using a different CPLD/Software combination and it would be as tedious for you to wade through dozens of redundant screen as it would be for me to do it.

cpld/fulladder.png

Once I had typed in the Verilog, and got it to compile, I was able to use the RTL Netlist viewer to show me exactly what it had created from my Verilog (See left!). Reassuringly it was a completely conventional full adder circuit! One of the (many) reports generated by the system told me I had used 2 out of 240 logic elements on the CPLD (Presumably one for each output).

Now compiled, I needed to map the pins. The compiler had assigned signals to pins in an aparrently random fashion, which I could have used, but I had already connected my Gertboard to the CPLD and wanted to use the mapping I had randomly chosen. A bit of headscratching and I worked out how to use the pin mapper, recompiled and was ready to go.

I connected the USB Blaster to the computer and tried setting it up. Which of course it didn't and I had to do some work with permissions and UDEV rules to get things going. However, that aside I got it working and the chip programmed, cycled the power supply and ...

... It worked!

To say I was excited is an understatement. OK so it's the simplest bit of logic, but it proves that the whole toolchain worked. My total spend (assuming you cost my time as £0/hr) was less than £20 and I had a working CPLD project.

Coming Soon:

  • Counter fed from the 50MHz clock on my dev board
  • Knight Rider!

Version 2 updated 20 Nov 2013, 6:54 p.m.