-
        

Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 12

Thema: Atmega: Prozessorauslastung feststellen und Fehlerhandling

  1. #1
    Erfahrener Benutzer Begeisterter Techniker Avatar von schorsch_76
    Registriert seit
    25.03.2012
    Ort
    Kurz vor Neuschwanstein
    Alter
    41
    Beiträge
    398

    Atmega: Prozessorauslastung feststellen und Fehlerhandling

    Anzeige

    Hallo zusammen!

    Zur Prozessorauslastung:
    Ich würde gern wissen wie es um die CPU Zeit auf meinem Atmega aussieht. Nur .. wie feststellen. Ich habe keinen Taskmanager

    Mein Programmaufbau ist eigentlich immer gleich: I2C/UART/SPI läuft im Interrupt und wird über fifos gefüttert und gelesen. Hauptprogramm macht den Rest wie die generellen Abläufe, stößt dann über die Fifos senden and Display etc an. Nur: Wie kann ich sagen wieviel CPU Zeit ich noch zu Verfügung habe. Einfach über einen Ausgang und Oszi die Zeit eines Main while Schleifen Durchgang messen?

    Wie macht ihr das? Klar kommt das darauf an, wie viel Zeit ich für eine Schleife haben will.

    Zum Fehlerhandling:
    Sagenb wir mal es fällt ein I2C Slave aus. Dann bekomm ich ja vom I2C eine Antwort dass der Slave nicht antwortet. Hier kann man bsp. im Display eine Seite machen die Zeigt ob die Slaves i.O. sind. und für den "Gesamtstatus" noch eine klassische LED direkt am Atmega.

    Wie macht ihr das?

  2. #2
    Erfahrener Benutzer Lebende Robotik Legende Avatar von PICture
    Registriert seit
    10.10.2005
    Ort
    Freyung bei Passau in Bayern
    Alter
    66
    Beiträge
    10.970
    Hallo!

    Zitat Zitat von schorsch_76 Beitrag anzeigen
    Ich würde gern wissen wie es um die CPU Zeit auf meinem Atmega aussieht.
    Ich denke, dass bei in einer endloser Schleife laufendem Programm die CPU immer 100 % ausgelastet ist.
    MfG (Mit feinem Grübeln) Wir unterstützen dich bei deinen Projekten, aber wir entwickeln sie nicht für dich. (radbruch) "Irgendwas" geht "irgendwie" immer...(Rabenauge) Machs - und berichte.(oberallgeier) Man weißt wie, aber nie warum. Gut zu wissen, was man nicht weiß. Zuerst messen, danach fragen. Was heute geht, wurde gestern gebastelt. http://www.youtube.com/watch?v=qOAnVO3y2u8 Danke!

  3. #3
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    13.01.2014
    Beiträge
    398
    Blog-Einträge
    3
    Du vermischt hier ein bischen was...
    Betriebssysteme managen die CPU-Nutzung normalerweise via Dispatcher / Prozess-Scheduler.

    Da Atmegas aber in den seltensten Fällen mit Betriebssystem laufen, musst du selbst die Sytem-Resourcen verwalten.
    Ansonsten ist die CPU-Auslastung ist immer 100%.

  4. #4
    Erfahrener Benutzer Begeisterter Techniker Avatar von schorsch_76
    Registriert seit
    25.03.2012
    Ort
    Kurz vor Neuschwanstein
    Alter
    41
    Beiträge
    398
    Na ich kenn das bsp. von Beckhoffsteuerungen. Hier läuft auch der Echtzeitteil in einer Endlosschleife, aber in Zeitscheiben. Ok. Ich werd einfach den Durchlauf einer Main while schleife messen.

    Wie macht ihr bsp. das Fehlerhandling bei nicht antwortenden Slaves?

  5. #5
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    7.554
    ... Prozessorauslastung ... auf meinem Atmega ... I2C/UART/SPI läuft im Interrupt ... über fifos gefüttert ...
    Diese Messungen sind so ne Sache.

    Du KÖNNTEST natürlich in jeder ISR zu Beginn ne LED anknippsen und vorm RETI wieder ausmachen. Das wäre ziemlich real, total chaotisch und es fehlt dabei der ISR-Overhead zum Sichern und Wiederbeleben von Registern etc.

    Die andere Möglichkeit ist etwas Handarbeit (Kopfarbeit): in der Datei deinfile.lls steht der komplette Code als Hex, dazu disassembliert - also Mnemonics - und als Assemblercode mit den zugehörigen, absoluten Adressen. Hier kannst Du Dir also anhand der jeweiligen Befehlslaufdauer (Zyklenzahl) und der Anzahl Befehle die benötigte Laufdauer (beachte die Zeit pro Befehl - abhängig vom Quarztakt) von Programmabschnitten, Subroutinen und ISRs errechnen.

    Nachtrag zu Fehlerbehandlung:
    ... Wie macht ihr bsp. das Fehlerhandling bei nicht antwortenden Slaves ...
    Je nach (z.B. I²C-) Bibliothek bzw. Gestaltung der Subroutinen muss evtl. der Hänger abgefangen werden. Und die Fehlererkennung/-meldung/-behandlung geht bei mir z.B. so :
    Code:
        if(!(i2c_start(SLAVE_MoCo+I2C_WRITE))) //Slave bereit zum schreiben?
        {                                   //
          i2cdmy  =  i2c_write (0x01);      // Buffer Startadresse 01 setzen     
          i2cdmy  =  i2c_write (byte1);     //   zum Schreiben. 01 {0, 10}
          i2cdmy  =  i2c_write (byte2);     //
          i2cdmy  =  i2c_write (byte3);     //
                    i2c_stop();             // Zugriff beenden
        }                                   //
        else                                  // Melde jetzt: Kein Byte geschrieben
        {                                     //   und Fehlerblinken
          uputs0("\r\n\tKein I2C-Schreiben möglich.\r\n");     //
          i2cerr      = 0b00000010;           // i2c-write nicht möglich
          for(i=0; i<2; i++)  {               // Fehlermeldung: LED i-fach blinken
            SetBit(PORTC, 2);                 // LED EIN, HELL
            waitms(3);                        // 
            ClrBit(PORTC, 2);                 // LED AUS, Dunkel
        }                   // Ende if(!(i2c_start(SLAVE_MoCo+I2C_WRITE)))
    //      Schreiben an Slave ist erledigt oder nicht - dann Fehlermeldung
    das sieht dann in der *.lls so aus (und da drin stehen dann wirklich auch die entsprechenden Zeilen mit dem Quellcode ! ! !) :
    Code:
        if(!(i2c_start(SLAVE_MoCo+I2C_WRITE))) //Slave bereit zum schreiben?
        1d38:    82 e8           ldi    r24, 0x82    ; 130
        1d3a:    0e 94 6d 00     call    0xda    ; 0xda <i2c_start>
        1d3e:    88 23           and    r24, r24
        1d40:    d9 f5           brne    .+118        ; 0x1db8 <I2CTST01+0x10c>
        {                                   //
          i2cdmy  =  i2c_write (0x01);      // Buffer Startadresse 01 setzen     
        1d42:    81 e0           ldi    r24, 0x01    ; 1
        1d44:    0e 94 c6 00     call    0x18c    ; 0x18c <i2c_write>
          i2cdmy  =  i2c_write (byte1);     //   zum Schreiben. 01 {0, 10}
        1d48:    80 2f           mov    r24, r16
        1d4a:    0e 94 c6 00     call    0x18c    ; 0x18c <i2c_write>
          i2cdmy  =  i2c_write (byte2);     //
        1d4e:    81 2f           mov    r24, r17
        1d50:    0e 94 c6 00     call    0x18c    ; 0x18c <i2c_write>
          i2cdmy  =  i2c_write (byte3);     //
        1d54:    8f 2d           mov    r24, r15
        1d56:    0e 94 c6 00     call    0x18c    ; 0x18c <i2c_write>
     Terminates the data transfer and releases the I2C bus
    *************************************************************************/
    void i2c_stop(void)
    {
        /* send stop condition */
        TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
        1d5a:    60 92 bc 00     sts    0x00BC, r6
        
        // wait until stop condition is executed and bus released
        while(TWCR & (1<<TWSTO));
        1d5e:    80 91 bc 00     lds    r24, 0x00BC
        1d62:    84 fd           sbrc    r24, 4
        1d64:    fc cf           rjmp    .-8          ; 0x1d5e <I2CTST01+0xb2>
                    i2c_stop();             // Zugriff beenden
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          uputs0("\t3 Bytes an Slave\t");    // Melde: Bytes wurden geschrieben an
        1d66:    85 e1           ldi    r24, 0x15    ; 21
        1d68:    94 e0           ldi    r25, 0x04    ; 4
        1d6a:    0e 94 b1 01     call    0x362    ; 0x362 <uputs0_>
          uputs0i (SLAVE_MoCo+I2C_WRITE);     //   Slaveadresse
        1d6e:    82 e8           ldi    r24, 0x82    ; 130
        1d70:    90 e0           ldi    r25, 0x00    ; 0
        1d72:    0e 94 b7 0b     call    0x176e    ; 0x176e <uputs0i>
          uputs0("   =>\t");                 // 
        1d76:    88 e2           ldi    r24, 0x28    ; 40
        1d78:    94 e0           ldi    r25, 0x04    ; 4
        1d7a:    0e 94 b1 01     call    0x362    ; 0x362 <uputs0_>
          uputs0i(byte1);     uputs0("    ");
        1d7e:    80 2f           mov    r24, r16
        1d80:    90 e0           ldi    r25, 0x00    ; 0
        1d82:    0e 94 b7 0b     call    0x176e    ; 0x176e <uputs0i>
        1d86:    8f e2           ldi    r24, 0x2F    ; 47
        1d88:    94 e0           ldi    r25, 0x04    ; 4
        1d8a:    0e 94 b1 01     call    0x362    ; 0x362 <uputs0_>
          uputs0i(byte2);     uputs0("    ");
        1d8e:    81 2f           mov    r24, r17
        1d90:    90 e0           ldi    r25, 0x00    ; 0
        1d92:    0e 94 b7 0b     call    0x176e    ; 0x176e <uputs0i>
        1d96:    8f e2           ldi    r24, 0x2F    ; 47
        1d98:    94 e0           ldi    r25, 0x04    ; 4
        1d9a:    0e 94 b1 01     call    0x362    ; 0x362 <uputs0_>
          uputs0i(byte3);     uputs0("    ");
        1d9e:    8f 2d           mov    r24, r15
        1da0:    90 e0           ldi    r25, 0x00    ; 0
        1da2:    0e 94 b7 0b     call    0x176e    ; 0x176e <uputs0i>
        1da6:    8f e2           ldi    r24, 0x2F    ; 47
        1da8:    94 e0           ldi    r25, 0x04    ; 4
        1daa:    0e 94 b1 01     call    0x362    ; 0x362 <uputs0_>
          uputs0("\r\n");                // Zeilenvorschub
        1dae:    87 e4           ldi    r24, 0x47    ; 71
        1db0:    91 e0           ldi    r25, 0x01    ; 1
        1db2:    0e 94 b1 01     call    0x362    ; 0x362 <uputs0_>
        1db6:    1c c0           rjmp    .+56         ; 0x1df0 <I2CTST01+0x144>
        }                                   //
        else                                  // Melde jetzt: Kein Byte geschrieben
        {                                     //   und Fehlerblinken
          uputs0("\r\n\tKein I2C-Schreiben möglich.\r\n");     //
        1db8:    89 e5           ldi    r24, 0x59    ; 89
        1dba:    94 e0           ldi    r25, 0x04    ; 4
        1dbc:    0e 94 b1 01     call    0x362    ; 0x362 <uputs0_>
          i2cerr      = 0b00000010;           // i2c-write nicht möglich
        1dc0:    30 92 3f 0f     sts    0x0F3F, r3
        1dc4:    20 e0           ldi    r18, 0x00    ; 0
          for(i=0; i<2; i++)  {               // Fehlermeldung: LED i-fach blinken
            SetBit(PORTC, 2);                 // LED EIN, HELL
        1dc6:    42 9a           sbi    0x08, 2    ; 8
        1dc8:    c6 01           movw    r24, r12
        1dca:    01 97           sbiw    r24, 0x01    ; 1
        1dcc:    f1 f7           brne    .-4          ; 0x1dca <I2CTST01+0x11e>
        1dce:    c6 01           movw    r24, r12
        1dd0:    01 97           sbiw    r24, 0x01    ; 1
        1dd2:    f1 f7           brne    .-4          ; 0x1dd0 <I2CTST01+0x124>
        1dd4:    c6 01           movw    r24, r12
        1dd6:    01 97           sbiw    r24, 0x01    ; 1
        1dd8:    f1 f7           brne    .-4          ; 0x1dd6 <I2CTST01+0x12a>
            waitms(3);                        // 
            ClrBit(PORTC, 2);                 // LED AUS, Dunkel
        1dda:    42 98           cbi    0x08, 2    ; 8
        1ddc:    8f e2           ldi    r24, 0x2F    ; 47
        1dde:    90 e0           ldi    r25, 0x00    ; 0
        1de0:    f6 01           movw    r30, r12
        1de2:    31 97           sbiw    r30, 0x01    ; 1
        1de4:    f1 f7           brne    .-4          ; 0x1de2 <I2CTST01+0x136>
    // ============================================================================= =
    // ============================================================================= =
    //### Programm pausieren lassen  !! Der Pausenwert ist nur experimentell !
      void waitms(uint16_t ms)      //
      {                             //
        for(; ms>0; ms--) 
        1de6:    01 97           sbiw    r24, 0x01    ; 1
        1de8:    d9 f7           brne    .-10         ; 0x1de0 <I2CTST01+0x134>
        }                                   //
        else                                  // Melde jetzt: Kein Byte geschrieben
        {                                     //   und Fehlerblinken
          uputs0("\r\n\tKein I2C-Schreiben möglich.\r\n");     //
          i2cerr      = 0b00000010;           // i2c-write nicht möglich
          for(i=0; i<2; i++)  {               // Fehlermeldung: LED i-fach blinken
        1dea:    2f 5f           subi    r18, 0xFF    ; 255
        1dec:    22 30           cpi    r18, 0x02    ; 2
        1dee:    59 f7           brne    .-42         ; 0x1dc6 <I2CTST01+0x11a>
        }                   // Ende if(!(i2c_start(SLAVE_MoCo+I2C_WRITE)))
    //      Schreiben an Slave ist erledigt oder nicht - dann Fehlermeldung
    Geändert von oberallgeier (02.09.2014 um 16:22 Uhr) Grund: Nachtrag zur Fehlerbehandlung
    Ciao sagt der JoeamBerg

  6. #6
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    20.08.2008
    Ort
    Kandel
    Alter
    29
    Beiträge
    1.220
    Zitat Zitat von schorsch_76 Beitrag anzeigen
    Mein Programmaufbau ist eigentlich immer gleich: I2C/UART/SPI läuft im Interrupt und wird über fifos gefüttert und gelesen. Hauptprogramm macht den Rest wie die generellen Abläufe, stößt dann über die Fifos senden and Display etc an. Nur: Wie kann ich sagen wieviel CPU Zeit ich noch zu Verfügung habe.
    Du musst mit der "freien" Zeit etwas Anfangen das Messbar ist. Wenn deine Hauptschleife so schnell läuft wie möglich, hast du 100% Auslastung. Wenn deine Hauptschleife (etwa über einen Timer) getaktet läuft, verbringt sie einen Teil der Zeit damit, auf einen Zählerstand oder Interrupt zu warten. In dieser Warteschleife könntest du nun einen Pin togglen und dann auf einem Oszi das Verhältnis zwischen den Ruhephasen und Umschaltphasen messen. Oder du inkrementierst einen Zähler, misst parallel dazu die Zeit und kannst dann über die Anzahl Instruktionen je Zählerinkrement durch die Anzahl der Takte/Zeiteinheit die Prozessorauslastung ermitteln. Der erste Ansatz hat den Vorteil, dass du die Worst-Case-Situation erkennen kannst (etwa weil verschiedene Interrupts zusammen kommen).

    Noch eine Anmerkung zu den 100%. Wenn du deinen Prozessor schlafen legst, durch einen Timer-Interrupt aufwachst und eine LED an/ausschaltest, hast du auch 100% Auslastung. Nämlich 100% der Takte in denen die CPU überhaupt läuft

    mfG
    Markus
    Tiny ASURO Library: Thread und sf.net Seite

  7. #7
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    26.11.2005
    Ort
    bei Uelzen (Niedersachsen)
    Beiträge
    7.942
    Bei so etwas wie UART, IC2 und ähnliches per Interrupt ist weniger die Prozessorauslastung (in der Regel 100% wenn die Hauptschleife nicht definiert wartet), sondern oft mehr der Anteil den die CPU in den ISRs im Mittel verbringt und dann die Worst case Antwortzeit für Interrupts. Den Anteil der Interrupts an der Gesamtlaufzeit lässt sich ggf. über die Geschwindigkeit der Hauptschleife messen, sofern die noch relativ einfach ist - sonst kann man besser rechnen aus den Aufruf-Frequenzen für die ISRs und die jeweiligen Laufzeiten. Die Interrupts Latenz kann man Rechnen: die Laufzeit der einzelnen ISRs lässt sich meist ganz gut im Simulator bestimmen. Den Worst case kann man dann ausrechnen als die Verzögerung durch die ggf. vorrangig ausgeführten ISRs + die eine die noch zu Ende erledigt werden muss und ggf. Verzögerungen aus CLI-SEI Blöcken.

    Es sind übliche weise die 2 Bedingungen die passen müssen: Einhalten einer maximalen Verzögerung für Interrupts und genügend restliche Rechenzeit für da Hauptprogramm.

  8. #8
    Erfahrener Benutzer Begeisterter Techniker Avatar von schorsch_76
    Registriert seit
    25.03.2012
    Ort
    Kurz vor Neuschwanstein
    Alter
    41
    Beiträge
    398
    Also kann ich hier einen ähnlichen Ansatz wählen wie unter Industriesteuerungen. Meine maximale Zeitscheibe definieren, bsp. 1 ms, in der meine Aktoren bedient werden sollen. Worst case Bedingungen herausfinden und optimieren.

    Ich habe eben die ganzen Interface Geschichten mit Absicht als IRQ laufen lassen, damit ich eben sowohl SPI, UART, und TWI parallel arbeiten lassen kann. Bsp. twimaster.c von P.Fleury ist ja polling basiert. Hier kann immer nur eine Sache, der TWI laufen. (ok ok, andere IRQs gehen auch, aber der TWI ist hier gepollt.) Meine IRQ basierten Interface Geschichten haben eben Abfragen wie "is_busy()/is_error()" um dann im Scheduler was anderes machen zu können wenn bsp. UART oder TWI noch nicht fertig ist. Alle Aktionen welche bsp. über TWI laufen müssen natürlich sequentiell laufen, wenn ich wie beim Atmega nur ein TWI habe ...das muss ich sicherstellen in meinem Scheduler, der ja "Auftraggeber" über die fifos ist. Damit habe ich aus Softwaresicht ein schön gelayertes Design. Oben der Scheduler und im unteren Layer die Hardwareschicht.

    Bei Industriesteuerungen läuft halt der main task immer im fixen Interval. Bei Zeitscheibenverletzungen kann man, muss man aber nicht, sollte aber, reagieren. Mir ging es darum zu erfahren wie ihr die Zykluszeiten aus dem Atmega herausholt. Sprich die Messwerte. Da scheint mir die Methode mit dem Togglepin von Markus recht gut. Das muss ich ausprobieren! Die Zählvariante der Takte ist sicher die genauste, aber aufwendigste. Danke für die Tipps an alle!

    Gruß
    Georg

  9. #9
    Erfahrener Benutzer Lebende Robotik Legende Avatar von PICture
    Registriert seit
    10.10.2005
    Ort
    Freyung bei Passau in Bayern
    Alter
    66
    Beiträge
    10.970
    Zitat Zitat von schorsch_76 Beitrag anzeigen
    Also kann ich hier einen ähnlichen Ansatz wählen wie unter Industriesteuerungen.
    Das weiß ich nicht, weil ich Industriesteuerungen zu gering kenne, aber bei µCs läuft es meistens so: http://rn-wissen.de/wiki/index.php/P...r#Multitasking .
    MfG (Mit feinem Grübeln) Wir unterstützen dich bei deinen Projekten, aber wir entwickeln sie nicht für dich. (radbruch) "Irgendwas" geht "irgendwie" immer...(Rabenauge) Machs - und berichte.(oberallgeier) Man weißt wie, aber nie warum. Gut zu wissen, was man nicht weiß. Zuerst messen, danach fragen. Was heute geht, wurde gestern gebastelt. http://www.youtube.com/watch?v=qOAnVO3y2u8 Danke!

  10. #10
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    26.11.2005
    Ort
    bei Uelzen (Niedersachsen)
    Beiträge
    7.942
    In der Realen HW kann man per Toogle/Signal Pin messen.

    Das Zählen / Aufaddieren der Takte kann einem größtenteils der Simulator abnehmen: einfach 2 Break-Punkte auf den Anfang und das Ende der ISR, und dann den Zyklenzähler nutzen. Der Aufwand hält sich so in Grenzen - mit etwas Übung eher einfacher als über die Hardware.

Seite 1 von 2 12 LetzteLetzte

Ähnliche Themen

  1. Drehbegwegung feststellen ???
    Von opus84 im Forum Suche bestimmtes Bauteil bzw. Empfehlung
    Antworten: 12
    Letzter Beitrag: 02.04.2013, 21:06
  2. Pinchange und Pegel feststellen gleichzeitig...
    Von Willa im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 5
    Letzter Beitrag: 25.01.2010, 22:03
  3. Drehrichtung feststellen
    Von Static im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 2
    Letzter Beitrag: 08.04.2006, 17:09
  4. Höhe feststellen
    Von BlackBroom im Forum Sensoren / Sensorik
    Antworten: 9
    Letzter Beitrag: 14.03.2006, 22:06
  5. Windrichtung feststellen
    Von BlackBroom im Forum Sensoren / Sensorik
    Antworten: 30
    Letzter Beitrag: 06.03.2004, 16:56

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •