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.

