I have lessons about VHDL in one of my university class and I have to write simple entity
which will generate clock from 1MHz source. I'm using CoolRunner-II CPLD Starter Kit with ISE Webpack 13.1.
When I run simulation of my code, I've got odd results. I have no idea, where the problem is. My VHDL entity looks like this:
entity clock is
Port ( clk_in : in STD_LOGIC;
clk_1M : out STD_LOGIC;
clk_500k : out STD_LOGIC;
clk_100k : out STD_LOGIC;
clk_1k : out STD_LOGIC;
clk_1hz: out STD_LOGIC);
end clock;
Input is 1MHz signal from oscilator and I want to create 1MHz, 500kHz, 100kHz, 1kHz and 1Hz output signal. I defined several signals:
signal c100k: std_logic_vector(3 downto 0) := (others => '0' );
signal c1k: std_logic_vector(9 downto 0) := (others => '0' );
signal c1hz: std_logic_vector(9 downto 0) := (others => '0' );
--
signal c500k_out: std_logic := '0';
signal c100k_out: std_logic := '0';
signal c1k_out: std_logic := '0';
signal c1hz_out: std_logic := '0';
And finally, my code is:
process (clk_in) begin
if clk_in'event and clk_in = '1' then
-- 500kHz
c500k_out <= not c500k_out;
end if;
end process;
process (clk_in) begin
if clk_in'event and clk_in = '1' then
-- 100kHz
c100k <= c100k + '1';
if c100k = X"A" then
c100k <= (others => '0' );
c100k_out <= '1';
else
c100k_out <= '0';
end if;
end if;
end process;
--
-- Code for 1kHz and 1Hz is same as 100kHz
--
clk_1M <= clk_in; -- Clock source 1Mhz
clk_500k <= c500k_out; -- Clock source 500kHz
clk_100k <= c100k_out; -- Clock source 100kHz
clk_1k <= c1k_out; -- Clock source 1kHz
clk_1hz <= c1hz_out; -- Clock source 1Hz
When I run simulation, I got this odd results:
What is wrong with my code?
Answer
The first thing I see, which isn't likely causing your problem, is a lack of any kind of reset. ModelSim does not automatically declare all signals to be '0', and trying to say s <= not s when s is not 1 or 0 is not going to give you what you want. I see you declaring them all '0' at the top but a proper circuit would have a reset input that you briefly drive at the start of your simulation.
Your basic counter process looks wrong; basically when the count reaches ten you're outputting a '1' and for the other 9/10ths of the time you're outputting a '0' (for the 100k example, the 1Hz example would be a 1us pulse high and a 999us low time. I think what you want is something like this:
gen_clk100: process(clk, rst)
begin
if rising_edge(clk) then
if count = 10 then
clk100 <= not clk100;
count <= 0;
else
count <= count + 1;
end if;
end if;
if rst = '1' then
clk100 <= '0';
count <= 0;
end if;
end process;
Note several things:
I'm not incrementing all the time. I increment if the count is not at its max, and increment otherwise.
I'm toggling the output clock when the maximum count is reached
I've included an asynchronous reset (with synchronous clear) -- this ensures that your signals initialize correctly and have no metastability problems when reset is released.
You also mention that the other sections are the same. I think you're having a problem with multiple drivers like Yann mentioned. Check and double-check your code to make sure you are not assigning the output in two different processes, because that is exactly what the simulation is saying you're doing. Better to either make a generic counter module or...
Why so many counters? All your frequency dividers can be handled with a single count and then "peeling off" the conditions to do the divisions you're interested in. You could also have a single counter and use the mod
(modulus) operator to handle each divider case.
Finally, I'd also use real or integer types for the count instead of std_logic_vector
s but that's just me.
No comments:
Post a Comment