Hallo, ich habe ein Problem bei der I/O-Steuerung meines SAM3S-Controllers. Ich möchte einen Pin der als output konfiguriert ist auf input schalten und dann wieder auf output, im Prinzip eine Unterbrechung simulieren. Die funktioniert auch wunderbar nur mit der Zeit passt etwas nicht. Ich hätte gerne, dass das aus- und wieder einschalten innerhalb von einer Mikrosekunde erledigt wird. Es dauert aber ca. 4us. Auch bei anderen Zeiten, hab ich einen Offset von ca. 3us. Hat da jemand eine Idee woran das liegen könnte und wie man das beheben kann? Den sysclk hab ich auf 12MHz RC Oszillator konfiguriert und meine delay-Funktion besteht im Prinzip aus lauter nop's. Hoffe mir kann jemand bei diesem Problem helfen oder Hinweise geben wo ich denn nachschauen könnte. Gruß Sigi
Und wir sollen jetzt raten was da schief läuft? Zeig uns doch etwas Code. Sigi Maier schrieb: > Den sysclk hab ich auf 12MHz RC Oszillator konfiguriert und meine > delay-Funktion besteht im Prinzip aus lauter nop's. Hast du den Overhead, der durch die Schleife entsteht (Vergleich und Sprungbefehl) mit in deine Überlegung einberechnet?
1 | pio_set_output(PIOC, PIO_PC16, HIGH, DISABLE, ENABLE); |
2 | pio_set_input(PIOC, PIO_PC16, PIO_DEFAULT); |
3 | delay(1); |
4 | pio_set_output(PIOC, PIO_PC16, HIGH, DISABLE, ENABLE); |
die delay-Funktion
1 | __attribute__( ( always_inline) ) static __INLINGE void _DELAY_1US(void) |
2 | |
3 | {
|
4 | __ASM volatile ("nop"); |
5 | __ASM volatile ("nop"); |
6 | __ASM volatile ("nop"); |
7 | __ASM volatile ("nop"); |
8 | __ASM volatile ("nop"); |
9 | __ASM volatile ("nop"); |
10 | __ASM volatile ("nop"); |
11 | __ASM volatile ("nop"); |
12 | __ASM volatile ("nop"); |
13 | __ASM volatile ("nop"); |
14 | __ASM volatile ("nop"); |
15 | __ASM volatile ("nop"); |
16 | __ASM volatile ("nop"); |
17 | __ASM volatile ("nop"); |
18 | __ASM volatile ("nop"); |
19 | __ASM volatile ("nop"); |
20 | __ASM volatile ("nop"); |
21 | __ASM volatile ("nop"); |
22 | __ASM volatile ("nop"); |
23 | __ASM volatile ("nop"); |
24 | __ASM volatile ("nop"); |
25 | __ASM volatile ("nop"); |
26 | __ASM volatile ("nop"); |
27 | __ASM volatile ("nop"); |
28 | __ASM volatile ("nop"); |
29 | __ASM volatile ("nop"); |
30 | __ASM volatile ("nop"); |
31 | __ASM volatile ("nop"); |
32 | __ASM volatile ("nop"); |
33 | __ASM volatile ("nop"); |
34 | __ASM volatile ("nop"); |
35 | __ASM volatile ("nop"); |
36 | __ASM volatile ("nop"); |
37 | __ASM volatile ("nop"); |
38 | __ASM volatile ("nop"); |
39 | __ASM volatile ("nop"); |
40 | __ASM volatile ("nop"); |
41 | __ASM volatile ("nop"); |
42 | __ASM volatile ("nop"); |
43 | __ASM volatile ("nop"); |
44 | __ASM volatile ("nop"); |
45 | __ASM volatile ("nop"); |
46 | __ASM volatile ("nop"); |
47 | __ASM volatile ("nop"); |
48 | __ASM volatile ("nop"); |
49 | __ASM volatile ("nop"); |
50 | __ASM volatile ("nop"); |
51 | __ASM volatile ("nop"); |
52 | __ASM volatile ("nop"); |
53 | |
54 | }
|
der Aufruf davon geschieht in einer for-Schleife
1 | static void delay(unsigned int DiscTime) |
2 | {
|
3 | for ( int i = 0; i < DiscTime; i++) |
4 | {
|
5 | __DELAY_1US(); |
6 | }
|
7 | }
|
1/12MHz gibt mir doch wie lang ein Befehl dauert und dann 1us/Ergebnis gibt mir Anzahl der nop's die ich brauch, oder nicht?
Sigi Maier schrieb: > 1/12MHz gibt mir doch wie lang ein Befehl dauert und dann 1us/Ergebnis > gibt mir Anzahl der nop's die ich brauch, oder nicht? Wenn ein NOP einen Takt benötigt und eine Mikrosekunde aus 12 Takten besteht, wieviel NOPs benötigt man dann für eine Mikrosekunde? [ ] 24, weil Befehl 16 Bit gross, Prozessor hat ja 32 Bits, [ ] 12, weil ich so blöd frag, [ ] keine Ahnung, Rechnen ist nicht so mein Ding.
Ja kann, dass ich da paar zuviele zusammen kopiert habe, da ich mit dem Rechner mit dem ich arbeite keinen Internet Zugang habe. Die Sache ist, dass ich diesen 3us offset auch bei z.B. nur einem nop oder auch bei 10 habe...
Sigi Maier schrieb: > delay(1); > die delay-Funktion__attribute__( ( always_inline) ) static __INLINGE void _DELAY_1US(void) kannst du uns vielleicht auch die funktion delay() zeigen?
Sigi Maier schrieb: > Auch bei > anderen Zeiten, hab ich einen Offset von ca. 3us. Hat da jemand eine > Idee woran das liegen könnte und wie man das beheben kann? Weil dein Funktionsaufruf und vor allen Dingen die Schleife diese Zeit benötigen und dein Compiler das nicht vollständig optimiert. Bei solchen Taktzählverzögerungen gehört alles dazu: push-pop, Schleife initialisieren, Schleifenzähler inkrementieren, Schleifenendebedingung prüfen etc.. Und das Hin- und Herschalten des Ports kostet Zeit. Da werden auch wieder Funktionen aufgerufen. Eine µs in Software bei 12MHz bekommst du nur mit Inline-Assembler hin. setbit passende Anzahl nops clrbit Keine Ahnung, wie die Befehle heissen. Such dir das selber raus. mfg.
Ich kenne mich zwar mit den hier verwendeten Mikrocontrollern nicht aus, allerdings wäre deine Berechnung für einen PIC falsch... und ich denke dass der Unterschied von Controller zu Controller bezüglich der Rechnungsart nicht sonderlich ändert. 1/12 MHz = 0.000000083 s Das bedeutet allerdings nicht, dass er Controller alle 83nS ein NOP ausführen kann. Bei einem PIC wären es 4*83nS. Falls das bei diesem / generell bei anderen Controllern anders ist, wäre ich froh wenn da jemand etwas dazu sagen kann, da es mich gerade selbst interessiert. Nochmal: Ich behaupte NICHT dass jeder Controller so funktioniert, ich weiss es lediglich von den PIC's, klärt mich auf falls es hier anders ist, danke. Nebenbei, unendlich viele NOP's aneinander zu Reihen ist nicht sonderlich schlau. Benutz lieber eine Schleife, in der du X-Mal ein NOP aufrufst. Leider kann ich nicht sonderlich gut C Programmieren, aber das geht 100 % einfacher. Da ich bisher nur Assembler kann, poste ich mal. Evtl. hilft dir sowas:
1 | movlw d'3' |
2 | movwf Variable |
3 | |
4 | 1us |
5 | decfsz Variable ; Dekrementiere Variable (1 Prog. Zyklus - 4 Taktschläge - 0.000000332s) |
6 | goto 1us |
7 | ... weiter mit Code |
Marc Liechti schrieb: > Falls das bei diesem / generell bei anderen Controllern anders ist, wäre > ich froh wenn da jemand etwas dazu sagen kann, da es mich gerade selbst > interessiert. Das ist je nach Prozessor anders und bewegt sich so zwischen ARM, AVR, PIC24 mit 1 Takt und 8051ern (bei altem Core) mit 12 Takten pro NOP.
A. K. schrieb: > Das ist je nach Prozessor anders und bewegt sich so zwischen ARM, AVR, > > PIC24 mit 1 Takt und 8051ern (bei altem Core) mit 12 Takten pro NOP. Danke für die Antwort ;) und wieder was dazu gelernt.
>oder Hinweise geben wo ich denn nachschauen könnte. Der kürzeste Befehl hängt immer vom Masch.Takt ab, nicht vom OscTakt (steht im DB) Masch.Takt = OscTakt. / x z.B ist x bei Pics<=18 4; bei PIC24 2; bei '51 (norm) 12; bei HC11 4; bei AVR, EZ8, RL78, STM8 1.
Schau Dir den Assembler-Code an (z.B. im Debugger) und zähle die Befehle. Irgendwoher muß Deine Laufzeit ja kommen.
Also wenns hier auf genaue Einschaltzeiten oder Verzögerungen ankommt, dann würde ich das überhaupt nicht in Software machen, sondern einen Timer mit Output-Compare benutzen. Damit kannste dann deinen Pulse auf den Prozessortakt genau vorgeben, ohne viel Spaghate machen zu müssen.
Walter S. schrieb: > Sigi Maier schrieb: >> delay(1); >> die delay-Funktion__attribute__( ( always_inline) ) static __INLINGE void > _DELAY_1US(void) > > kannst du uns vielleicht auch die funktion delay() zeigen? liest hier eigentlich jemand mit? Damit wollte ich den Hinweis geben dass delay aufgerufen wird und nicht die dargestellte Funktion DELAY_1US
Walter S. schrieb: > Damit wollte ich den Hinweis geben dass delay aufgerufen wird und nicht > die dargestellte Funktion DELAY_1US Die ist unterhalb der ganzen nops. Vor lauter nops übersieht man die schnell ;)
Sooo...also erst einmal danke an alle, aber das Problem lag ganz wo anders. Es ist ein bisschen peinlich, aber jetzt wo ich den Optimizer wieder aktiviert habe komm ich mit einem nop auf 820 ns...
Mal angenommen, delay(1) würde wirklich GENAU 1µs warten, dann hast Du immer noch den Aufruf der nachfolgenden Funktion und die Dauer dieser Funktion zusätzlich. Insofern kann dein Ausgangs-Impuls zwangsläufig niemals exakt 1ms dauern. Angenommen, dein Mikrocontroller braucht nur 1 Takt pro Befehl, dann bezweifle ich, dass Du ohne Assembler auch nur ansatzweise an die gewünschten 1µS heran kommen wirst, denn das alles müsste mit maximal 12 Assembler Befehlen realisiert werden. Eher weniger, weil einige Befehle sicher mehrere Takte benötigen. Deine gemessenen 3µS liegen in dem Bereich, den ich erwarte. Compiliere das Programm und schau dann in's Assembler Listing. Dann kannst Du die Ausführzeiten der einzelnen Befehle zusammen addieren. Lösung wird wohl der Einsatz eines Hardware-Timers sein.
Hallo zusammen, also wie schon gesagt es funktioniert bereits und die Zeiten sind auch relativ in Ordnung, da dann noch die Laufzeit auf der richtigen Hardware beachtet werden muss. Im Anhang sind die eingegebenen und gemessenen Zeiten mit einem nop in der Schleife. Jetzt meine Frage: Kann mir jemand vielleicht erklären warum da so unterschiedliche Zeiten rauskommen und nicht ungefähr im gleichen Verhältnis? Also, dass wenn ich 10us als Zeit eingebe es auch auch das 10-fache von 1us rauskommt. Ich habe zwar schon dem Atmel-Support geschrieben und auf einer Messe mit einem Mitarbeiter geredet, aber naja...nach fünf Emails und 3 erklären hatte ich dann keine Lust mehr. Ich hoffe jemand kann mich da aufklären woran es liegt, da ich echt keine Ahnung habe woher diese Unterschiede kommen.
So etwas macht man nicht mit Warteschleifen, das ist NIEMALS genau. Falls du das wirklich mit einer Schleife machen willst, dann darf dein µC NICHTS andres machen als genau diese eine Schleife, und schon mal glatt gar keine Interrupts. Dafür gibt es Hardwaremodule auf dem Chip, die können das sehr gut. Nennen sich Timer.
Sigi Maier schrieb: > also wie schon gesagt es funktioniert bereits und die Zeiten sind auch > relativ in Ordnung, da dann noch die Laufzeit auf der richtigen > Hardware beachtet werden muss. Im Anhang sind die eingegebenen und Lol, das ist jetzt nicht dein Ernst oder? > gemessenen Zeiten mit einem nop in der Schleife. > Jetzt meine Frage: Kann mir jemand vielleicht erklären warum da so > unterschiedliche Zeiten rauskommen und nicht ungefähr im gleichen > Verhältnis? > Also, dass wenn ich 10us als Zeit eingebe es auch auch das 10-fache von > 1us rauskommt. Ich habe zwar schon dem Atmel-Support geschrieben und auf > einer Messe mit einem Mitarbeiter geredet, aber naja...nach fünf Emails > und 3 erklären hatte ich dann keine Lust mehr. > Ich hoffe jemand kann mich da aufklären woran es liegt, da ich echt > keine Ahnung habe woher diese Unterschiede kommen. Wenn Du einfach mal das gemacht hättest was hier schon zwei mal geschrieben wurde, dann müsstest Du es eigentlich wissen. Schaue Dir den erzeugten Assembler-Code an und rechne Dir die genaue Laufzeit selbst aus. Oder denkst du etwa: - das der Aufruf der delay Funktion in 0-Zeit stattfindet? - das die Schleife an sich ebenfalls ohne eine einzige Anweisung auskommt? Wenn man schon solche Software-Verzögerungsschleifen benutzt, dann kodiert man immer direkt in Assembler für die jeweilige Platform. Nur dann kann man eine halbwegs vernünftige Vorhersage für die Laufzeit machen. Die richtige Lösung mit dem Timer wurde Dir auch schon genannt. Hast du schon mal darüber nachgedacht, dass Dir: - jeder Interrupt dein schön zurechtgebasteltes Timing zerschießt - Der Flash-Speicher nicht unbedingt mit vollem CPU-Takt Läuft (In deinem Fall aber schon)
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.