PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : VHDL problem


Drill
2012-05-17, 18:28:30
hi,
muss für die uni eine stopuhr in VHDL programmieren und diese anschließend auf einem FPGA testen.

habe keinerlei programmiererfahrung und kämpfe mich halt so ein wenig durch.
im prinzip gibt man dem zähler eine 50Mhz clock des FPGAs als externes signal und lässt in dann jede sekunde um eins inkrementieren.

das funkioniert auch soweit, dass problem was ich habe, ist dass ich die stopuhr über einen button auf dem FPGA starten soll (und stoppen bzw zurücksetzen). bei mir zählt er aber nur hoch solange ich den button gedrückt halte. er soll aber zählen, wenn ich einmal drücke und aufhören wenn ich noochmals drücke.
wie realisiere ich das?

im folgenden mein code

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity myCounter is port(
clk, rst, startStop : in std_logic;
countOut : out std_logic_vector(7 downto 0));
end myCounter;

architecture behavioral of myCounter is
signal clkTemp : std_logic_vector(30 downto 0);
signal counterTemp : std_logic_vector(7 downto 0);

begin
process(clk, rst, startStop)
begin
if rst = '0' or then
counterTemp <= (others => '0');
elsif rising_edge(clk) and startStop = '0' then
if clkTemp >= 50000000 then
counterTemp <= counterTemp + 1;
clkTemp <= (others => '0');
else
clkTemp <= clkTemp + 1;
end if;
end if;
end process;
countOut <= counterTemp;
end behavioral;

mir ist klar das es an : "elsif rising_edge(clk) and startStop = '0' then"
liegt, da er von da an den code nur ausführt wenn startStop = 0 ist.
ich weiß aber nicht wie ich das sonst realisieren soll (wie gesagt 0 programmiererfahrung).

jemand vorschläge?

Coda
2012-05-17, 19:29:25
Darf man fragen was du studierst, wo man VHDL ohne Programmiererfahrung schreiben soll?

Drill
2012-05-17, 19:51:29
Darf man fragen was du studierst, wo man VHDL ohne Programmiererfahrung schreiben soll?


mikrosystemtechnik :smile:
dieses hardwarepraktikum ist ein wahlfach (für die infos bei uns glaube ich ein plichtpraktikum im 2ten semester) in dem es halt darum geht den grundlegenden umgang mit VHDL zu lernen. fand es halt ganz interessant.

hättest du auch eine antwort auf meine frage (so trivial das für dich auch sein mag?)

Coda
2012-05-17, 20:41:47
Du brauchst ein Flip-Flop, das den Zustand hält ("zählen" oder "stop"). Das dürfte in euren Vorlesungsunterlagen beschrieben sein, den genauen VHDL-Syntax kenne ich leider auch nicht.

Senior Sanchez
2012-05-18, 01:36:33
Du solltest das Drücken des Tasters in einer Variable (wird realisiert durch das angesprochene Flip-Flop) speichern statt es über Signals abzufragen.

http://www.gmvhdl.com/variable.htm

GloomY
2012-05-19, 14:25:14
Du solltest das Drücken des Tasters in einer Variable (wird realisiert durch das angesprochene Flip-Flop) speichern statt es über Signals abzufragen.

http://www.gmvhdl.com/variable.htmHmm, Variablen sind Prozess-intern. Solange er in der Entity nur einen Prozess hat, ist das sicher unproblematisch, aber prinzipiell sollte man schon Signale für die Zustandsspeicherung verwenden - allein schon deshalb weil man nur Signale nach "außen" (also zu den Ports der Entity) führen kann und keine Variablen.

In etwa so (Vorsicht, ungetestet!):

entity myCounter is port(
clk, rst, startStop : in std_logic;
countOut : out std_logic_vector(7 downto 0));
end myCounter;

architecture behavioral of myCounter is
signal clkTemp : std_logic_vector(30 downto 0);
signal counterTemp : std_logic_vector(7 downto 0);
signal running : std_logic;

begin

process(clk, rst, startStop)
variable r : std_logic;
variable counter : std_logic_vector(7 downto 0);
variable divider : std_logic_vector(30 downto 0);
begin
r := running;
counter := counterTemp;
divider := clkTemp;

if rst = '0' then
counter := (others => '0');
r := '0';
divider := (others => '0');
elsif rising_edge(clk) and startStop = '0' then
r := not r; -- this infers a Flip-Flop
end if;

if r = '1' then
divider := divider + 1;
if divider >= 50000000 then
counter := counter + 1;
divider := (others => '0');
end if;
end if;

running <= r;
counterTemp <= counter;
clkTemp <= divider;

end process;


countOut <= counterTemp;
end behavioral;Beim Coding-Style sollte man sich angewöhnen nur genau eine Zuweisung der Signale am Ende eines Prozesses zu machen. Den Rest zwischendrin macht man mit Variablen, die man am Anfang des Prozesses mit den Werten der Signale initialisiert hat. Das vergrößert zwar die Anzahl an Unbekannten (Variablen und Signale) im Code, man hat dadurch aber nie das Problem, dass man den Wert eines Signals irgendwo zwischendrin zuweist und diesen dann später wieder abfragt und somit noch den "alten" Wert bekommt (Signale werden erst am Ende des Prozesses aktualisiert).

Und für Konstanten (50000000) definiert man normalerweise eine 'constant' mit entsprechendem Namen (z.B. FPGA_clk) und packt alle davon in ein Package rein, so dass man diese an einer zentralen Stelle editieren kann (Single point of maintenance).

Drill
2012-05-19, 15:53:25
Hmm, Variablen sind Prozess-intern. Solange er in der Entity nur einen Prozess hat, ist das sicher unproblematisch, aber prinzipiell sollte man schon Signale für die Zustandsspeicherung verwenden - allein schon deshalb weil man nur Signale nach "außen" (also zu den Ports der Entity) führen kann und keine Variablen.

In etwa so (Vorsicht, ungetestet!):

entity myCounter is port(
clk, rst, startStop : in std_logic;
countOut : out std_logic_vector(7 downto 0));
end myCounter;

architecture behavioral of myCounter is
signal clkTemp : std_logic_vector(30 downto 0);
signal counterTemp : std_logic_vector(7 downto 0);
signal running : std_logic;

begin

process(clk, rst, startStop)
variable r : std_logic;
variable counter : std_logic_vector(7 downto 0);
variable divider : std_logic_vector(30 downto 0);
begin
r := running;
counter := counterTemp;
divider := clkTemp;

if rst = '0' then
counter := (others => '0');
r := '0';
divider := (others => '0');
elsif rising_edge(clk) and startStop = '0' then
r := not r; -- this infers a Flip-Flop
end if;

if r = '1' then
divider := divider + 1;
if divider >= 50000000 then
counter := counter + 1;
divider := (others => '0');
end if;
end if;

running <= r;
counterTemp <= counter;
clkTemp <= divider;

end process;


countOut <= counterTemp;
end behavioral;Beim Coding-Style sollte man sich angewöhnen nur genau eine Zuweisung der Signale am Ende eines Prozesses zu machen. Den Rest zwischendrin macht man mit Variablen, die man am Anfang des Prozesses mit den Werten der Signale initialisiert hat. Das vergrößert zwar die Anzahl an Unbekannten (Variablen und Signale) im Code, man hat dadurch aber nie das Problem, dass man den Wert eines Signals irgendwo zwischendrin zuweist und diesen dann später wieder abfragt und somit noch den "alten" Wert bekommt (Signale werden erst am Ende des Prozesses aktualisiert).

Und für Konstanten (50000000) definiert man normalerweise eine 'constant' mit entsprechendem Namen (z.B. FPGA_clk) und packt alle davon in ein Package rein, so dass man diese an einer zentralen Stelle editieren kann (Single point of maintenance).


an der stelle "if rst = '0' then" wirft er mir beim kompilieren folgenden fehler aus: "Error (10818): Can't infer register for "r" at myCounter.vhd(27) because it does not hold its value outside the clock edge"

danke für deine mühe

Gast
2012-05-19, 18:24:02
Habe einen Zustandsautomaten eingefügt der die Flanke von deinem Start-Stop-Signal auswertet. Hoffe es hilft dir weiter. Hast du Zugriff auf einen Simulator wie z.B. ModelSim?

---------------------- library -----------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

---------------------- entity ------------------------------------
entity myCounter is port(
clk, rst, startStop : in std_logic;
countOut : out std_logic_vector(7 downto 0));
end myCounter;

---------------------- architecture ------------------------------
architecture behavioral of myCounter is

---------------------- types -------------------------------------
type state_s is (state1, state2, state3, state4);

---------------------- signals -----------------------------------
signal clkTemp : std_logic_vector(30 downto 0);
signal startStopTemp : std_logic;
signal counterTemp : std_logic_vector(7 downto 0);

signal current_s : state_s;
signal next_s : state_s;

------------------------------------------------------------------
begin
process(clk, rst, startStopTemp)
begin
if rst = '0' then
counterTemp <= (others => '0');
elsif rising_edge(clk) and startStopTemp = '0' then
if clkTemp >= 50000000 then
counterTemp <= counterTemp + 1;
clkTemp <= (others => '0');
else
clkTemp <= clkTemp + 1;
end if;
end if;
end process;
countOut <= counterTemp;

------------------------------------------------------------------

fsm_reg: process(clk, rst)
begin
if rising_edge(clk) then
if rst = '0' then
current_s <= state1;
else
current_s <= next_s;
end if;
end if;
end process fsm_reg;

fsm_in: process(current_s, startStop)
begin

next_s <= current_s; -- Default

case current_s is
when state1 =>
if startStop = '0' then -- Fallende Flanke erkannt -> Zähler eingeschalten
next_s <= state2;
end if;
when state2 =>
if startStop = '1' then -- Steigende Flanke erkannt
next_s <= state3;
end if;
when state3 =>
if startStop = '0' then -- Fallende Flanke erkannt -> Zähler ausgeschalten
next_s <= state4;
end if;
when state4 =>
if startStop = '1' then -- Steigende Flanke erkannt
next_s <= state1;
end if;
end case;
end process fsm_in;

fsm_out: process(current_s)
begin
case current_s is
when state1 =>
startStopTemp <= '1'; -- Zähler stoppt
when state2 =>
startStopTemp <= '0'; -- Zähler läuft
when state3 =>
startStopTemp <= '0'; -- Zähler läuft
when state4 =>
startStopTemp <= '1'; -- Zähler stoppt
end case;
end process fsm_out;

end behavioral;

Drill
2012-05-19, 22:09:30
Habe einen Zustandsautomaten eingefügt der die Flanke von deinem Start-Stop-Signal auswertet. Hoffe es hilft dir weiter. Hast du Zugriff auf einen Simulator wie z.B. ModelSim?


ja habe ich, aber kann das hier direkt über LEDs auf dem FPGA testen.

funktioniert anscheinend, auch wenn ich erstmal durchsteigen muss, was du da gemacht hast ;)
danke für deine mühe.

GloomY
2012-05-20, 15:47:12
an der stelle "if rst = '0' then" wirft er mir beim kompilieren folgenden fehler aus: "Error (10818): Can't infer register for "r" at myCounter.vhd(27) because it does not hold its value outside the clock edge"Ah okay, ich hab's nicht kompiliert sondern nur aus dem Kopf ein paar Zeilen Code hingeschrieben. Ich werde heute abend mal wieder ISE anwerfen und schauen, was das ausgibt.

Ich verstehe die Fehlermeldung nicht ganz. Die einzige Stelle, an der r außerhalb der "if rising_edge(clk)"-Region geändert wird ist der Reset, der ja anscheinend asynchron sein soll. Also muss das Synthesetool nur raffen, dass der Ausgang von r eben noch mit "rst" verundet werden muss.

Von welcher Synthese-Software stammt die Fehlermeldung?

Drill
2012-05-20, 18:31:43
Von welcher Synthese-Software stammt die Fehlermeldung?

Quartus II

GloomY
2012-05-21, 02:03:03
Quartus IIOkay, mit ISE 12.4 geht es, jedoch kommt ziemlicher Müll dabei heraus (Latches statt Flip-Flops). Ich habe den Code nochmal umgeschrieben und ausprobiert. Bei mir kommen hier 42 FF raus:

architecture behavioral of myCounter is

signal counterTemp : std_logic_vector(7 downto 0);
signal running : std_logic;

begin

process(clk, rst, startStop, counterTemp, running)
variable counter : std_logic_vector(7 downto 0);
variable divider : std_logic_vector(31 downto 0);
variable r, lastStartStop : std_logic;
begin
r := running;
counter := counterTemp;

if rising_edge(clk) then
if ((startStop = '0') and (lastStartStop = '1')) or
((startStop = '1') and (lastStartStop = '0'))
then
r := not r;
end if;
lastStartStop := startStop;

if r = '1' then
divider := divider + 1;
if divider >= 50000000 then
counter := counter + 1;
divider := (others => '0');
end if;
end if;

counterTemp <= counter;
running <= r;
end if;

if rst = '0' then
counter := (others => '0');
r := '0';
divider := (others => '0');
lastStartStop := '1';
end if;

end process;


countOut <= counterTemp;
end behavioral;Der Gast hat eine Statemaschine gebaut, die den Flankenwechsel erkennt. Etwas Ähnliches habe ich auch gemacht (siehe nach dem "if rising_edge(clk)"). :)

Drill
2012-05-22, 18:34:00
Okay, mit ISE 12.4 geht es, jedoch kommt ziemlicher Müll dabei heraus (Latches statt Flip-Flops). Ich habe den Code nochmal umgeschrieben und ausprobiert. Bei mir kommen hier 42 FF raus:

architecture behavioral of myCounter is

signal counterTemp : std_logic_vector(7 downto 0);
signal running : std_logic;

begin

process(clk, rst, startStop, counterTemp, running)
variable counter : std_logic_vector(7 downto 0);
variable divider : std_logic_vector(31 downto 0);
variable r, lastStartStop : std_logic;
begin
r := running;
counter := counterTemp;

if rising_edge(clk) then
if ((startStop = '0') and (lastStartStop = '1')) or
((startStop = '1') and (lastStartStop = '0'))
then
r := not r;
end if;
lastStartStop := startStop;

if r = '1' then
divider := divider + 1;
if divider >= 50000000 then
counter := counter + 1;
divider := (others => '0');
end if;
end if;

counterTemp <= counter;
running <= r;
end if;

if rst = '0' then
counter := (others => '0');
r := '0';
divider := (others => '0');
lastStartStop := '1';
end if;

end process;


countOut <= counterTemp;
end behavioral;Der Gast hat eine Statemaschine gebaut, die den Flankenwechsel erkennt. Etwas Ähnliches habe ich auch gemacht (siehe nach dem "if rising_edge(clk)"). :)

werds morgen mal testen, danke für deine mühe.