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
Here's a modified version of one of my pet projects. It should do exactly as you wanted: display 4 3 2 1
on the 4dig7seg display. I tested it on an Amani GTX CPLD, and it should transfer cleanly to your board.
I like separating projects into separate modules to keep organized. The top level module takes the on board clock as an input and outputs 14 signals to a four-digit-seven-segment serial display. Make sure the pins are correctly assigned.
module SevenSeg(clk, odig, onum, col, ap);
input clk; // 50 MHz oscillator
output [3:0] odig; // selected digit output
output [7:0] onum; // selected display output
output col = 1; // turns the colon off
output ap = 1; // turns the apostrophe off
wire clock; // divided oscillator to slow the display output
parameter a = 8'b11111110; // low means on, high means off
parameter b = 8'b11111101; // these are just parameters
parameter c = 8'b11111011; // defining each of the
parameter d = 8'b11110111; // seven segments
parameter e = 8'b11101111; // making life easier
parameter f = 8'b11011111;
parameter g = 8'b10111111;
parameter dp = 8'b01111111;
parameter off = 8'b11111111;
parameter one = b & c; // parameters for outputs
parameter two = a & b & d & e & g;
parameter three = a & b & c & d & g;
parameter four = b & c & f & g;
wire [7:0] port1 = one; // This is set up so these can change dynamically...
wire [7:0] port2 = two; // ... if so desired.
wire [7:0] port3 = three;
wire [7:0] port4 = four;
slowclk m1(clk, clock); // divides clk by 500, for 50 MHz in, 100 kHz out
digitize m2(clock, port1, port2, port3, port4, odig, onum); // rotates the digit outputs
endmodule
Next I have a simple clock divider. The case count = 500 can be modified to divide your clock to whatever frequency you like. The output should look fine in the range of about 120 Hz to about 2 MHz.
module slowclk(clk, clock);
input clk;
output reg clock;
integer count;
always @(posedge clk)
case(count)
500: begin clock <= clock + 1; count <= 0; end // Change 500 to any divisor you like
default: count <= count + 1;
endcase
endmodule
Then we have to rotate the digits. Note if you change the anodes and cathodes at the "same" time, there will be a small leakage current into the neighboring segments causing a "ghost" effect.
module digitize(clock, num1, num2, num3, num4, odig, onum);
input wire clock;
input [7:0] num1; // rightmost digit
input [7:0] num2;
input [7:0] num3;
input [7:0] num4; // leftmost digit
output reg [3:0] odig;
output reg [7:0] onum;
parameter [7:0] off = 8'b11111111;
reg [3:0] dstate;
always @(posedge clock)
case(dstate)
0:begin odig <= 4'b0001; dstate <= 1; end
1:begin onum <= num1; dstate <= 2; end
2:begin onum <= off; dstate <= 3; end // off states prevent 'ghosting'
3:begin odig <= 4'b0010; dstate <= 4; end // when changing output digit
4:begin onum <= num2; dstate <= 5; end
5:begin onum <= off; dstate <= 6; end
6:begin odig <= 4'b0100; dstate <= 7; end
7:begin onum <= num3; dstate <= 8; end
8:begin onum <= off; dstate <= 9; end
9:begin odig <= 4'b1000; dstate <= 10; end
10:begin onum <= num4; dstate <= 11; end
11:begin onum <= off; dstate <= 0; end
default: dstate <= 0;
endcase
endmodule