Tengo lecciones sobre VHDL en una de mis clases de la universidad y tengo que escribir de forma simple entity
que generará un reloj a partir de una fuente de 1MHz. Estoy usando CoolRunner-II CPLD Starter Kit con ISE Webpack 13.1.
Cuando ejecuto la simulación de mi código, obtengo resultados extraños. No tengo idea, dónde está el problema. Mi entidad VHDL se ve así:
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;
La entrada es una señal de 1MHz del oscilador y quiero crear una señal de salida de 1MHz, 500kHz, 100kHz, 1kHz y 1Hz. Definí varias señales:
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';
Y finalmente, mi código es:
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
Cuando ejecuto la simulación, obtuve estos resultados extraños:
¿Qué está mal con mi código?
Lo primero que veo, que probablemente no sea la causa de su problema, es la falta de cualquier tipo de reinicio. ModelSim no declara automáticamente que todas las señales sean '0', y tratar de decir s <= not s cuando s no es 1 o 0 no le dará lo que desea. Veo que los declara todos '0' en la parte superior, pero un circuito adecuado tendría una entrada de reinicio que maneja brevemente al comienzo de su simulación.
Su proceso de contador básico se ve mal; básicamente, cuando el conteo llega a diez, está emitiendo un '1' y durante los otros 9/10 del tiempo está emitiendo un '0' (para el ejemplo de 100k, el ejemplo de 1Hz sería un pulso alto de 1us y un 999us poco tiempo Creo que lo que quieres es algo como esto:
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;
Tenga en cuenta varias cosas:
No estoy incrementando todo el tiempo. Incremento si el conteo no está al máximo, y lo incremento de lo contrario.
Estoy alternando el reloj de salida cuando se alcanza el conteo máximo
Incluí un reinicio asíncrono (con borrado síncrono); esto garantiza que sus señales se inicialicen correctamente y no tengan problemas de metaestabilidad cuando se libera el reinicio.
También mencionas que las otras secciones son iguales. Creo que tienes un problema con varios controladores como el que mencionó Yann. Verifique una y otra vez su código para asegurarse de que no está asignando la salida en dos procesos diferentes, porque eso es exactamente lo que la simulación dice que está haciendo. Es mejor hacer un módulo contador genérico o...
¿Por qué tantos contadores? Todos sus divisores de frecuencia se pueden manejar con un solo conteo y luego "quitar" las condiciones para hacer las divisiones que le interesan. También puede tener un solo contador y usar el operador (módulo) para manejar cada caso de divisor mod
.
Finalmente, también usaría tipos reales o enteros para el conteo en lugar de std_logic_vector
s, pero solo soy yo.
if rising_edge(clk) then if ce_100k = '1' then ... end if; end if;
) en lugar de crear nuevos relojes ( if rising_edge(clk100k) then ... end if;
) y hay diferentes formas de optimizar el sistema como señaló @DavidKessner, pero creo que lo que sugerí fue el mejor "propósito general" y el consejo "más seguro". y consejos que tienen muchas posibilidades de hacer lo que necesita.Estás asignando señales clk_1M, clk_500k, clk_100k, clk_1k y clk_1hz en diferentes procesos en el banco de pruebas. Al mismo tiempo, ha creado una instancia de su DUT que (como sugiere Yann Vernier) genera las mismas señales. Descomente los procesos del banco de pruebas (¡excepto clk_in!) y estará bien.
Además, le aconsejaría que agregue una señal de reinicio asíncrono a la entidad del reloj para que sea sintetizable.
Tienes varios conductores. No se muestran en los fragmentos de código publicados, pero son evidentes en los archivos no fragmentados .
Mirando el archivo test_clock.vhd, crea una instancia de su unidad bajo prueba. En el mapa de puertos, asigna una salida de clock() a clk_1M. Más tarde, tienes este trozo de código:
clk_1M_process :process
begin
clk_1M <= '0';
wait for clk_1M_period/2;
clk_1M <= '1';
wait for clk_1M_period/2;
end process;
Este código también asigna un valor a clk_1M; por lo tanto, tiene varios controladores en sus señales.
Otras señales tienen problemas similares, así que no los revisaré aquí.
No lo veo en los fragmentos de código, pero la simulación se parece mucho a que tiene varios controladores para algunas señales. Cuando están de acuerdo, obtienes un nivel lógico, pero cada vez que no están de acuerdo, obtienes X: un conflicto en la simulación, que probablemente no sea sintetizable (si lo fuera, significaría una fritura corta). Una suposición es que es posible que haya cometido un error en alguna parte al copiar ese proceso de divisor de reloj, y le vendría bien un componente que podría instanciar en su lugar.
vasco