Forum: Mikrocontroller und Digitale Elektronik I/O Steuerung 1us


von Sigi M. (sigim)


Lesenswert?

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

von Floh (Gast)


Lesenswert?

Sigi Maier schrieb:
> SAM3S-Controllers

Schau mal ins Datenblatt wie hoch die I/O-Clock ist.

von AVR (Gast)


Lesenswert?

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?

von Sigi M. (sigim)


Lesenswert?

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
}

von (prx) A. K. (prx)


Lesenswert?

Wie kommst du auf die Idee, dass diese zig NOPs bei 12MHz Takt 1µs 
brauchen?

von Sigi M. (sigim)


Lesenswert?

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?

von Floh (Gast)


Lesenswert?

Lass mal die Nops / Delays weg und schau, wie schnell er überhaupt kann 
:-)

von (prx) A. K. (prx)


Lesenswert?

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.

von Sigi M. (sigim)


Lesenswert?

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...

von Walter S. (avatar)


Lesenswert?

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?

von Thomas E. (thomase)


Lesenswert?

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.

von Marc L. (dasbaum)


Lesenswert?

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

von (prx) A. K. (prx)


Lesenswert?

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.

von Marc L. (dasbaum)


Lesenswert?

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.

von MCUA (Gast)


Lesenswert?

>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.

von Bronco (Gast)


Lesenswert?

Schau Dir den Assembler-Code an (z.B. im Debugger) und zähle die 
Befehle.
Irgendwoher muß Deine Laufzeit ja kommen.

von Alexander V. (avogra)


Lesenswert?

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.

von Walter S. (avatar)


Lesenswert?

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

von Ziegenpeter (Gast)


Lesenswert?

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 ;)

von Sigi M. (sigim)


Lesenswert?

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...

von Stefan (Gast)


Lesenswert?

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.

von Sigi M. (sigim)


Angehängte Dateien:

Lesenswert?

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.

von Ralph (Gast)


Lesenswert?

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.

von Andreas M. (amesser)


Lesenswert?

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