I/O Steuerung 1us

OP #2893285
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
Gast #2893295
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?
OP #2893334
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
}
#2893383
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.
#2893846
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.
#2893987
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
Gast #2894235
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.
Gast #2906734
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.
OP #2944933
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.
Angehängte Dateien:
Gast #2944958
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.
#2944968
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)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren