Hallo, ich habe da ein Programm das bei Betätigung einer Taste Bits für die Zeit einer Registerlänge toggeln soll. Nur schaffe ich es nicht ganz sauber eine Variable die inkremetiert und am Ende noch abgefragt wird einzubauen. zB: Registerlänge n = 8 bits => wenn my_variable = n-1 setze ich das signal Off das defaultmäßig auf '0' ist auf '1'. Könnte mir jemand da ein Tipp geben. Grüße Rudi. Codeabschnitt: library ieee; use std.textio.all; use ieee.std_logic_textio.all; use ieee.std_logic_1164.all; use work.BER_Meas_pkg.all; entity ErrorOut is port( clock : in std_logic; reset : in std_logic; SerIn : in std_logic; -- Data input SingleErrorEna : in std_logic; -- Enable error generation BurstErrorEna : in std_logic; -- Enable error generation TxFault0Ena : in std_logic; -- Enable error generation TxFault1Ena : in std_logic; -- Enable error generation SingleErrorOff : out std_logic; -- Stop Error Enable BurstErrorOff : out std_logic; -- Stop Error Enable TxFault0Off : out std_logic; -- Stop Error Enable TxFault1Off : out std_logic; -- Stop Error Enable SerOut : out std_logic -- Tx Main output ); end entity; architecture ErrorOur_arch of ErrorOut is signal s_tmp: std_logic_vector(n-1 downto 0); begin reg_proc: process (clock,reset,SingleErrorEna,BurstErrorEna,TxFault0Ena,TxFault1Ena ) variable my_line : line; variable cntVal : integer := 0 ; begin if reset = '1' then s_tmp <= (others => '0'); SerOut <='0'; cntVal := 0 ; elsif rising_edge(clock) then s_tmp(0) <= SerIn; for i in 0 to n-2 loop s_tmp(i+1) <= s_tmp(i); end loop; if SingleErrorEna = '1' then cntVal := cntVal+1; SerOut <= not s_tmp(n-1); if cntVal = 1 then SingleErrorOff <= '1'; cntVal := 0; else SingleErrorOff <= '0'; end if; elsif BurstErrorEna = '1' then for i in 0 to n-1 loop SerOut <= not s_tmp(n-1); cntVal := cntVal+1; end loop; if cntVal = n-1 then BurstErrorOff <= '1'; cntVal := 0; else BurstErrorOff <= '0'; end if; elsif TxFault0Ena = '1' then for i in 0 to TxF_Len-1 loop s_tmp(n-1) <= '0'; cntVal := cntVal+1; end loop; if cntVal = TxF_len-1 then TxFault0Off <= '1'; cntVal := 0; else TxFault0Off <= '0'; end if; elsif TxFault1Ena = '1' then for i in 0 to TxF_Len-1 loop s_tmp(n-1) <= '1'; cntVal := cntVal+1; end loop; if cntVal = TxF_len-1 then TxFault1Off <= '1'; cntVal := 0; else TxFault1Off <= '0'; end if; SerOut <= s_tmp(n-1); end if; end if; end process; end architecture;
ICh habe nicht direkt eine Lösung für Dein Problem, aber einen Tipp: viele posten hier ganze Programme ohne genau zu erklären, was gemacht werden muss. Ich meine nur, es ist schwer durchzuschauen, was da gemacht wird. Allgemein zu VHDL: es ist nicht so toll mit verschachtelten elsif's zu hantieren. Schreib' lieber alles in CASE OF um. Zumindest kann man dann alles besser lesen. Ansonsten kann man was toggeln lassen mit ein Paar Zeilen VHDL-Code, ohne, dass Du noch jetzt extra signal s_tmp: std_logic_vector(n-1 downto 0); hast. Grüße, Kest
wenn ich das richtig verstanden hab weillst du nach einem tastendruck einfach eine zeitlang ein Bit blinken lassen. Das ganze hat mehrere eingänge. Was mir schon mal auffällt sind die for-schleifen im code, und das grausige else-if. Ich frag mich ehrlich ob das ding überhaupt funktioniert, bzw. synthetisiert werden kann. erstes problem ist schon mal, dass s_tmp nie aktualisiert wird(ist ja ein signal, und keine variable). Ich würde das ganze besser als FSM-D aufbauen, ist wesentlich einfacher. am besten nimmst du für die signale records, dann hast du nurnoch einen Reg und einen nextReg und in der sensitivity-list ist auch alles fein, irgendwo schwirrt ein dokument. Zum code. Der erste process ist der einzige der takt-gesteuert ist, er stellt ein einfaches register dar und übernimmt einfach zu bestimmten zeiten die Werte vom Eingang zum Ausgang. Der zweite process ist die combinatorik. Hier darf kein Takt vorkommen. Hier werden eingänge und die letzten Ausgangwerte berechnet, daraus ergibt sich der neue State bzw. rechenwert. architecture signal cnt : unsigned(7 downto 0); signal nextCnt : unsigned (7 downto 0); type astate is (idle, blinking); signal state : astate := idle; signal nextstate : astate := idle; signal blink: std_ulogic := '0'; signal nextblink: std_ulogic := '0'; constant max_cnt 20; begin Registers: process(iClk, nResetAsync) begin if nResetAsync then cnt <= 0; blink <= '0'; state <= idle else if rising_edge(iClk) then cnt <= newCnt; state <= nextstate; blink <= nextblink; end if; end process fsm: process(SingleErrorEna, BurstErrorEna,..) begin switch(state) when idle => nextblink <= '0'; if SingleErrorEna='1' or BurstErrorEna = '1' or ... then nextState <= blinking; nextCnt <= 0; end if; when blinking => nextCnt <= Cnt +1; nextblink <= not blink; if Cnt = max_cnt then nextState <= idle; end if; when others => null; end; end process; end architecture;
Erstmal vielen Fank für die vielen Reaktionen und die Tipps in euren Beiträge. Um mein Problem deutlicher zu machen, folgendes: ich hab am Eingang 4 Tasten die jeweils einen bit unterschiedlich lang togglen lassen sollen. Und an der Stelle weiss ich nicht wie diese verschieden Zeiten implmentieren kann. MfG Rudi
@Rudi: Ein Prozess toggelt, wenn ihm ein Flag das erlaubt (z.B. enable). Ein weiterer Prozess ist ein Abwärtszähler, der bei Start enbale setzt und bei Null enable zurücknimmt. Außerdem läßt sich er Zähler mit einem Startwert laden. Jetzt entprellst Du die Tasten und je nachdem welche gedrückt wurde lädst Du Deinen Zähler mit einem anderen Wert. Falls ich dich falsch verstanden habe und Du vier Bits toggeln lassen willst, instanzierst Du den Zähler eben viermal. Rick
Du musst eigentlich nur diesen state ändern(ja, das ganze wird eine Mealy-FSM) when idle => nextblink <= '0'; if SingleErrorEna='1' or BurstErrorEna = '1' or ... then nextState <= blinking; nextCnt <= 0; end if; durch when idle => nextblink <= '0'; if BurstErrorEna = '1' or ... then nextState <= blinking; nextCnt <= 255; end if; if SingleErrorEna='1' then nextState <= blinking; nextCnt <= 128; end if; und beim anderen state runter zählen auf 0. du hast dann für jeden Taster ein if(oder elsif wenns dir lieber ist) und das ding sollte funktionieren. Wie Rick Dangerus schon gesagt hast musst du die Tasten einsynchronisieren. lg Azrael
@Rudi: bedeutet "unterschiedlich lang" tatsächlich "unterschiedlich lang" oder eher "unterschiedlich oft"? Falls nur unterschiedlich oft, dann gehts doch auch so: 1) Tasten entprellen und Flankentrigger erzeugen 2) Abhängig von Taste Zähler mit unterschiedlichen Werten laden 3) Zähler herunterzählen 4) irgendein Bit des Zählers auf LED ausgeben
1 | :
|
2 | :
|
3 | port( |
4 | clk: in std_logic; |
5 | taste_1: in std_logic; |
6 | taste_2: in std_logic; |
7 | taste_3: in std_logic; |
8 | taste_4: in std_logic; |
9 | led: out std_logic; |
10 | :
|
11 | :
|
12 | :
|
13 | signal cnt: std_logic_vector(15 downto 0) := x"0000"; |
14 | signal t1_entprellt: std_logic_vector(7 downto 0) := x"00"; |
15 | signal t2_entprellt: std_logic_vector(7 downto 0) := x"00"; |
16 | signal t3_entprellt: std_logic_vector(7 downto 0) := x"00"; |
17 | signal t4_entprellt: std_logic_vector(7 downto 0) := x"00"; |
18 | :
|
19 | :
|
20 | process (clk) |
21 | if rising_edge(clk) then |
22 | -- Tasten entprellen (einsynchronisieren)
|
23 | -- entfällt, wenn sowieso schon synchron
|
24 | t1_entprellt <= t1_entprellt(6 downto 0) & taste_1; |
25 | t2_entprellt <= t2_entprellt(6 downto 0) & taste_2; |
26 | t3_entprellt <= t3_entprellt(6 downto 0) & taste_3; |
27 | t4_entprellt <= t4_entprellt(6 downto 0) & taste_4; |
28 | |
29 | -- auf steigende Flanke Zähler laden
|
30 | if (t1_entprellt="00001111") then cnt<=x"1000"; |
31 | elsif (t2_entprellt="00001111") then cnt<=x"2000"; |
32 | elsif (t3_entprellt="00001111") then cnt<=x"4000"; |
33 | elsif (t4_entprellt="00001111") then cnt<=x"8000"; |
34 | -- Zähler herunterzählen, solange ungleich Null
|
35 | elsif (cnt/=(others=>'0')) then |
36 | cnt<=cnt-'1'; |
37 | end if; |
38 | end if; |
39 | end process; |
40 | |
41 | -- LED ansteuern
|
42 | led <= cnt(13); |
43 | :
|
44 | :
|
45 | :
|
Kleines Detail am Rand: Ich brauche hier keinen Reset weil ich das FPGA mit definierten Werten vorbelegen kann (so ein FPGA ist ja nichts anderes als ein RAM, das beim Power-Up aus dem Config-PROM geladen wird (die Herren von ACTEL mögen mir meine Ignoranz verzeihen)). Wenn ich keinen Wert vorgebe, dann werden die Bits default mit '0' vorbelegt. Die Zeile
1 | t1_entprellt <= t1_entprellt(6 downto 0) & taste_1; |
macht übrigens das gleiche wie
1 | t1_entprellt(0) <= taste_1; |
2 | for i in 0 to 6 loop |
3 | t1_entprellt(i+1) <= t1_entprellt(i); |
4 | end loop; |
Viel Erfolg Lothar
Hallo, hier habe ich eine verbesserte Version meines Programms. Leider scheint es noch eine kleine Macke zu haben.Ich lege testmuster am Eingang an sollte am Ausgang entsprechende Antworten bekommen was nicht passiert. Anscheinend bleibt es nach dem ersten Durlauf irgenwo hängen. Kann jemand bitte einen Blick darauf werfen. Grüße R. library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; use work.BER_Meas_pkg.all; entity TxErrorControl is port( clock : in std_logic; reset : in std_logic; ErrorCmd : in std_logic_vector(2 downto 0); TxErrorEna : out std_logic_vector(2 downto 0) ); end entity; architecture TxErrorControl_arch of TxErrorControl is type state_type is(Idle,SingleErrorTx,BurstErrorTx,TxFault0,TxFault1); signal curr_state, next_state: state_type; signal s_SETrig : std_logic; -- Single error Increment trigger signals signal s_BETrig : std_logic; -- Burst error Increment trigger signals signal s_TxFTrig: std_logic; -- TxF Increment trigger signals signal s_SEcnt : std_logic_vector(4 downto 0); -- Single error counter signal s_BEcnt : std_logic_vector(4 downto 0); -- Burst error counter signal s_TxFcnt : std_logic_vector(4 downto 0); -- TxF error counter begin Sync_proc: process(clock,reset) begin if reset = '1' then curr_state <= Idle; else if rising_edge(clock) then curr_state <= next_state; end if; end if; end process; decode_proc: process(curr_state,ErrorCmd,s_SEcnt,s_BEcnt,s_TxFcnt) begin case curr_state is when Idle => s_SETrig <= '0'; -- Reset all increment trigger signals s_BETrig <= '0'; s_TxFTrig <= '0'; TxErrorEna <= (others => '0'); -- Set output to NULL case ErrorCmd is -- switch on key pressed when "000" => -- No key pressed next_state <= curr_state; when "001" => -- Single Error Key next_state <= SingleErrorTx; when "010" => -- Burst Error Key next_state <= BurstErrorTx; when "011" => -- TxF0 Key next_state <= TxFault0; when "100" => -- TxF1 Key next_state <= TxFault1; when others => -- Undefined combinations next_state <= curr_state; end case; when SingleErrorTx => TxErrorEna <= "001"; -- Transmit SE ErrorMode s_SETrig <= '1'; -- Enable SE count process when BurstErrorTx => TxErrorEna <= "010"; s_BETRig <= '1'; when TxFault0 => TxErrorEna <= "011"; s_TxFTrig <= '1'; when TxFault1 => TxErrorEna <= "100"; s_TxFTrig <= '1'; when others => TxErrorEna <= (others => '0'); next_state <= curr_state; end case; end process; Cnt_proc: process(clock,reset) begin if (reset = '1') then s_SEcnt <= (others => '0'); s_BEcnt <= (others => '0'); s_TxFcnt <= (others => '0'); else if rising_edge(clock) then if s_SETrig = '1' then if s_SEcnt >= "00001" then -- only an iteration s_SEcnt <= c_zero; -- Reset counter else s_SEcnt <= s_SEcnt + c_one; -- increment by one; end if; else if s_BETrig = '1' then if s_BEcnt >= "00101" then -- pngen register length-1 s_BEcnt <= c_zero; else s_BEcnt <= s_BEcnt + c_one; -- increment by one end if; else if s_TxFTrig = '1' then if s_TxFcnt >= "10100" then -- (3x pngen register length)-1 s_TxFcnt <= c_zero; else s_TxFcnt <= s_TxFcnt + c_one; -- increment by one end if; end if; end if; --end if; end if; end if; end if; end process; end architecture ;
Ich hab dir mal deine fsm aufgezeichnet. den fehler drüftest du leicht erkennen. Du gehst nie wieder aus dem jeweiligen state raus. Du musst dir also überlegen, wann du den state verlassen willst. Für uns wäre es sciher hilfreich wenn du selber mal so eine Statemachine aufzeichnest und sie postest. Mir is um ehrlich zu sein, nicht ganz klar was jetzt was wie lang wo machen soll. Was soll gleichzeitig passieren, was nicht. z.B. soll der fault-cnt gleichzeitig wie der burstmode-cnt zählen? oder strikt getrennt? lg Azrael
Hallo, eigeintlich hatte ich mir schon eine fsm gezeichnet, konnte aber nicht so ganz sortieren wie was realisiert werden sollte. Und was ich eigenlich implemtieren wollte war das mit der Eingabe der ErrCmd einen von den Vielen Triggersignal(SETrig,BETrig,TxFTrig) gesetzt wird und somit der entsprechende Zähler gestartet.Bei dem Maximum sollte dieses TriggerSignal zurückgesetzt und somit das Zählprocess gestopt. Dieser Schritt habe ich anscheinend nicht umgesetzt und das schau ich mir an. Danke R.
also wir haben fsm-Ds recht gut gelernt, das prinzip ist, dass du z.B. counter in deiner fsm einbaust ohne einen eigenen process. insgesamt braucht man nur 2processes, einmal das register, und die combinatorik. Das ganze noch mit einem record verfeinert und man kann 90% der fsmds mit dem semben prinzip machen. Ich hoffe das prinzip hinter dieser fsm ist klar. Ich finde FsmD's sind wesentlich einfacher zum lesen. und man spart sich den lästigen counter-process. aja, hier wird nur ein counter verwendet, für alle counter, das part Flipflops und signale. wie du siehst ist der eigentliche teil recht schnell runter programmiert, und ich glaub das design ist sogar richtig(habs jetzt nicht ausprobiert) und 30% kannst du für deine nächste fsm übernehmen(den register-Prozess z.B.) wenn du weitere register benötigst, musst du sie nur im Record hinzufügen, und in der Init-Konstante den default wert zuweisen. Du vergisst dadurch nicht, das signal zur Sensitivity-list hinzuzufügen. www.gaisler.com/doc/structdes.pdf hier kannst du alles mal nachlesen. (ja ich bin ein kleiner fan von fsmd, aber wenn man mal bei einer klausur wenig zeit hat, nimmt man die variante bei der man am wenigsten fehler hat, und wo man nicht viel schreiben muss XD library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; use work.BER_Meas_pkg.all; entity TxErrorControl is port( iclock : in std_logic; ireset : in std_logic; iErrorCmd : in std_logic_vector(2 downto 0); oTxErrorEna : out std_logic_vector(2 downto 0) ); end entity; architecture TxErrorControl_arch of TxErrorControl is type state_type is(Idle, SingleErrorTx, BurstErrorTx, TxFault0, TxFault1); type aRegSet is record State : aState; TxErrorEna : std_logic_vector(2 downto 0); cnt : natural range 0 to 20; end record; constant cInitValR : aRegSet := ( State => Idle, TxErrorEna => (other => '0'), cnt = 0; ); aRegSet R, NxR; begin -- das sind die einzigen Register im ganzen design!!! registerProc : process(iclock, ireset) is begin if ireset = '0' then R <= cInitValR; elsif iclock'event and iclock = '1' then R <= NxR; end if; end process; -- reine combinatoric, also keine register!!! comb : process(R, iErrorCmd) -- R und alle eingänge begin NxR <= R; -- default zuweisung, damit keine latches entstehen case R.State is when Idle => NxR.cnt <= 0; case ErrorCmd is -- switch on key pressed when "000" => -- No key pressed next_state <= curr_state; when "001" => -- Single Error Key next_state <= SingleErrorTx; when "010" => -- Burst Error Key next_state <= BurstErrorTx; when "011" => -- TxF0 Key next_state <= TxFault0; when "100" => -- TxF1 Key next_state <= TxFault1; when others => null -- Undefined combinations end case; when SingleErrorTx => NxR.TxErrorEna <= "001"; if R.cnt = 20 then NxR.State = Idle; NxR.cnt = 0; else NxR.cnt = NxR.cnt +1; end if; when BurstErrorTx => NxR.TxErrorEna <= "010"; if R.cnt = 16 then NxR.State = Idle; NxR.cnt = 0; else NxR.cnt = NxR.cnt +1; end if; when TxFault0 => NxR.TxErrorEna <= "011"; if R.cnt = 8 then NxR.State = Idle; NxR.cnt = 0; else NxR.cnt = NxR.cnt +1; end if; when TxFault1=> NxR.TxErrorEna <= "100"; if R.cnt = 2 then NxR.State = Idle; NxR.cnt = 0; else NxR.cnt = NxR.cnt +1; end if; end case; end process; end architecture; lg Azrael
:) Wir hatten heute Klausur zu dem Thema, da ist der Stoff noch frisch und saftig ^^ lg Azrael
@Lothar, Hallo, ich versuche gerade deine Lösungsvorschlag (Codeabschnitt mit weissem Hitergrund) zu implementieren und hab das Problem das mein Ausgang dauer auf '1' steht. Ich habe auch ein Reset eingebaut da bei mir keine Vorbelgung möglich ist. Kannst du mir da weiterhelfen. LG R.
@Azrael: endlich mal einer der für einen Zähler einen vernünftigen Typen verwendet: natural ! Gut so, VHDL Synthesewerkzeuge brauchen nicht mehr die Vorgabe von Bit-Vektoren, das ist schon seit Jahren vorbei, wird aber immer wieder gern gemacht (s. Lothar) Einige Syntaxfehler sind im Code, das wichtigste ist aber, dass alle Signale die in den Kombinatorischen Prozess eingehen SYNCHRON zum Clock sein müssen! Sonst funktioniert die FSM nur im Simulator, aber nie in der Praxis. clock'event and clock='1' kann man schon seit Jahren durch rising_edge(clock) ersetzen, das liest sich besser!
Hehe, ja natural ist schon was feines, vor allem weil mans gleich als bit-index nehmen kann. syntax-fehler, ja stimmt, ein paar <= hab ich falsch gemacht, das kommt davon wenn man emacs mit ",," gewohnt ist. Generell gewöhnt man sich an so viele feinheiten von emacs. clock'event and clock='1' <= stimmt, geht auch mit rising_edge, aber nachdem ich register eh immer vom emacs erstellen lass,... :D Zum Thema synchronisierung. Stimmt, ich bin davon ausgegangen das alles synchron ist, liegt daran das ich das so gewohnt bin. Meiner ansicht nach hat die Synchronisation in der fsm nichts verloren. Das gehört in die Testbed, in der man auch die fsm-instanzieirt und alle synchronisations-geschichten macht. * Man tut sich unglaublich einfacher wenn man sich um synchrone signale nicht kümmern muss, und wenn man das an einer stelle macht, vergisst man 1tens nichts, 2tens muss man nie überlegen ob das jetzt synchron ist oder nicht. * Ich arbeite mit einer namenskonversion. iSignal <= input signal oSignal <= outputsingal iSignalAsync <= Asynchrones eingangssignal iSignalAsync <= Asynchrones ausgangssignal Signal <= einfaches signal emacs unterstützt mich da leider nicht :/ aber wennst den code von am kollegen liest kennt man sich sofort aus, und wehe er hält sich nicht dran slap ^^ lg Azrael
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.