Guten Morgen lieber Mikrocontroller.net,
ich baue gerade einen I-Regler im FPGA eines Zynq. Zum besseren
rumspielen wird der Integrierbeiwert Ki über ein Register aus einer der
CPUs des Zynq an den FPGA übergeben, als ganzzahliger Bruch der Form Ki
= kin_i / kid_i.
Dies hat in Variante A) Probleme gemacht, d.h. die Regelgröße hat mit
von Ki unabhängiger Amplitude und Frequenz geschwungen, weil die
Stellgröße fröhlich vom oberem zu unterem Anschlagpunkt hin-und-her
gesprungen ist, und zwar selbst für lächerlich kleine Werte für Ki wie
Ki = 1 / 1e9. Variante B funktioniert nun wie gewünscht und ist
obendrein verständlicher geschrieben.
Mich würde nun aber brennend interessieren wo bei Variante A) das
Problem liegt. Weiterhin ist jede Art Feedback zum Programmierstil gerne
willkommen.
Andreas F. schrieb:> Dies hat in Variante A) Probleme gemacht
In der Realität und/oder in der Simulation?
> Weiterhin ist jede Art Feedback zum Programmierstil gerne willkommen.
Du meinst den Beschreibungsstil... ;-)
1
esum_v:=esum+(e*signed(kin_i))/signed(kid_i);
Hast du mal angesehen, wie diese Division umgesetzt wird? Was wird
daraus tatsächlich gemacht? Wäre es sinnvoller, hier eine Multiplikation
mit dem Kehrwert der Konstanten einzufügen?
Irgendwie kommt mir sowieso das "e" im gesamten Code so verlassen und
nutzlos vor...
> Mich würde nun aber brennend interessieren wo bei Variante A) das> Problem liegt.
Hast du nicht einfach mal in der Simulation nachgeschaut, wo da was
schiefgeht? Passen da evtl irgenwelche Wortbreiten nicht? Das hatten wir
kürzlich im Beitrag "rechnen mit unsigned"
Lothar M. schrieb:> In der Realität und/oder in der Simulation?
Ups, völlig vergessen. Das Simulation ist völlig in Ordnung, die
Realität leider nicht.
Lothar M. schrieb:> Du meinst den Beschreibungsstil... ;-)
Wollte erst Konfigurationsstil schreiben, aber Beschreibungsstil war das
Wort das ich gesucht hatte :-)
Lothar M. schrieb:> Hast du mal angesehen, wie diese Division umgesetzt wird?
Nein, aber die Division ist in beiden Varianten ja gleich? Ich hatte
eher die Vermutung dass ich bei der Variablen einen Denkfehler habe...
Lothar M. schrieb:> Irgendwie kommt mir sowieso das "e" im gesamten Code so verlassen und> nutzlos vor..
Das e ist der Fehler zwischen Regel- und Führungsgröße und wird in einem
separaten Prozess richtig berechnet.
Lothar M. schrieb:> Hast du nicht einfach mal in der Simulation nachgeschaut
s.o.
Andreas F. schrieb:> Könnten fehlende Constraints das Problem sein?
Ja denn wenn dein Design nur 10MHz kann, du es aber mit 50MHz taktest,
dann passiert sowas.
Deshalb auch meine Frage, wie die Division in Hardware umgesetzt wird.
Sag der Toolchain welchen Takt verwendest oder verwenden willst, und die
sagt dir dann, ob sie es schafft.
Könnte es bei Timingproblemen denn helfen eine zusätzliche Pipelinestufe
einzubauen? D.h. den Prozess in 2 aufzuteilen, und im ersten z.B. die
Multiplikation und im 2. die Division + Begrenzung durchzuführen?
Andreas F. schrieb:> Könnte es bei Timingproblemen denn helfen eine zusätzliche Pipelinestufe> einzubauen?
Könnte schon, aber dazu muss man erst wissen, ob es einer ist, und
wo das Problem auftritt. Dann kann man überlegen, was zu tun ist. Und
vorab wäre wie gesagt zuallererst interessant, wie die Division
realisiert wird.
Stichworte dazu: "Statische Timinganalyse" und "kritischer Pfad".
> D.h. den Prozess in 2 aufzuteilen, und im ersten z.B. die> Multiplikation und im 2. die Division + Begrenzung durchzuführen?
Allein das Aufteilen des Prozesses in 2 Prozesse ergibt noch nicht
unbedingt ein Pipelining (du bist da offenbar zu sehr
"softwarebasiert").
Oder andersrum: ein Pipelining mitsamt dem resultierenden einen Takt
Latency (das Wort solltest du dir gleich mal merken, das kommt später
nochmal) bekomme ich mit weniger Schreibarbeit über ien getaktetes
Zeischenregister auch in 1 Prozess unter.
Lothar M. schrieb:> Oder andersrum: ein Pipelining mitsamt dem resultierenden einen Takt> Latency (das Wort solltest du dir gleich mal merken, das kommt später> nochmal) bekomme ich mit weniger Schreibarbeit über ien getaktetes> Zeischenregister auch in 1 Prozess unter.
Okay das leuchtet ein. Przesse dienen nur der Strukturierung der
Beschreibung, demnach wäre es sogar schlechter den "I-Prozess"
auseinanderzustückeln..
Lothar M. schrieb:> Und> vorab wäre wie gesagt zuallererst interessant, wie die Division> realisiert wird.
Laut "RTL Analysis" ist die Division ein RTL_DIV Block. Ich vermute
interessanter wäre aber wie dieser Block implementiert wird oder? Wie
finde ich jetzt aber die Implementierng in dem riesigen Wirrwarr aus
Netzen und Blöcken im Syntheseschaltplan? Den Netzen folgen? Danke für
deine Gedult!
Andreas F. schrieb:> Wie finde ich jetzt aber die Implementierng in dem riesigen Wirrwarr> aus Netzen und Blöcken im Syntheseschaltplan? Den Netzen folgen?
Ja. du solltest sie "sogar" wieder erkennen. Denn weil VHDL eine
Hardwarebeschreibungssprache ist, solltest/hast du damit ja deine
Schaltung, die du letztlich willst, beschrieben.
> Laut "RTL Analysis" ist die Division ein RTL_DIV Block.
Und in diesem Block ist dieser kombinatorische Wirrwarr? Dann hast du
eine kombinatorische Division hingelegt. Und die ist garantiert langsam.
Siehe den Beitrag "Division in VHDL"
und den Beitrag "Rechnen mit unsigned vs. signed und einer division"
Welcher Takt geht denn in das System rein? Ich meine die Zeitkonstanten
für den Regler hängen ja mit dem äußeren System zusammen, müssen also
berechnet werden. Die muss man dann noch unter Berücksichtigung des
VHDL-Integratortaktes quantisieren.
Meine Erfahrung ist dass gerade ein zu langsam eingestellter I-Regler
zum Schwingen des Gesamtsystems führt?
Andreas M. schrieb:> Ich meine die Zeitkonstanten> für den Regler hängen ja mit dem äußeren System zusammen, müssen also> berechnet werden. Die muss man dann noch unter Berücksichtigung des> VHDL-Integratortaktes quantisieren.
Genau, ist in https://rn-wissen.de/wiki/index.php?title=Regelungstechnik
ganz gern beschrieben.
Mein Problem war tatsächlich wie von Lothar vermutet eine Timing Sache.
Die Addition, Multiplikation, Division und anschließende Limitierung
waren einfach zu viel für einen 1 clk Zyklus. Ich habe die
Multiplikation jetzt in eine extra Pipelinestufe gepackt (nochmal danke
für den Hinweis mit dem Prozess) und die Divisoren zusätzlich auf Zahlen
der Form 2^n beschränkt mittels
Andreas M. schrieb:> Welcher Takt geht denn in das System rein?
Das ist auch noch eine Frage, die prinzipiell zu klären ist.
Denn das FPGA wird ja z.B. mit einer Frequenz um 50MHz getaktet. Wenn
das zu regelnde System viel langsamer ist, dann kann man z.B. eine
32-Bit-Division ja locker auch auf 32 FPGA-Takte "verteilen" und ist
immer noch schnell genug.
Andreas F. schrieb:> Der Synthesizer ist so schlau, dass er die Division dann als Bitshift> implementiert.
Allerdings wird da nichts geschoben, sondern einfach "abgeschnitten"
oder besser noch "ignoriert" und gar nicht weiterverdrahtet.
Allerdings ist eben nicht jede Konstante automatisch ein
Zweierexponent...
Lothar M. schrieb:> Allerdings wird da nichts geschoben, sondern einfach "abgeschnitten"> oder besser noch "ignoriert" und gar nicht weiterverdrahtet.
Was das Ganze noch besser macht :-)
Lothar M. schrieb:> Allerdings ist eben nicht jede Konstante automatisch ein> Zweierexponent...
Ja, aber für meine Zwecke lassen sie sich hinreichend genau in der Form
N / 2^M darstellen.
Eine Frage kommt mir gerade noch: Die "Konstanten"
1
kin_i
und
1
kid_i
werden ja über Ports eingelesen. Ist es grundsätzlich ratsam bzw. guter
Stil diese direkt in Flipflops zu buffern? Schließlich weiß man ja
zunächst nicht wie lange die kombinatorische Signalkette ist die die
Konstante in das Modul führt.
Andreas F. schrieb:> Ist es grundsätzlich ratsam bzw. guter> Stil diese direkt in Flipflops zu buffern? Schließlich weiß man ja> zunächst nicht wie lange die kombinatorische Signalkette ist die die> Konstante in das Modul führt.
Ja, ich mache das so. Auch meine Ausgangssignale laufen üblicherweise
über Register. Bei größeren Designs hat es der Router dann etwas
leichter beim Plazieren.
Duke