Hallo Leute,
folgendes Problem: Ich möchte gern ein DFC77-Signal in VHDL auswerten.
Wie ich das THEORETISCH mache, habe ich auch schon überlegt. Ich möchte
von jeder fallenden Flanke aus anfangen und den Abstand zur nächsten
steigenden Flanke messen (scheinbar funktioniert es nicht, von einer
fallenden zu einer steigenden Flanke zu messen - wenn doch, dann bitte
klärt mich auf - Quartus meint auf jeden Fall, es ginge nicht).
Jetzt hab ich mir folgenden Codefetzen überlegt:
1
if(reset='1')then
2
timer_hh<=0;
3
sek_nr<=0;
4
zustand<=0;
5
endif;
6
7
if(rising_edge(takt))then
8
timer_hh<=timer_hh+1;
9
endif;
10
if(falling_edge(dcf))then
11
-- hier beginnen wir mit dem zaehlen
12
timer_hh<=0;
13
elsif(rising_edge(dcf))then
14
-- zaehler stoppen und Zeit auswerten
15
if(timer_hh=200)then
16
-- jetzt haben wir eine 1 bekommen
17
sek_nr<=sek_nr+1;
18
elsif(timer_hh=100)then
19
-- jetzt haben wir eine 0 bekommen
20
sek_nr<=sek_nr+1;
21
elsif(timer_hh>500)then
22
-- jetzt sind wir synchron zur Minute
23
sek_nr<=0;
24
endif;
25
endif;
Dieser Code funktioniert problemlos (zumindest was das synthetisieren
angeht).
1
if(reset='1')then
2
timer_hh<=0;
3
sek_nr<=0;
4
zustand<=0;
5
endif;
6
7
if(rising_edge(takt))then
8
timer_hh<=timer_hh+1;
9
endif;
10
if(falling_edge(dcf))then
11
-- hier beginnen wir mit dem zaehlen
12
timer_hh<=0;
13
elsif(rising_edge(dcf))then
14
-- zaehler stoppen und Zeit auswerten
15
if(timer_hh=200)then
16
-- jetzt haben wir eine 1 bekommen
17
sek_nr<=sek_nr+1;
18
elsif(timer_hh=100)then
19
-- jetzt haben wir eine 0 bekommen
20
sek_nr<=sek_nr+1;
21
elsif(timer_hh>500)then
22
-- jetzt sind wir synchron zur Minute
23
sek_nr<=0;
24
sync<='1';
25
endif;
26
endif;
Hier bekomme ich komischerweise den Fehler, dass "timer_hh" nicht
außerhalb des "clock_edge" gelesen werden kann.
Der einzige Unterschied ist doch, dass ich jetzt den Ausgang SYNC mit
einer 1 belege. Was genau hat jetzt der "timer_hh" damit zu tun?
Ich verstehe nicht, was genau da gerade passiert.
Kann mir das vielleicht jemand erklären?
Hier kommt es zum gleichen Problem, sobald ich diesen Code UNTER den
anderen, funktionierenden, schiebe.
Wie bekomme ich denn jetzt die Variable "timer_hh" nach "außen" (d.h.
innerhalb des gleichen Blocks) ausgewertet?
Gesamter Quelltext:
1
--DCF77Block
2
3
4
libraryieee;
5
useieee.std_logic_1164.all;
6
useieee.numeric_std.all;
7
useieee.std_logic_arith.all;
8
9
10
entitydcf77is
11
12
port
13
(
14
dcf:instd_logic;
15
takt:instd_logic;
16
reset:instd_logic;
17
sync:outstd_logic;
18
sync_lvl:outstd_logic_vector(1downto0);
19
out_min:outstd_logic_vector(5downto0);
20
out_std:outstd_logic_vector(5downto0);
21
out_tag:outstd_logic_vector(5downto0);
22
out_mon:outstd_logic_vector(5downto0);
23
out_jhr:outstd_logic_vector(5downto0)
24
);
25
26
endentity;
27
28
-- Programmablauf:
29
-- warte auf fallende Flanke
30
--
31
32
33
architectureverhaltenofdcf77is
34
signalzustand:integer:=0;
35
-- sek_nr bestimmt Position innerhalb der laufenden Minute
36
signalsek_nr:integer:=0;
37
-- timer tiefhoch
38
signaltimer_hh:integer:=0;
39
signaltemp:integer:=0;
40
begin
41
42
process(dcf,reset,takt)
43
begin
44
-- Zustand 0: Programmstart
45
-- Zustand 1: Programm laeuft und hat erste fallende Flanke gefunden
voodoopuppe schrieb:> if(falling_edge(dcf)) then> :> elsif(rising_edge(dcf)) then> Dieser Code funktioniert problemlos (zumindest was das synthetisieren> angeht).
Das mußt du mir aber erst mal beweisen... :-/
Solche Bueteile die auf fallende und auf steigende Flanken reagieren
gibt es in einem FPGA nicht.
> (scheinbar funktioniert es nicht, von einer fallenden zu einer> steigenden Flanke zu messen - wenn doch, dann bitte> klärt mich auf - Quartus meint auf jeden Fall, es ginge nicht).
Natürlich geht das. Aber ganz anders.
Lies mal dort meine Postulate und meditiere mal, welche du alle verletzt
hast: Beitrag "vhdl-richtlinien f. synthese?"voodoopuppe schrieb:> Wie bekomme ich denn jetzt die Variable "timer_hh" nach "außen" (d.h.> innerhalb des gleichen Blocks) ausgewertet?
Gar nicht.
Variablen sind nur innerhalb eines Prozesses sichtbar. Nach aussen
verwendest du Signale. Ich brauche nur im seltensten Fall mal eine
Variable. Warum brauchst du so viele?
Beitrag "Variable vs Signal"
Geh mal in dich und deinen ganzen Code nochmal durch...
Und wie gesagt: nur 1 Takt (der Quarz).
Und externe Signale einsynchronisieren (hier dein DCF-Signal).
Hallo,
danke erstmal für deine Antwort!
"Das mußt du mir aber erst mal beweisen... :-/
Solche Bueteile die auf fallende und auf steigende Flanken reagieren
gibt es in einem FPGA nicht."
Das habe ich mir schon fast gedacht - und genau das ist der Witz - der
genannte Code funktioniert PROBLEMLOS. Sobald ich z.B. den sync-Ausgang
belegen will, kommt der genannte Fehler. Das ist ja das verwirrende für
mich an der ganzen Sache.
Ich muss sagen, ich bin selbst kein VHDL-Freak und ich mache das auch
nur, weil ich das Fach für den Studienabschluss belegen "muss" (im
Grunde nur um eine andere Note ggf. ausgleichen zu können). Ganz ehrlich
bin ich kein Fan dieser Sprache - und hätte nicht gedacht, dass das
Ganze so viele Probleme bereitet - hat es doch im Semester zuvor
wunderbar geklappt, als wir eine normale Uhr (ohne Funk-Zusatz)
programmiert haben.
So recht weiter bin ich nach dem ersten Lesen der Threads, bzw. der
Anleitung zum Einsynchronisieren noch nicht.
Bezüglich des einsynchronisieres des externen Signals:
Vermutlich wird es auf ein "wait until rising_edge(dcf);" rauslaufen,
welches ich dann irgendwie mit einem "dcfsig <= 1;" belegen werde, um es
dann in einem anderen Prozess mittels
Jetzt mal ganz davon abgesehen, dass das so nicht funktioniert, weil ich
wohl versuche mehrmals auf das gleiche Signal zuzugreifen (dcfok <= 0
und timer_hh <= 0).
Ist das der richtige Weg, wie es aussehen sollte?
Mir fehlt leider ein wenig eine "konkretere" Hilfe. Natürlich kann ich
mir jetzt auch ein Buch über VHDL zulegen oder das ganze Internet nach
Tutorials durchforsten. Das hilft mir bei meinem Problem aber eher
weniger.
voodoopuppe schrieb:> Jetzt mal ganz davon abgesehen, dass das so nicht funktioniert, weil ich> wohl versuche mehrmals auf das gleiche Signal zuzugreifen (dcfok <= 0> und timer_hh <= 0).
Richtig, das gibt "Multiple Sources", weil von mehreren Prozessen (oder
auch concurrent) auf das Selbe Signal geschrieben wird.
voodoopuppe schrieb:> Vermutlich wird es auf ein "wait until rising_edge(dcf);" rauslaufen,
Nein. Das dcf ist ein stinknormales asynchrones externes Signal. Der
einzige Takt, den du in deinem Design haben wirst, heißt (bei dir
offenbar) takt und kommt vom Quarzoszillator im Bereich um
20...100MHz. Ausschliesslich diese Buchstabenkombination wird bei
rising_edge() stehen. Ein falling_edge() wirst du nicht haben.
Ich würde das Problem aufteilen:
1. Erkennen einer 0, 1 und des Sync-Bits (die lange 0)
2. Ein 60 Bit langes Schieberegister, das den Datenstrom aufnimmt
3. Einen Übergabeimpuls an die Stunden- und Minuten-Register.
Ich würde eine DCF-Uhr so aufbauen, dass die Uhr an sich erst mal läuft
und nur ab und an, wenn das DCF-Signal gut ist, neu synchronisiert wird.
> hat es doch im Semester zuvor wunderbar geklappt, als wir eine> normale Uhr (ohne Funk-Zusatz) programmiert haben.
Nur zur Info: wieviele Takte waren da drin?
Im Grunde hatten wir dort eben nur EINEN Takt - nämlich den Quarz mit
seinen ~50Mhz (war ne etwas krumme MHz-Zahl, also nicht exakt 50).
Für die Schalter zum stellen der Uhr haben wir den weiter
runtergebrochen - was aber im Grunde nichts daran geändert hat, dass wir
in jedem Prozess/Entity nur auf EIN Signal prüfen mussten, welches er
von außen bekommen hat.
Ich würde das Problem aufteilen:
1. Erkennen einer 0, 1 und des Sync-Bits (die lange 0)
2. Ein 60 Bit langes Schieberegister, das den Datenstrom aufnimmt
3. Einen Übergabeimpuls an die Stunden- und Minuten-Register.
So ähnlich haben wir uns das auch gedacht. Die Frage ist eben:
Wie messe ich, nachdem ich die ganzen Takte mit gezählt habe (muss ja
wissen, wieviele ms vergangen sind seit der letzten Flanke), die Zeit
zwischen 2 Flanken?
Theoretisch könnte man auch ohne Flanke arbeiten, indem man misst, wie
lang das Signal auf "1" oder "0" war - im Sinne von (Pseudocode):
1
processbegin
2
waituntilrising_edge(takt);
3
if(dcf='1')then
4
timer_hh<=timer_hh+1;
5
endif;
6
endprocess;
7
8
processbegin
9
if(dcf='0')then
10
if(zustand=1)then
11
if(timer_hh=900)then
12
-- wir haben ne 0
13
elsif(timer_hh=800)then
14
-- wir haben ne 1
15
elsif(timer_hh>1000)then
16
-- wir haben ne neue Sekunde
17
endif;
18
timer_hh<=0;
19
zustand<=0;
20
endif;
21
elsif(dcf='1')then
22
zustand<=1;
23
endif;
24
endprocess;
Damit könnte man vorerst scheinbar die Nullen und Einsen erkennen - und
sich theoretisch wohl auch zum Signal synchronisieren (auf Grund der
langen 0).
Aber ob das funktionieren wird, bzw. so gedacht ist wie du das meinst?
Damit würde ich nur auswerten ob das DCF-Signal 0 oder 1 ist.
Das Problem mit den Multiple Sources hätte ich allerdings ja auch in
meinem neuen Beispiel. Dort schreibe ich einmal die timer_hh im ersten
und einmal im zweiten Prozess. Natürlich könnte ich das jetzt abhängig
von der Variable "zustand" machen, ob ich den Wert zurück auf 0 setze.
Denn den Zustand setze ich ja erst dann auf 0, wenn ich alle benötigten
Werte ausgelesen habe.
Soll heißen, ich hätte es jetzt so probiert:
1
processbegin
2
waituntilrising_edge(takt);
3
if(dcf='1')then
4
timer_hh<=timer_hh+1;
5
endif;
6
if(zustand=0)then
7
timer_hh<=0;
8
endif;
9
endprocess;
10
11
processbegin
12
if(dcf='0')then
13
if(zustand=1)then
14
if(timer_hh=900)then
15
-- wir haben ne 0
16
elsif(timer_hh=800)then
17
-- wir haben ne 1
18
elsif(timer_hh>1000)then
19
-- wir haben ne neue Sekunde
20
endif;
21
zustand<=0;
22
endif;
23
elsif(dcf='1')then
24
zustand<=1;
25
endif;
26
endprocess;
Somit schreibe ich die jeweiligen Variablen nur innerhalb EINES
Prozesses.
Ob das jetzt aber 100% so klappt weiß ich nicht.
Was sagen die Profis? ;)
voodoopuppe schrieb:> Im Grunde hatten wir dort eben nur EINEN Takt - nämlich den Quarz mit> seinen ~50Mhz (war ne etwas krumme MHz-Zahl, also nicht exakt 50).>> Für die Schalter zum stellen der Uhr haben wir den weiter> runtergebrochen - was aber im Grunde nichts daran geändert hat, dass wir> in jedem Prozess/Entity nur auf EIN Signal prüfen mussten, welches er> von außen bekommen hat.
Ein Takt ist das, was irgendwo bei rising_edge() oder falling_edge()
in der Klammer oder vor 'event steht. Und dort hat immer die selbe
ASCII-Zeichenkette zu stehen. Erst dann ist wirklich nur 1 Takt im
System.
voodoopuppe schrieb:> Somit schreibe ich die jeweiligen Variablen nur innerhalb EINES> Prozesses
Du programmierst hier nicht mit Variablen, sondern mit Signalen.
Variable sind in VHDL ganz was anderes. Aber lass da erst mal die Finger
davon...
Ich würde deinen Code ein wenig umschreiben:
voodoopuppe schrieb:
> als wir eine normale Uhr (ohne Funk-Zusatz) programmiert haben.
Hmm, immer wenn ich lese, dass jemand in VHDL PROGRAMMIERT hat (oder
schreibt, dass das VHLD-PROGRAMM doch in der Simulation problemlos
LÄUFT), weiß ich schon fast, mit welchen Problemen er zu kämpfen hat.
Man (be)schreibt etwas (nämlich eine Hardware) in VHDL. Und man muss
anders denken als bei einer traditionellen Programmiersprache (für
serielle Logik).
@Lothar: ich bewundere immer wieder Deine Geduld!
VHDL-User schrieb:> Die Wahrscheinlichkeit, dass der> Flankenwechsel im richtigen Takt (if (onems='1')) kommt ist 1/50000!
Das ist gewünscht und hat mit Wahrscheinlichkeiten gar nichts zu tun.
Denn das Signal kommt nicht mit einer Wahrscheinlichkeit, sondern
garantiert genau jede Millisekunde. So kommt das Signal auch zu seinem
Namen: "One Millisecond". Toll, nicht wahr... ;-)
Das ist übrigens genau die praktische Umsetzung des Clock-Enable aus dem
Artikel Taktung FPGA/CPLD
if(dcf_sr(2downto1)="10")then-- fallende Flanke vom DCF-Signal
8
sync<='1';
9
if(dcf_cnt<12)then-- Null einschieben
10
dcf_bits<='0'&dcf_bits(58downto1);
11
else-- Eins einschieben
12
dcf_bits<='1'&dcf_bits(58downto1);
13
endif;
14
endif;
15
if(dcf_sr(2downto1)="01")then-- steigende Flanke vom DCF-Signal
16
sync<='1';
17
if(dcf_cnt>1000)then-- Sync --> Daten übernehmen
18
dcf_min1<=dcf_bits(23downto20);-- anpassen
19
dcf_min10<=dcf_bits(26downto24);
20
endif;
21
dcf_cnt<=0;-- Zähler zurücksetzen
22
endif;
23
endif;
Bitte nicht über die geringen Werte bei dcf_cnt wundern - die sind
gesetzt, damit sich das Ganze schneller simulieren lässt.
Es scheint so, als ob das Programm nie in den Zweig kommt, wo es auf
fallende/steigende Flanke geprüft hat.
Denn egal, wie rum ich das sync <= '1'; da rein tu - es wird schlichtweg
nicht ausgewertet. sync bleibt durchgängig 0.
In den onems='1'-Bereich kommt man rein, denn dort lässt sich sync noch
setzen. Bei den Teilen danach jedoch nicht mehr.
Wie gesagt: es kommt mir so vor, als würde das Programm NIE in den
Bereich nach den steigenden/fallenden Flanken kommen.
Woran das liegt, weiß ich absolut nicht.
voodoopuppe schrieb:> Es scheint so, als ob das Programm nie in den Zweig kommt, wo es auf> fallende/steigende Flanke geprüft hat.
Häng doch mal deinen VHDL-Code und deine Testbench als .vhd Dateien hier
an...
Bei mir geht das... ;-)
Das Programm von Lothar hat noch ein paar andere "Fehler", aber ich
denke mal das das von Lothar Absicht war, um dich ein wenig zum Denken
anzuregen.
Schon allein dein Codeabschnitt strotzt nur so vor Fehlern, wundert mich
das die Synthese überhaupt klappt.
1) dcf_count wird falsch zurückgesetzt
2) Deine Einrückungen sind grauselig zu lesen
3) Sync wird nie auf 0 gesetzt.
4) Fallende Flanke wird jede ms geprüft, steigende jedoch jeden Takt
Offensichtlich ist dir nicht klar, wann Signale gesetzt werden.
>hat es doch im Semester zuvor>wunderbar geklappt, als wir eine normale Uhr (ohne Funk-Zusatz)>programmiert haben.
Wer ist wir ? auf deinem Mist ist das sicherlich nicht gewachsen. Es
fehlen dir wichtige Grundlagen.
>Halte ich für problematisch: Die Wahrscheinlichkeit, dass der>Flankenwechsel im richtigen Takt (if (onems='1')) kommt ist 1/50000!
sehe ich genauso.
>Denn das Signal kommt nicht mit einer Wahrscheinlichkeit, sondern>garantiert genau jede Millisekunde.
das ist richtig, aber dcf_count und auch onemscount wird nie auf
irgendetwas synchronisiert.
@lothar
Du synchronisiert zwar dcf auf den Takt mit 2 FF, aber bei der
Flankenabfrage benutzt du schon eines der Beiden FF, ist das gewollt ?
"1) dcf_count wird falsch zurückgesetzt"
Ist im Grunde vollkommen egal - da man ja anscheinend nicht mal bis zum
entsprechendem Punkt im Code kommt, wo ein Rücksetzen Sinn machen
könnte.
"2) Deine Einrückungen sind grauselig zu lesen"
Sind hier aus dem Forum zum ausprobieren des Codes so übernommen - macht
im Code selbst auch keinen Unterschied, wie das nun eingerückt ist ....
"3) Sync wird nie auf 0 gesetzt."
Es wird beim Reset auf 0 gesetzt. Warum sollte ich es an einer anderen
Stelle noch einmal auf 0 setzen, wenn ich das gar nicht will?!
"4) Fallende Flanke wird jede ms geprüft, steigende jedoch jeden Takt"
Komisch - wenn diese Flanke IM "1ms" drin steht, sollte die Flanke auch
jede MS - und nicht jeden Takt - geprüft werden.
Eventuell den Code einfach nochmal lesen?
Ich vereinfache es dir noch einmal:
1
waituntilrising_edge(takt);
2
if(onems='1')then
3
sync<='1';
4
if(dcf_sr(2downto1)="10")then-- fallende Flanke vom DCF-Signal
5
sync<='1';
6
endif;
7
if(dcf_sr(2downto1)="01")then-- steigende Flanke vom DCF-Signal
8
sync<='1';
9
endif;
10
endif;
Für mich sieht das so aus, als würde sowohl fallende als auch steigende
Flanke jede ms geprüft. Sollte dem nicht so sein - berichtige mich ....
"Schon allein dein Codeabschnitt strotzt nur so vor Fehlern, wundert
mich
das die Synthese überhaupt klappt."
Dann zeige mir diese FEHLER bitte auf. Scheinbar muss es sich um massive
Logikfehler handeln - denn beim synthetisieren bekomme ich zumindest
keine Fehler ....
Also: Wo stecken hier die massiven Fehler? Oder war das etwa deine
Aufzählung, die ich dir oben näher erläutert habe? Wenn ja war das ja
wohl nichts.
"Wer ist wir ? auf deinem Mist ist das sicherlich nicht gewachsen."
Nun, glücklicherweise habe ich das Projekte damals fast allein umgesetzt
- trotz zweier Gruppen. Mag sein, dass ein paar einfache Zählschleifen
etwas einfacher sind als dieses Programm, wo man auf zwei verschiedene
Signale reagieren muss. Ist auch vollkommen egal, auf diese
Unterstellungen lasse ich mich mal gar nicht weiter ein.
@Lothar Miller
Ich lade das Freitag Nachmittag/Abend mal hoch. Sowohl die vhd als auch
die vhst (? hieß glaub ich so).
Danke so weit für die Hilfe. Warum das Stückchen so nicht funktioniert
und mir die sync-Ausgänge nicht belegt, begreife ich leider nicht. Es
kann eigentlich nur die Abfrage nach den Flanken sein, die fehlerhaft
ist. Aber da das so oft im Netz so beschrieben wird, müsste es doch
eigentlich (!) gehen.
Da ging beim vorigen Beitrag mit den Anhängen was schief... :-(
Falk schrieb:> Das Programm von Lothar hat noch ein paar andere "Fehler", aber ich> denke mal das das von Lothar Absicht war, um dich ein wenig zum Denken> anzuregen.
Ich habe das aus dem Kopf schnell hingeschreiben, und der Syntaxcheck
hier im Forum tut noch nicht so richtig... ;-)
Wobei: Syntaxfehler waren nicht mal drin (abgesehen von der 499999),
aber ein Denkfehler beim Einsynchronisieren des dcf-Signals. Bis da mal
auf die Flanken abgefragt wird, ist das Schieberegister schon längst
"000" oder "111". Und deshalb wird keine Flanke erkannt.
Abhilfe schafft, das Eintakten in den ms-Takt zu übernehmen:
1
-- Einsynchronisieren
2
processbegin
3
waituntilrising_edge(clk);
4
if(onems='1')then
5
dcf_sr<=dcf_sr(1downto0)&dcf;
6
endif;
7
endprocess;
oder so:
1
processbegin
2
waituntilrising_edge(clk);
3
if(onems='1')then
4
5
dcf_sr<=dcf_sr(1downto0)&dcf;-- Asynchrones Signal einsynchronisieren
6
7
if(dcf_cnt<2000)then-- zählen mit Begrenzung
8
dcf_cnt<=dcf_cnt+1;
9
endif;
10
:
Tron schrieb:> @lothar> Du synchronisiert zwar dcf auf den Takt mit 2 FF, aber bei der> Flankenabfrage benutzt du schon eines der Beiden FF, ist das gewollt ?
Ja, zum Einsynchronisieren sind 2 FFs nötig. Das mittlere der dreien ist
schon das zweite ;-)
voodoopuppe schrieb:> @Lothar Miller> Ich lade das Freitag Nachmittag/Abend mal hoch. Sowohl die vhd als auch> die vhst (? hieß glaub ich so).
Was ist die vhst?
Meine Testbench heißt zum Nachnamen auch .vhd :-o
Lothar Miller schrieb:> ..aber ein Denkfehler beim Einsynchronisieren des dcf-Signals. Bis da mal> auf die Flanken abgefragt wird, ist das Schieberegister schon längst> "000" oder "111".
...das meinte ich oben mit der Wahrscheinlichkeit :-)
Hi,
ich bin mittlerweile ganz gut voran gekommen.
Habe lediglich ein paar kleinere Fehlerchen festgestellt, die ich
behoben habe - unter anderem fiel mir irgendwann auf, dass es ja
zwischen sekunden, milisekunden und nanosekunden auch noch die
mikrosekunden gibt ..... das hat die meisten Probleme behoben .... keine
Ahnung, was mich bei der Umrechnung von MHz in Sekunden geritten hat -
jetzt funktioniert es jedenfalls.
Danke für die Hilfe, morgen mache ich intensiv weiter und schaue mal,
wie weit ich komme. Es fehlt lediglich noch das Verarbeiten der Daten in
den entsprechenden "Bauteilen".