Forum: Mikrocontroller und Digitale Elektronik Timer, Ticks Verständnis


von Michael (Gast)


Lesenswert?

Hallo,

ich konnte leider keine passende Erklärung auf die Schnelle vorfinden, 
es geht um Timer bzw. Delays.
Bei einem 4MHz System habe ich eine Tickzeit von 1/4000000 = 0,25us
Wenn ich eine Delayfunktion erstelle,

[code]
//25ms
delay_func(100000);

status delay_func(uint32 param)
{
    for(uint32 i=0; i<param;)
    {
        i++;
    }

    return OK;
}
[code/]

so wie ich es verstehe bräuchte ich 100000 Ticks um die 25ms zu 
überbrücken,
wird aber die komplette for Schleife pro Tick abgearbeitet ?
Mir ist nicht ganz klar, welche Operation pro Tick durchgeführt wird.

VG
Michael

von Sebastian R. (sebastian_r569)


Lesenswert?

Michael schrieb:
> wird aber die komplette for Schleife pro Tick abgearbeitet ?
> Mir ist nicht ganz klar, welche Operation pro Tick durchgeführt wird.

Diese Frage ist einer der wenigen Gründe, weshalb man ein bisschen 
Assembler können sollte und weshalb es nützlich ist, dass die meisten 
(alle?) Compiler auch Assembler mit Mnemonics als Zwischenschritt 
ausspuckt.

Wenn die Funktion nicht vom Optimizer weggeschmissen wird, dann kann man 
sich mal den Assembler dazu angucken und nachvollziehen, wie viele 
Schritte wie oft passieren.

Inkrementieren, Compare, Springen,... Wenn man dann noch weiß, wie viele 
Zyklen pro Befehl notwendig sind (ist vom Controller abhängig), findet 
man raus, wie lange das Delay ist.

: Bearbeitet durch User
von Teo D. (teoderix)


Lesenswert?

Was du meinst ist die Prozessor-Taktung und dem je nach Prozessor 
unterschiedlichen Maschinenzyklus, der aus einem bis vielen 
Prozessor-Takten besteht!
https://de.wikipedia.org/wiki/Taktsignal

von Axel S. (a-za-z0-9)


Lesenswert?

Michael schrieb:
> ich konnte leider keine passende Erklärung auf die Schnelle vorfinden,
> es geht um Timer bzw. Delays.

Zwei sehr verschiedene Dinge. Man kann eine Verzögerung zwar mit einem 
Timer erzeugen, aber du machst das nicht. Was du machst, nennt man
busy waiting oder auf deutsch: CPU-Zeit verbrennen.

> Bei einem 4MHz System habe ich eine Tickzeit von 1/4000000 = 0,25us
> Wenn ich eine Delayfunktion erstelle,

Von Tick spricht man nur bei einem Timer, aber hier ist keiner 
beteiligt. Und Systeme haben nur im Ausnahmefall eine einzelne 
Taktfrequenz. Aber nehmen wir einfach mal an, die 4MHz wären der 
CPU-Takt. Dann sagt man nicht Ticks, sondern Taktzyklen.
1
> status delay_func(uint32 param)
2
> {
3
>     for(uint32 i=0; i<param;)
4
>     {
5
>         i++;
6
>     }
7
> 
8
>     return OK;
9
> }

> so wie ich es verstehe bräuchte ich 100000 Ticks um die 25ms zu
> überbrücken

100.000 Taktzyklen, ja.

> wird aber die komplette for Schleife pro Tick abgearbeitet ?

Sicher nicht.

> Mir ist nicht ganz klar, welche Operation pro Tick durchgeführt wird.

Das kommt auf den Prozessor an. Aber auch im besten Fall kann der nur 
einen (Maschinen-) Befehl pro Taktzyklus ausführen. Die Schleife besteht 
aber sicher aus mehreren Befehlen: einem 32-Bit Inkrement, einem 32-Bit 
Vergleich, einem bedingten Sprung. Aber es ist noch schlimmer: da das C 
Code ist, kommt es auch noch darauf an, was der C Compiler daraus für 
Maschinencode erzeugt. Das das hängt wieder davon ab, welche 
Optimierungseinstellung der Compiler bekommen hat. Und wenn nächsten 
Monat eine neue Version des Compilers herauskommen sollte, macht die es 
vielleicht noch anders.

Genau ist ein solches busy waiting also nicht. Oder gar portabel. Was du 
machen kannst: setze eine große Zahl ein, sagen wir 10.000.000. Und dann 
stoppe die Zeit, die deine CPU für die Abarbeitung der Funktion braucht. 
Dann kannst du zurückrechnen, wieviel Taktzyklen pro Durchlauf verbraten 
werden.

von merciMerci (Gast)


Lesenswert?

Mit "timer tick" wird normalerweise eine HW Timer Periode gemeint.
z.B. wenn der HW Timer initialisiert wird damit Interrupt auslöst wird 
mit 1ms ..., dann sprechen wir von 1ms Timer Tick.

von merciMerci (Gast)


Lesenswert?

Michael schrieb:
> Bei einem 4MHz System habe ich eine Tickzeit von 1/4000000 = 0,25us

NO!

Der Begriff "Tickzeit" wäre eher falsch, besser wäre Instruction Cycle.
und mit "1/4000000" ABER auch nur, WENN das eine One-Cycle MCU wäre. 
Auch dann gibt es noch Intructions, die mehr als einen Instruction Cycle 
benötigen, e.g. call oder so, wo die Instruction pipeline nichts bringt 
...

von Arno (Gast)


Lesenswert?

Michael schrieb:
> so wie ich es verstehe bräuchte ich 100000 Ticks um die 25ms zu
> überbrücken,
> wird aber die komplette for Schleife pro Tick abgearbeitet ?
> Mir ist nicht ganz klar, welche Operation pro Tick durchgeführt wird.

Das kommt auf den Compiler und die CPU an.

Meine Glaskugel sagt, du willst das auf einem AVR ausführen, da wird ein 
Schleifendurchlauf mit Sicherheit länger als einen CPU-Takt brauchen, 
wenn nicht wegoptimiert.

Herausfinden kann man das, indem man sich den vom Compiler generierten 
Assembler-Code anschaut und dann im Datenblatt der CPU oder CPU-Familie 
nachschaut, wie viele Taktzyklen jeder Befehl braucht.

In vielen verbreiteten Makefiles für gcc für AVR wird der Assembler-Code 
direkt mit in eine Datei ausgegeben, mit *.lst oder *.s oder 
*.lss-Endung. Das sieht dann (Ausschnitt) zum Beispiel so aus:
1
  25:main.c        ****   // Activate pullup on PA6/OC1A
2
  26:main.c        ****   PORTA = (1<<PA6);
3
  45                   .loc 1 26 3 is_stmt 1 view .LVU6
4
  46                   .loc 1 26 9 is_stmt 0 view .LVU7
5
  47 000e 90E4          ldi r25,lo8(64)
6
  48 0010 9BBB          out 0x1b,r25

Daran sieht man: Der C-Code
1
PORTA = (1<<PA6);
wird übersetzt zu Assembler-Code
1
ldi r25,lo8(64)
2
out 0x1b,r25

(Ist leider nicht immer so eindeutig, gerade bei starken Optimierungen)

Im AVR Instruction Set Manual 
http://ww1.microchip.com/downloads/en/devicedoc/atmel-0856-avr-instruction-set-manual.pdf 
findet man dann:

> 73. LDI – Load Immediate
> [...]
> Cycles 1

und

> 88. OUT – Store Register to I/O Location
> [...]
> Cycles 1

...weiß also, dass
1
PORTA = (1<<PA6);

genau zwei Taktzyklen braucht.

MfG, Arno

von Einer K. (Gast)


Lesenswert?

Michael schrieb:
> wird aber die komplette for Schleife pro Tick abgearbeitet ?

Habe dein Programm mal so für Arduino abgeändert, dass es testbar ist.
1
enum status{OK,BAD};
2
status delay_func(uint32_t param)
3
{
4
    for(uint32_t i=0; i<param;)
5
    {
6
        i++;
7
    }
8
    return OK;
9
}
10
11
12
int main() 
13
{
14
  delay_func(100000);
15
}

--------

Auszug aus dem Kompilat:
1
00000080 <main>:
2
3
4
int main() 
5
{
6
  delay_func(100000);
7
}
8
  80:  90 e0         ldi  r25, 0x00  ; 0
9
  82:  80 e0         ldi  r24, 0x00  ; 0
10
  84:  08 95         ret
11
12
00000086 <_exit>:
13
  86:  f8 94         cli
14
15
00000088 <__stop_program>:
16
  88:  ff cf         rjmp  .-2        ; 0x88 <__stop_program>

In Worten:
Die Funktion  wird vollständig weg optimiert.
Die DelayZeit ist somit Null Takte.

von merciMerci (Gast)


Lesenswert?

... und wenn es hier nur um blocked delay geht, dann hilft das Macro
_delay_ms(), das macht auch alles richtig entsprechend angegebenen Takt.

https://www.nongnu.org/avr-libc/user-manual/group__util__delay.html

von Michael (Gast)


Lesenswert?

danke für die Klarstellung.

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.