Forum: FPGA, VHDL & Co. VHDL Prozessdauer oder Programmierfehler bei Rechnung


von Max U. (Gast)


Lesenswert?

Hallo,

ich bin noch recht neu in VHDL, daher mag meine Frage für euch sicher 
etwas zu einfach wirken.
Mir geht es aber um die Berechnungsdauer und eventuell um einen groben 
Denkfehler meinerseits.


Ich benutze ein Arty A7-35T Entwicklungsboard und steuere einen ADC an.
Der ADC-Ansteuerprozess schreibt mir in ein std_logic_vector(11 downto 
0) -Signal den gemessenen Wert hinein.

Jetzt möchte ich aber den Wert noch etwas weiterverarbeiten.
Deswegen wandele ich den std_logic_vector in ein Integer um und ziehe 
davon etwas ab und multipliziere das Ganze und teile wieder.

Ich mache das auf diese Art, weil ich auf einem FPGA noch nie mit 
Gleitkomma gearbeitet habe und ich die Werte auch möglichst schnell 
umgewandelt bekommen möchte.
1
ADC_Werte_aufbereiten: process(CLK)
2
3
begin
4
5
    if(rising_edge(CLK)) then
6
    
7
        spannung <= (to_integer(unsigned(bin_ADC_Channel)) - 328) * 762 / 10;
8
9
    end if;
10
 end process;


Bei jedem Takt wird meines Wissens nach der Prozess aufgerufen.

Nun zu meiner konkreten Frage:

Wie aber funktioniert das dann mit der Rechnung?
Fängt er jedes Mal von Vorne an, weil CLK der Systemtakt ist und die 
Multiplikation und Addition ja mehrere Takte dauert?

Schöne Grüße
Max

von Tobias B. (Firma: www.elpra.de) (ttobsen) Benutzerseite


Lesenswert?

Hallo Max,

der Workflow ist etwas anderst als du ihn vll von der Software 
Entwicklung kennst. Der Ausdruck:
1
spannung <= (to_integer(unsigned(bin_ADC_Channel)) - 328) * 762 / 10;

wird in jedem Taktzyklus durchgefuehrt. Jedoch kann solch ein Zyklus 
nicht beliebig schnell ablaufen, irgendwann ist ein Punkt erreicht an 
dem die FPGA interne Schaltung das Rechenergebnis nicht schnell genug 
auf ein stabiles bringen kann und die nachfolgenden Schritte die mit dem 
Ergebnis arbeiten erhalten irgendwelche Zufallszahlen.

Was du jetzt mchen musst, ist deinem Tool, in diesem Fall Vivado, 
mitteilen welche Periodendauer CLK hat. Das Tool wird dir dann im 
Gegenzug sagen ob es diese Berechnung innerhalb dieser Periodendauer 
sauber ausfuehren kann oder eben nicht. Das noetige Stichwort dazu ist 
Timing Constraints und Static Timing Analysis. Durch ersteres kann ein 
Timing Report zu zweiterem generiert werden

Sehr wahrscheinlich wirst du da Probleme bekommen. Wenn du soweit bist, 
schlage ich aus didaktischen Gruenden vor, du meldest dich nochmal und 
haengst den Timing Report an. Dann gehen wir Schritt fuer Schritt durch, 
wie das zu handhaben ist. ;-)

: Bearbeitet durch User
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Max U. schrieb:
> Bei jedem Takt wird meines Wissens nach der Prozess aufgerufen.
Bei jeder Änderung von clk wird der Prozess im Simulator(!!) neu 
berechnet.
Und fürs FPGA wird aus dieser Beschreibung etwas mit viel, viel 
Logik(**) und Flipflops gemacht. Diese Flipflops erhalten dann den clk 
als Takt.

(**) eine kombinatorische Division ist ziemlich ressourcenfressend. Du 
solltest deine Rechnung eher so machen, dann kommst du mit einer 
Multiplikation aus:
1
spannung <= (to_integer(unsigned(bin_ADC_Channel)) - 328) * 1219 / 16;
Denn die Division durch 16 wird einfach durch das Weglassen der 
untersten 4 Leitungen realisiert. Und auf die 1219 komme ich per 762*1,6
Denn bei 762*1,6 / 16 kürzt sich die 1,6 dann heraus zu einer / 10

Oder andersrum:
su willst eigentlich sowas rechnen:
1
spannung <= (to_integer(unsigned(bin_ADC_Channel)) - 328) * 76,2;
Schlags kaputt, eine Fließkommazahl. Das geht nicht in Hardware.
Also hättest du mit der behelfsweise genommenen Näherungsrechnung
1
spannung <= (to_integer(unsigned(bin_ADC_Channel)) - 328) * 76;
Einen Fehler von 76/76,2 = 0,26%
Für einen 8-Bit Wandler wäre das schon genau genug.
Wenn das nicht reicht, dann musst du das ganze mit einer Zweierpotenz so 
lange erweitern, bis du (annähernd) auf ,0 kommst. Also mal losgelegt:
76,2*2 = 152,4 --> unbrauchbar, der Fehler 152/152,4 ist noch immer 
gleich groß
152,4*2 = 304,8 --> schon besser, denn ,8 ist recht nahe bei ,0 und 
somit ergibt 305/304,8 einen Fehler von nur 0,065%
Und das ist sogar für einen 12-Bit-Wandler schon genau genug.

Also wäre meine Lösung für dieses Problem etwa so:
1
spannung <= (to_integer(unsigned(bin_ADC_Channel)) - 328) * 305 / 4;
Voila, keine ressourcenfressende Division mehr nötig, lediglich die 
untersten beiden Leitungen werden nicht verdrahtet.

Tobias B. schrieb:
> Sehr wahrscheinlich wirst du da Probleme bekommen.
Siehe dazu auch den Beitrag "Re: Modulofunktion" 
und die Links darin...

: Bearbeitet durch Moderator
von Hans Kanns (Gast)


Lesenswert?

Max U. schrieb:
> Wie aber funktioniert das dann mit der Rechnung?
> Fängt er jedes Mal von Vorne an, weil CLK der Systemtakt ist und die
> Multiplikation und Addition ja mehrere Takte dauert?

Du solltest dich erst einmal in die Funktion digitaler Schaltungen 
reinarbeiten, statt das von der Softwareseite anzugehen und zu fragen, 
was in VHDL passiert. Das ist nur eine Sprache, die von einem Übersetzer 
ausgewertet wird. Um diese Abstraktionsebene zu verstehen, muss man mal 
ein paar 4000er und 7400er angeschaut und verstanden haben.

Allein dieser Begriff "Prozessdauer" zeigt, dass Dir überhaupt nicht 
klar ist, was im VHDL und der Übersetzung passiert und was eine 
Digitalschaltung ist.

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
Noch kein Account? Hier anmelden.