为什么我的Nexys3 FPGA板上的VHDL倒计时器在59和68之间切换?

huangapple go评论50阅读模式
英文:

Why does my VHDL countdown timer on Nexys3 FPGA board switch between 59 and 68?

问题

我在VHDL中创建了一个60秒倒计时器,并将其连接到nexys3 FPGA板上的7段显示器,但它不起作用。这是我大学课程的一个项目。

我并不是非常擅长VHDL或数字电子,但我已经使用学院提供的材料和一些互联网资料拼凑了一些代码。但它不起作用。它从60开始,倒计时到59,然后下一个时钟脉冲变成了68,再次倒计时到59,然后回到68,一直以这种循环模式运行。

an输出控制着四个7段显示器中的哪一个应该打开,seg是我想要输出到显示器的数字。temp_jed是个位数,temp_dek是十位数。我不知道为什么它表现得像这样,我已经向我的教授请教过,他说逻辑看起来没问题,让我自己找出问题所在。我不知道是不是我犯了一个愚蠢的逻辑错误,还是在语法和流程方面做错了什么?任何帮助将不胜感激。

英文:

I created a 60 second countdown timer in VHDL and connected it to the 7-seg displays on a nexys3 FPGA boar but it doesn't work. This is a project for my college class.

I'm not really skilled at VHDL or digital electronics at all, but I've managed to put together some code using college materials and a bit of internet. It doesn't work. It starts at 60, goes down to 59, next clock pulse goes to 68, counts down to 59 and back to 68 in a repeating pattern.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
 
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
 
entity kv_zad is
  port(
    rst, clk: in std_logic;
    an: out std_logic_vector(3 downto 0) := "1100";
    seg: inout std_logic_vector(6 downto 0) :="0000000"
  );
end kv_zad;
 
architecture Behavioral of kv_zad is
  signal temp_jed: std_logic_vector(3 downto 0);
  signal temp_dek: std_logic_vector(3 downto 0);
  signal clk_o: std_logic;
  signal clk_rf: std_logic;
  signal a: std_logic;
  begin
    s1: entity work.freqGen generic map(100_000_000) port map(clk, clk_o);
    s2: entity work.freqGen generic map(500_000) port map(clk, clk_rf);

    process(clk_rf)
    begin
      if (clk_rf'event and clk_rf='1') then
        a <= not a;
      end if;
    end process;

  process(rst, clk_o)
  begin
    if (rst = '0') then
      temp_jed <= "0000";
      temp_dek <= "0110";
      if (clk_o'event and clk_o='1') then
        if (temp_jed = "0000" and temp_dek = "0000") then
          temp_jed <= "0000";
          temp_dek <= "0000";
        elsif (temp_jed = "0000") then
          temp_dek <= temp_dek - 1;
          temp_jed <= "1001";
        else
          temp_jed <= temp_jed - 1;
        end if;
      end if;
    else
      temp_jed <= "0000";
      temp_dek <= "0110";
    end if;
  end process;
  with a select
    an <= "1110" when '0',
          "1101" when '1';
  process(temp_jed, temp_dek)
  begin
    if (a='0') then
      case temp_jed is
        when "0000" => seg <= "0000001";
        when "0001" => seg <= "1001111";
        when "0010" => seg <= "0010010";
        when "0011" => seg <= "0000110";
        when "0100" => seg <= "1101100";
        when "0101" => seg <= "0100100";
        when "0110" => seg <= "0100000";
        when "0111" => seg <= "0001111";
        when "1000" => seg <= "0000000";
        when "1001" => seg <= "0000100";
        when others => seg <= "0110000";
      end case;

    elsif (a='1') then

      case temp_dek is
        when "0000" => seg <= "0000001";
        when "0001" => seg <= "1001111";
        when "0010" => seg <= "0010010";
        when "0011" => seg <= "0000110";
        when "0100" => seg <= "1101100";
        when "0101" => seg <= "0100100";
        when "0110" => seg <= "0100000";
        when others => seg <= "0110000";
      end case;
    end if;
  end process;
end Behavioral;

the an output controls which of the 4 7-seg displays should be on and seg is the number I want to output to the display. temp_jed are the ones and temp_dek are the tens digits. I don't know why it behaves like it does, I've asked my professor and he said the logic looks fine to him and told me to figure it out. I don't know if I'm making a stupid logic mistake or am I doing something wrong with the syntax and the processes? Any help would be GREATLY appreciated.

答案1

得分: 1

尝试删除以下2行。问题出在clk_o上升沿时,temp_dek/tmep_jed被递减。但在下降沿时,它们被赋予默认值60,导致计数器失效。

      process(rst, clk_o)
      begin
        if (rst = '0') then
          temp_jed <= "0000";  -- 删除这一行
          temp_dek <= "0110";  -- 删除这一行
          if (clk_o'event and clk_o='1') then
英文:

Try to remove the following 2 lines. The problem is on the clk_o rising-edge, temp_dek/tmep_jed are decremented. But on falling-edge, they are assigned to default value 60 that causes the counter failure.

  process(rst, clk_o)
  begin
    if (rst = &#39;0&#39;) then
      temp_jed &lt;= &quot;0000&quot;;  -- Remove this
      temp_dek &lt;= &quot;0110&quot;;  -- Remove this
      if (clk_o&#39;event and clk_o=&#39;1&#39;) then

答案2

得分: 0

以下是要翻译的内容:

"一个缺失的其他选择或表达式类型转换在选择的信号分配状态中丢失,其目标是 'an':"

IEEE 标准 1076-1993
9.5.2 选择信号分配

选择的信号分配表示一个进程语句,其中信号变换是一个 case 语句。
...
选择分配语句中的选择表达式、波形和选择必须使等效进程语句中的 case 语句成为合法语句。

8.8 case 语句

如果表达式是一个局部静态子类型的对象名称,无论是标量类型还是数组类型,那么子类型的每个值必须在 case 语句的选择集中表示一次且仅一次,不允许其他值;如果表达式是一个限定表达式或类型转换,其类型标记表示局部静态子类型,或者表达式是对返回类型标记表示局部静态子类型的函数的调用,则同样应用此规则。

该类型转换可以采用形式 with To_bit(a) select...,其中转换函数在 IEEE 包 std_logic_1164 中定义,而不是其他选择。

您的问题还缺少一个最小、完整和可验证的示例,以演示问题,这里需要一个测试台驱动 rstclk,以及 freqGen 的实体声明和体系结构体,这些在使用保留字 entity 实例化组件之前应该已经被分析到工作库中。

这个过程有一些奇怪之处:

process(rst, clk_o)
  begin
    if (rst = '0') then
      temp_jed <= "0000";
      temp_dek <= "0110";
      if (clk_o'event and clk_o='1') then
        if (temp_jed = "0000" and temp_dek = "0000") then
          temp_jed <= "0000";
          temp_dek <= "0000";
        elsif (temp_jed = "0000") then
          temp_dek <= temp_dek - 1;
          temp_jed <= "1001";
        else
          temp_jed <= temp_jed - 1;
        end if;
      end if;
    else   -- if (rst = 0) then .../else 
      temp_jed <= "0000";
      temp_dek <= "0110";
    end if;
  end process;

乍一看,这似乎不适合综合,因为在时钟边沿条件之外存在一个异步赋值,而这不是异步复位。另请注意,时钟边沿条件仅在复位为 '0' 时在嵌套的 if 语句中进行评估。

一个由 temp_jed 和 temp_dek 计数器组成的两位十进制计数器只有在 temp_jed 从 "1001" 到 "0000" 时,temp_dek 才会递增。

TWO_DECADE_COUNTER:       -- 从 59 计数到 0,然后重复。
  process (rst, clk_o)
  begin
      if rst = '0' then
          temp_jed <= "1001";
          temp_dek <= "0101";
      elsif rising_edge(clk_o) then
          if temp_jed <= "0000" then
              temp_jed <= "1001";   -- 9
              if temp_dek <= "0000" then
                  temp_dek <= "0101";  -- 5
              else
                  temp_dek <= temp_dek - 1;
              end if;
          else
              temp_jed <= temp_jed - 1;
          end if;
      end if; 
  end process;

设计模型(freqGen 和测试台)已被修改为在相同的秒数内运行时使用更慢的时钟。这样做的目的是在仿真期间不存储几乎完全由时钟转换填充的吉比字节范围的波形转储文件。理想情况下,两个 freqGen 实例的通用常量可以通过测试台中的通用常量传递,而忽略 freqGen 中的任何微妙之处。此外,阳极选择可以由上游位提供,用于一个单独的计数器的十年计数器递减。这将通过使用模数计数器来完成,以提供一个启用以获得十年计数器更新速率除以二的一半,从而获得十年计数器更新时钟。在这里,多路复用的阳极切换显示的数码刷新速率看起来太高。您的 Nexsys 3 用户指南应该解释了实际需要的内容。

在设计规范的顶级实体中使用模式 inout 端口也不是一个好主意。

在这里没有必要对 std_logic_vector 值进行算术运算。结果不会在端口上输出。

整个组合模型用于仿真:

library ieee;
use ieee.std_logic_1164.all;

entity freqGen is   -- 这是为了仿真而修改的
    generic (
        constant counts: positive := 100_000_000;  -- 在 100 MHz 时钟中
        constant scale:  positive := 1             -- 用于仿真时钟
    );
    port (
        clk:    in  std_logic;
        clk_o:  out std_logic
    );
end entity;

architecture scaled_clock of freqGen is
    constant MAX_COUNT: natural := counts/scale/2 - 1;
    signal counter: natural range 0 to MAX_COUNT := 0;   
         -- 带缩放时钟的半个 clk_o 周期
    signal clk_out: std_logic := '1'; 
begin
    process (clk)
    begin
        if rising_edge(clk) then
            if counter = MAX_COUNT then
                counter <= 0;
                clk_out <= not clk_out;
            else

<details>
<summary>英文:</summary>

There&#39;s a missing others choice or expression type conversion missing in the selected signal assignment state targeting `an`:

IEEE Std 1076-1993  
9.5.2 Selected signal assignments  

&gt;The selected signal assignment represents a process statement in which the signal transform is a case statement.  
&gt;...  
&gt;The characteristics of the select expression, the waveforms, and the choices in the selected assignment statement must be such that the case statement in the equivalent process statement is a legal statement.

8.8 Case statement  

&gt;If the expression is the name of an object whose subtype is locally static, whether a scalar type or an array type, then each value of the subtype must be represented once and only once in the set of choices of the case statement, and no other value is allowed; this rule is likewise applied if the expression is a qualified expression or type conversion whose type mark denotes a locally static subtype, or if the expression is a call to a function whose return type mark denotes a locally static subtype. 

That type conversion can be of the form `with To_bit(a) select`... with the conversion function defined in IEEE package std_logic_1164 in lieu of an others choice.

Your question is also missing a [minimal, complete, and verifiable example](https://stackoverflow.com/help/minimal-reproducible-example) demonstrating the problem which here would imply a testbench driving `rst` and `clk` as well as an entity declaration and architecture body for freqGen which would be required to have been analyzed into the working library prior to the component instantiations with the reserved word **entity**.

There&#39;s something peculiar about this process:

```vhdl
process(rst, clk_o)
  begin
    if (rst = &#39;0&#39;) then
      temp_jed &lt;= &quot;0000&quot;;
      temp_dek &lt;= &quot;0110&quot;;
      if (clk_o&#39;event and clk_o=&#39;1&#39;) then
        if (temp_jed = &quot;0000&quot; and temp_dek = &quot;0000&quot;) then
          temp_jed &lt;= &quot;0000&quot;;
          temp_dek &lt;= &quot;0000&quot;;
        elsif (temp_jed = &quot;0000&quot;) then
          temp_dek &lt;= temp_dek - 1;
          temp_jed &lt;= &quot;1001&quot;;
        else
          temp_jed &lt;= temp_jed - 1;
        end if;
      end if;
    else   -- if (rst = 0) then .../else 
      temp_jed &lt;= &quot;0000&quot;;
      temp_dek &lt;= &quot;0110&quot;;
    end if;
  end process;

At first look this doesn't appear synthesis eligible having an asynchronous assignment outside of the clock edge condition that isn't an asynchronous reset. Also note the clock edge condition is evaluated only when reset = '0' in a nested if statement.

A two decade counter comprised of counters temp_jed and temp_dek would have temp_dek only increment when temp_jed is going from "1001" to "000"

TWO_DECADE_COUNTER:       -- counts down from 59 to 0, then repeats.
  process (rst, clk_o)
  begin
      if rst = &#39;0&#39; then
          temp_jed &lt;= &quot;1001&quot;;
          temp_dek &lt;= &quot;0101&quot;;
      elsif rising_edge(clk_o) then
          if temp_jed &lt;= &quot;0000&quot; then
              temp_jed &lt;= &quot;1001&quot;;   -- 9
              if temp_dek &lt;= &quot;0000&quot; then
                  temp_dek &lt;= &quot;0101&quot;;  -- 5
              else
                  temp_dek &lt;= temp_dek - 1;
              end if;
          else
              temp_jed &lt;= temp_jed - 1;
          end if;
      end if; 
  end process;

The design model (freqGen and the testbench) has been modified to use a slower clock while running for the same time in seconds. The idea is to not store gigabyte range waveform dump files during simulation filled almost entirely with clock transitions. Ideally the generic constants to the two freqGen instances could be fed through generics in kv_zad from the testbench ignoring any slight of hand in freqGen. Also the anode selects can be fed from bits up stream in a single counter used for the decade counters decrement. This would be done by suing a modulo counter for the anode switch rate providing an enable to a ganged modulo counter to get to the decade counter update rate divided by two to get the decade counter update clock. Here the digit refresh rate for the multiplexed anode switched display looks way to high. Your Nexsys 3 userguide should address what's actually needed.

It's also not a good idea to use mode inout ports in the top level entity of a design specification undergoing synthesis.

There's no reason to do arithmetic on std_logic_vector values here. The results aren't output on ports.

The entire genned together model for simulation:

library ieee;
use ieee.std_logic_1164.all;

entity freqGen is   -- this is modified for simulation
    generic (
        constant counts: positive := 100_000_000;  -- in 100 MHz clocks
        constant scale:  positive := 1             -- for sim clock
    );
    port (
        clk:    in  std_logic;
        clk_o:  out std_logic
    );
end entity;

architecture scaled_clock of freqGen is
    constant MAX_COUNT: natural := counts/scale/2 - 1;
    signal counter: natural range 0 to MAX_COUNT := 0;   
         -- half clk_o period with scaled clock
    signal clk_out: std_logic := &#39;1&#39;; 
begin
    process (clk)
    begin
        if rising_edge(clk) then
            if counter = MAX_COUNT then
                counter &lt;= 0;
                clk_out &lt;= not clk_out;
            else
                counter &lt;= counter + 1;
            end if;
        end if;
    end process;
    clk_o &lt;= clk_out;
end architecture;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
 
entity kv_zad is
  port(
    rst, clk: in std_logic;
    an: out std_logic_vector(3 downto 0) := &quot;1100&quot;;
    seg: inout std_logic_vector(6 downto 0) :=&quot;0000000&quot;
  );
end kv_zad;
 
architecture Behavioral of kv_zad is
  signal temp_jed: std_logic_vector(3 downto 0);
  signal temp_dek: std_logic_vector(3 downto 0);
  signal clk_o: std_logic;
  signal clk_rf: std_logic;
  -- signal a: std_logic;
  signal a:     std_logic := &#39;0&#39;; -- CHANGED for SIMULATION a &lt;= not a;
  begin
    s1: entity work.freqGen generic map(100_000_000, 1000) port map(clk, clk_o);
    s2: entity work.freqGen generic map(500_000, 1000) port map(clk, clk_rf);

    process(clk_rf)
    begin
      -- if (clk_rf&#39;event and clk_rf=&#39;1&#39;) then -- CHANGED for SIMULATION
      if rising_edge(clk_rf) then
        a &lt;= not a;
      end if;
    end process;

  -- process(rst, clk_o)
  -- begin
  --   if (rst = &#39;0&#39;) then
  --     temp_jed &lt;= &quot;0000&quot;;
  --     temp_dek &lt;= &quot;0110&quot;;
  --     -- if (clk_o&#39;event and clk_o=&#39;1&#39;) then -- CHANGED for SIMULATION
  --     if rising_edge(clk_o) then
  --       if (temp_jed = &quot;0000&quot; and temp_dek = &quot;0000&quot;) then
  --         temp_jed &lt;= &quot;0000&quot;;
  --         temp_dek &lt;= &quot;0000&quot;;
  --       elsif (temp_jed = &quot;0000&quot;) then
  --         temp_dek &lt;= temp_dek - 1;
  --         temp_jed &lt;= &quot;1001&quot;;
  --       else
  --         temp_jed &lt;= temp_jed - 1;
  --       end if;
  --     end if;
  --   else
  --     temp_jed &lt;= &quot;0000&quot;;
  --     temp_dek &lt;= &quot;0110&quot;;
  --   end if;
  -- end process;

TWO_DECADE_COUNTER:       -- counts down from 59 to 0, then repeats.
  process (rst, clk_o)
  begin
      if rst = &#39;0&#39; then
          temp_jed &lt;= &quot;1001&quot;;
          temp_dek &lt;= &quot;0101&quot;;
      elsif rising_edge(clk_o) then
          if temp_jed &lt;= &quot;0000&quot; then
              temp_jed &lt;= &quot;1001&quot;;   -- 9
              if temp_dek &lt;= &quot;0000&quot; then
                  temp_dek &lt;= &quot;0101&quot;;  -- 5
              else
                  temp_dek &lt;= temp_dek - 1;
              end if;
          else
              temp_jed &lt;= temp_jed - 1;
          end if;
      end if; 
  end process;
  
  with to_bit(a) select  -- CHANGED, for standards compliance
    an &lt;= &quot;1110&quot; when &#39;0&#39;,
          &quot;1101&quot; when &#39;1&#39;;
  process(a, temp_jed, temp_dek)
  begin
    if (a = &#39;0&#39;) then
      case temp_jed is
        when &quot;0000&quot; =&gt; seg &lt;= &quot;0000001&quot;;
        when &quot;0001&quot; =&gt; seg &lt;= &quot;1001111&quot;;
        when &quot;0010&quot; =&gt; seg &lt;= &quot;0010010&quot;;
        when &quot;0011&quot; =&gt; seg &lt;= &quot;0000110&quot;;
        when &quot;0100&quot; =&gt; seg &lt;= &quot;1101100&quot;;
        when &quot;0101&quot; =&gt; seg &lt;= &quot;0100100&quot;;
        when &quot;0110&quot; =&gt; seg &lt;= &quot;0100000&quot;;
        when &quot;0111&quot; =&gt; seg &lt;= &quot;0001111&quot;;
        when &quot;1000&quot; =&gt; seg &lt;= &quot;0000000&quot;;
        when &quot;1001&quot; =&gt; seg &lt;= &quot;0000100&quot;;
        when others =&gt; seg &lt;= &quot;0110000&quot;;
      end case;

    elsif (a =&#39;1&#39;) then

      case temp_dek is
        when &quot;0000&quot; =&gt; seg &lt;= &quot;0000001&quot;;
        when &quot;0001&quot; =&gt; seg &lt;= &quot;1001111&quot;;
        when &quot;0010&quot; =&gt; seg &lt;= &quot;0010010&quot;;
        when &quot;0011&quot; =&gt; seg &lt;= &quot;0000110&quot;;
        when &quot;0100&quot; =&gt; seg &lt;= &quot;1101100&quot;;
        when &quot;0101&quot; =&gt; seg &lt;= &quot;0100100&quot;;
        when &quot;0110&quot; =&gt; seg &lt;= &quot;0100000&quot;;
        when others =&gt; seg &lt;= &quot;0110000&quot;;
      end case;
    end if;
  end process;
end Behavioral;

library ieee;
use ieee.std_logic_1164.all;

entity kv_zad_tb is
end entity;

architecture tb of kv_zad_tb is
    signal clk:     std_logic := &#39;0&#39;; 
    signal rst:     std_logic := &#39;1&#39;;
    signal an:      std_logic_vector(3 downto 0);
    signal seg:     std_logic_vector(6 downto 0); -- careful, no driver here
begin
DUT:
    entity work.kv_zad
        port map (
            clk =&gt; clk,
            rst =&gt; rst,
            an =&gt; an,
            seg =&gt; seg
        );
    
CLOCK:         -- from the freqGen generic 100 MHz for 1 sec display update
    process    -- we&#39;ll modify that and freqGen for faster simulation
    begin
        wait for 5000 ns;  -- 1000X slower clock, high or low interval
        clk &lt;= not clk;
        if now &gt; 65 sec then  -- end simulation by stopping clock
            wait;
        end if;
    end process;
RESET:
    process
    begin
        wait for 400 ns;
        rst &lt;= &#39;0&#39;;
        wait for 800 ns;
        rst &lt;= &#39;1&#39;;
        wait;
    end process;
end architecture;

The added generic scale can be removed from the component instantiations. It has a default value of 1.

The model produced a simulation waveform:
为什么我的Nexys3 FPGA板上的VHDL倒计时器在59和68之间切换?

This was done using ghdl and gtkwave on a 2020 Macbook Air M1 running MacOS Ventura 13.4, the restrictive SSD size the reason for trying to hold down the waveform dump file sizes. A simulation with a 100 MHz clock was very slow and had a 14 GB waveform dump file size before scaling the clock by 1000. The simulation speed up was also appreciated.

huangapple
  • 本文由 发表于 2023年6月1日 16:56:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/76380224.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定