CPLD Verilog intro 2: Toggle a LED with a button

From DP

Jump to: navigation , search

Contents

Overview

In tutorial 2 we extend the first CPLD design by controlling the LED with a push button.

  • Press the button to turn off the LED
  • Release the button to turn on the LED
Tutorial 2 truth table
Button PB LED D1
Pressed OFF
NOT pressed ON

Schematic

Cpld-tutorial-external-circuit.png

The development boards have a simple push button (PB) connected to pin P18 of the CPLD.

PB truth table
Button P18
Pressed LOW (0)
NOT pressed HIGH (1)

A pull-up resistor (R1) holds P18 high when the button is NOT pressed. When pressed, the button connects P18 to ground and produces a low/0 state. See the truth table above.

The XC2C64A CPLD has internal pullup resistors
R1 is unpopulated on the XC2C64A development board

In this demo we'll use the input on pin P18 to control the LED D1 connected to pin P39. Due to the inverse logic of the button, the LED will turn off when the button is pressed.

Verilog

Cpld-xc9572xl-intro2.png

module CPLDIntro2Ledbutton(
    LED,  //these are the connections to the module that we expose externally
     LED_INV, //external pin number is assigned in the UCF file like this:
     BUTTON //
                //NET "LED"            LOC =  "P39";
                //NET "LED_INV"        LOC =  "P38";
    );        //NET "BUTTON"        LOC =  "P18";
 
 
    output LED;//LED D1 is an output from the module
    output LED_INV; //LED_INV is also an output
 
    input BUTTON; //button is an input signal
 
    reg LED;//a register to output LED
    reg LED_INV; //a register to output LED_INV
 
    wire BUTTON; //input button is a wire
 
    always @ (BUTTON) //start of the action section
    begin
        LED=BUTTON; //Set reg LED to the value of wire button
        LED_INV=1'b0; //Hold LED D2 off (low)
                    //other states are
                    //1'b1 HIGH 
                    //1'b0 LOW
                    //1'bz HiZ (input)
    end
 
endmodule

This is a simple variant on tutorial 1. Instead of connecting the LED directly to the power supply, we connect it to the input from the button.

  • BUTTON is an input. This is where the push button input will enter the CPLD. We assign this to a specific pin number in the UCF file below
  • LED is an output. This is where the CPLD will output to the LED. We assign this to a specific pin in the UCF file

Module

module CPLDIntro2Ledbutton(
    LED,  //these are the connections to the module that we expose externally
     LED_INV, //external pin number is assigned in the UCF file like this:
     BUTTON //
                //NET "LED"            LOC =  "P39";
                //NET "LED_INV"        LOC =  "P38";
    );        //NET "BUTTON"        LOC =  "P18";
//...
//...
//...
endmodule
  • Addition of a new signal to the module, BUTTON
  • This is where the push button input will enter the CPLD. We assign this to a specific pin number in the UCF file

Input

 
    output LED;//LED D1 is an output from the module
    output LED_INV; //LED_INV is also an output
 
     input BUTTON; //button is an input signal

The new signal is an input.

Wire

 
    reg LED;//a register to output LED
    reg LED_INV; //a register to output LED_INV
 
     wire BUTTON; //input button is a wire

The new signal is a wire, it carries the button input into the CPLD.

  • Wires carry signals, but do not store values like a register
  • Reg can be changed in the always block (LED output), but not wires (BUTTON input)

Always

 
    always @ (BUTTON)//start of the action section
    begin
        LED=BUTTON; //Set reg LED to the value of wire button
        LED_INV=1'b0; //Hold LED D2 off (low)
                    //other states are
                    //1'b1 HIGH 
                    //1'b0 LOW
                    //1'bz HiZ (input)
    end

The always block defines the logic:

  • Always do this when BUTTON changes. @ (BUTTON) can be omitted, but simulations will not run correctly
  • Set LED register output equal to the BUTTON wire input
  • LED_INV (LED D2) is still held to ground to keep it off

UCF

XC9572XL UCF

Cpld-xc9572xl-intro2.png

#PIN MAP OF DANGEROUSPROTOTYPES.COM CPLD BREAKOUT BOARDS
#lICENSE: CC-0 (CREATIVE COMMONS 0)
#http://dangerousprototypes.com/docs/XC9500XL_CPLD_breakout_board
#http://dangerousprototypes.com/docs/CoolRunner-II_CPLD_breakout_board
NET "LED"            LOC =  "P39";
NET "LED_INV"        LOC =  "P38";
NET "BUTTON"        LOC =  "P18";

Input and outputs in the module are mapped to actual CPLD pin numbers in the UCF file. This is an example UCF file that defines the three IO connections on the development boards.

  • The Pxx numbers are the actual pin number on the CPLD. Easy.

We mapped the BUTTON input market to pin 18 and the LED output marker to pin 39.

XC2C64A UCF

Cpld-xc2c-intro2.png

#PIN MAP OF DANGEROUSPROTOTYPES.COM CPLD BREAKOUT BOARDS
#lICENSE: CC-0 (CREATIVE COMMONS 0)
#http://dangerousprototypes.com/docs/XC9500XL_CPLD_breakout_board
#http://dangerousprototypes.com/docs/CoolRunner-II_CPLD_breakout_board
NET "LED"            LOC =  "P39";
NET "LED_INV"        LOC =  "P38";
NET "BUTTON"         PULLUP;
NET "BUTTON"         LOC =  "P18";

The XC2C64A UCF is slightly different than the XC9572XL version. The CoolRunner-II family (XC2C) is newer and has some advanced features like configurable pull-up resistors.

Cpld-tut-external-curicut-xc2c.png

The XC2C64A development board takes advantage of the CoolRunner-II internal resistors and omits external resistor R1. This doesn't save a lot of money, but it provides a nice contrast between the devices.

NET "BUTTON" PULLUP;

To use the pullups in Verilog, we can follow several methods, but the easiest is to make a minor addition to the UCF file as shown.

TIP: To enable the in internal pull-up resistors in a new project go to fit and change default pin type to float or pull-up. Keeper and pull-ups are mutually exclusive in a single design.

Alternate version

module CPLDIntro2Ledbutton(
    LED,  //these are the connections to the module that we expose externally
     LED_INV, //external pin number is assigned in the UCF file like this:
     BUTTON //
                //NET "LED"            LOC =  "P39";
                //NET "LED_INV"        LOC =  "P38";
    );        //NET "BUTTON"        LOC =  "P18";
 
 
    output LED;//LED D1 is an output from the module
    output LED_INV; //LED_INV is also an output
 
    input BUTTON; //button is an input signal
 
    wire LED;//a register to output LED
    wire LED_INV; //a register to output LED_INV
 
    wire BUTTON; //input button is a wire
 
    assign LED=BUTTON; //Set reg LED to the value of wire button
    assign LED_INV=1'b0; //Hold LED D2 off (low)
                    //other states are
                    //1'b1 HIGH 
                    //1'b0 LOW
                    //1'bz HiZ (input)
endmodule

This example uses all wires and the assign command instead of registers and an always block.

  • Wires cannot be manipulated in an always block like registers
  • Wires are assigned a value with the assign command