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


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Max U. (Gast)


Bewertung
0 lesenswert
nicht 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.
ADC_Werte_aufbereiten: process(CLK)

begin

    if(rising_edge(CLK)) then
    
        spannung <= (to_integer(unsigned(bin_ADC_Channel)) - 328) * 762 / 10;

    end if;
 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


Bewertung
0 lesenswert
nicht lesenswert
Hallo Max,

der Workflow ist etwas anderst als du ihn vll von der Software 
Entwicklung kennst. Der Ausdruck:
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. (lkmiller) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht 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:
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:
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
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:
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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.