我对VHDL和硬件设计非常陌生,并且想知道是否有人能告诉我,如果我对我遇到的以下问题的理解是正确的。
我一直在为Nexys4板制作一个简单的BCD到7段显示驱动程序 - 这是我的VHDL代码(标题被剥离)。
entity BCDTo7SegDriver is
Port ( CLK : in STD_LOGIC;
VAL : in STD_LOGIC_VECTOR (31 downto 0);
ANODE : out STD_LOGIC_VECTOR (7 downto 0);
SEGMENT : out STD_LOGIC_VECTOR (6 downto 0));
function BCD_TO_DEC7(bcd : std_logic_vector(3 downto 0))
return std_logic_vector is
begin
case bcd is
when "0000" => return "1000000";
when "0001" => return "1111001";
when "0010" => return "0100100";
when "0011" => return "0110000";
when others => return "1111111";
end case;
end BCD_TO_DEC7;
end BCDTo7SegDriver;
architecture Behavioral of BCDTo7SegDriver is
signal cur_val : std_logic_vector(31 downto 0);
signal cur_anode : unsigned(7 downto 0) := "11111101";
signal cur_seg : std_logic_vector(6 downto 0) := "0000001";
begin
process (CLK, VAL, cur_anode, cur_seg)
begin
if rising_edge(CLK) then
cur_val <= VAL;
cur_anode <= cur_anode rol 1;
ANODE <= std_logic_vector(cur_anode);
SEGMENT <= cur_seg;
end if;
-- Decode segments
case cur_anode is
when "11111110" => cur_seg <= BCD_TO_DEC7(cur_val(3 downto 0));
when "11111101" => cur_seg <= BCD_TO_DEC7(cur_val(7 downto 4));
when "11111011" => cur_seg <= BCD_TO_DEC7(cur_val(11 downto 8));
when "11110111" => cur_seg <= BCD_TO_DEC7(cur_val(15 downto 12));
when "11101111" => cur_seg <= BCD_TO_DEC7(cur_val(19 downto 16));
when "11011111" => cur_seg <= BCD_TO_DEC7(cur_val(23 downto 20));
when "10111111" => cur_seg <= BCD_TO_DEC7(cur_val(27 downto 24));
when "01111111" => cur_seg <= BCD_TO_DEC7(cur_val(31 downto 28));
when others => cur_seg <= "0011111";
end case;
end process;
end Behavioral;
现在,起初我试图从约束文件中定义的电路板时钟中天真地驱动这个电路:
## Clock signal
##Bank = 35, Pin name = IO_L12P_T1_MRCC_35, Sch name = CLK100MHZ
set_property PACKAGE_PIN E3 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports clk]
这给了我七段显示器上几乎是垃圾输出的样子 - 看起来每个解码数字都叠加到每个数字位置。基本上,如果被解码的值的第3位0是“0001”,则显示器连续显示8个1而不是00000001(但不完全 - 其他部分被点亮但看起来更暗)。
将时钟减慢到更合理的水平,这个技巧和电路的工作方式与我的预期相符。
当我看到精心设计给我的时候(我正在使用Vivado 2014.1),它给了我一个VAL并联8个RTL_ROM的电路(每个解码4位输入)。这些ROM的输出被送入RTL_MUX,cur_anode的值被用作选择器。 RTL_MUX的输出提供cur_val寄存器;然后将cur_val和cur_anode寄存器链接到输出。
那么,考虑到这一点,电路的哪个部分无法处理时钟频率?根据我的阅读,我觉得这与我可能需要添加的时序约束有关;我在想正确的方向吗?
答案 0 :(得分:2)
您的计时报告是否表明您有计时问题?在我看来,你只是非常快速地浏览分段值。无论您为更高的时钟速度设计得多好,每个时钟周期都会旋转cur_anode
,因此您的显示会相应改变。如果你的时钟太快,显示器的变化将比人类能够读取的速度快得多。
其他一些建议:
您应该将单个进程拆分为单独的时钟和非时钟进程。并不是说你所做的事情最终不会合成(很明显),但这是非常规的,并可能导致意想不到的结果。
您在cur_seg
上的初始化确实无法执行任何操作,因为它始终由您的流程驱动(组合)。这不是问题 - 只是想确保你知道。
答案 1 :(得分:2)
这有两个部分。
你的片段看起来很模糊,因为你基本上以1/8占空比运行它们的速度比片段有时间反应的速度更快(每个时钟脉冲你正在改变哪个片段点亮然后你停止驱动它在下一个脉冲)。
通过将瞬态电流(段需要时间加速)切换到稳态电流来增加段的亮度(当驱动段慢于其固有驱动频率时,电流会更长,让电流达到所需的水平)。因此亮度增加。
关于你的代码的另一件事。您可能已经意识到这一点,但当您在那里锁定时钟时,标记为cur_anode的变量会提前并实际上代表NEXT阳极。您还可以分别将ANODE和SEGMENT锁定到当前阳极和段。只是指出cur_anode可能是用词不当(并且因为它通常是NEXT而令人困惑)。
答案 2 :(得分:2)
请记住Paul Seeb和fru1bat关于时钟速度的答案,Paul对NEXT阳极的评论,以及fru1bat关于分离时钟和非时钟进程的建议正如你注意到你有8个ROM,有其他架构。
带有ANODE环形计数器和多个ROM的架构恰好是速度的最佳选择,因为Paul和fru1bat都不需要注意。相反,你可以优化面积。
由于时钟速度是外部的,或者是通过添加定期提供的启用来控制的,因此在区域优化中无法解决:
architecture foo of BCDTo7SegDriver is
signal digit: natural range 0 to 7; -- 3 bit binary counter
signal bcd: std_logic_vector (3 downto 0); -- input to ROM
begin
UNLABELED:
process (CLK)
begin
if rising_edge(CLK) then
if digit = 7 then -- integer/unsigned "+" result range
digit <= 0; -- not tied to digit range in simulation
else
digit <= digit + 1;
end if;
SEGMENT_REG:
SEGMENT <= BCD_TO_DEC7(bcd); -- single ROM look up
ANODE_REG:
for i in ANODE'range loop
if digit = i then
ANODE(i) <= '0';
else
ANODE(i) <= '1';
end if;
end loop;
end if;
end process;
BCD_MUX:
with digit select
bcd <= VAL(3 downto 0) when 0,
VAL(7 downto 4) when 1,
VAL(11 downto 8) when 2,
VAL(15 downto 12) when 3,
VAL(19 downto 16) when 4,
VAL(23 downto 20) when 5,
VAL(27 downto 24) when 6,
VAL(31 downto 28) when 7;
end architecture;
这会将32位寄存器(cur_val
),一个8位环形计数器(cur_anode
)以及函数BCD_TO_DEC7
所暗示的七个ROM副本换成三位二进制计数器
事实上,关于你是否应该使用单独的顺序(时钟)和组合(非时钟)过程的争论有点让人想起Liliput和Blefuscu对Endian-ness的战争。
由于不共享敏感度列表,单独的进程通常执行效率更高一些。您还可以注意到所有并发语句都具有进程或块语句等效项。在这种设计中也没有任何东西能够特别利用变量,这些变量可以在暗示单个过程的同时实现更有效的模拟。 (XST不支持共享变量)。
我还没有证实这将合成但是在阅读了XST用户指南的14.1版本后认为应该。如果没有,您可以将digit
转换为长度为3的std_logic_vector。
+ 1
的{{1}}将得到优化,增量小于完整加法器。