mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Delay-Funktion STM32: delay_ns()


Autor: Walter T. (nicolas)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Hallo zusammen,

für einen Bitbanging-Treiber auf einem STM32F446 und einem STM32F103 
habe ich mir mal einen krude Delay-Funktion für Nanosekunden 
zusammengebastelt:
      static inline void delay_us_(uint64_t delayval)
      {
        if(delayval)
            {
          asm volatile (\
                "1:   subs %0, %0, #1  \n\t" \
                "     bne  1b\n\t" \
                :  "+r" (delayval) );
        }
        else
            {
          asm volatile("nop");
        }
      }

      static inline void delay_ns(uint32_t delayval)
      {
            const uint64_t nCycle = (uint64_t) (SYSTEMCORECLOCK) * delayval / 1000000000ULL;
            switch( nCycle )
            {
                case 6:
                    asm volatile("nop;");
                case 5:
                    asm volatile("nop;");
                case 4:
                    asm volatile("nop;");
                case 3:
                    asm volatile("nop;");
                case 2:
                    asm volatile("nop;");
                case 1:
                case 0:
                    asm volatile("nop;");
                    break;
                default:
                    delay_us_(nCycle/3);
            }
      }



Wie man sieht, ist die bei sehr kurzen Verzögerungen Taktgenau 
(mindestens aber einen Takt) und bei längeren Verzögerungen auf 5 Takte 
genau.

Da ein Bitbanging-Treiber nun wirklich eine Stelle ist, wo mir jeder 
eingesparte Taktzyklus nützt, würde ich das jetzt gerne noch ein bischen 
genauer bekommen. Perfekt wäre eine Genauigkeit von +0...+1 Takt.

Nun bin ich dummerweise nicht fit genug in Assembler/Inline Assembler, 
um zu zählen, wieviele Takte exakt der Ein- und der Rücksprung der 
inline-Assembler-Funktion kostet.

An dieser Stelle frage ich tatsächlich zum ersten Mal nicht nach Hilfe 
zur Selbsthilfe, sondern in der Richtung "Wer kann mir was machen"?

Einfach deshalb, weil hier "wissen/können und einfach machen" und 
"einarbeiten und selbst machen" in so krassem Unterschied stehen.

Vielleicht bist Du der Nachbar/Fremde/Bekannte, dem ich schon ein Brett 
gehobelt, das Gartentor geschweißt oder dem Auto Starthilfe gegeben habe 
und kannst mir ein paar Zeilen Inline Assembler schenken.

Viele Grüße
W.T.

Autor: Curby23523 N. (nils_h494)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich frage mich eher, wofür du einen hochgenauen Nanosekunen-Timer 
brauchst?

Autor: Lutz (Gast)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Nun kann ich da wohl wahrlich nicht helfen, aber mal 3 Gegenfragen:

Macht auf einem 32-bitter mit 64 bit zu rechnen nicht mehr "overhead" 
als die wirklich wenigen Takte, die du sparen willst?

Ist DWT_CYCCNT nicht das Einfachste und Genaueste für sowas?

Ist das "harte" Rechnen in einer delay-Funktion nicht kontraproduktiv?

Autor: Walter T. (nicolas)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lutz schrieb:
> Macht auf einem 32-bitter mit 64 bit zu rechnen nicht mehr "overhead"
> als die wirklich wenigen Takte, die du sparen willst?

Da die Funktion "static inline" ist und der Eingabeparameter schon zur 
Compilezeit feststeht: Nein.

Lutz schrieb:
> Ist DWT_CYCCNT nicht das Einfachste und Genaueste für sowas?
>
> Ist das "harte" Rechnen in einer delay-Funktion nicht kontraproduktiv?

Es geht um einen Bitbanging-Treiber (paralleler Bus).

Um ein Gefühl für die Größenordnung zu bekommen: Der längste Wert, mit 
dem die Funktion bislang aufgerufen wird, ist 30 ns, d.h. die Funktion 
evaluiert zu gerade einmal sechs NOP() (auf dem STM32 mit 168 Mhz), der 
häufigste Aufruf erfolgt mit 10 ns, also zwei NOP().

Aber: Diese Funktion brennt im Auge. Ich weiß, daß es besser gehen muß. 
Sie hat mich vor allen Dingen viel Zeit bei der Hardware-Fehlersuche 
gekostet (Liegt es am Timing? Warum sehe ich nichts am Oszilloskop, wenn 
ich von 30 auf 40 ns umstelle ?????)

Nur leider übersteigt "besser machen" hier meine Fähigkeiten.

Autor: Nop (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lutz schrieb:

> Ist DWT_CYCCNT nicht das Einfachste und Genaueste für sowas?

Das macht man üblicherweise mit einer Schleife, und allein schon des 
Branchings wegen wird das in diesem Fall kaum möglich sein. Bis etwa 
runter auf 1 Mikrosekunde geht das noch, aber wenn hier auch 10 ns 
gefordert sind, dann ist DWT_CYCCNT nicht gangbar.

Autor: Nop (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Walter T. schrieb:

> Nun bin ich dummerweise nicht fit genug in Assembler/Inline Assembler,
> um zu zählen, wieviele Takte exakt der Ein- und der Rücksprung der
> inline-Assembler-Funktion kostet.

Naja wenn Du die Funktion static inline machst, dann gibt's keinen 
Sprung.

Ich nehme mal an, Du nimmst GCC, oder?

Die grundsäztliche Syntax geht so:
inline static void __attribute__((always_inline)) My_Delay(void)
    __asm volatile (
        ".thumb_func\n"
        "NOP\n"
        "\n" : : : "memory");
}

Das Gesaue mit dem attribute ist nötig, weil "inline" nur ein 
unverbindlicher Vorschlag für den Compiler ist. Und "inline" selber ist 
nötig, weil das attribute alleine nicht bei GCC durchgeht.

Das kannst Du als C-Funktion aufrufen, und die wird vom Compiler 
garantiert ge-inlined. Jetzt kannste dann erstmal am Oszi mit 
unterschiedlich vielen NOPs messen, wieviel Delay Du da eigentlich 
bekommst bei Deinen Controllern, den eingestellten Taktfrequenzen und 
DCache/ICache/Prefetch.

Also im C-Code ein IO toggeln und dazwischen die Funktion aufrufen und 
erstmal schauen, wo man da eigentlich so landet.

Im nächsten Schritt, wenn Du die Daten hast, kannst Du dann einen 
Parameter an die Funktion übergeben, einen uint32_t, der dann in R0 
landet. Nur, 10ns, das sind 100 MHz. Da ist keine Zeit mehr für 
irgendwelche Abfragen, fürchte ich.

Von daher kann's bei so kurzen Delays das Einfachste sein, eine 
delay-10ns-Funktion zu haben, eine für 20, eine für 30, und dann erst 
eine, die dynamisch Delay ergibt.

Autor: Nop (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab die geschweifte Klammer vergessen:
inline static void __attribute__((always_inline)) My_Delay(void)
{
    __asm volatile (
        ".thumb_func\n"
        "NOP\n"
        "\n" : : : "memory");
}

Autor: Nop (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Ach ja, und die GPIOs natürlich nicht über HAL setzen, das gibt keine 
aussagefähige Messung, sondern direkt über das betreffende BSRR. Damit 
hast dann auch nicht die Arie mit Laden, AND/OR, Speichern.

Autor: holger (Gast)
Datum:

Bewertung
3 lesenswert
nicht lesenswert
>Perfekt wäre eine Genauigkeit von +0...+1 Takt.

>Nun bin ich dummerweise nicht fit genug in Assembler/Inline Assembler,
>um zu zählen, wieviele Takte exakt der Ein- und der Rücksprung der
>inline-Assembler-Funktion kostet.

Vergiss es. Jeder Interrupt versaut dir das. Oder DMA Transfers.
Wer sowas will sollte einen CPLD oder FPGA nehmen.

Autor: Nop (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
holger schrieb:
> Jeder Interrupt versaut dir das.

Das ist ein Assembler-Befehl, und die sind alle abgeschaltet. Sogar der 
Systick, obwohl der eine Exception ist.

> Oder DMA Transfers.

Muß man nicht anschalten. Scho gar nicht bei so einem Projekt.

Autor: Walter T. (nicolas)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Guten Morgen,

holger schrieb:
> Vergiss es. Jeder Interrupt versaut dir das. Oder DMA Transfers.

Wenn ich ISRs und Peripheriebuslast durch DMA-Transfers nicht schon viel 
früher berücksichtig hätte als erst zu dem Zeitpunkt, wo ich die 
Wartezeiten*) taktgenau bekommen will, wäre das doch grob fahrlässig.

Nop schrieb:
> Also im C-Code ein IO toggeln und dazwischen die Funktion aufrufen und
> erstmal schauen, wo man da eigentlich so landet.

Das mache ich natürlich. Allerdings ist die Aussagekraft kleiner, als 
man glauben mag. In Anbetracht dessen, daß ein MCU-Takt noch schlappe 
5,6 ns beträgt, einer Slew-Rate, die in der gleichen Größenordnung liegt 
und dem Peripheral Bus, der auch einen gewissen Jitter verursacht, weil 
er niedriger als die MCU getaktet ist, ist es schwer bis unmöglich zu 
beurteilen, ob jetzt eine Funktion 6 oder 7 Takte gewartet hat.

Die Zeiten für langes warten stimmen schon (im Rahmen meiner 
Meßgenauigkeit) in der Funktion, die ich oben gepostet habe. Die für 
kurze Wartezeiten bis 6 Takte natürlich auch. Jetzt wäre es noch schön, 
wenn der Zwischenbereich auch stimmen würde.

Ich gehe auch davon aus, daß eine Funktion, die das für kurze und lange 
Wartezeiten taktgenau hinbekommt, prinzipiell komplett identisch ist: Im 
Wesentlichen eine Herunterzählschleife mit bekannter Anzahl an Takten 
und ein Jump über mehrere NOPs, um den (Divisions-) Rest an Takten auch 
noch zu verbrauchen.

Ich denke, für einen guten Taktzähler ist das eine kleine Fingerübung. 
Ich bin nur leider komplett unmusikalisch.

Viele Grüße
W.T.


*) Wartezeiten := Mindest-Wartezeiten

: Bearbeitet durch User
Autor: Nop (Gast)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Walter T. schrieb:

> Wartezeiten taktgenau hinbekommt, prinzipiell komplett identisch ist: Im
> Wesentlichen eine Herunterzählschleife mit bekannter Anzahl an Takten
> und ein Jump über mehrere NOPs, um den (Divisions-) Rest an Takten auch
> noch zu verbrauchen.

Wenn Du auch 10 ns warten können willst, ein Takt aber schon gut 5 ns 
dauern, dann wirst Du da keine Division, kein Herunterzählen, kein 
compare und keinen Branch schaffen. Ist einfach so.

Autor: Falk B. (falk)
Datum:

Bewertung
4 lesenswert
nicht lesenswert
Ziemlicher Käse das Ganze. Entweder, man MUSS wirklich taktgenau 
arbeiten, dann packt man das als KOMPLETTE Funktion in eine separate 
Funktion in einer separaten Assemblerdatei. Damit kann man normal und 
ohne Handstände ASM programmieren und bekommt EXAKT was man braucht.
Oder es ist soweit zeitunkritisch, daß man kein ASM und auch keine 
ASM-Macros braucht, dann bleibt man bei C und gut.
Aber auf C-Ebene mit solchen Stunts taktgenaues ASM hinzubiegen ist 
Murks^3.

Autor: Ingo Tarzan (Gast)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Falk B. schrieb:
> Aber auf C-Ebene mit solchen Stunts taktgenaues ASM hinzubiegen ist
> Murks^3.

Danke sehr!

Manche brauchen das .... im Elfenbeinturm vor sich hinspinnen.

Autor: Nop (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Nop schrieb:
> kein Herunterzählen, kein compare und keinen Branch schaffen.

Wobei, das compare braucht es nicht, weil die Statusflags beim 
Herunterzählen ohnehin setzbar sind. Ändert nichts daran, daß man mit 
zwei Takten nicht den Overhead eines Schleifenkörpers nebst Division 
realisiert bekommt.

Zudem hat Falk natürlich auch insofern recht, als daß man die 
Delay-Funktion zwar als inline-C-Funktion aufrufen kann, aber keine 
Kontrolle hat, was der Compiler dann noch alles tut, beispielsweise 
register spill. Besonders, wenn dann auch noch etwas gerechnet werden 
soll, also Schleife und Division.

Autor: Walter T. (nicolas)
Datum:

Bewertung
-2 lesenswert
nicht lesenswert
Nop schrieb:
> Wenn Du auch 10 ns warten können willst, ein Takt aber schon gut 5 ns
> dauern, dann wirst Du da keine Division, kein Herunterzählen, kein
> compare und keinen Branch schaffen. Ist einfach so.

Wenn ich 10 ns warten will, mache ich 2 Nops. Oder 1 Nop. Je nach 
Target.

Falk B. schrieb:
> man MUSS wirklich taktgenau
> arbeiten,

Ich muß nicht komplett taktgenau arbeiten. Ich brauche nur 
Mindest-Wartezeiten. Und je genauer meine IST-Wartezeiten an den 
Mindest-Wartezeiten sind, desto mehr Bus-Durchsatz habe ich.

: Bearbeitet durch User
Autor: Walter T. (nicolas)
Datum:

Bewertung
-4 lesenswert
nicht lesenswert
Ist OK. Ich habe verstanden. Hier finde ich niemanden, der helfen will, 
dafür viele, die lästern wollen. Ist auch einfacher. Dafür muß man 
nichts können.

Autor: Ingo Tarzan (Gast)
Datum:

Bewertung
4 lesenswert
nicht lesenswert
Walter T. schrieb:
> Und je genauer meine IST-Wartezeiten an den
> Mindest-Wartezeiten sind, desto mehr Bus-Durchsatz habe ich.

Ja schon klar. Und dafür muss man dann an den letzten
Nanosekunden herumpfriemeln.

Walter T. schrieb:
> Hier finde ich niemanden, der helfen will,

Nein. Richtig ist: Hier findest du niemanden der deine
Krümelkackerei mitmachen will.

Autor: Nop (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Walter T. schrieb:

> Wenn ich 10 ns warten will, mache ich 2 Nops. Oder 1 Nop. Je nach
> Target.

Eben, Und wenn Du zur Laufzeit rausfinden willst, wieviel Du brauchst, 
ist das zuviel Overhead. Deswegen nichts mit Divisionen und Schleifen 
für zwei Takte.


Walter T. schrieb:
> Ist OK. Ich habe verstanden.

Nein, hast Du nicht. Zudem finde ich es unverschämt von Dir, daß ich Dir 
erst eine Assemblerversion zumindest mal zur Messung mundgerecht 
serviere und dann sowas kommt:

Walter T. schrieb:
> Hier finde ich niemanden, der helfen will

Autor: Walter T. (nicolas)
Datum:

Bewertung
-2 lesenswert
nicht lesenswert
Nop schrieb:
> Eben, Und wenn Du zur Laufzeit rausfinden willst, wieviel Du brauchst,
> ist das zuviel Overhead.

Niemand hat davon gesprochen, daß das zur Laufzeit berechnet werden 
soll. Wird es doch aktuell auch nicht.

Nop schrieb:
> Nein, hast Du nicht. Zudem finde ich es unverschämt von Dir, daß ich Dir
> erst eine Assemblerversion zumindest mal zur Messung mundgerecht
> serviere

Wunderbar. Diese Zeilen Assembler machen genau einmal NOP();. Da ist 
mein Gebastel im Eingangsposting ja schon weiter.

Autor: Nop (Gast)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Walter T. schrieb:

> Wunderbar. Diese Zeilen Assembler machen genau einmal NOP();.

Ich ging davon aus, daß Du in der Lage bist, weitere NOP-Zeilen zu 
ergänzen. Editoren haben dafür copy&paste. Dann ging ich davon aus, daß 
Du erstmal NACHMISST, was da für ein Timing rauskommt, bevor man das 
komplexer macht. Machste alles nicht, weil Du zu faul bist.

> Da ist
> mein Gebastel im Eingangsposting ja schon weiter.

Dann noch viel Spaß mit Deiner Switch-Struktur und zwei Takten Delay. Du 
machst das schon.

Autor: Johnny B. (johnnyb)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist nur eine Frage, da ich selber nicht so der Hirsch bin; aber wie 
sieht es denn mit den Waitstates aus, wenn der ART Accelerator™ noch 
dreinfunkt beim STM32F446?

Autor: Joerg W. (joergwolfram)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Ich glaube nicht, dass das überhaupt "stabil" lösbar ist, sobald 
Prefetch und/oder Cache ins Spiel kommen. Je nachdem, wo Deine Loop 
liegt, kann sie unterschiedlich schnell sein. Nur mit ASM (und .balign) 
sehe ich da überhaupt eine Chance.

Jörg

Autor: Walter T. (nicolas)
Datum:
Angehängte Dateien:

Bewertung
-2 lesenswert
nicht lesenswert
Es geht mir nur darum, eine Funktion zu haben, die taktgenau eine 
bestimmte Anzahl an Takten verbraucht. Die Anzahl an Takten ist zur 
Build-Zeit bekannt und minimal 1.

Lassen wir mal Caching- und Bus-Effekte außen vor. Wir können sie eh 
nicht vermeiden. Cortex M3 und M4 bieten keine Out-of-Order-Execution - 
das heißt das Problem ist prinzipiell lösbar. Wenn eine einzelne 
Wartezeit mal einen oder zwei Takte länger dauert, ist das kein 
Weltuntergang.

Die C-Funktion im Anhang erfüllt all diese Anforderungen, hat aber 
gewisse Nachteile. Ich bin sicher, dass es mit einer oder zwei 
Inline-Assembler-Funktionen deutlich eleganter geht.

Selbst bekomme ich eine solche Funktion nicht hin. Der DWT-Zähler ist 
zwar super für grobes Profiling, aber eine taktgenaue Aussage, wie lange 
jetzt mein Inline-Assembler gebraucht hat, klappt so nicht. Da hilft nur 
Zyklen zählen.

Autor: W.S. (Gast)
Datum:

Bewertung
3 lesenswert
nicht lesenswert
Walter T. schrieb:
> Es geht mir nur darum, eine Funktion zu haben, die taktgenau eine
> bestimmte Anzahl an Takten verbraucht.

Deine gesamte Herangehensweise ist falsch. Das ist es.

Wenn du mal genauer hinschauen würdest, dann sähest du, daß jeder 
Interrupt deine ganze Taktgenauigkeit zunichte macht. Und wenn du jetzt 
bockig reagierst und dir sagst, 'dann verbiete ich die eben', dann bist 
du auf der ollen AVR-Denke, die man besser bleiben lassen sollte.

Also pfeife auf die ganze "Taktgenauigkeit" und nimm für kürzere Zeiten 
eine simple Delayschleife OHNE Assemblereinschub und schätze diese 
einfach per Oszi ein. Bei Interrupts wird sie länger, also plane das 
ein. Und wenn deine Hardware damit nicht klarkommt, dann hast du selbige 
falsch entwickelt.

W.S.

Autor: Walter T. (nicolas)
Datum:

Bewertung
-2 lesenswert
nicht lesenswert
W.S. schrieb:
> Wenn du mal genauer hinschauen würdest, dann sähest du, daß jeder
> Interrupt deine ganze Taktgenauigkeit zunichte macht.

Ich habe doch nie taktgenaue Verzögerung gefordert. Ich will lediglich 
eine taktgenaue Auflösung der Verzögerungsfunktion. Mehr nicht.

W.S. schrieb:
> und nimm für kürzere Zeiten
> eine simple Delayschleif

Schleifen sind mir an einigen Stellen schon viel zu lang. Mindestens 3 
Zyklen.

W.S. schrieb:
> Bei Interrupts wird sie länger, also plane das
> ein. Und wenn deine Hardware damit nicht klarkommt, dann hast du selbige
> falsch entwickelt.

Interrupts sind kein Problem, und alles kommt damit klar.

W.S. schrieb:
> und schätze diese einfach per Oszi ein

Genau darauf habe ich keine Lust. Für jedes Delay für jedes Target bei 
jeder einstellbare Taktkonfiguration von vorn einschätzen - nein.

Die Hardware funktioniert ganz hervorragend, wenn ich die mit dem 
Taschenrechner berechnete Anzahl an NOP(); einfüge. Also ist der 
sinnvolle nächste Schritt, das Ganze vom Compiler vorberechnen zu 
lassen. Bevor bei der nächsten Taktänderung des Targets alles wieder von 
vorn in Handarbeit eingepflegt werden muss.

Autor: Stefanus F. (stefanus)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Walter Walter,
Liest du eigentlich, was du da schreibst?

> Es geht mir nur darum, eine Funktion zu haben, die taktgenau eine
> bestimmte Anzahl an Takten verbraucht.
> Die Anzahl an Takten ist zur Build-Zeit bekannt und minimal 1.

und dann gleich kommt gleich hinterher:

> Wenn eine einzelne Wartezeit mal einen oder zwei Takte länger dauert,
> ist das kein Weltuntergang.

Ein oder zwei Takte mehr macht also bis 300% Abweichung. Ist das etwas 
"taktgenau"?

Hinzu kommt, dass die Ungenauigkeit tatsächlich sogar größer sein wird. 
Da ist nichts mehr genau.

Das Einzige, was realistisch machbar ist, sind mindest-Verzögerungen. 
Nenne deine Funktion doch "delay_mindestens_ns()".

: Bearbeitet durch User
Autor: Walter T. (nicolas)
Datum:

Bewertung
-2 lesenswert
nicht lesenswert
Das ist wohl eher ein Problem der Textauslegung: Wenn ich fordere, dass 
eine Funktion genau 3 Takte verbraucht, heißt das, dass nach dem Ende 
der Funktion mindestens 3 Takte vergangen sein müssen.

Jede Verzögerung ist eine Mindest-Verzögerung. Das ist eine typische 
Eigenschaften von Verzögerungen, dass es unter Umständen noch länger 
dauern kann.

: Bearbeitet durch User
Autor: Stefanus F. (stefanus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Na dann sind wir uns ja einig.

Autor: Nop (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Walter T. schrieb:

> Die Hardware funktioniert ganz hervorragend, wenn ich die mit dem
> Taschenrechner berechnete Anzahl an NOP(); einfüge. Also ist der
> sinnvolle nächste Schritt, das Ganze vom Compiler vorberechnen zu
> lassen. Bevor bei der nächsten Taktänderung des Targets alles wieder von
> vorn in Handarbeit eingepflegt werden muss.

Steht die Taktfrequenz sowie die Anzahl der Nanosekunden bei jedem 
Delay-Aufruf als Compilezeit-Konstante zur Verfügung?

Autor: Walter T. (nicolas)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Nop schrieb:
> Steht die Taktfrequenz sowie die Anzahl der Nanosekunden bei jedem
> Delay-Aufruf als Compilezeit-Konstante zur Verfügung?

Natürlich. Sonst wäre die Aufgabe nicht lösbar.

Autor: Nop (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Walter T. schrieb:

> Natürlich. Sonst wäre die Aufgabe nicht lösbar.

Ich glaub, ich hab ne Idee.. welchen Nanosekundenbereich brauchst Du 
dafür? Reicht 0-50?

Autor: Lachmir Nenast (Gast)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Nop schrieb:
> welchen Nanosekundenbereich brauchst Du dafür?

Gar keinen.
Er spinnt nur herum und meint so etwas zu brauchen.

Und alle die, die krampfhaft eine Lösung finden wollen
sind die Verarschten.

Autor: Walter T. (nicolas)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Nop schrieb:
> welchen Nanosekundenbereich

Naja, also ob 1...50 Nanosekunden oder 1...12782640 Nanosekunden (bei 
168 MHz) sollte bei der Implementierung nicht viel Unterschied machen.

Es wird ja auf das hier hinauslaufen:

Walter T. schrieb:
> eine Herunterzählschleife mit bekannter Anzahl an Takten
> und ein Jump über mehrere NOPs, um den (Divisions-) Rest an Takten auch
> noch zu verbrauchen.

Autor: Nop (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Walter T. schrieb:

> Es wird ja auf das hier hinauslaufen:

Nein, ich dachte eher an ein paar üble Makro-Hacks, die ohne Schleife 
auskommen. Ich hab aber nicht daran gedacht, daß der Präprozessor keine 
Ausdrücke auswertet, sondern erst der Compiler im Schritt danach.

Autor: Nop (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tja, ansonsten kannst Du das case noch aufbohren, bis die verbleibende 
Genauigkeit beim generischen Delay vernachlässigbar wird. Mit 
Taktzählung wirst Du hier eh nichts, das sagte Falk ja auch schon, wenn 
Du nicht ALLES in Assembler machst, also auch den Rest vom Treiber.

Da hängt zuviel daran, wie der Compiler im konkreten Fall gerade 
optimieren kann. Da wird mal ein Register auf den Stack geworfen und 
wieder zurückgeholt oder auch nicht, bei minimalen Anpassungen im 
Quelltext. Mit LTO nochmal mehr.

Autor: derjaeger (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Derjenige, der nach dir später mal den Code nachvollziehen muss, tut mir 
jetzt schon leid.

Autor: Nop (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Aber die Idee mit den Macros geht doch! Muß ja gar nicht über den 
Präprozessor sein, das darf irgendwo in der Buildchain sein.

Im simpelsten Fall schreibst Du Dir ein Programm, dem Du auf der 
Kommandozeile die Taktfrequenz des Systems übergibt, und das schmeißt 
dann ein .h-File mit Macros für die relevanten Delays raus. Sowas hier:
#define DELAY_NS_10 { \
    asm volatile("nop;"); \
    asm volatile("nop;"); \
} while 0

#define DELAY_NS_15 { \
    asm volatile("nop;"); \
    asm volatile("nop;"); \
    asm volatile("nop;"); \
} while 0

Wieviele Nops da reinkommen, kann sich das Tool ja nach Dreisatz 
berechnen mit Auf- oder Abrundung.

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]
  • [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.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

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