Hallo zusammen,
ich beschäftige mich im Moment mit AVR und STM32 mit AVR-GCC bzw
ARM-GCC. Und
schon wieder bin ich auf eine Anfängerfrage gestoßen: Wie werden auf
einem Mikrocontroller eigentlich error()- und assert()-Funktionen
implementiert.
Momentan sieht es bei mir so aus, daß ich selbst eine Funktion void
error(void) implmentiert habe, die alle Ausgänge hochohmig schaltet und
dann in eine Dauer-while-Schleife übergeht. Irgendwann sieht man, daß
das "heartbeat"-Signal ausbleibt und kann dann mit dem Debugger
nachsehen.
Aber wie wird soetwas "richtig" gemacht?
Kennt ihr Quellen, die bewährte Verfahren beschreiben?
Viele Grüße
W.T.
assert() hab ich auf einem uC noch nie verwendet.
Ich versuch aber immer eine LED an irgendeinen freien port zu hängen,
die sendet im Normalfall eine Art "Heartbeat" (alle paar Sekunden kurz
blinken), und dann hab ich immer noch ein "panic(uint8_t code)"
Funktion, die blinkt mir zuerst ein SOS zu, und dann den code (meist nur
die unteren vier Bit) als eine Art Morsecode (0=kurz, 1=lang) zu.
Klaus Wachtler schrieb:> http://nongnu.org/avr-libc/user-manual/group__avr_...> http://nongnu.org/avr-libc/user-manual/group__avr_...>
Die beiden kannte ich schon. Leider fehlt mir die Erfahrung, um aus
dieser Beschreibung best practices abzuleiten.
> Wobei ich das noch nie gemacht habe. Wenn der Controller gar nichts mehr> macht, hat man nicht viel davon.> Evtl. ist es sinnvoller, neu zu starten?
Das hängt davon ab, in welchem Entwicklungstadium sich die Firmware
befindet. Wenn sie ausentwickelt ist, ist es sicherlich sinnvoll, wenn
sie irgendwie weiterläuft oder neustartet, wenn ein Fehler aufgetreten
ist (graceful degradation).
Im Stadium der Firmwareentwicklung will ich jedoch jeden Fehler so hart
und deutlich wie möglich merken, um ihn möglichst einfach beheben zu
können.
Na ja, so hart und deutlich wie möglich wäre 1 kg C4 mit Zünder an einem
Ausgang, der im Fehlerfall gesetzt wird.
Ansosonsten hiflt nur das übliche: Simuator, Emulator,
Debug-Textausgabe. Da kannst du dann aich assert-Macros der avr-libc
nutzen.
Oliver
Ich verwende am Cortex-M in Anlehnung an das normale assert() und Visual
Studio's "VERIFY" gerne sowas:
1
inlinevoidverify(boolcond){
2
if(!cond){
3
while(1){
4
asmvolatile("cpsid i\nbkpt");
5
}
6
}
7
}
8
9
#ifdef NDEBUG
10
// because eventual evaluation of the argument
11
#define assert(c) static_cast<void>(0)
12
#else
13
inlinevoidassert(boolcond){
14
verify(cond);
15
}
16
#endif
Die verify() -Funktion prüft ihr Argument immer, und schaltet im
Fehlerfall Interrupts ab und ruft "BKPT" auf, sodass ein evtl.
angeschlossener Debugger das als Breakpoint sieht und man wunderschön im
Backtrace etc. sehen kann was schief gelaufen ist.
Das assert() ist nur im Debug-Modus aktiv (sonst macht es gar nichts)
und prüft nur dann sein Argument. Man kann so in seinem Code auf
Verdacht überall mit assert() alle möglichen Variablen prüfen, und im
End-Programm nimmts keinen Platz/Rechenzeit weg. Hab so schon einige
Bugs gefunden.
Eventuell kann man ja noch Code einfügen um Pins auf Floating zu
schalten etc. Wenn man kein C++ sondern C verwendet muss man das
static_cast und das "bool" ändern.
Danke für die Antworten!
Aber das kann doch nicht alles sein?
Ich hätte gedacht, daß Fehlerbehandlung zu den Problemen für
Fortgeschrittene gehört und es deshalb schön formulierte best practices
gibt, damit wir Normalsterbliche nicht ziellos umherprogrammieren
müssen.
Oder gibt es soetwas erst ab Systemen mit Betriebssystemen?
EDIT: Nanu, kursiv geht nicht, wenn ein Zeilenumbruch drin ist (?)
Walter Tarpan schrieb:> Ich hätte gedacht, daß Fehlerbehandlung zu den Problemen für> Fortgeschrittene gehört und es deshalb schön formulierte best practices> gibt, damit wir Normalsterbliche nicht ziellos umherprogrammieren> müssen.
Nun ja, ein "assert" kann man schwer als "Fehlerbehandlung" bezeichnen.
Das ist sozusagen der Not-Aus, und in Produktivcode sollten sich meines
Wissens nach auch keine Asserts mehr befinden. Das ist eher ein
Testwerkzeug und muss auch nur anzeigen, wo etwas wie fehlgeschlagen
ist. Je nach Vorliebe und Möglichkeiten eben mit LEDs o.a.
Was du mit "error()" meinst musst du vielleicht noch etwas genauer
ausführen. Meinst du das als Synonym zu assert()? Oder im Sinne von
Exception-Handling usw., also echter Fehlerbehandlung?
OK, "assert" und "error" sind sicherlich keine Fehlerbehandlung für
Fortgeschrittene.
Also hätte ich den Thread eher "bewährte Methoden der Fehlerbehandlung
auf ARM und AVR" nennen sollen.
Walter Tarpan schrieb:> Also hätte ich den Thread eher "bewährte Methoden der Fehlerbehandlung> auf ARM und AVR" nennen sollen.
Viele Programmiersprachen bieten mit Exceptions einen vereinheitlichten
mächtigen Mechanismus zur Fehlerbehandlung; auf ARM's mit genug Speicher
kann man die in C++ verwenden. Ansonsten muss man sich halt wie immer
mit return codes behelfen. Da aber das typischer µC-Programm keine 100
Aufruf-Ebenen hat, ist das da noch verkraftbar...