FPGA clock using Quartus II and a little Verilog
In this topic I want to talk about how you can implement a clock on an FPGA. Someone might find this strange, unnecessary - but you have to start somewhere, therefore, this topic will be useful for beginners who blink with LEDs and want something more interesting.
This means that we have:
1) Terasic DE0-Nano debug board with Cyclone IV on board.
2) A breadboard with a seven-segment indicator soldered on it, to which we will display hours and minutes /
For these two points, complete freedom of choice almost any FPGA will do, and everyone will make a breadboard with an indicator as it does.
Now about the project.


We will go in order. First of all, we ask ourselves: what is a watch? A watch is a device that counts time. In order to count it, we need an accurate source. Our board has a 50 MHz clock. Too much, so we need to divide it by 50,000,000 to get a frequency of 1 Hz (one “tick” per second). How to share? I did this in two stages: using PLL, divided by 50 and using the counter, divided by a million.
What is a PLL? Roughly speaking, this is such a thing that can change the clock signal: multiply, divide, shift in phase, change the duty cycle. There are 4 of them in Cyclone IV, so why not use one ...
To do this, open the MegaWizard Plugin Manager and use the ALT_PLL from the IO section:
1) Set the input frequency to 50 MHz:

2) Disable unnecessary inputs: 3) Click Next three times and get into the signal parameter selection window, where we set the division factor 50: Then you can safely click Finish, save and paste into the project. Here we have such beauty: On the left, the input is 50 MHz, on the right is 1 MHz. Now we need to divide by another million - for this we use a counter modulo 1,000,000. The counting module is the number of possible states of the counter. We create it using the same MegaWizard, using LPM_Counter. We set the bit depth to 20 bits, and select modulus, with a count modulus of 1000000. We get this: Now we have a neat 1 Hz, which can be obtained from the senior (19) bit.




Next, we need to implement a cascade of 3 counters: two modulo 60 (minutes and seconds), and one modulo 24 (obviously, hours).
Second counter - with an asynchronous reset that occurs when any button is pressed (setting hours / minutes): As you can see, the Carry Out output is used (transfer when overflowing to the next counter), and seconds are displayed on the LEDs. The following 2 counters are constructed in the same way, with one exception: to set the time, it is necessary to apply a clock signal faster than 1 Hz, so as not to fall asleep during tuning. :) For this we use button-controlled multiplexers:


The upper multiplexer is used to select which frequency to apply to the input of the counter, and the lower one selects what to send to the input cin: transfer from the cout of the second counter, or simply the log level. "1".
The essence of the input cin is that the counter counts only if there is a logical unit level at this input. That is, when the second counter overflows, it raises cout to one. This "1" goes to the input cin of the next counter and it reports one minute, and so on.
Thus, when the key [0] is released, the minute counter counts 1 time per minute (which is logical), and when pressed - about 4 times per second.
Similarly for the hour meter:

The upper multiplexer manages the transfer, and the lower frequency, with the exception of one point: when the key [0] button is pressed, clock signals do not arrive at the counter water (this is done so that it does not go astray when setting the minutes). This is done due to the AND element, to the input of which a clock signal and key [0] are supplied. When the button on key [0] is released, the level is high and q [19] passes through it, when pressed, the level is “0” and the output is also “0”. In principle, it would be possible to turn on the counter input “count enable” and turn off the counter through it - in this task, this is unprincipled.
Now we need to display the data from the counters. To do this, we need to make a converter from binary to binary decimal. This is such a representation of a decimal number in binary code, when each decimal digit is specified by a separate 4 binary digits.
Example:
738 = 0111 0011 1000.
For this conversion, we use the double-dabble algorithm.
The essence of the algorithm:
1) Shift the binary number to the left by one bit.
2) If 4 shifts - the number of BCDs in the “tens” and “units” columns. The end of the algorithm
3) If in any column the number is more than 4, add 3.
Go to step 1.
Here is an illustration:

And here is what we need to implement so that this conversion is performed without delay:
s16.radikal.ru/i191/1107/a4/59618e3101ca.png
Each module C adds 3 to the input, if the input has a number greater than 4.
Here it is and the truth table of its work:

To implement this whole economy, write two such modules on verilog: Save and insert into the project in the amount of two pieces: One will be for hours, the other for minutes. Now it is necessary to make a digression regarding our indicator. I used Lite-On ltc-4727js.

According to the datasheet, it has segments with a common cathode for each digit + the inputs of the anodes of the segments of each digit are combined. This means that we can only light 1 digit at a time. It doesn’t matter, we will light them in turn, only we will switch very quickly. So fast that even Chuck Norris will not notice the flicker ;-)
The most interesting parts from the datasheet:

and How did I connect it all? But using such pins: With segments, I think everything is clear, but what is the mysterious digit [4..0] ... It's simple - digit [4..1] is our numbers, and digit [0] is auxiliary segments (colon between 2 and 3 digits). I’ll tell you, the most difficult thing is to connect everything correctly and to correctly match the FPGA outputs and our pins!


Now we will analyze the output mechanism for the indicator.
This monster design is doing this: On our left, bin-to-BCD converters. The focus is on a 5-input 4-bit multiplexer. The first 4 inputs are numbers, the fifth input is for igniting dots (which flash once per second). Below you can see a diagram that sends 1111 or 1110 to this second input. About why exactly this is a little further. Depending on what combination comes to the control input of the multiplexer, it outputs the necessary bit to the decoder (the device of which we will consider a little later). Above it is a device that selects which cathode to feed “0” to light up the desired segment. Here are his insides:

Pay attention to a record like 5'b0zzzz. Here 5'b means that we set 5 bits in binary form, 0 is the zero level, z is the high-resistance state (current does not flow to the pin). And why exactly 0? Yes, because we have a common cathode on a digit, the current flows from the anode to the cathode, or from 1 to 0. Here we set 0 on the cathode and 1 on the anode.
Now the decoder device is: assign {segA, segB, segC, segD, segE, segF, segG, segDP} = SevenSeg; endmodule Here, depending on which digit we need, we choose which segments to light.
Two points are of interest - default and the number 1111. When our BCD takes a value different from the given ones (1110, which was mentioned earlier), then all segments are turned off. When 1111 arrives at us, segments A and B are ignited. As you can see from the datasheet, they are also connected to points L1 and L2.
That, in fact, is all.
We put everything inone pile, one project, assign pins, compile (yeah, less than 1% of our mighty pebble is used) and fill it in the FPGA.
Here is the project:
ifolder.ru/24865983 You
must select your FPGA, and reassign pins. True, I used PLL ... Therefore, when transferring the project to another FPGA, it will be necessary to divide your input frequency (not the fact that you will have 50 MHz there).
Here's a video:
www.youtube.com/watch?v=iUoiOO8wYls
Sources:
1) Data indicator:
pdf.eicom.ru/datasheets/lite-on_pdfs/ltc-4727js/ltc-4727js.pdf
2) Transfer from BIN to BCD:
www. johnloomis.org/ece314/notes/devices/binary_to_BCD/bin_to_bcd.html
www.ece.msstate.edu/courses/ece4743/fall2007/Shift_add_3.pdf
3) Output to segments:
www2.engr.arizona.edu/~rlysecky/courses /ece274-07f/labs/lab4.pdf
we.easyelectronics.ru/Shematech/dinamicheskaya-indikaciya_2.html
www.fpga4fun.com/Opto4.html
4)
Decryptor : www.fpga4fun.com/Opto3.html
Thank you for your attention, I hope , useful to someone!
UPD
Thanks for the comments to everyone!
I do not know how it turned out on this blog. I wanted to cut, fill in the pictures of norms, remake something ... But today I didn’t go to the Habr!
There is an idea about how to get time from the outside, for example via NTP.
About hosting - I was advised in PM, pour over there.
This is my first topic, before this experience there were no publications, I uploaded the pictures to the first hosting that I remembered.
I just ended up in my hometown and with normal internet. Tomorrow I will cut according to wishes!


We will go in order. First of all, we ask ourselves: what is a watch? A watch is a device that counts time. In order to count it, we need an accurate source. Our board has a 50 MHz clock. Too much, so we need to divide it by 50,000,000 to get a frequency of 1 Hz (one “tick” per second). How to share? I did this in two stages: using PLL, divided by 50 and using the counter, divided by a million.
What is a PLL? Roughly speaking, this is such a thing that can change the clock signal: multiply, divide, shift in phase, change the duty cycle. There are 4 of them in Cyclone IV, so why not use one ...
To do this, open the MegaWizard Plugin Manager and use the ALT_PLL from the IO section:
1) Set the input frequency to 50 MHz:

2) Disable unnecessary inputs: 3) Click Next three times and get into the signal parameter selection window, where we set the division factor 50: Then you can safely click Finish, save and paste into the project. Here we have such beauty: On the left, the input is 50 MHz, on the right is 1 MHz. Now we need to divide by another million - for this we use a counter modulo 1,000,000. The counting module is the number of possible states of the counter. We create it using the same MegaWizard, using LPM_Counter. We set the bit depth to 20 bits, and select modulus, with a count modulus of 1000000. We get this: Now we have a neat 1 Hz, which can be obtained from the senior (19) bit.




Next, we need to implement a cascade of 3 counters: two modulo 60 (minutes and seconds), and one modulo 24 (obviously, hours).
Second counter - with an asynchronous reset that occurs when any button is pressed (setting hours / minutes): As you can see, the Carry Out output is used (transfer when overflowing to the next counter), and seconds are displayed on the LEDs. The following 2 counters are constructed in the same way, with one exception: to set the time, it is necessary to apply a clock signal faster than 1 Hz, so as not to fall asleep during tuning. :) For this we use button-controlled multiplexers:


The upper multiplexer is used to select which frequency to apply to the input of the counter, and the lower one selects what to send to the input cin: transfer from the cout of the second counter, or simply the log level. "1".
The essence of the input cin is that the counter counts only if there is a logical unit level at this input. That is, when the second counter overflows, it raises cout to one. This "1" goes to the input cin of the next counter and it reports one minute, and so on.
Thus, when the key [0] is released, the minute counter counts 1 time per minute (which is logical), and when pressed - about 4 times per second.
Similarly for the hour meter:

The upper multiplexer manages the transfer, and the lower frequency, with the exception of one point: when the key [0] button is pressed, clock signals do not arrive at the counter water (this is done so that it does not go astray when setting the minutes). This is done due to the AND element, to the input of which a clock signal and key [0] are supplied. When the button on key [0] is released, the level is high and q [19] passes through it, when pressed, the level is “0” and the output is also “0”. In principle, it would be possible to turn on the counter input “count enable” and turn off the counter through it - in this task, this is unprincipled.
Now we need to display the data from the counters. To do this, we need to make a converter from binary to binary decimal. This is such a representation of a decimal number in binary code, when each decimal digit is specified by a separate 4 binary digits.
Example:
738 = 0111 0011 1000.
For this conversion, we use the double-dabble algorithm.
The essence of the algorithm:
1) Shift the binary number to the left by one bit.
2) If 4 shifts - the number of BCDs in the “tens” and “units” columns. The end of the algorithm
3) If in any column the number is more than 4, add 3.
Go to step 1.
Here is an illustration:

And here is what we need to implement so that this conversion is performed without delay:
s16.radikal.ru/i191/1107/a4/59618e3101ca.png
Each module C adds 3 to the input, if the input has a number greater than 4.
Here it is and the truth table of its work:

To implement this whole economy, write two such modules on verilog: Save and insert into the project in the amount of two pieces: One will be for hours, the other for minutes. Now it is necessary to make a digression regarding our indicator. I used Lite-On ltc-4727js.
module add3(in,out);
input [3:0] in;
output [3:0] out;
reg [3:0] out;
always @ (in)
case (in)
4'b0000: out <= 4'b0000;
4'b0001: out <= 4'b0001;
4'b0010: out <= 4'b0010;
4'b0011: out <= 4'b0011;
4'b0100: out <= 4'b0100;
4'b0101: out <= 4'b1000;
4'b0110: out <= 4'b1001;
4'b0111: out <= 4'b1010;
4'b1000: out <= 4'b1011;
4'b1001: out <= 4'b1100;
default: out <= 4'b0000;
endcase
endmodule
module binary_to_BCD(A,ONES,TENS);
input [5:0] A;
output [3:0] ONES, TENS;
wire [3:0] c1,c2,c3;
wire [3:0] d1,d2,d3;
assign d1 = {1'b0,A[5:3]};
assign d2 = {c1[2:0],A[2]};
assign d3 = {c2[2:0],A[1]};
add3 m1(d1,c1);
add3 m2(d2,c2);
add3 m3(d3,c3);
assign ONES = {c3[2:0],A[0]};
assign TENS = {1'b0,c1[3],c2[3],c3[3]};
endmodule

According to the datasheet, it has segments with a common cathode for each digit + the inputs of the anodes of the segments of each digit are combined. This means that we can only light 1 digit at a time. It doesn’t matter, we will light them in turn, only we will switch very quickly. So fast that even Chuck Norris will not notice the flicker ;-)
The most interesting parts from the datasheet:

and How did I connect it all? But using such pins: With segments, I think everything is clear, but what is the mysterious digit [4..0] ... It's simple - digit [4..1] is our numbers, and digit [0] is auxiliary segments (colon between 2 and 3 digits). I’ll tell you, the most difficult thing is to connect everything correctly and to correctly match the FPGA outputs and our pins!


Now we will analyze the output mechanism for the indicator.
This monster design is doing this: On our left, bin-to-BCD converters. The focus is on a 5-input 4-bit multiplexer. The first 4 inputs are numbers, the fifth input is for igniting dots (which flash once per second). Below you can see a diagram that sends 1111 or 1110 to this second input. About why exactly this is a little further. Depending on what combination comes to the control input of the multiplexer, it outputs the necessary bit to the decoder (the device of which we will consider a little later). Above it is a device that selects which cathode to feed “0” to light up the desired segment. Here are his insides:

module segment_select (in,out,sel);
input in;
output reg [4:0] out;
output reg [2:0] sel;
always @ (posedge in)
if (sel == 4)
sel = 0;
else sel = sel + 1;
always @(*)
case (sel)
0: out <= 5'b0zzzz;
1: out <= 5'bz0zzz;
2: out <= 5'bzz0zz;
3: out <= 5'bzzz0z;
4: out <= 5'bzzzz0;
default: out <= 5'bzzzzz;
endcase
endmodule
Pay attention to a record like 5'b0zzzz. Here 5'b means that we set 5 bits in binary form, 0 is the zero level, z is the high-resistance state (current does not flow to the pin). And why exactly 0? Yes, because we have a common cathode on a digit, the current flows from the anode to the cathode, or from 1 to 0. Here we set 0 on the cathode and 1 on the anode.
Now the decoder device is: assign {segA, segB, segC, segD, segE, segF, segG, segDP} = SevenSeg; endmodule Here, depending on which digit we need, we choose which segments to light.
module decoder_7seg (BCD, segA, segB, segC, segD, segE, segF, segG, segDP);
input [3:0] BCD;
output segA, segB, segC, segD, segE, segF, segG, segDP;
reg [7:0] SevenSeg;
always @(BCD)
case(BCD)
4'h0: SevenSeg = 8'b11111100;
4'h1: SevenSeg = 8'b01100000;
4'h2: SevenSeg = 8'b11011010;
4'h3: SevenSeg = 8'b11110010;
4'h4: SevenSeg = 8'b01100110;
4'h5: SevenSeg = 8'b10110110;
4'h6: SevenSeg = 8'b10111110;
4'h7: SevenSeg = 8'b11100000;
4'h8: SevenSeg = 8'b11111110;
4'h9: SevenSeg = 8'b11110110;
4'b1111: SevenSeg = 8'b11000000;
default: SevenSeg = 8'b00000000;
endcase
Two points are of interest - default and the number 1111. When our BCD takes a value different from the given ones (1110, which was mentioned earlier), then all segments are turned off. When 1111 arrives at us, segments A and B are ignited. As you can see from the datasheet, they are also connected to points L1 and L2.
That, in fact, is all.
We put everything in
Here is the project:
ifolder.ru/24865983 You
must select your FPGA, and reassign pins. True, I used PLL ... Therefore, when transferring the project to another FPGA, it will be necessary to divide your input frequency (not the fact that you will have 50 MHz there).
Here's a video:
www.youtube.com/watch?v=iUoiOO8wYls
Sources:
1) Data indicator:
pdf.eicom.ru/datasheets/lite-on_pdfs/ltc-4727js/ltc-4727js.pdf
2) Transfer from BIN to BCD:
www. johnloomis.org/ece314/notes/devices/binary_to_BCD/bin_to_bcd.html
www.ece.msstate.edu/courses/ece4743/fall2007/Shift_add_3.pdf
3) Output to segments:
www2.engr.arizona.edu/~rlysecky/courses /ece274-07f/labs/lab4.pdf
we.easyelectronics.ru/Shematech/dinamicheskaya-indikaciya_2.html
www.fpga4fun.com/Opto4.html
4)
Decryptor : www.fpga4fun.com/Opto3.html
Thank you for your attention, I hope , useful to someone!
UPD
Thanks for the comments to everyone!
I do not know how it turned out on this blog. I wanted to cut, fill in the pictures of norms, remake something ... But today I didn’t go to the Habr!
There is an idea about how to get time from the outside, for example via NTP.
About hosting - I was advised in PM, pour over there.
This is my first topic, before this experience there were no publications, I uploaded the pictures to the first hosting that I remembered.
I just ended up in my hometown and with normal internet. Tomorrow I will cut according to wishes!