Search code examples
verilogfpgahdlsynthesismultiplexing

Seven Segment Multiplexing on Basys2


this is my first post so I hope I'm doing this correctly. I'm trying to output a "4 3 2 1" on a four digit seven segment display on a BASYS2 board. I have checked to make sure that 0 enables the signal and that I have the ports mapped correctly. I believe the error is within my multiplexing logic since I am only able to display a single digit. I'm new to Verilog (am used to C) and would appreciate any suggestions. Thanks

`timescale 1ns / 1ps

module main (clock, AN0, AN1, AN2, AN3, CA, CB, CC, CD, CE, CF, CG, CDP);


//USED FOR SEVEN SEG
input clock;

output AN0, AN1, AN2, AN3, CA, CB, CC, CD, CE, CF, CG, CDP;

reg [7:0] cathodedata; //cathode data
reg [3:0] anodedata; //anode data
reg [2:0] digit = 1;
reg [6:0] data;
reg setdp;
reg [19:0] counter = 0;

assign CA = cathodedata [7];
assign CB = cathodedata [6];
assign CC = cathodedata [5];
assign CD = cathodedata [4];
assign CE = cathodedata [3];
assign CF = cathodedata [2];
assign CG = cathodedata [1];
assign CDP = cathodedata [0];
assign AN3 = anodedata [3];
assign AN2 = anodedata [2];
assign AN1 = anodedata [1];
assign AN0 = anodedata [0];
//USED FOR SEVEN SEG

    //Multiplexing
    //Board Clock: 50MHz
    //p = t*f
    //t = 16ms
    //p = 16ms * 50*10^6 = 800,000 cycles
    //200,000 cycles for each digit
    //Refreshed every 16ms (~60Hz)

always@(negedge clock)
begin
    if (digit == 1)
        begin
            if (counter == 200_000)
                begin
                    digit = 2;
                end
            else
                begin
                counter = counter + 1;
                data = 4;
                end
        end
    else if (digit == 2)
        begin
            if (counter == 400_000)
                begin
                    digit = 3;
                end
            else
                begin
                    counter = counter + 1;
                    data = 3;
                end
        end
    else if (digit == 3)
        begin
            if (counter == 600_000)
                begin
                    digit = 4;
                end
            else
                begin
                    counter = counter + 1;
                    data = 2;
                end
        end
    else if (digit == 4)
        begin
            if (counter == 800_000)
                begin
                    digit = 1;
                    counter = 0;
                end 
            else
                begin
                    counter = counter + 1;
                    data = 1;
                end
        end 
end


always @ (*)
begin

    case (data)
        6'd0: cathodedata = 8'b00000011; //0
        6'd1: cathodedata = 8'b10011111; //1
        6'd2: cathodedata = 8'b00100101; //2
        6'd3: cathodedata = 8'b00001101; //3
        6'd4: cathodedata = 8'b10011001; //4
        6'd5: cathodedata = 8'b01001001; //5
        6'd6: cathodedata = 8'b01000001; //6
        6'd7: cathodedata = 8'b00011111; //7
        6'd8: cathodedata = 8'b00000001; //8
        6'd9: cathodedata = 8'b00001001; //9
        6'd10: cathodedata = 8'b00010001; //A
        6'd11: cathodedata = 8'b11000001; //B
        6'd12: cathodedata = 8'b01100011; //C
        6'd13: cathodedata = 8'b10000101; //D
        6'd14: cathodedata = 8'b00100001; //E
        6'd15: cathodedata = 8'b01110001; //F
        default: cathodedata = 8'b11111111; //default all off
    endcase

    if (setdp == 1) //decimal point
        cathodedata = cathodedata & 8'hFE;

    case(digit)
        0: anodedata = 4'b1111; //all OFF
        4: anodedata = 4'b1110; //AN0
        3: anodedata = 4'b1101; //AN1
        2: anodedata = 4'b1011; //AN2
        1: anodedata = 4'b0111; //AN3
        default:
        anodedata = 4'b1111; //all OFF
    endcase

end 
endmodule

Solution

  • I too am using a basys2 and looking for a 7-seg driver. Nathan G's code did not work for me (using system verilog perhaps?), but I found this article: http://simplefpga.blogspot.co.uk/2012/12/scrolling-or-moving-text-using-7.html?showComment=1362783256904#c5783969326158067433 and I cannibalized it to my own ends.The modified code is below. It should take (although I haven't checked the decoding fully yet) four hex values and display them on the 7-seg. In my example my board now says 'FAAF' (because getting this working was faf)

    ucf file taken from digilent site:

    # Pin assignment for DispCtl
    # Connected to Basys2 onBoard 7seg display
    NET "seg<0>" LOC = "L14"; # Bank = 1, Signal name = CA
    NET "seg<1>" LOC = "H12"; # Bank = 1, Signal name = CB
    NET "seg<2>" LOC = "N14"; # Bank = 1, Signal name = CC
    NET "seg<3>" LOC = "N11"; # Bank = 2, Signal name = CD
    NET "seg<4>" LOC = "P12"; # Bank = 2, Signal name = CE
    NET "seg<5>" LOC = "L13"; # Bank = 1, Signal name = CF
    NET "seg<6>" LOC = "M12"; # Bank = 1, Signal name = CG
    
    NET "dp" LOC = "N13"; # Bank = 1, Signal name = DP
    
    NET "an<3>" LOC = "K14"; # Bank = 1, Signal name = AN3
    NET "an<2>" LOC = "M13"; # Bank = 1, Signal name = AN2
    NET "an<1>" LOC = "J12"; # Bank = 1, Signal name = AN1
    NET "an<0>" LOC = "F12"; # Bank = 1, Signal name = AN0
    

    Top level module has this:

    module top_level(     
    
    //clock input
    input CLK,
    
    output [7:0] seg,
    output dp,
    output [3:0] an
    
    );    
    
    scrolling_name scrolling_name(
    .clock(CLK),
    .reset(RESET),
    .a(seg[0]),
    .b(seg[1]),
    .c(seg[2]),
    .d(seg[3]),
    .e(seg[4]),
    .f(seg[5]),
    .g(seg[6]),
    .dp(dp),
    .an(an),
    //.XPosition(XPosition),
    //.YPosition(YPosition)
    .XPosition(8'hFA),
    .YPosition(8'hAF)
    );
    
    endmodule
    

    and the file I took from the guy in the link and have edited is:

    `timescale 1ns / 1ps
    
    module scrolling_name(
    input clock,
    input reset,
    output a,
    output b,
    output c,
    output d,
    output e,
    output f,
    output g,
    output dp,
    output [3:0] an,
    input [7:0] XPosition,
    input [7:0] YPosition
    );
    
    reg [28:0] ticker; //to hold a count of 50M
    wire click;
    reg [3:0] fourth, third, second, first; // registers to hold the LED values
    
    always @ (posedge clock or posedge reset) //always block for the ticker
    begin
    if(reset)
    ticker <= 0;
    else if(ticker == 50000000) //reset after 1 second
    ticker <= 0;
    else
    ticker <= ticker + 1;
    end
    
    reg [3:0] clickcount; //register to hold the count upto 9. That is why a 4 bit     register is used. 3 bit would not have been enough.
    
    assign click = ((ticker == 50000000)?1'b1:1'b0); //click every second
    
    always @ (posedge click or posedge reset)
    begin
     if(reset)
      clickcount <= 0;
     else if(clickcount == 8)
       clickcount <= 0;
      else
      clickcount <= clickcount + 1;
    
    end
    
    always@(posedge clock)
    begin
    fourth = XPosition[7:4]; 
    third = XPosition[3:0]; 
    
    second = YPosition[7:4]; 
    first = YPosition[3:0]; 
    end
    
    //see my other post on explanation of LED multiplexing.
    
    localparam N = 18;
    
    reg [N-1:0]count;
    
    always @ (posedge clock or posedge reset)
     begin
      if (reset)
       count <= 0;
      else
       count <= count + 1;
     end
    
    reg [6:0]sseg;
    reg [3:0]an_temp;
    
    always @ (*)
     begin
      case(count[N-1:N-2])
    
       2'b00 :
        begin
         sseg = first;
         an_temp = 4'b1110;
        end
    
       2'b01:
        begin
         sseg = second;
         an_temp = 4'b1101;
        end
    
       2'b10:
        begin
         sseg = third;
         an_temp = 4'b1011;
        end
    
       2'b11:
        begin
         sseg = fourth;
         an_temp = 4'b0111;
        end
      endcase
     end
    assign an = an_temp;
    
    reg [6:0] sseg_temp;
    
    always @ (*)
     begin
      case(sseg)
       0 : sseg_temp = 7'b1000000; //to display 0
       1 : sseg_temp = 7'b1001111; //to display 1
       2 : sseg_temp = 7'b0100100; //to display 2
       3 : sseg_temp = 7'b0110000; //to display 3
       4 : sseg_temp = 7'b0011001; //to display 4
       5 : sseg_temp = 7'b0010010; //to display 5
       6 : sseg_temp = 7'b0000011; //to display 6
       7 : sseg_temp = 7'b1111000; //to display 7
       8 : sseg_temp = 7'b0000000; //to display 8
       9 : sseg_temp = 7'b0011000; //to display 9
       10 : sseg_temp = 7'b0001000; //to display A
       11 : sseg_temp = 7'b0000011; //to display B
       12 : sseg_temp = 7'b1000110; //to display C
       13 : sseg_temp = 7'b0100001; //to display D
       14 : sseg_temp = 7'b0000110; //to display E
       15 : sseg_temp = 7'b0001110; //to display F
    
    default : sseg_temp = 7'b1111111; //blank
    endcase
    end
    
    assign {g, f, e, d, c, b, a} = sseg_temp;
    assign dp = 1'b1;
    
    endmodule
    

    Please excuse the horrible formatting/indenting - there is a combination of his, mine, and adding four spaces to get stack overflow to recognize it as code. I don't have time to make things pretty unfortunately. I can bundle all this together and put it on dropbox if you would like.

    Nathan