Ich brauche Hilfe beim Optimieren eines Codeabschnittes

Gast #1736677
Lesenswert?

Guten Tag

Ich verwende einen ATtiny24 um die Zeitdauer zwischen Signalflanken zu 
stoppen.
Dies mache ich über das PCINT Ereignis.
Ich habe bis jetzt nur sehr wenig mit Mikrocontrollern gearbeitet.
Desswegen weis ich nicht ob und wie man das Programm noch schneller 
machen kann.
Kann mir bitte jemand einen Tipp geben wie ich den Quellcode im Bereich 
der Interruptroutine optimieren kann?
1
// Pin change 0-7 interrupt service routine
2
ISR( PCINT0_vect )
3
{
4
  // Sichern des Zählerwertes, da der Zähler nicht angehalten werden 
5
  Timer1Aus;// Der Timer wird über eine Deffinition angehalten
6
  unsigned short  usTimerTemp = TCNT1; 
7
  Timer1An;// Der Timer wird über eine Deffinition gestartet
8

9
  // Sichern des Port's, da sich dieser während des Abarbeiten des Interupt's ändern kann
10
     unsigned char   uchPortIn = PINA ^ uchBitMaskeXorA; // uchBitMaskeXorA dient dazu, einzelne Signale zur Laufzeit zu invertieren
11

12
//////////////////// Signal 1 ////////////////////    
13
  // Ermitteln des aktuellen Signalwertes
14
  unsigned short uchWert  = uchPortIn & DEF_PIN_SIGNAL_1;  
15
  
16
  // Pegeländerung beim Signal?
17
  if(uchWert != (uchPortAalt & DEF_PIN_SIGNAL_1))
18
  {
19
    /*High/Low Pegel?*/
20

21
    if(uchWert > 0)/* High-Pegel*/
22
    {
23
      usStartSignal[1]= usTimerTemp; // Sichern der Startzeit;
24
    
25
    }
26
    else  /* Low-Pegel*/
27
    {  
28
      // Berechnen der Signalzeit
29
      // Ein Auftreten des Überlaufs des 16 Bit Zählers während der Zeitmessung
30
      // wird bewusst in Kauf genommen.
31
      usInputSignal[DEF_FELD_SIGNAL_1] = usTimerTemp - usStartSignal[1];
32

33
    }
34
    uchPortAalt = uchPortIn; // Aktueller Portwert = Portwert für nächste für die nächste Zeitermittlung
35
    return;
36
  }
37
//////////////////// Signal 3 ////////////////////    
38
  // Ermitteln des aktuellen Signalwertes
39
  uchWert  = uchPortIn & DEF_PIN_SIGNAL_3;  
40
  
41
  // Pegeländerung bei Signal3?
42
  if(uchWert != (uchPortAalt & DEF_PIN_SIGNAL_3))
43
  {
44
    /*High/Low Pegel?*/
45
    if(uchWert > 0)/* High-Pegel*/
46
    {
47
      usStartSignal[3]= usTimerTemp; // Sichern der Startzeit;
48
    }
49
    else  /* Low-Pegel*/
50
    {  
51
      // Berechnen der Signalzeit
52
      usInputSignal[DEF_FELD_SIGNAL_3 ] = usTimerTemp - usStartSignal[3];
53
    }
54
    uchPortAalt = uchPortIn; // Aktueller Portwert = Portwert für nächste für die nächste Zeitermittlung
55
    return;
56
  }
57
// Hier werden die weiteren Signale die am Port liegen ausgewertet
58
}
#1736684
Lesenswert?

Grundsätzlich gilt, bei Optimierungsfragen im das Listing durchschauen. 
Poste das doch mal.
Willst du auf Codegrö0e oder auf Dauer optimieren?

Was bei dir sein könnte (Bauchgefühl): Arrays ansteuern kann durch die 
Multiplikationen (wenn kein Hardware Multiplizierer da ist) viel Code 
brauchen.
Aber wie gesagt, poste das Listing und dann wird dir geholfen.
#1736693
Lesenswert?

Damit kann keiner was anfangen.
Du mußt schon einen compilierbaren Code schicken (als Anhang!).

D.h. sämtliche verwendete Variablen, Macros, Unterfunktionen müssen 
definiert sein.

Unterfunktionen in Interrupts sind generell ne schlechte Idee. Entweder 
als Macro oder Inline-Funktion.


Peter
Gast #1736765
Lesenswert?

Michael H. schrieb:
> Grundsätzlich gilt, bei Optimierungsfragen im das Listing durchschauen.
> Poste das doch mal.
> Willst du auf Codegrö0e oder auf Dauer optimieren?
Ich möchte auf Geschwindigkeit optimieren.
(Der Programmcode sollte aber nicht all zu groß werden.)
Die LSS Datei habe ich in die Zip-Datei gepackt.

Peter Dannegger schrieb:
> Unterfunktionen in Interrupts sind generell ne schlechte Idee. Entweder
> als Macro oder Inline-Funktion.
Wo bitte siehst du im Interrupt einen Aufruf einer Unterfunktion?
Wenn du auf Timer1Aus; und Timer1An; anspielst, dass sind Deffinitionen.
Damit verhindere ich, dass ich beim Ändern des Timer-Taktes eine Stelle 
übersehe.


Ich habe den Quellcode zusammengekürzt und die benötigten Funktionen und 
Deffinitionen in die Main-Datei kopiert.

Könnt ihr mir bitte Tipps geben, wieich die Abarbeitung in dieser 
Interruptroutiene beschleunigen kann?
Denn die Signalzeiten sollten möglichst nicht zu stark verfälscht 
werden.


Bernhard
Angehängte Dateien:
Gast #1736777
Lesenswert?

Danke für dan Hinweis.
Den Fehler hatte ich glatt übersehen.

Aber beim Arbeiten mit 16Bit Arrays dürfte man sicherlich auch einiges 
rausholen können wenn man die richtigen Kniffe kennt.
Oder sehe ich das falsch?

mfg Bernhard
#1737223
Lesenswert?

Auf mehrere Pin-Changes des gleichen Ports so zu reagieren, dass weder 
Information verloren geht noch doppelt gezählt wird, ist nicht ganz 
einfach. Wenn zwischen dem Eintritt in den ISR und dem Auslesen des 
Portregisters eine weitere Flanke (ggf. an einem anderen Pin) reinkommt, 
dann ist das Interrupt-Flag wieder gesetzt, infolgedessen wird dein 
Handler dafür noch einmal aufgerufen und die gleiche Sache ggf. zweimal 
betrachtet.

Da du den Handler nach dem ersten erkannten Bit beendest, hängt das 
Vehalten dann auch noch von der exakten Reihenfolge der Flanken ab und 
es kann Information dabei sowohl doppelt gezählt werden, als auch 
verloren gehen.
Gast #1737276
Lesenswert?

A. K. schrieb:
> Auf mehrere Pin-Changes des gleichen Ports so zu reagieren, dass weder
> Information verloren geht noch doppelt gezählt wird, ist nicht ganz
> einfach. Wenn zwischen dem Eintritt in den ISR und dem Auslesen des
> Portregisters eine weitere Flanke (ggf. an einem anderen Pin) reinkommt,
> dann ist das Interrupt-Flag wieder gesetzt, infolgedessen wird dein
> Handler dafür noch einmal aufgerufen und die gleiche Sache ggf. zweimal
> betrachtet.
>
> Da du den Handler nach dem ersten erkannten Bit beendest, hängt das
> Vehalten dann auch noch von der exakten Reihenfolge der Flanken ab und
> es kann Information dabei sowohl doppelt gezählt werden, als auch
> verloren gehen.
Ich dachte, dass ich dass doppelt Zählen / Auslassen gelöst habe, indem 
ich den Portwert gleich beim Eintritt in den Interrupt sichere und 
diesen Wert für die Flankenerkennung verwende.
Habe ich da etwa einen Denkfehler?

A. K. schrieb:
> Da sämtliche Indizes konstant sind kannst du zwar den Sourcecode kürzen
> indem eine Schleife draus wird, die Laufzeit wird dadurch aber
> schlechter.
Aus diesem Grund habe ich zum ungeliebten Wurst-Code gegriffen.
Gibt es einen Weg die Abarbeitung zu beschleunigen?
#1737287
Lesenswert?

Bernd schrieb:

> Ich dachte, dass ich dass doppelt Zählen / Auslassen gelöst habe, indem
> ich den Portwert gleich beim Eintritt in den Interrupt sichere und
> diesen Wert für die Flankenerkennung verwende.
> Habe ich da etwa einen Denkfehler?

Ja.
Du sicherst zwar den Wert, das ist schon richtig.
Aber wenn du in der Auswertung auf die erste Änderung triffst, 
bearbeitest du diese und hörst danach auf, nach weiteren Änderungen zu 
suchen.

Deine ISR barbeitet prinzipiell nur 1 Pin Änderung bei einem Aufruf. Nur 
garantiert dir niemand, dass nicht 2 Änderungen gleichzeitig auftreten 
können.

> Gibt es einen Weg die Abarbeitung zu beschleunigen?

Du musst zb hier
1
  if(uchWert != (uchPortAalt & DEF_PIN_SIGNAL_1))
jedesmal aus uchPortAalt den interessierenden Pin extrahieren. Wenn du 
für jeden Pin eine eigene 'alt' Variable hättest, könntest du dir das 
sparen.
#1737298
Lesenswert?

Eine andere Möglichkeit:

Wenn du den neuen Port Wert mit dem alten kompletten Port-Wert 
ver-xoderst, so bleiben dir genau dort 1 Bits stehen, wo es eine 
Änderung gab.

Dadurch werden dann in weiterer Folge die Abfragen auf die Änderungen 
einfacher.
1
  unsigned char   uchPortIn = PINA ^ uchBitMaskeXorA; // uchBitMaskeXorA dient dazu, einzelne Signale zur Laufzeit zu invertieren
2

3
  unsigned char   changedBits = uchPortIn ^ uchPortAalt;
4

5
  if( changedBits & DEF_PIN_SIGNAL_1 )
6
    behandle Änderung an PIN 1
7

8
  if( changedBits & DEF_PIN_SIGNAL_2 )
9
    behandle Änderung an PIN 2
10

11
  if( changedBits & DEF_PIN_SIGNAL_3 )
12
    behandle Änderung an PIN 3
13

14
  ...
15

16
  uchPortAalt = uchPortIn;
17
}
Gast #1737422
Lesenswert?

Karl heinz Buchegger schrieb:
> Vielleicht sollte man auch einmal darüber sprechen, warum du denkst
> optimieren zu müssen.
> Hast du ein Problem, von dem du denkst das du es mit Optimierung lösen
> könntest?
Aktuell ist der Prozessor mit dem Ermitteln, Verarbeiten und 
weiterleiten der Signale voll ausgelastet.
Ich will jetzt noch eine zusätzliche Plausibilitätsprufung mit einbauen.
Dafür ist aber leider in der aktuellen Version nicht mehr genug 
Rechenzeit übrig.

Dein Lösungsansatz hat was.
Gibt es einen Weg zu verhindern dass die Interrupt-Routiene "leer" 
durchläuft wenn mehrere Pegeländerungen gleichzeitig auftreten?
Gast #1737531
Lesenswert?

Karl heinz Buchegger schrieb:
>> Aktuell ist der Prozessor mit dem Ermitteln, Verarbeiten und
>> weiterleiten der Signale voll ausgelastet.
>
> Wie schnell sind die Signale?

Es sind bis zu 8 unterschiedliche Signale zwischen 50Hz und 100Hz.
Dabei treffen die einzelnen Signale asynchron ein.
Dass bedeutet, es können sich ein oder mehrere Pegel gleichzeitig 
ändern.

Karl heinz Buchegger schrieb:
> Zeig mal den Rest

Da ist eigentlich nicht viel zu zeigen.
Aktuell wird nur dass Array mit den Daten über die USI im SPI-Modus 
übertragen. Ich vermute, dass der Fehler (starkes "flattern" der Werte), 
der bei zusätzlichen Aufgaben aufgetreten ist, vom Fehler bei der 
Auswertung aufgetreten ist.

Ich werde deinen Vorschlag ausprobieren und bescheid geben wie sich der 
uC verhält.

mfg Bernhard
#1737536
Lesenswert?

Bernhard schrieb:
> Karl heinz Buchegger schrieb:
>>> Aktuell ist der Prozessor mit dem Ermitteln, Verarbeiten und
>>> weiterleiten der Signale voll ausgelastet.
>>
>> Wie schnell sind die Signale?
>
> Es sind bis zu 8 unterschiedliche Signale zwischen 50Hz und 100Hz.

Das gibts nicht, dass dein µC da nicht hinterher kommt.
Da hast du irgendwo einen kompletten Bock geschossen

>> Zeig mal den Rest
>
> Da ist eigentlich nicht viel zu zeigen.

Zeigs trotzdem.
Wenn du Rat zu einem Code haben willst:
Zeig den Code her und beschreibe ihn nicht.
Gast #1742214
Lesenswert?

Karl heinz Buchegger schrieb:
> Das gibts nicht, dass dein µC da nicht hinterher kommt.
> Da hast du irgendwo einen kompletten Bock geschossen
Ja.
Nach einiger Suche habe ich den erlegten Bock gefunden.
Der Fehler lag nicht im bestehenden Programm.
Er lag darin, dass ich versucht hatte, Teile der Plausibilitätsprüfung 
im Interrupt zu erledigen.

Wenn alle Signalle gleichzeitig eine steigende Flanke und innerhalb 3 
bis 4 ms eine Fallende haben, tritt der Fehler auf.

Ich habe die gesammte Plausibilitätsprüfung in die Hauptschleife gelegt 
und jetzt läuft alles reibungslos.

Karl heinz Buchegger schrieb:
> Zeigs trotzdem.
> Wenn du Rat zu einem Code haben willst:
> Zeig den Code her und beschreibe ihn nicht.
Lieber nicht. Ich schäme mich dafür zu sehr.

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