PIC: Laufzeit eines Programmabschnittes bestimmen?

OP #5818818
Lesenswert?

Hallo zusammen,

Ich habe Laufzeitprobleme. Dass heisst, der Code-Block im Anhang braucht 
zu lange.

Ist es möglich, dass ich die Laufzeit eines Programmabschnittes (in C) 
berechnen (oder messen?) kann? Der 8-bit PIC16F15325 läuft mit 4MHz.
Ich weiss, dass eine Instruktion bei meinem PIC 4 Takte braucht, aber 
wie viele Instruktionen braucht dann ein if, ein floor(), ein kleiner 
als, ...?

Der Code im Anhang berechnet die Ziffern einer 4-stelligen 
7-Segment-Anzeige die aber nur in 25-er Schritten anzeigen soll 
(0,25,50,75,100,125,150,...2750).

Danke & Grüsse
Severin
Angehängte Dateien:
#5818842
Lesenswert?

Severin E. schrieb:
> Ist es möglich, dass ich die Laufzeit eines Programmabschnittes (in C)
> berechnen (oder messen?) kann?

direkt nicht. Entweder am Anfang einen Pin high und am Ende wieder low 
schalten (und Oszi dran), oder in der Assemblerdatei Instructions/Zyklen 
zählen, oder aber step für step Simulieren und Steps zählen.

Rest wurde schon gesagt:
Michael schrieb:
> Kein Wunder, die Gleitkommaarithmetik (float) ist ursächlich dafür.
OP #5818882
Lesenswert?

Danke für die Infos. Hab den Block mit Pin hoch/tief und Oszi gemessen. 
Braucht etwa 10ms. Seeehr lang. Dass heisst ja bei 4MHz, dass da 10'000 
Instruktionen ausgeführt werden. Ich werde mal versuchen, die floats 
wegzubringen ...

Ausserdem könnte ich den Chiptakt bis auf 32MHz erhöhen.
#5818898
Lesenswert?

Severin E. schrieb:
> Ich werde mal versuchen, die floats
> wegzubringen ...

Nicht versuchen, machen! Das Schlimmste was dabei passieren kann, ist 
dass Du ne Menge dabei lernst und wenn gar nichts mehr geht, dass Du 
hier noch mal fragen musst. Bei solchen Problemen ist hier jeder gern 
bereit zu helfen.

> Ausserdem könnte ich den Chiptakt bis auf 32MHz erhöhen.

Das ist cheaten..
OP #5818904
Lesenswert?

Thomas S. schrieb:
> Severin E. schrieb:
>> Ich werde mal versuchen, die floats
>> wegzubringen ...
>
> Nicht versuchen, machen! Das Schlimmste was dabei passieren kann, ist
> dass Du ne Menge dabei lernst und wenn gar nichts mehr geht, dass Du
> hier noch mal fragen musst. Bei solchen Problemen ist hier jeder gern
> bereit zu helfen.
>
>> Ausserdem könnte ich den Chiptakt bis auf 32MHz erhöhen.
>
> Das ist cheaten..

GENAU! Takt bleibt erst mal auf 4MHz. Die Berechnung muss sich ändern. 
Aber vielleicht nicht mehr heute Abend.

Danke euch allen!
OP #5818915
Lesenswert?

leo schrieb:
> Severin E. schrieb:
>> Der Code im Anhang berechnet die Ziffern einer 4-stelligen
>> 7-Segment-Anzeige
>
> Interessant. Wer liest die Anzeige so schnell ab, dass das ein Problem
> ist?
>
> leo

Die 4 Ziffern sollen nicht flackern. Als etwa 100Hz-Betrieb damit die 
Augen das nicht mitbekommen. 100Hz heisst bei 4 Ziffern, dass jede 
Ziffer 2,5ms bekommt. Da sollte man nicht noch andauernd 
10ms-Berechnungen dazwischenschieben.
Gast #5818925
Lesenswert?

Okay, was mir auffaellt:
1
uint16_t RPMdec;
2
uint16_t PWM10bit = 323;
3

4
RPMdec = (float)PWM10bit*2750/1024;
Wozu der Cast auf float? Die Nachkommastellen werden ja eh 
abgeschnitten. Dann tut es auch ein Cast nach uint32_t statt float.
1
DIG1 = (RPMdev/1000) % 10;
Mathematisch macht es keinen Unterschied ob du durch 1000 teilst oder 
nicht und dann den Rest nimmst.
(RPMdev/1000) % 10 = RPMdev % 10.
Ob es im erzeugten Code einen Unterschied macht musst du gucken.

Selbiges fuer DIG2.
1
float temp1;
2
temp1 = RPMdec - 100 * (floor(RPMdec/100));
Den Aufruf von floor() koenntest du auch sparen. Es ist eine 
Integer-Division. Das Abrunden passiert ja von ganz alleine.
Kurz:
100 * (floor(RPMdec/100)) = 100 * (RPMdec/100)

Und damit ist auch der float weg.

Gruesse
Gast #5818938
Lesenswert?

Severin E. schrieb:
> Die 4 Ziffern sollen nicht flackern. Als etwa 100Hz-Betrieb damit die
> Augen das nicht mitbekommen. 100Hz heisst bei 4 Ziffern, dass jede
> Ziffer 2,5ms bekommt. Da sollte man nicht noch andauernd
> 10ms-Berechnungen dazwischenschieben.

Du darfst du nur keine festen 10ms Blöcke dazwischen schieben. Die 
Rechnerei kann ganz in Ruhe ablaufen und die Anzeigesteuerung muss dann 
alle 2.5ms per Interrupt die Rechnerei irgendwo kurz unterbrechen und 
ein paar Takte für die Aktualisierung einfordern.
Gast #5820432
Lesenswert?

Volker S. schrieb:
> Severin E. schrieb:
>> Der Screenshot von MPLAB ist spannend. Dass heisst, es gibt irgendwo
>> beim Debuggen ein "Stopwatch" zum messen von Laufzeiten. Muss mal suchen
>> gehen...
>
> Geht im Simulator. https://www.youtube.com/watch?v=bUookr-2O-s
> (Stopwatch kommt so bei 5min.)

Nicht nur. Das geht so auch zur Laufzeit auf dem Device. Man setzt zwei 
Breakpoints, und kann die Anzahl der Takte zwischen diesen messen.

Das ist dann praktisch, wenn die Laufzeit von externen Faktoren abhängt.
Außerdem kann man sich den Simulator so sparen.
Gast #5820443
Lesenswert?

Volker S. schrieb:
> soso... schrieb:
>> Nicht nur. Das geht so auch zur Laufzeit auf dem Device. Man setzt zwei
>> Breakpoints, und kann die Anzahl der Takte zwischen diesen messen.
>
> Aber leider nicht mit jedem Debugger-Tool und nicht bei jedem PIC.

Hmm. Also ich sehe aus dem Datenblatt des erwähnten PIC keine Grund, 
warum das nicht ginge. Man sollte den ja debuggen können, und ein 
PICkit3 kann Stopwatch. Eigentlich sollte das auch mit den billigen 
Klones gehen.

Woran sieht man, ob das geht oder nicht?

Bei mir gings bisher immer (hauptsächlich PIC24 allerdings).
Gast #5820468
Lesenswert?

Es wird zum Testen des Codeabschnittes keinerlei wechselwirksamer 
Peripherie beansprucht. Also Simulator. Da gibt es jede menge 
Breakpoints, Stopwatch, Disassembly, ...

Und man sieht gleich, wie langsam der Code des freien XC8 ist. Gut 
optimierend käme wohl sowas wie folgend raus.

1
uint8_t segment_code(uint8_t x)
2
{
3
    asm ("andlw 0x0f");
4
    asm ("brw");
5
    asm ("retlw 0xfc");
6
    asm ("retlw 0x60");
7
    asm ("retlw 0xda");
8
    asm ("retlw 0xf2");
9
    asm ("retlw 0x66");
10
    asm ("retlw 0xb6");
11
    asm ("retlw 0xbe");
12
    asm ("retlw 0xe0");
13
    asm ("retlw 0xfe");
14
    asm ("retlw 0xf6");
15
    asm ("retlw 0x00");
16
    asm ("retlw 0x02");
17
    asm ("retlw 0x01");
18
    asm ("retlw 0xff");
19
    asm ("retlw 0xff");
20
    asm ("retlw 0xff");
21
    
22
    return 0xff;        // suppress warning
23
}
#5820484
Lesenswert?

soso... schrieb:
> ein PICkit3 kann Stopwatch...
>
> Bei mir gings bisher immer (hauptsächlich PIC24 allerdings).

Ups, da muss ich mal schauen, ob das bei PIC16/18 auch geht.
Sollte laut dieser Tabelle mit PICkit3 eigentlich gar nicht gehen:
http://microchipdeveloper.com/tls0201:debug-tool-capabilities

Vielleicht veraltet?
(ging evtl. früher nicht und ich habe es noch gar nicht bemerkt,
dass das jetzt geht, weil ich den Simulator praktisch nicht benutze)
Gast #5820964
Lesenswert?

Volker S. schrieb:
> soso... schrieb:
>> ein PICkit3 kann Stopwatch...
>>
>> Bei mir gings bisher immer (hauptsächlich PIC24 allerdings).
>
> Ups, da muss ich mal schauen, ob das bei PIC16/18 auch geht.
> Sollte laut dieser Tabelle mit PICkit3 eigentlich gar nicht gehen:
> http://microchipdeveloper.com/tls0201:debug-tool-capabilities
>
> Vielleicht veraltet?
> (ging evtl. früher nicht und ich habe es noch gar nicht bemerkt,
> dass das jetzt geht, weil ich den Simulator praktisch nicht benutze)

Interessant, laut deinem Link dürfte es mit dem PICkit3 nicht gehen.

Ich bin mir aber zu sicher, dass ich mit MPLABX, dem PICkit3 und der 
Stopwatch auf und einige Projekte damit optimiert zu haben (zu 100% 
sicher bin ich mir bei den Devices PIC24FJ128GB204  und PIC32MX370). Das 
war mit einem MPLABX 3.xx.

Naja, falls alle Stricke reißen, gibts ja noch Timer. Man kann sich 
einen aufsetzen, der im µs-Takt zählt, und damit die Zeit messen. Man 
kann sogar OC-Timer nehmen, falls vorhanden.

Das Scope wurde schon genannt.
Gast #5825469
Lesenswert?

Was ich gesehen habe, nutzt du das ganze für Anzeigezwecke im 
BCD-Format. Da könntest du die Berechnung doch auch mehr oder weniger 
gleich in BCD machen. Den Quelltext habe ich mal angehängt.
Die 1000er Stelle kann ja nur 0, 1 oder 2 werden --> deswegen if - 
Abfrage "zu Fuß".
Die noch verbliebenen Hunderter können Wertemäßig noch über 255 sein, 
deshalb wird ein konstantes 16 Bit Array zum Vergleich genutzt und die 
Wertigkeit bestimmt.
Bei der Berechnung der 10er - Stelle kann im verbleibenden Wert niemals 
etwas über 255 stehen --> es wird mit 8 Bit gearbeitet, das macht das 
ganze schneller.
Auf die Berechnung der 1er Stelle habe ich verzichtet, das würde ich 
dann aber auch wieder "zu Fuß" machen, wenn benötigt - ungenau ist es 
allemal.
Damit sollte sich noch etwas mehr Rechenzeit sparen lassen, schlecht ist 
nur: Es muss ggf. bei anderer Skalierung der Drehzahl umgeschrieben 
werden.

Ob du dir so eine Code-Krake ins Programm holen willst, ist auch noch 
eine Frage... :)
1
#define MUL 1024*1024/2750
2
const unsigned int div100[9] = { //16 Bit Vergleichsarray für 100er
3
   1*MUL/10, 2*MUL/10, 3*MUL/10, 4*MUL/10, 5*MUL/10, 
4
   6*MUL/10, 7*MUL/10, 8*MUL/10, 9*MUL/10 };
5

6
const unsigned char div10[9] = { //8 Bit Vergleichsarray für 10er
7
   1*MUL/100, 2*MUL/100, 3*MUL/100, 4*MUL/100, 5*MUL/100,
8
   6*MUL/100, 7*MUL/100, 8*MUL/100, 9*MUL/100 };
9

10
unsigned char bcdout[4] = {0,0,0,0}; //BCD-Ausgabe-Array (1000er - 1er)
11
unsigned char j;  //Schleifenzähler
12
unsigned char RPMdecLowerByte;
13

14
RPMdec = PWM10bit;
15

16
if (RPMdec >= 2*MUL) {  //1000er Stelle --> Wertigkeit 2
17
  bcdout[0] = 2;
18
  RPMdec -= 2*MUL;
19
}
20
if (RPMdec >= 1*MUL) {  //1000er Stelle --> Wertigkeit 1
21
  bcdout[0] = 1;
22
  RPMdec -= 1*MUL;
23
}
24

25

26
//Ermittle 100er Stelle mit 16-Bit-Vergleichsarray
27
for (j = 8; j >= 0; j--) {  // fange bei höchster Wertigkeit an
28
  if (RPMdec >= div100[j]) {  //sobald RPMdec größer als vergleichswert
29
    bcdout[1] = j + 1;  //schreibe Ziffer
30
    RPMdec -= div100[j]; //Ziehe Ziffernwertigkeit von RPMdec ab
31
    break;  //und beende for-schleife
32
  }
33
}
34

35
RPMdecLowerByte = RPMdec & 0xFF; //Lower Byte in 8 Bit Variable
36

37
//Ermittle 10er Stelle mit 8-Bit-Vergleichsarray
38
for (j = 8; j >= 0; j--) {  // fange bei höchster Wertigkeit an
39
  if (RPMdecLowerByte >= div10[j]) {  //sobald RPMdec größer als vergleichswert
40
    bcdout[2] = j + 1;  //schreibe Ziffer
41
    RPMdecLowerByte -= div10[j]; //Ziehe Ziffernwertigkeit von RPMdec ab
42
    break;  //und beende for-schleife
43
  }
44
}

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