It just occurred to me that learning to program FPGAs is making me feel young again. It’s not taking years off my countenance or anything, but I’m once again working with circuits I was building in my high school
electronics class back in the age of dinosaurs and dweebs.
In this column, I’ve added a binary to seven-segment decoder to the binary counting configuration I used in my previous blog. The seven-segment display I’m using is an old FND500 that I purchased in 1980 when building my first computer — a CDP1802-based singleboard
thing. My primary objectives with this project are to build on my starting project by adding more functions and to get something running that I can use to learn about the ChipScope virtual logic analyzer (a device discussed here before).
I’ve used almost all the available I/O on my Spartan FPGA, but I was able to bring out both the binary count and the seven-segment hex count. My push-on/push-off switch starts and stops the count, while my plain momentary contact push-button switch activates the decimal point. I’ve uploaded the complete UCF and Verilog file here, so you can follow our “create project” steps from previous blogs to start with working code before heading to ChipScope. I named my project “FND500count.” You can skip the “New Source Wizard” steps and just put the Verilog file and UCF into your empty project as complete source files. Copy the two files, “7-segment count.v” and “7-segment.ucf,” into a “source” folder in your project folder.
After that, you just add the Verilog file, followed by the UCF file, into the project through the “Add file” option.
Since we’ll be using ChipScope once this is all done, actual hardware isn’t really necessary. However, if you want to build it up, take a look at the picture at the start of this article.
In our previous sample code, the binary counting came out on the four LEDs built into the
Spartan 6 LX9 board. I started out using that sample code (both the Verilog file and the UCF).
For this exercise, I changed the binary count to drive four external LEDs, just to make it easier
to see both the binary count and the seven-segment count.
I had to change a few things in the UCF. For example, the “LOC” chip pin values for COUNTING_LEDS have changed to represent the pins connected to the header on the PCB. (Refer to Header J5 on Sheet 5 of
the Spartan schematic.)
As illustrated in the image below, I also changed the IOSTANDARD constraint from “LVCMOS18” to “LVCMOS33.” The four on-board LEDs are connected to Bank 3 of the Spartan chip, and this bank has 1.8-volt pins (Sheet 7 of the schematic). However, the headers J5 and J4 run from pins in Bank 1, which has 3.3-volt pins, hence “LVCMOS33.” I left “DRIVE” at 8mA. With an 8mA forward current and 1.7-volt forward voltage on my LEDs, I would need a 220-ohm resister to match everything up. The Spartan 6 chip will drive currents of 2, 4, 6, 8, 12, 16, and 24 mA. My LEDs will take a maximum of 20mA, but they light reliably with quite a bit less, so 8mA is fine for my parts.
I put my momentary contact switch between pins 4 and 6 (chip pin E18 and Vcc) of header J4. The push-on/push-off switch goes between pins 10 and 12 (chip pin F18 and Vcc), also on header J4.
The real spaghetti connects to my solderless breadboard. I’m using that ancient FND500 seven-segment LED I told you about earlier. This is a common cathode LED, so you’ll want to use the same if you plug in a different device. The pin-outs for this part are shown below. Your pin-outs may differ if you have a different part.
Now that you have the project created and the hardware built (or visualized in your head), you can synthesize, implement, generate, and configure as we’ve done in past blogs. The result should look something like mine, which I’ve captured in the following video:
The new construct in the Verilog file (lines 80 to 99 in my file) is the binary to seven-segment decoder. I feed it (SEG_OUT) the same four bits (led_count[28:25]) that I feed the binary leds (COUNTING_LEDS). It introduced the reserved words “assign” and “case.” It also brought in the use of the term “reg” instead of “wire” back up on line 27. I still need to do a bit more reading before I can explain how this all works, but that will come later — unless anyone wants to read up and explain it to the rest of us by posting comments to this blog.
In my next post, I’ll bring up ChipScope, and I’ll explain the reg, assign, and case keywords in more detail.