Sunday, 22 July 2012

Seven Segment LED Multiplexing Circuit in Verilog

The seven segment LED circuit uses seven different and individual LED's to display a hexadecimal symbol. It has 7 wires to control the individual LED's one wire to control the decimal point and one enable wire. The demo board I am using here consists of four such 7-segment LED's(As do any other demo board). To reduce the number of wires a multiplexing circuit is used to control the display. Using the multiplexing circuit the number of wires required to light up all 4 displays are reduced from 32 to 12 (8 data bits and 4 enable bits). All bits here are active low, such that to enable them a '0' is required. For example the figure below shows how to display a 3 on the seven segment.

The multiplexing circuit can take 4 inputs and have only one output. But the inputs should be displayed on the output fast enough to fool the viewer into thinking all outputs are enabled individually and simultaneously. This is achieved by having an enable signal that changes so fast that it appears that all displays are on simultaneously. The refreshing rate of the enable signal should be around 1000Hz to achieve this desired effect. Since the BASYS2 board has a 50Mhz clock and if an 18 bit counter is used and only the 2 MSB's are used to generate the enable signal then the refreshing rate of an individual enable bit will be 50MHz/(2^16) which comes to about 800 Hz.

Once the multiplexing is done the next code block is always the data bits for the seven segment. This is usually a case statement which encodes the hexadecimal digits into binary format. Since the LED's here are active low the segments that need to be enabled must be low.

The code for the LED multiplexing is shown below:

module sevenseg(
 input clock, reset,
 input in0, in1, in2, in3,  //the 4 inputs for each display
 output a, b, c, d, e, f, g, dp, //the individual LED output for the seven segment along with the digital point
 output [3:0] an   // the 4 bit enable signal
 );

localparam N = 18;

reg [N-1:0]count; //the 18 bit counter which allows us to multiplex at 1000Hz

always @ (posedge clock or posedge reset)
 begin
  if (reset)
   count <= 0;
  else
   count <= count + 1;
 end

reg [6:0]sseg; //the 7 bit register to hold the data to output
reg [3:0]an_temp; //register for the 4 bit enable

always @ (*)
 begin
  case(count[N-1:N-2]) //using only the 2 MSB's of the counter 
   
   2'b00 :  //When the 2 MSB's are 00 enable the fourth display
    begin
     sseg = in0;
     an_temp = 4'b1110;
    end
   
   2'b01:  //When the 2 MSB's are 01 enable the third display
    begin
     sseg = in1;
     an_temp = 4'b1101;
    end
   
   2'b10:  //When the 2 MSB's are 10 enable the second display
    begin
     sseg = in2;
     an_temp = 4'b1011;
    end
    
   2'b11:  //When the 2 MSB's are 11 enable the first display
    begin
     sseg = in3;
     an_temp = 4'b0111;
    end
  endcase
 end
assign an = an_temp;


reg [6:0] sseg_temp; // 7 bit register to hold the binary value of each input given

always @ (*)
 begin
  case(sseg)
   4'd0 : sseg_temp = 7'b1000000; //to display 0
   4'd1 : sseg_temp = 7'b1111001; //to display 1
   4'd2 : sseg_temp = 7'b0100100; //to display 2
   4'd3 : sseg_temp = 7'b0110000; //to display 3
   4'd4 : sseg_temp = 7'b0011001; //to display 4
   4'd5 : sseg_temp = 7'b0010010; //to display 5
   4'd6 : sseg_temp = 7'b0000010; //to display 6
   4'd7 : sseg_temp = 7'b1111000; //to display 7
   4'd8 : sseg_temp = 7'b0000000; //to display 8
   4'd9 : sseg_temp = 7'b0010000; //to display 9
   default : sseg_temp = 7'b0111111; //dash
  endcase
 end
assign {g, f, e, d, c, b, a} = sseg_temp; //concatenate the outputs to the register, this is just a more neat way of doing this.
// I could have done in the case statement: 4'd0 : {g, f, e, d, c, b, a} = 7'b1000000; 
// its the same thing.. write however you like it

assign dp = 1'b1; //since the decimal point is not needed, all 4 of them are turned off


endmodule


10 comments:

  1. Hi, I copied pasted the source to the *.v
    created the *.ucf
    Here is my ucf:
    NET "reset" LOC = "a7";

    # Pin assignment for 7-segment displays
    NET "a" LOC = "l14" ;
    NET "b" LOC = "h12" ;
    NET "c" LOC = "n14" ;
    NET "d" LOC = "n11" ;
    NET "e" LOC = "p12" ;
    NET "f" LOC = "l13" ;
    NET "g" LOC = "m12" ;
    NET "dp" LOC = "n13" ;

    NET "in0" LOC = "k14";
    NET "in1" LOC = "m13";
    NET "in2" LOC = "j12";
    NET "in3" LOC = "f12";

    # Pin assignment for clock
    NET "clock" LOC = "b8";

    But it's doing nothing?
    How can work it? thanks :)

    ReplyDelete
  2. The code above is not a stand alone module. It is to be used within or connected to another module. In your ucf file you linked the in0 - in3 registers but in this code there is no data coming to them. The reason it does not work is that it has nothing to display.

    Check out this post to get an idea of how to use this within another module: http://simplefpga.blogspot.co.uk/2012/07/00-to-99-two-digit-decimal-counter-via.html

    ReplyDelete
  3. Hello, i am using a DE1 altera board and dont know how to assign the pins after using mux.
    Could you help out? Thank you

    ReplyDelete
    Replies
    1. You have to use the ucf file for your board. That will give you pin assignment info. Google it. It's easily available.

      Delete
  4. Please explain me why did you use 18 bit register for count

    ReplyDelete
    Replies
    1. I mentioned the reason for that in the text explanation. Below I have copied the relevant part again:

      The refreshing rate of the enable signal should be around 1000Hz to achieve this desired effect. Since the BASYS2 board has a 50Mhz clock and if an 18 bit counter is used and only the 2 MSB's are used to generate the enable signal then the refreshing rate of an individual enable bit will be 50MHz/(2^16) which comes to about 800 Hz.

      Delete
  5. Hello..I am trying to implement this in spartan 3e but the lcd interfacing is totally different in spartan 3e ..can you please give me some direction on how to multiplex lcd in spartan 3e?

    regards
    rahul

    ReplyDelete
    Replies
    1. Hi Rahul. Interfacing an LCD is different that multiplexing the seven segment display. Please refer to your board handbook for that if its an onboard LCD

      Delete
  6. define all inputs
    as a vector [4:0]
    ie, input [4:0]in0;
    input [4:0]in1;
    and same for in2 and in3.
    and also change the vector [6:0]sseg to [4:0]. should be the same as input vectors.
    It work fine afterthen

    ReplyDelete