3
\$\begingroup\$

I'm trying to write a digital clock on vhdl for an fpga that runs on 100mhz. I can write it on 4 anodes by creating a counter as shown below(count1 = 249999), the digits seem pretty clear. However, when I want to display the time in the format HH:MM:SS (when I want to use 6 anodes instead of 4), I couldn't display the digits clearly. When I increase the count1 value much, the LEDs start blinking, when I decrease the count1 value, the digits look hard to identify.

Is there any theoretical way to determine this counter(counter1) value? Is it possible to show 6 digits clearly in the way I'm trying?

Thanks from now.

the code responsible for displaying 4 anodes:

anode_clock : process(count1, clk_in, A_counter) -- counter to display all digits using anodes
begin 
    if(rising_edge(clk_in)) then
        count1 <= count1 + 1;
        if(count1 = 249999) then  -- ATTENTION HERE
            A_counter <= A_counter + 1;
            count1 <= 0;
        end if;
    end if;
end process;

anode_display : process (A_counter, tmp_AN, min0, min1, hour0) begin -- matching anodes to display
    AN <= tmp_AN;
    case A_counter is
        when 0 =>
            tmp_AN <= "1110";
            if (min0 = 0) then
                DISP <= "1000000";
            elsif min0 = 1 then
                DISP <= "1111001";
            elsif min0 = 2 then
                DISP <= "0100100";
            elsif min0 = 3 then
                DISP <= "0110000";
            elsif min0 = 4 then
                DISP <= "0011001";
            elsif min0 = 5 then
                DISP <= "0010010";
            elsif min0 = 6 then
                DISP <= "0000010";
            elsif min0 = 7 then
                DISP <= "1111000";
            elsif min0 = 8 then
                DISP <= "0000000";
            elsif min0 = 9 then
                DISP <= "0010000";
            end if;
        when 1 =>
            tmp_AN <= "1101";
            if (min1 = 0) then
                DISP <= "1000000";
            elsif min1 = 1 then
                DISP <= "1111001";
            elsif min1 = 2 then
                DISP <= "0100100";
            elsif min1 = 3 then
                DISP <= "0110000";
            elsif min1 = 4 then
                DISP <= "0011001";
            elsif min1 = 5 then
                DISP <= "0010010";
            elsif min1 = 6 then
                DISP <= "1000000";
            end if;
        when 2 =>
            tmp_AN <= "1011";
            if (hour0 = 0) then
                DISP <= "1000000";
            elsif hour0 = 1 then
                DISP <= "1111001";
            elsif hour0 = 2 then
                DISP <= "0100100";
            elsif hour0 = 3 then
                DISP <= "0110000";
            elsif hour0 = 4 then
                DISP <= "0011001";
            elsif hour0 = 5 then
                DISP <= "0010010";
            elsif hour0 = 6 then
                DISP <= "0000010";
            elsif hour0 = 7 then
                DISP <= "1111000";
            elsif hour0 = 8 then
                DISP <= "0000000";
            elsif hour0 = 9 then
                DISP <= "0010000";
            elsif hour0 = 10 then
                DISP <= "1000000";
            elsif hour0 = 11 then
                DISP <= "1111001";
            elsif hour0 = 12 then
                DISP <= "0100100";
            elsif hour0 = 13 then
                DISP <= "1000000";
            end if;
        when 3 =>
            tmp_AN <= "0111";
            if (hour0 = 10) then
                DISP <= "1111001";
            elsif hour0 = 11 then
                DISP <= "1111001";
            elsif hour0 = 12 then
                DISP <= "1111001";
            else 
                DISP <= "1000000";
            end if;
    end case;
end process;

the output (as I wanted):enter image description here

the code responsible for displaying 6 anodes(digits are not clear to read):

anode_clock : process(count1, clk_in, A_counter) -- counter to display all digits using anodes
begin 
    if(rising_edge(clk_in)) then
        count1 <= count1 + 1;
        if(count1 = 125000) then -- experimental value: 249999
            A_counter <= A_counter + 1;
            count1 <= 0;
        end if;
    end if;
end process;

anode_display : process (A_counter, tmp_AN, sec0,sec1, min0, min1, hour0) begin -- matching anodes to display
    AN <= tmp_AN;
    case A_counter is
        when 0 =>
            tmp_AN <= "111110";
            if (sec0 = 0) then
                DISP <= "1000000";
            elsif sec0 = 1 then
                DISP <= "1111001";
            elsif sec0 = 2 then
                DISP <= "0100100";
            elsif sec0 = 3 then
                DISP <= "0110000";
            elsif sec0 = 4 then
                DISP <= "0011001";
            elsif sec0 = 5 then
                DISP <= "0010010";
            elsif sec0 = 6 then
                DISP <= "0000010";
            elsif sec0 = 7 then
                DISP <= "1111000";
            elsif sec0 = 8 then
                DISP <= "0000000";
            elsif sec0 = 9 then
                DISP <= "0010000";
            end if;
        when 1 =>
            tmp_AN <= "111101";
            if (sec1 = 0) then
                DISP <= "1000000";
            elsif sec1 = 1 then
                DISP <= "1111001";
            elsif sec1 = 2 then
                DISP <= "0100100";
            elsif sec1 = 3 then
                DISP <= "0110000";
            elsif sec1 = 4 then
                DISP <= "0011001";
            elsif sec1 = 5 then
                DISP <= "0010010";
            elsif sec1 = 6 then
                DISP <= "1000000";
            end if;
        when 2 =>
            tmp_AN <= "111011";
            if (min0 = 0) then
                DISP <= "1000000";
            elsif min0 = 1 then
                DISP <= "1111001";
            elsif min0 = 2 then
                DISP <= "0100100";
            elsif min0 = 3 then
                DISP <= "0110000";
            elsif min0 = 4 then
                DISP <= "0011001";
            elsif min0 = 5 then
                DISP <= "0010010";
            elsif min0 = 6 then
                DISP <= "0000010";
            elsif min0 = 7 then
                DISP <= "1111000";
            elsif min0 = 8 then
                DISP <= "0000000";
            elsif min0 = 9 then
                DISP <= "0010000";
            end if;
        when 3 =>
            tmp_AN <= "110111";
            if (min1 = 0) then
                DISP <= "1000000";
            elsif min1 = 1 then
                DISP <= "1111001";
            elsif min1 = 2 then
                DISP <= "0100100";
            elsif min1 = 3 then
                DISP <= "0110000";
            elsif min1 = 4 then
                DISP <= "0011001";
            elsif min1 = 5 then
                DISP <= "0010010";
            elsif min1 = 6 then
                DISP <= "1000000";
            end if;
        when 4 =>
            tmp_AN <= "101111";
            if (hour0 = 0) then
                DISP <= "1000000";
            elsif hour0 = 1 then
                DISP <= "1111001";
            elsif hour0 = 2 then
                DISP <= "0100100";
            elsif hour0 = 3 then
                DISP <= "0110000";
            elsif hour0 = 4 then
                DISP <= "0011001";
            elsif hour0 = 5 then
                DISP <= "0010010";
            elsif hour0 = 6 then
                DISP <= "0000010";
            elsif hour0 = 7 then
                DISP <= "1111000";
            elsif hour0 = 8 then
                DISP <= "0000000";
            elsif hour0 = 9 then
                DISP <= "0010000";
            elsif hour0 = 10 then
                DISP <= "1000000";
            elsif hour0 = 11 then
                DISP <= "1111001";
            elsif hour0 = 12 then
                DISP <= "0100100";
            elsif hour0 = 13 then
                DISP <= "1000000";
            end if;
        when 5 =>
            tmp_AN <= "011111";
            if (hour0 = 10) then
                DISP <= "1111001";
            elsif hour0 = 11 then
                DISP <= "1111001";
            elsif hour0 = 12 then
                DISP <= "1111001";
            else 
                DISP <= "1000000";
            end if;
    end case;
end process;

the output (digits are not as I wanted, something looks wrong with the display counter):enter image description here

\$\endgroup\$
  • 2
    \$\begingroup\$ Are you sure anodes is the word you want? An anode is just one terminal of a two-terminal device. \$\endgroup\$ – The Photon May 15 '17 at 23:34
  • \$\begingroup\$ yhmm you have a pretty fast watch (100MHz ) but you must teach it to use 6 BCD nibbles (4bit) and not 4 binary bytes (8). Then put dark red clear plastic filter to improve contrast. I see 88061817. Is it a BCD digit or HEX? \$\endgroup\$ – Tony Stewart Sunnyskyguy EE75 May 15 '17 at 23:46
  • \$\begingroup\$ @ThePhoton I know the physical meaning. For Seven Segment Displays, as far as I know, an anode is just a digit. For example on my FPGA, there are 8 anodes for my seven segments. I might be wrong and be appreciated if you tell me if I'm wrong. \$\endgroup\$ – ErenL May 16 '17 at 6:24
  • \$\begingroup\$ @TonyStewart.EEsince'75 well, my fpga and vhdl knowledge is pretty limited. I can write codes like above but don't know how to implement your suggestion. Can you tell me any source on how to do that? \$\endgroup\$ – ErenL May 16 '17 at 6:28
  • 1
    \$\begingroup\$ If LED values are just memory addresses then google the mathcode for a BCD clock output with a precision clock input `to internal counter idc-online.com/technical_references/pdfs/electronic_engineering and en.wikipedia.org/wiki/Binary-coded_decimal/… \$\endgroup\$ – Tony Stewart Sunnyskyguy EE75 May 16 '17 at 6:46
1
\$\begingroup\$

This is an inherent limitation of multiplexing: since you're only driving a single digit at a time, your display gets fainter as you increase the number of digits. However, you should be able to drive 8 digits just fine.

I would try to wrap your counter explicitely to make sure you drive a specific digit at any given time:

    if(count1 = 249999) then  -- ATTENTION HERE
        A_counter <= A_counter + 1;
        if(A_counter < 6) then -- 6 or 4, depending on how many digits you drive
            A_counter <= A_counter + 1;
        else
            counter <= 0;
        end if;
        count1 <= 0;
    end if;
\$\endgroup\$
2
\$\begingroup\$

It looks like in the 6 digit code you have A_COUNTER cycling continuously which means there are at least 2 states, state 6 and state 7, which are not being explicitly decoded. Try explicitly turning off all segments for states 6 and 7. If A_COUNTER is more than 3 bits then you need to figure out what is happening to the display when A_COUNTER is not 0 to 5.

Since the display enables are active low (0=on) it is likely that all segments are turned on by default whenever you don't tell them to turn off, as may be happening in states 6 and 7.

As a diagnostic approach maybe you can increase COUNT1 so large that the digits change extremely slowly, so you can watch the illumination steps in slow motion.

I am not sure that there are extra cases 6 and 7. But since the 2 unused digits (far left) are turned on with all segments lit, it seems some digits/segments are lit by default if you don't turn them off. If there are only 6 cases, and 1 digit is enabled for each, then there should be no time for digits 6 and 7 to be on, but they are on. I believe that both the row and segment are receiving (00000000,00000000) by default for some short interval and turning on all digits and all segments.

Test this by outputting digit enable values with 8 binary digits (11xxxxxx) rather than 6 (xxxxxx) so the upper 2 unused digits are turned off. The leftmost 2 digits will be dimmer, but still partially lit.

\$\endgroup\$
  • \$\begingroup\$ When there are undecoded cases, Xilinx gives error. Are you sure there are state 6 and state 7. Because counter1 is defined as an integer range from 0 to 5. \$\endgroup\$ – ErenL May 16 '17 at 6:33
  • \$\begingroup\$ Updated answer. \$\endgroup\$ – Entrepreneur May 16 '17 at 11:26
1
\$\begingroup\$

There are some issues with your code which I would suggest you fix to simplify debugging. Firstly you have duplicated the cathode [segment] decoding several times - this needs to be done only once - I would suggest a process which has the current decimal digit as a signal on the sensitivity list and sets the segments. The main clock driven process would then be much simpler without the duplicated decoding. In practice the synthesis tools will probably efficiently map such decoding to a RAM loop up table on the FPGA - they may not be able to do that for your code e.g.

The main clock driven routing then cycles round setting the appropriate decimal signal and anode signal. My approach would be to initialise the anode output to "111110" and cyclically shift this left on every clock cycle in the clocked process and put in logic to set the appropriate digit signal to display.

What isn't clear is what clock you are using to drive this process. It shouldn't probably be at the 100MHz or so system clock if driving LEDs - I would suggest running it at about 1kHz or so.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.