Forum: Mikrocontroller und Digitale Elektronik AVR-Debugging: Speicherstelle überwachen


von Anton (Gast)


Lesenswert?

Hallo,

welche Möglichkeiten gibt es beim AVR-Debugging, eine konkrete 
Speicherstelle zu überwachen und beim Schreiben dorthin mit einem Halt 
abzubrechen damit man ermitteln kann welcher Code dazu führte?

Bei mir wird ein Stück Speicher falsch überschrieben und ich wüßte gern 
von welcher Stelle eines recht umfangreichen Programms inkl. vieler 
Interrupts.

Anton

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Anton schrieb:
> welche Möglichkeiten gibt es beim AVR-Debugging, eine konkrete
> Speicherstelle zu überwachen
Welcher AVR mit welcher Toolchain?

Ohne genauere Definition hier ein paar Suchbegriffe:
https://onlinedocs.microchip.com/pr/GUID-ECD8A826-B1DA-44FC-BE0B-5A53418A47BD-en-US-7/index.html?GUID-1A162E91-DAA7-4E50-AD74-8CF56E5BAC35

von Anton (Gast)


Lesenswert?

Danke Lothar, das schaut doch schon mal gut aus. Ich hoffe es ist so mit 
einem AVR128DBx Asm-programmiert möglich.

Anton

von Purzel H. (hacky)


Lesenswert?

Ich wuerd Funktionalitaeten abschalten und schauen, ob's immer noch 
passiert. Allenfalls einen Pin toggeln um zu erkennen, wo der Code 
durchgeht.

von Anton (Gast)


Lesenswert?

Purzel H. schrieb:
> Ich wuerd Funktionalitaeten abschalten und schauen, ob's immer noch
> passiert.

Das Problem ist der Fehler tritt nur selten unter ungeklärten 
Bedingungungen auf. Das so herauszufinden dauert zu lange.

Purzel H. schrieb:
> Allenfalls einen Pin toggeln um zu erkennen, wo der Code durchgeht.

So kannst Du aber nicht herausfinden welcher Code schreibend auf eine 
Speicherstelle zugreift.

Die oben erwähnten Data-Breakpoints scheinen das Mittel der Wahl. Leider 
finden sich im Netz nur Hinweise dazu zum Support bei Mega/XMega und 
nichts zu den neueren AVRxxDx... Habe momentan leider keinen Zugriff auf 
die Hardware.

von Hugo H. (hugo_hu)


Lesenswert?

Anton schrieb:
> Danke Lothar, das schaut doch schon mal gut aus. Ich hoffe es ist so mit
> einem AVR128DBx Asm-programmiert möglich.

Auch danke, schick - wusste ich noch nicht:

http://atmel-studio-doc.s3-website-us-east-1.amazonaws.com/webhelp/GUID-ECD8A826-B1DA-44FC-BE0B-5A53418A47BD-en-US-5/index.html?GUID-F9ABAF2B-36E5-4ABA-AC34-8E63007A1E84

von Elektrolurch (Gast)


Lesenswert?

Funktionieren denn die Data-Breakpoints bei den AVRs?
Die müssen doch vom Prozessor unterstützt werden.
Selbst bei den XMegas hat das, so weit ich weis - nicht funktioniert.
Wie sieht das bei den SAMs aus?
Rückmeldung wäre schön.

von Purzel H. (hacky)


Lesenswert?

Es ist aber schon klar, dass mit Hardware Debugging das 
Echtzeitverhalten kaputt ist. Denn die MegaAVR haben keinen Hardware 
Tracebuffer, oder Debugregister. Soweit ich weiss. Das laeuft dann ueber 
JTAG, und dauerndes Lesen/Schreiben.

von Peter D. (peda)


Lesenswert?

Anton schrieb:
> Bei mir wird ein Stück Speicher falsch überschrieben

Typisch sind das Pointerfehler. Z.B. eine Funktion will 2 Byte 
schreiben, der Pointer zeigt aber nur auf ein Bytearray. Oder das Array 
ist zu klein (Puffer ohne Test auf Arraygrenzen). Oder ein Pointer wird 
an einen Interrupt nicht atomar übergeben.
Die Indexschreibweise ist in der Regel weniger fehleranfällig, als die 
Pointerschreibweise.

von Purzel H. (hacky)


Lesenswert?

>>Purzel H. schrieb:
>> Ich wuerd Funktionalitaeten abschalten und schauen, ob's immer noch
>> passiert.
>
>Das Problem ist der Fehler tritt nur selten unter ungeklärten
>Bedingungungen auf. Das so herauszufinden dauert zu lange.

Ja... ich habe schon Tage(Wochen) an einem Stueck verbracht um solche 
Fehler zu finden. Ich wuensche viel Glueck.

von Peter D. (peda)


Lesenswert?

Anton schrieb:
> AVR128DBx Asm-programmiert

Schreib das Programm in C um, das eliminiert schonmal 90% der möglichen 
Fehlerquellen.
Ich hab gemerkt, ab einer Größe von 4..8kB sind Assemblerprogramme nicht 
mehr beherrschbar. Schon bei 2kB Größe fällt es schwer, nach einem Jahr 
wieder durchzublicken.

von Anton (Gast)


Lesenswert?

Peter D. schrieb:
> Anton schrieb:
>
>> Bei mir wird ein Stück Speicher falsch überschrieben
>
> Typisch sind ...

Ja, davon wird sicher etwas zutreffen. Fraglich nur an welcher Stelle.
Den Fall erschwert daß die Codeausführung maßgeblich von Input der über 
serielle Schnittstellen reinkommt abhängt.

Purzel H. schrieb:
> Ja... ich habe schon Tage(Wochen) an einem Stueck verbracht um solche
> Fehler zu finden. Ich wuensche viel Glueck.

Danke. Das werde ich brauchen. Vor allem sollten die Data-Breakpoints 
nicht funktionieren. Das Programm ist komplex, die Speicherstelle 
kritisch, mit diversen Nebenwirkungen des Überschreibens die schlecht 
überschaubar sind.

von Peter D. (peda)


Lesenswert?

Anton schrieb:
> Den Fall erschwert daß die Codeausführung maßgeblich von Input der über
> serielle Schnittstellen reinkommt abhängt.

Dann kommt noch hinzu, ob Du auch wirklich ein sauberes fehlertolerantes 
Protokoll definiert und implementiert hast. Alle Signale von außen 
können gestört sein. Du benutzt natürlich einen Quarz und der 
Baudratenfehler ist <1%?

: Bearbeitet durch User
von Anton (Gast)


Lesenswert?

Purzel H. schrieb:
> Es ist aber schon klar, dass mit Hardware Debugging das
> Echtzeitverhalten kaputt ist.

Zum Glück ist das in diesem Fall weitgehend egal.

Peter D. schrieb:
> Schreib das Programm in C um, das eliminiert schonmal 90% der möglichen
> Fehlerquellen.

Definitiv nicht. Auch wenn da sicher was dran ist. Soll hier aber jetzt 
keine Grundsatz-Diskussion werden.

von Anton (Gast)


Lesenswert?

Peter D. schrieb:
> Du benutzt natürlich einen Quarz und der Baudratenfehler ist <1%?

Nein. Die neueren AVRs sind bei den verwendeten Baudraten (9600/19200) 
mit internem Oszillator hinreichend genau, der Input ist OK (kann man 
sich ja im Debugger anschaun).

Peter D. schrieb:
> Dann kommt noch hinzu, ob Du auch wirklich ein sauberes fehlertolerantes
> Protokoll definiert und implementiert hast

Der Eingabestrom könnte Fehler enthalten die nicht berücksichtigt 
werden. Da das nicht geändert werden kann soll das Programm darüber 
hinwegsehen können.

von Oliver S. (oliverso)


Lesenswert?

Anton schrieb:
> Purzel H. schrieb:
>> Es ist aber schon klar, dass mit Hardware Debugging das
>> Echtzeitverhalten kaputt ist.
>
> Zum Glück ist das in diesem Fall weitgehend egal.

Wenn auf die Speicherstelle bis zum Auftreten des Fehler schon ein paar 
(tausend) Mal korrekt zugegriffen wird, ist das nicht mehr ganz so egal.

Oliver

von Peter D. (peda)


Lesenswert?

Anton schrieb:
> Nein. Die neueren AVRs sind bei den verwendeten Baudraten (9600/19200)
> mit internem Oszillator hinreichend genau

https://www.prosieben.de/tv/galileo/themen/mittwoch-17-dezember-2014/schlaumeier-pferd-vor-der-apotheke-kotzen-sehen

Vermutlich willst Du das Produkt nicht komerziell vermarkten.

Anton schrieb:
> Der Eingabestrom könnte Fehler enthalten die nicht berücksichtigt
> werden. Da das nicht geändert werden kann soll das Programm darüber
> hinwegsehen können.

Dafür muß aber der Programmierer selber sorgen, z.B. mit einem 
Protokoll. Außerdem müssen Pufferüberläufe in jedem Fall abgefangen 
werden.

von Anton (Gast)


Lesenswert?

Oliver S. schrieb:
> Wenn auf die Speicherstelle bis zum Auftreten des Fehler schon ein paar
> (tausend) Mal korrekt zugegriffen wird, ist das nicht mehr ganz so egal.

Ja.
Im normalen Ablauf wird darauf aber nur lesend zugegriffen. Ob dieser 
eine oder tausendfache falsche Schreib-Zugriff jetzt die Codeausführung 
verzögert oder nicht ist beim Debugging zweitrangig da ich nur 
herausfinden will von woher er kommt.

von Anton (Gast)


Lesenswert?

Peter D. schrieb:
> Vermutlich willst Du das Produkt nicht komerziell vermarkten.

Nein. Ein Hobbyprojekt.

Peter D. schrieb:
> Außerdem müssen Pufferüberläufe in jedem Fall abgefangen werden.

Ja. Diese gilt es auszuschließen. Den Speicher im Fehlerfall konnte ich 
mir aber schon angesehen. Dabei waren keine Überläufe bei den UART 
Empfangspuffern festzustellen.

von Gerald K. (geku)


Lesenswert?

Die große Frage ist, ob die Beobachtung in Echtzeit erfolgen muss.

Ohne einer Hardwareunzerstützung wid es in Echtzeit nicht möglich sein. 
Speziell bei MCs ohne externen Adress und Datenbus.

1.) Früher baute man eine Bond-Out Version des Chips um direkt ins 
Prozessorinnere sehen zu können. 
https://en.m.wikipedia.org/wiki/Bond-out_processor

2.) Bei neueren Prozessoren gibt es fürs Debugging eine am Prozessorchip 
implementierte Hardware. Stichwort: Hardware Breakpoints. 
https://stackoverflow.com/questions/8878716/what-is-the-difference-between-hardware-and-software-breakpoints

In beiden Fällen ist es möglich eine Exeption(Interrupt) zu setzen wenn 
die zu beobachtende Adresse benutzt wird. Bis an diese Stelle und nach 
dieser Stelle kann der Code in Echtzeit ausgeführt werden. Beim 
Auftreten der Adresse kann fürs Debugging durch die Exeption ein Code 
eingeschoben werden, um Programmzähler und alle anderen internen 
Register zwischendurch auslesen zu können.

Bei MCs ohne Hardwareinterrupt ist der Zugriff auf interne Register nur 
mittels Singlestep möglich. Das Programm funktioniert dann nicht mehr in 
Echtzeit, da gebe es auch die Möglichkeit das Programm auf einer anderen 
Plattform zu simulieren.

Als ersten Schritt würde ich mich informieren ob der MC oder die CPU 
über Hardwarebreakpoints verfügt. Dann könnte man wichtige Daten, wie 
Programmzähler, Stackaufrufhistorie übrr den Exeptioncode in einem 
unverlierbaren Speicherbereich aufheben oder über serielle Schnittstelle 
ausgeben.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Anton schrieb:
> Das Programm ist komplex
Von nix kommt nix. Natürlich neigen gerade "komplexe" (oder auch einfach 
nur "komplizierte") Programme zu Fehlfunktionen. Besonders an Ecken, wo 
man bei der Implementierung von fehlerfreier undgestörter Hardware 
ausgegangen ist.

> die Speicherstelle kritisch
Öffne das Map-File. Finde heraus, wo diese "Speicherstelle" ist. Sieh 
nach, was davor liegt. Gerne auch einige Bytes weiter vorne. Könnte bei 
einer dort liegenden Variable/Array/Puffer so ein amoklaufender 
Pointer/Index die nachfolgenden "Speicherstellen" überschreiben?

Wenn du nicht weiter kommst: sieh zu, dass du vor diese "Speicherstelle" 
leeren Speicher platzierst. Schau dann und wann nach, ob da irgdenwer 
irgendwas reingeschrieben hat. Versuche zu erkennen, was das für Daten 
sind.

: Bearbeitet durch Moderator
von Anton (Gast)


Lesenswert?

Lothar M. schrieb:
> Öffne das Map-File. Finde heraus, wo diese "Speicherstelle" ist. Sieh
> nach, was davor liegt.

Es ist Assembler Code.
Daher weiß ich genau und selbstbestimmt was wo ist.

> Könnte bei einer dort liegenden Variable/Array/Puffer so ein
> amoklaufender Pointer/Index die nachfolgenden "Speicherstellen"
> überschreiben?

Es schaut nicht danach aus. Vielmehr werden von irgendwoher (noch) 
unbekannte Daten in einen wichtigen Sendepuffer reingeknallt. Da es sich 
um Daten für ein Display handelt habe ich unmittelbare Rückmeldung.

> Besonders an Ecken, wo man bei der Implementierung von fehlerfreier
> und gestörter Hardware ausgegangen ist.

An und für sich habe ich keinen konkreten Anlass an der Hardware zu 
zweifeln, aber wer bin ich um da was sicher auszuschließen. Falls Du 
auch auf das quarzlose UART abzielst kann ich meine problemlose 
Erfahrung mit anderen Projekten gleicher/ähnlicher AVRs geltend machen. 
Ein 4809+UART Übertragung arbeitet sogar außen in einer Wetterstation 
unter Witterungsbedingungen absolut unauffällig.

von Oliver S. (oliverso)


Lesenswert?

Anton schrieb:
> Es ist Assembler Code.
> Daher weiß ich genau und selbstbestimmt was wo ist.

YMMD ;)

Oliver

von Alter Native (Gast)


Lesenswert?

Anton schrieb:
> Daher weiß ich genau und selbstbestimmt was wo ist.

Deswegen läuft's ja auch so gut ....

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Anton schrieb:
> Vielmehr werden von irgendwoher (noch) unbekannte Daten in einen
> wichtigen Sendepuffer reingeknallt.
Ist das ein Block oder nur einzelne Bytes? Mitten drin im Puffer oder 
"am Rand"? Immer an der selben Stelle oder immer wieder beliebig 
woanders?

> An und für sich habe ich keinen konkreten Anlass an der Hardware zu
> zweifeln, aber wer bin ich um da was sicher auszuschließen.
Nein, ich meine, dass ich Schaltungen teste, indem ich mit einem 
"Viehtreiber" entwicklungsbegleitend EMV-Tests mache wie im 
Beitrag "Re: Probleme mit Störungen aus dem Netz" 
beschrieben. Machst du solche ähnliche Störfestigkeitstests auch? Es 
reicht z.B. bei einigen Schaltungen schon aus, wenn ich die Weller 
Lötstatiom daneben stelle und die ein- und ausschalte...

> Falls Du auch auf das quarzlose UART abzielst
Nein, tu ich nicht. Ich hab keine Probleme mit so einer Frickelei. Ich 
habe das auch mal gemacht. Aber ich baue jetzt immmer einen Quarz ein.

> arbeitet sogar außen in einer Wetterstation unter Witterungsbedingungen
> absolut unauffällig.
Mein Glückwunsch.
Bei mir hatten halt ca. 2 von 1000 ab&zu Probleme. Und dann fährt ein 
Monteur hin, sucht und flucht 2 Tage herum und tauscht dann das Modul. 
Und das kostet letztlich so viel, da kann ich locker überall einen Quarz 
ranbauen...

: Bearbeitet durch Moderator
von Peter D. (peda)


Lesenswert?

Anton schrieb:
> Es ist Assembler Code.
> Daher weiß ich genau und selbstbestimmt was wo ist.

Dann kannst Du doch testweise Bereiche an ne andere Stelle verschieben. 
Du wirst ja nicht den gesamten RAM vollgeknallt haben.
Laß aber an der Originalstelle eine entsprechende Lücke. Wenn Du alles 
gegeneinander verschiebst, wandert alles und Du bist nicht schlauer.

Schwer zu debuggen sind nicht atomare Zugriffe zwischen Main und 
Interrupt. Wenn der Interrupt genau zwischen 2 Bytes zuschlägt, kriegt 
er ein neues und ein altes Byte. Und schon hat er einen Pointer, der in 
den Wald zeigt.
Also lieber zuviel atomar kapseln (CLI, Zugriffe, SEI), als einmal zu 
wenig.

Anton schrieb:
> An und für sich habe ich keinen konkreten Anlass an der Hardware zu
> zweifeln

Stimmt. Zu 99,99% sitzt der Fehler vor dem Bildschirm.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Elektrolurch schrieb:
> Funktionieren denn die Data-Breakpoints bei den AVRs?

Habe ich schon vor Jahren mit dem GDB genutzt, als irgendwelche Studios 
das noch lange nicht konnten.

> Die müssen doch vom Prozessor unterstützt werden.

Ja, klar. Also: beim GDB nicht notwendigerweise, allerdings wird er 
grottenlahm, wenn er das in Software emulieren muss. Dann wird nämlich 
Einzelschritt gearbeitet und jedesmal die Speicherstelle gelesen.

> Selbst bei den XMegas hat das, so weit ich weis - nicht funktioniert.

Bei Xmegas kenne ich mich gerade nicht aus, aber da das schon bei den 
alten Megas funktionierte, würde es mich wundern, wenn sie es dort 
kaputt gemacht hätten.

> Wie sieht das bei den SAMs aus?

Funktioniert auch.

Ein Unterschied zu Code-Breakpoints ist natürlich, dass ein Data 
Breakpoint (GDB nennt das "watchpoint") erst dann triggert, wenn die 
Daten auch geändert worden sind. Ein Code-Breakpoint triggert vor der 
Ausführung des Befehls.

von Anton (Gast)


Lesenswert?

Alter Native schrieb:
> Deswegen läuft's ja auch so gut ....

Tja wenn das mal alles wär ;-)

Lothar M. schrieb:
> Ist das ein Block oder nur einzelne Bytes? Mitten drin im Puffer oder
> "am Rand"? Immer an der selben Stelle oder immer wieder beliebig
> woanders?

Immer dasselbe, 28 Bytes, an derselben Stelle wild und quer über zwei 
von mehreren Datenpuffern (deren Zeiger hintereinander an die 
Senderoutine übergeben werden).

> Machst du solche ähnliche Störfestigkeitstests auch?

Nein. Vermutlich ist meine AVR Hardware da mit unter 10MHz unkritisch. 
Hatte da noch nie Probleme (vom DCF77 Empfang mal abgesehen). Da am 
augenblicklichen Entwicklerplatz (Monitore, Laptop, PC) aber im Äther 
einiges los sein dürfte zumal die seriellen Daten über Funk reinkommen 
möchte ich das im Hinterkopf behalten.

> Bei mir hatten halt ca. 2 von 1000 ab&zu Probleme.

Interessant. Neuere AVRs?
Ich mache mir immer auch die Mühe die tatsächliche Taktfrequenz zu 
messen und fein abzustimmen.

> Und das kostet letztlich so viel, da kann ich locker überall einen Quarz
> ranbauen...

Verständlich.

von Anton (Gast)


Lesenswert?

Peter D. schrieb:
> Schwer zu debuggen sind nicht atomare Zugriffe zwischen Main und
> Interrupt. Wenn der Interrupt genau zwischen 2 Bytes zuschlägt, kriegt
> er ein neues und ein altes Byte. Und schon hat er einen Pointer, der in
> den Wald zeigt.
> Also lieber zuviel atomar kapseln (CLI, Zugriffe, SEI), als einmal zu
> wenig.

Von der Programmstruktur her wird nichts von Main an Interrupts 
übergeben. Der Datenempfang im Interrupt initialisiert gleichzeitig die 
Interrupt-Ausgabe aufs Display. Das gesamte Handling spielt sich in 
Interrupts ab die dann höchstens (natürlich vollständige) Daten für Main 
zur Verfügung stellen.

> Stimmt. Zu 99,99% sitzt der Fehler vor dem Bildschirm.

Absolut. Und ich hoffe der Fehler ist nicht allzu peinlich. Momentan 
hoffe ich hier aber noch drauf ob mir jemand funktionierende 
Daten-Breakpoints für AVRxxDx bestätigen kann...

von Oliver S. (oliverso)


Lesenswert?

Anton schrieb:
> Momentan
> hoffe ich hier aber noch drauf ob mir jemand funktionierende
> Daten-Breakpoints für AVRxxDx bestätigen kann...

Was spricht gegen einfach ausprobieren?

Oliver

von Anton (Gast)


Lesenswert?

Oliver S. schrieb:
> Was spricht gegen einfach ausprobieren?

Nichts Oliver. Sobald möglich.

von Thomas (kosmos)


Lesenswert?

welche Speicherzelle ist das ein Register oder ist das im SRAM. Laß dir 
im Simulator das SRAM (in Memory1-Fenster) anzeigen, wenn das während 
der Programmausführung immer voller wird, dann fehlt wahrscheinlich in 
deinen Programm irgendwo ein ret, reti oder pop. Also entweder beendest 
du ein Unterprogramm nicht das mit dem abspeichern einer 
Rücksprungadresse angesprungen wird, du beendest einen Interrupt nicht, 
welcher ebenfall eine Rücksprungsdresse ablegt oder du pusht aus den 
eben genannten Gründen mehr als du popst.

von Peter D. (peda)


Lesenswert?

Anton schrieb:
> Der Datenempfang im Interrupt initialisiert gleichzeitig die
> Interrupt-Ausgabe aufs Display. Das gesamte Handling spielt sich in
> Interrupts ab

Das klingt sehr gefährlich. Hast Du bedacht, das Interfaces nicht 
reentrant sind, d.h. das Main darf keine weitere Instanz aufmachen.

Ich mache für die UART immer 2 FIFO Interrupts und das Main kümmert sich 
um das Parsen und die Ausgabe.

von Hugo H. (hugo_hu)


Lesenswert?

Anton schrieb:
> Nichts Oliver. Sobald möglich.

Arbeitest Du möglicherweise mit AVR Studio 4.x?

von Thomas (kosmos)


Lesenswert?

wenn das mit dem Simulator nicht so praktisch ist, da man keinen 
Debugger hat. Kannst du in deine Main auch irgendwo einbauen das ein 
Speicherzelle im RAM ausgelesen wird die 00 bzw. FF sein sollte und wenn 
das abweicht, weil die Speicherzelle erreicht wurde kann du einen LED 
einschalten, damit du weist, dass dein SRAM zu Neige geht.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Anton schrieb:
> zumal die seriellen Daten über Funk reinkommen

Also brauchst Du erstmal ein ordentliches Protokoll mit CRC, um die 
Störungen rauszufiltern.

von Anton (Gast)


Lesenswert?

Thomas O. schrieb:
> wenn das während der Programmausführung immer voller wird

Ja es  ist ein Bereich im SRAM des Controllers. Der Stackpointer bleibt 
artig in seinem Terrain. Beim Debugging kann man ja in den Speicher 
schauen. Mit "der Speicherzelle" meinte ich übrigens das 1.Byte des 
immergleichen überschriebenen Bereichs.

Peter D. schrieb:
> Das klingt sehr gefährlich. Hast Du bedacht, das Interfaces nicht
> reentrant sind, d.h. das Main darf keine weitere Instanz aufmachen.

Es ist eine zugegeben komplexe Konstruktion. Aber wiegesagt, die Main 
tut hier nichts zur Sache. Es arbeitet auch alles wie es soll und das 
dauerhaft. Nur unter bestimmten, eingrenzbaren Bedingungen, die 
bestimmtem seriellen Input zur Folge haben kommt es zum Fehler. Danke 
für die Überlegungen zum möglichen Fehlerbild aber den Fall in Gänze 
aufzudröseln würde das Thema  hier vollends sprengen.

von Anton (Gast)


Lesenswert?

Peter D. schrieb:
> Also brauchst Du erstmal ein ordentliches Protokoll mit CRC, um die
> Störungen rauszufiltern.

Das bietet bereits das verwendete Funkmodul. Darüber hinaus erfolgt 
übergeordnet ein Test über die 8Bit Summe aller Daten (Protokoll eines 
eDip240-7). Die Daten fließen ja auch plausibel und auf Dauer. Es muss 
an einem bestimmten Dateninhalt liegen. Stand meiner Analyse bis jetzt.

von Peter D. (peda)


Lesenswert?

Anton schrieb:
> Nur unter bestimmten, eingrenzbaren Bedingungen, die
> bestimmtem seriellen Input zur Folge haben kommt es zum Fehler.

Klingt dann doch sehr nach einem Problem mit dem Protokoll und einem 
Pufferüberlauf.
Die Entwicklung eines fehlertoleranten Protokolls ist keine einfache 
Sache. Die Protokollstacks in Industriesteuerungen über RS-485 sind oft 
sehr aufwendig und belegen viel Flash.

von EAF (Gast)


Lesenswert?

Peter D. schrieb:
> Die Indexschreibweise ist in der Regel weniger fehleranfällig, als die
> Pointerschreibweise.

Hier stimme ich nicht zu!
Die beiden Schreibweisen sind äquivalent.

Bieten somit exakt das gleiche Fehlerpotential.

von Oliver S. (oliverso)


Lesenswert?

Da es um Assembler geht, ist’s letztendlich eh egal.

Oliver

von Thomas (kosmos)


Lesenswert?

es gibt im AVR-Studio einen Watch Funktion habe damit noch nicht 
gearbeiten, glaube das müsste aber für eine Überwachung sein wie du es 
wünscht.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Thomas O. schrieb:
> es gibt im AVR-Studio einen Watch Funktion
Das Watch-Fenster wird nur aktualisiert, wenn du auf einem Breakpoint 
stehst.

Und dass du auf einen Breakpoint kommst, dafür brauchst du den besagten 
Data Breakpoint, der als spezielle Debug-Hardware im Controller 
eingebaut ist und in jedem Maschinenzyklus die Pointerregister X 
und/oder Y und/oder Z mit der gewünschten Speicheradresse vergleicht und 
dann beim Schreiben und/oder Lesen triggert.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Lothar M. schrieb:
> Thomas O. schrieb:
>> es gibt im AVR-Studio einen Watch Funktion
> Das Watch-Fenster wird nur aktualisiert, wenn du auf einem Breakpoint
> stehst.

Das ist die Begriffsverwirrung zwischen GDB, der diese Art von 
Datenüberwachung (egal ob in Hard- oder Software) schon immer 
"watchpoint" genannt hat und den IDEs, die Variablen/Speicherstellen 
gern "watchen".

von Rainer V. (a_zip)


Lesenswert?

Nach deinen Aussagen habe ich die Befürchtung, dass du in den 
Interrupt-Routinen viel zu viel "machen" läßt. In der Regel macht die IR 
nur das Nötigste, so dass die Main-Routine weiterkommt. Und bevor du 
jetzt mit irgendwelchen Breakpoints herumhampelst, schreib dir doch ein 
paar schlaue Testroutinen. Du kannst das Assemblerprogramm doch beliebig 
verkleinern und wenn es sein muß jeden "Mist" einzeln testen. Viel Spass 
jedenfalls...Rainer

von rbx (Gast)


Lesenswert?

Anton schrieb:
> Habe momentan leider keinen Zugriff auf
> die Hardware.

Tja, und wir haben leider keinen Zugriff auf dein Softwaretechnisches 
Möglichkeitspotential.
Deswegen kann man eigentlich nur herumstochern, und herumprojizieren.

http://www.avr-asm-tutorial.net/avr_sim/index_de.html

https://github.com/SilverBut/avr_helper

von Anton (Gast)


Lesenswert?

rbx schrieb:
> Tja, und wir haben leider keinen Zugriff auf dein Softwaretechnisches
> Möglichkeitspotential.
> Deswegen kann man eigentlich nur herumstochern,

Nicht unnütz rumstochern rbx, einfach die gestellte Eingangsfrage 
beantworten- damit wär ich schon zufrieden ;-)

von Anton (Gast)


Lesenswert?

Rainer V. schrieb:
> Nach deinen Aussagen habe ich die Befürchtung, dass du in den
> Interrupt-Routinen viel zu viel "machen" läßt. In der Regel

... braucht man hier nichts zur Regel betonieren. Du kannst ein Programm 
im Gegenteil auch nur aus Interrupts aufbauen und den Controller in Main 
schlafen lassen. Ich habe keinen Hinweis auf ein 'viel zu viel'. Die 
Interrupts werden round robin nacheinander abgearbeitet wenn jeweils 
fertig. Die serielle E/A funktioniert, von dem speziellen Fehler 
abgesehen. Dieses recht interessante Fehlerbild werde ich schon noch 
auflösen.

Rainer V. schrieb:
> bevor du jetzt mit irgendwelchen Breakpoints herumhampelst

Der Data-Breakpoint wär hier exakt das Mittel der Wahl. Da 
offensichtlich noch niemand damit und den neuen AVRs gearbeitet hat bin 
ich gespannt, was meine eigene Recherche demnächst ergibt.

von Rainer V. (a_zip)


Lesenswert?

Anton schrieb:
> Da
> offensichtlich noch niemand damit und den neuen AVRs gearbeitet hat bin
> ich gespannt, was meine eigene Recherche demnächst ergibt.

OK, ich auch...
Rainer

von Anton (Gast)


Angehängte Dateien:

Lesenswert?

Anton schrieb:
> Der Data-Breakpoint wär hier exakt das Mittel der Wahl.

Pustekuchen.
Der erste Minuspunkt der neuen AVR Architektur. Zumindest im aktuellen 
McStudio und mit einem AtmelICE.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

uff

Hätte ich nicht erwartet. Aber damit kann ich auch gerade mit AVaRICE 
nicht dienen, das hängt in dieser Hinsicht viel zu weit hinterher.

von Anton (Gast)


Angehängte Dateien:

Lesenswert?

Vielleicht läuft das ja unter MPLAB-X und dem neuen ICE4 Debugger...

von Rainer V. (a_zip)


Lesenswert?

Ich verstehe nicht, warum du dich so auf diese Breakpoints versteifst. 
Du hättest doch schon längst eine schlaue Testroutine in dein Programm 
einbauen können! Etwa so, ich nummeriere meine Unterprogramme durch und 
schreibe nach jedem Programmaufruf die Nummer weg und vergleiche den 
Inhalt des Speicherbereichs vorher/nachher. Dann hab ich schon mal den 
Punkt im Programm wo was passiert. Dann kann man weitersehen...
Rainer

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Rainer V. schrieb:
> Ich verstehe nicht, warum du dich so auf diese Breakpoints versteifst.

Weil sie für selten und von außen getriggerte Ereignisse, die man 
schlecht simulieren kann, die sinnvollste Methode sind?

Die Hersteller bauen die entsprechende Logik nicht umsonst da rein.

von Rainer V. (a_zip)


Lesenswert?

Jörg W. schrieb:
> Die Hersteller bauen die entsprechende Logik nicht umsonst da rein.

Ja, ist schon klar...sein Controller kann das aber nu mal nicht...

von Anton (Gast)


Lesenswert?

Rainer V. schrieb:
> Du hättest doch schon längst eine schlaue Testroutine in dein Programm
> einbauen können!

Schlauer Vorschlag Rainer.

Ganz so simpel wie Du Dir das vorstellst ist das bei einem Programm mit 
komplexerer Interrupt-Mechanik leider nicht. Da werden nicht einfach 
statisch geordnet nacheinander irgendwelche abgeschlossenen Routinen 
aufgerufen die man dann abtesten könnte. Was da womit wohin gespeichert 
und wie weitergeleitet wird hängt im Programm maßgeblich vom seriellen 
Input ab. Eine vertrackte Sache.

Dazu kommt im Moment ein ganz anderes "Problem": Den Fehler überhaupt zu 
provozieren. Da wird noch eine Menge Geduld nötig sein.

von Rainer V. (a_zip)


Lesenswert?

Anton schrieb:
> Dazu kommt im Moment ein ganz anderes "Problem": Den Fehler überhaupt zu
> provozieren. Da wird noch eine Menge Geduld nötig sein.

Ja, sorry, du hast ja recht. Aber wenn es keine Debugging-Möglichkeit 
gibt, dann ist halt das Elend groß. Natürlich kann ich großspurig 
"schlau" schreiben, aber machen muß ichs ja nicht...ich wünsche 
jedenfalls einen Erfolg!
Gruß Rainer

von rbx (Gast)


Lesenswert?

Anton schrieb:
> Dazu kommt im Moment ein ganz anderes "Problem": Den Fehler überhaupt zu
> provozieren.

Naja, vorher kommt noch die spannende Frage, wie gut kommst du 
eigentlich mit Linux, dem GDB, Radare oder IDA - läuft auch ganz gut in 
Wine - klar?

von Anton (Gast)


Lesenswert?

Rainer V. schrieb:
> ich wünsche jedenfalls einen Erfolg!

Danke. Wird schon. Fehlende Breakpoints müssen dann einfach durch 
Hartnäckigkeit ausgeglichen werden ;-)

Um mal kurz die Anwendung zu skizzieren: Ein Protokoll für die Anzeige 
auf verschiedenen eDIP240-7 soll ins richtige Protokoll für ein 
einzelnes uniTFT Display übersetzt und dessen Touchkey-Eingaben zurück 
geleitet werden. Das umfasst im Kern:
-Entgegennahme der eDIP240-7 Daten und Quittierung
-Umwandlung in uniTFT Daten
-Ausgabe aufs uniTFT nach dessen Timing und Quittierung
-Einlesen des uniTFT Buffers bei vorhandenen Daten
-Umwandlung ins eDIP240-7 Format und Ausgabe zurück an das alles 
steuernde System, hier aber nach dessen aktiver Daten-Anforderung.

von Thomas (kosmos)


Lesenswert?

um zu überprüfen ob der Stack voll läuft kann man doch in der 
Haputschleife einfach nachsehen ob etwas am Anfang des SRAM geändert 
wurde.

Der sieht ja normal so aus, geht z.B: von $0060-00DF und wird von unten 
her beschrieben. Jetzt schau man halt ab und zu nach ob $0070 verändert 
wurde und erkennt eine Hoche Stackbelastung was auf einen baldigen 
Überlauf hinweist.
Wenn das also sein kann muss man schauen was man alles anspringt und 
nicht wieder zurückspringt. Hier müsste man dann eben schauen ob jeder 
Interrupt mit reti und jeder Aufruf(rcall) eines Unterprogramms auch mit 
ret beendet wird. Das kann man normal selbst im Simulator mit ein paar 
Breakspoints finden wenn man an und ab mal die Interrupts auslöst, man 
braucht ja nur das Feld für den Interrupt zu setzen und schon verzweigt 
er nach ein paar Takten. Wenn du so ein Unterprogramm nicht mehr verläßt 
dann arbeite leiber mit jmp/rjmp anstatt mit call/rcall.
1
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
2
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
3
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
4
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
5
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
6
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
7
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
8
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
9
FF FF FF FF FF FF FF FF FF FF FF FF FF FF 10 33 55 77
10
...

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Anton schrieb:
> Ganz so simpel wie Du Dir das vorstellst ist das bei einem Programm mit
> komplexerer Interrupt-Mechanik leider nicht. Da werden nicht einfach
> statisch geordnet nacheinander irgendwelche abgeschlossenen Routinen
> aufgerufen die man dann abtesten könnte. Was da womit wohin gespeichert
> und wie weitergeleitet wird hängt im Programm maßgeblich vom seriellen
> Input ab.

Solche Anwendungen sind mein täglich Brot, aber nicht auf 
Mikrocontrollern sondern auf Servern im Backend. Mangels Zugriff auf die 
produktiven Maschinen kann ich dort keinen Debugger ansetzen. Außerdem 
kann ich wie du auch nicht ewig darauf warten, dass der Fehler zufällig 
auftritt während ich zugucke. Selbst wenn ich unendlich Zeit hätte, 
kommen die Ereignisse schneller rein, als ich gucken kann.

Also setze ich auf Logfiles. Diese kann ich nach Auftreten des Fehlers 
in aller Ruhe analysieren. Das kannst du auch. Gebe auf einem seriellen 
Port Log-Meldungen aus, wo die Maschine fortlaufend berichtet, was sie 
gerade warum tut. Diese Meldungen sendest du an einen PC, der sie mit 
Zeitstempeln anreichert und in eine Datei schreibt.

Bei der Gelegenheit kann man auch zyklisch Hinweise zur 
Speicher-Auslastung ausgeben. Das kontrolliere ich immer nach jeder 
größeren Änderung, denn Speicher-Lecks die erst nach vielen 
Tagen/Wochen/Monaten auftreten sind eklig.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

rbx schrieb:
> Naja, vorher kommt noch die spannende Frage, wie gut kommst du
> eigentlich mit Linux, dem GDB

Hilft aber an der Stelle nix. AVaRICE kann mit diesen Chips noch nicht 
umgehen.

Wenn es das Atmel Studio nicht kann, dann hilft das nicht viel, selbst 
falls die Hardware es eigentlich könnte.

von Anton (Gast)


Lesenswert?

Thomas O. schrieb:
> um zu überprüfen ob der Stack voll läuft

Anton schrieb:
> Der Stackpointer bleibt
> artig in seinem Terrain.

Stefan ⛄ F. schrieb:
> Hinweise zur
> Speicher-Auslastung

Der SRAM-Speicher ist bei weitem nicht ausgelastet.
Beim Debugging kann man sich den Speicher doch anschauen.
Entspricht den Vorgaben im Programm.

Stefan ⛄ F. schrieb:
> Gebe auf einem seriellen
> Port Log-Meldungen aus, wo die Maschine fortlaufend berichtet, was sie
> gerade warum tut.

Das wär viel hier zu grobkörnig. Ich möchte doch nur den kurzen Moment 
aufklären an dem etwas falsches an besagten Speicher geschrieben wird 
und dann den verusachenden Code samt seiner Eingangsdaten untersuchen.

von Rainer V. (a_zip)


Lesenswert?

Anton schrieb:
> Ich möchte doch nur den kurzen Moment
> aufklären an dem etwas falsches an besagten Speicher geschrieben wird
> und dann den verusachenden Code samt seiner Eingangsdaten untersuchen.

Die Betonung liegt wohl auf "nur" und gleichzeitig erzählst du von 
absolut sporadischen Fehlern. So wie Stefan vorschlägt, könnte das was 
werden. Das "sporadisch" zwingt dich geradezu, den ganzen Verkehr zu 
protokollieren. Aber vielleicht fällt dir ja doch was besseres 
(schnelleres!) ein...
Rainer

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Rainer V. schrieb:
> Das "sporadisch" zwingt dich geradezu, den ganzen Verkehr zu
> protokollieren.

Nur, wenn man es versuchen will, per Simulation nachzustellen. Dann wäre 
das ja die einzige Möglichkeit, um die externen Ereignisse in exakt 
gleicher Form reproduzieren zu können.

Nichtsdestrotz hat das Einfügen von Debug-Code oft genug 
Timing-Änderungen zur Folge, die u.U. das Problem dann auch gleich mal 
komplett maskieren können. Es ist dann nicht weg (das ist die Gefahr), 
tritt aber durch das geänderte Timing vielleicht viel seltener auf.

Ich kann mir immer noch nicht vorstellen, dass die Hardware dieser AVRs 
das nicht können sollte, habe aber gerade keine Zeit, mir das selbst 
anzusehen.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Anton schrieb:
> Du kannst ein Programm im Gegenteil auch nur aus Interrupts aufbauen
Huh, diese Art von Programmen sind aus Erfahrung unbeherrschbar. Einmal 
am Tag, in der Woche, Monat, Jahr tickt so ein Ding aus oder frisst sich 
dank Prioritätsinversion fest. Kann sein, dass man das nicht merkt, aber 
es passiert.

> Die Interrupts werden round robin nacheinander abgearbeitet wenn
> jeweils fertig.
Eben das ist nicht das Konzept von Interrupts. Sie werden bestenfalls in 
deinem Gedankenmodell aber niemals in der realität "zyklisch der Reihe 
nach" (= ROUND robin) abgearbeitet. Sondern eben immer dann, wenn sie 
dank ihrer Priorität und freier Rechenleistung drankommen. Und wenn ein 
externer Signalgeber mit hoher Prio austickt, dann kommt dieser 
Interrupt laufend. Bei uns war das z.B. ein Drehgeber in einer 
ausgeleierten Maschine, der halt wie blöd hin- und herzappelte. So einen 
Fehler hast du in der Firma nie, weil da nur neue Maschinen herumstehen.

Mein ideales µC-Programm ist eine Hauptschleife, die in <1ms durchläuft 
und dabei alles macht (ggfs. müssen längere Rechnungen halt in mehrere 
Zyklen aufgeteilt werden). Und die kurzen ISR speisen nur neue 
Informationen in diese Mainloop ein.
Ein Supervisor (das ist ein besserer Dreizeiler, der einen Hardwaretimer 
mit dem vorigen Timerstand vergleicht) überwacht die Laufzeit der 
Mainloop und gibt Alarm, wenn die mal stark nach oben ausreißt.

Rainer V. schrieb:
> Ich verstehe nicht, warum du dich so auf diese Breakpoints versteifst.
Wer in seinem Prozessor mal tatsächlich die Hardware für echte Data 
Breakpoints hatte (wenigstens für einen einzigen), der wird sie 
bitterlich vermissen, wenn er ein Problem wie das hier zu knacken hat.

Und wirklich elegant wird es, wenn diese Hardware es hergibt, nur dann 
den Breakpoint zu triggern, wenn genau ein bestimmter Wert an eine 
bestimmte Adresse geschrieben wird:
https://community.nxp.com/t5/ColdFire-68K-Microcontrollers/Setting-multiple-breakpoints-and-a-program-trace-on-MCF5216-V2/m-p/274479


Zurück zum Thema:
Anton schrieb:
> Ich möchte doch nur den kurzen Moment aufklären
> an dem etwas falsches an besagten Speicher geschrieben wird
Gibts nich weil is nich.

Du musst also wegkommen vom "kurzen Moment" hin zu statistischen 
Methoden: wenn das immmer die selben korrupten 28 Adressen sind, musst 
du dort eine Regelmäßigkeit finden.
Du musst dir also etwa solche Fragen ausdenken und die antworten darauf 
finden:
Welche Abstände haben die korrupten Bytes? Sind die einezeln, gepaart 
oder sonstige Cluster? steht immer der selbe Müll drin?  Wann passiert 
"es"? Passiert "es" immer an allen Speicherzellen gleichzeitig? Passiert 
"es" bei vielen Geräten gleich häufig? Passiert "es" auch, wenn an du 
bestimmte Hardwarekomponenten nichts anschließt, also bestimmte 
Interruptquellen nicht verwendest?

: Bearbeitet durch Moderator
von MaNi (Gast)


Lesenswert?

Was auch etwas Licht ins Dunkel bringen kann ist eine statische Code 
Analyse und die kritische Betrachtung der ausgegebenen Stellen.
Aus eigener Erfahrung kann ich sagen dass damit schon einige "Out of 
Bound" aufgedeckt wurden.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

MaNi schrieb:
> eine statische Code Analyse
Gibts da auch Tools für AVR-Assemblercode?

von Oliver S. (oliverso)


Lesenswert?

Anton schrieb:
> Das wär viel hier zu grobkörnig. Ich möchte doch nur den kurzen Moment
> aufklären an dem etwas falsches an besagten Speicher geschrieben wird
> und dann den verusachenden Code samt seiner Eingangsdaten untersuchen.

Tja, und ohne Databreakpoint geht das halt nur über eine ausführliche 
Codeanalyse. Und weil du das für das ganze Programm nicht sinnvoll 
machen kannst, musst du den Fehlerpunkt einkreisen. Dazu hilft alles, 
was dir dabei hilft. Wenn logging dann am veränderten Timing scheitert, 
ist dein ganzes Konzept Murks. Murks wegen zu großer Komplexität.
So furchtbar kompliziert klingt die Aufgabenstellung ja jetzt nicht.

Was ich bei deiner ganzen Geschichte allerdings sehr seltsam finde, ist, 
daß ein Writepointer von den Eingangsdaten abhängen soll, ohne dass du 
sagen kannst, wie, wo, und warum. Das kann doch eigentlich nicht sein.
Wenn’s nur ein klassischer Bufferüberlauf wäre, könntest (oder müsstest) 
du einfach JEDEN Bufferzugriff gegen Überlauf absichern.

Oliver

von Peter D. (peda)


Lesenswert?

Lothar M. schrieb:
> Anton schrieb:
>> Du kannst ein Programm im Gegenteil auch nur aus Interrupts aufbauen
> Huh, diese Art von Programmen sind aus Erfahrung unbeherrschbar.

Ist auch meine Erfahrung. Man bestiehlt sich nur unnötig um einen 
Ausführungslevel, der vieles einfacher macht.
Die zu große Komplexität Deines Programms ist also selbst verschuldet.

Bei den neuen AVRs kann man zwar round robin einstellen, statt fester 
Priorität, aber das macht alles nur noch unvorhersehbarer. Man hat ein 
völlig unterschiedliches Verhalten bei normaler und bei hoher 
Interruptlast.

Einer Mainloop ist dagegen die Interruptlast völlig schnurz. Sie 
arbeitet alles immer in der gleichen, von Dir bestimmten Reihenfolge ab 
und damit gibt es auch kein Chaos und keine Komplexität.
Das Schlimmste, was passieren kann, eine serielle FIFO läuft voll und 
schmeißt die überzähligen Bytes weg. Durch ein Protokoll mit 
Paketnummernzähler läßt sich das erkennen und die verlorenen Pakete 
können nochmal angefordert werden. Oder man erzeugt erstmal nur ne 
Fehlermeldung, daß was im Argen liegt.

von Peter D. (peda)


Lesenswert?

Anton schrieb:
> Der SRAM-Speicher ist bei weitem nicht ausgelastet.

Warum machst Du dann nicht, was ich bereits vorgeschlagen hatte?
Die Daten der einzelnen Funktionen in freie Bereiche zu verschieben und 
dann beobachten, bei welcher Funktion die ungewollten Änderungen mit 
wandern.

von Peter D. (peda)


Lesenswert?

EAF schrieb:
> Die beiden Schreibweisen sind äquivalent.

Rein formal schon.
Nur speziell auf einem 8Bitter macht ein Index vieles einfacher. Ist das 
Array <256 Byte, reicht ein Byte als Index und ich muß nichts atomar 
kapseln. Auch kann ich den Index einfach auf Überlauf testen (mit sizeof 
vergleichen), unterlaufen kann er ja nicht.

von MaNi (Gast)


Lesenswert?

Lothar M. schrieb:
> Gibts da auch Tools für AVR-Assemblercode?

Dieses Detail hatte ich übersehen.

von Stefan F. (Gast)


Lesenswert?

Anton schrieb:
> Das wär viel hier zu grobkörnig. Ich möchte doch nur den kurzen Moment
> aufklären an dem etwas falsches an besagten Speicher geschrieben wird
> und dann den verusachenden Code samt seiner Eingangsdaten untersuchen.

Dann füge halt nur an den relevanten Stellen Logmeldungen ein.

Wenn du nicht im laufenden Betrieb hinein schauen kannst, muss er dir 
anders mitteilen, was ab geht. Ansonsten bleibt es ein womöglich 
erfolgloses Ratespiel.

von Stefan F. (Gast)


Lesenswert?

Jörg W. schrieb:
> Nur, wenn man es versuchen will, per Simulation nachzustellen. Dann wäre
> das ja die einzige Möglichkeit, um die externen Ereignisse in exakt
> gleicher Form reproduzieren zu können.

Das wird sowieso nötig sein, um den Erfolg der Korrektur zu belegen.

Ich darf keine Fehlerkorrektur ohne Nachweis abliefern. Heist im 
Umkehrschluss: Wenn der Kunde/Betrieb keine detaillierte Anleitung 
liefert, wie man den Fehler auslöst, beginnt meine Arbeit damit, genau 
das heraus zu finden. Und zwar bevor ich ich die Fehlerursache suche.

Jörg W. schrieb:
> Nichtsdestrotz hat das Einfügen von Debug-Code oft genug
> Timing-Änderungen zur Folge, die u.U. das Problem dann auch gleich mal
> komplett maskieren können.

Ja, das kann passieren und wäre wirklich bitter wenn es hier passiert. 
Dagegen gibt es leider kein Allheilmittel.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Stefan ⛄ F. schrieb:
> Das wird sowieso nötig sein, um den Erfolg der Korrektur zu belegen.

In deiner Umgebung offenbar, an anderen Stellen wird es auch genügen, 
wenn man beim Debuggen die Ursache des Fehlers sauber erkennen konnte.

von Stefan F. (Gast)


Lesenswert?

Jörg W. schrieb:
> an anderen Stellen wird es auch genügen,
> wenn man beim Debuggen die Ursache des Fehlers sauber erkennen konnte.

Das würde dann gerne zu zweit machen, um sicher zu gehen.

Wenn Programmierer alleine ihre eigenen Fehler untersuchen, übersehen 
sie oft etwas.

von Gerald K. (geku)


Lesenswert?

Jörg W. schrieb:
> Die Hersteller bauen die entsprechende Logik nicht umsonst da rein.

In manchen Fällen macht es Sinn Fehlerstatisiken in eine "fertige" 
Software einzubauen um bei Kunden laufende Software auf Qualität zu 
überprüfen. Manche Fehler treten sehr selten auf und sind im Labor nicht 
zu erfassen, daher ist das Erfassen von Exeptions (z.B. Division durch 
Null) und deren Speicherung sinnvoll.

: Bearbeitet durch User
von Anton (Gast)


Lesenswert?

Peter D. schrieb:
> Bei den neuen AVRs kann man zwar round robin einstellen, statt fester
> Priorität, aber das macht alles nur noch unvorhersehbarer. Man hat ein
> völlig unterschiedliches Verhalten bei normaler und bei hoher
> Interruptlast.

Ich denke hier werde ich mal als erstes ansetzen und die vorgesehene 
Abarbeitung aller Interrupts mit der Wirklichkeit vergleichen, ob es 
hier zu Unregelmäßigkeiten kommt bzw. ob einzelne Interrupts womöglich 
und unbemerkterweise gar nicht zum Zuge kommen. Danke für die Beiträge 
soweit.

Noch unerwähnt blieb die Nutzung des zweiten Interrupt Prio1 Levels der 
neuen Controller zur unbedingten Sicherstellung des Empfangs der 
Eingangsdaten.

Was die Abwesenheit der Data Breakpoints bei den AVRs erklären könnte 
wäre evt. die verminderte Leistungsfähigkeit von UPDI (nur eine Leitung, 
bei PDI zwei).

von Stefan F. (Gast)


Lesenswert?

Anton schrieb:
> Was die Abwesenheit der Data Breakpoints bei den AVRs erklären könnte
> wäre evt. die verminderte Leistungsfähigkeit von UPDI (nur eine Leitung,
> bei PDI zwei).

Nö, denn viele ARM Kontroller können es über SWD, das ebenfalls nur zwei 
Leitungen hat. Die zwei Leitungen sind kein Hindernis.

von Anton (Gast)


Lesenswert?

Anton schrieb:
> bei den AVRs

diesen neueren AVRs war gemeint. Die alten Megas/XMegas beherrschen Data 
Breakpoints via PDI ja angeblich (hab ich selber dort noch nie 
verwendet).

von Stefan F. (Gast)


Lesenswert?

Anton schrieb:
> Die alten Megas/XMegas beherrschen Data
> Breakpoints via PDI ja angeblich

Die alten ATmegas haben kein PDI.

von Anton (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Die alten ATmegas haben kein PDI.

Ja stimmt, lang ists her, aber da standen zum Debugging ja noch mehr 
Leitungen zur Verfügung...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Anton schrieb:
> Was die Abwesenheit der Data Breakpoints bei den AVRs erklären könnte
> wäre evt. die verminderte Leistungsfähigkeit von UPDI (nur eine Leitung,
> bei PDI zwei).

Eigentlich nicht. debugWIRE ist auch ein Eindrahtprotokoll. Gut, die 
haben tatsächlich keine data breakpoints, aber das lag daran, dass sie 
gar keine separate Debug-Hardware in den MCUs vorgesehen hatten. 
debugWIRE war schlicht ein Monitor-ROM, also sowas, wie man schon vor 
30+ Jahren seine Mikroprozessoren debuggen konnte. Code-Breakpoints 
wurden dort durch Umflashen der jeweiligen Page eingefügt. Klingt 
gruselig, dafür hat es wiederum gar nicht so schlecht funktioniert.

Ansonsten verursachen data breakpoints ja (im Gegensatz bspw. zu trace 
data beim ARM) nicht per se mehr Traffic auf der Debug-Schnittstelle.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Peter D. schrieb:
> EAF schrieb:
>> Die beiden Schreibweisen sind äquivalent.
> Rein formal schon.
Aber in der Praxis sieht das schon spannender aus. Wenn da steht:

erg = *ptr+i*3;

Dann stellt sich die Frage, ob das so sein muss, oder ob das der Grund 
für den Fehler ist, den der Kollege gestern kurz vor Feierabend noch 
eingebaut hat, obwohl er eigentlich sowas wollte:

erg = *(ptr+i*3);

So ist das eindeutig:

erg = ptr[0]+i*3;

Statt:

erg = ptr[i+3];

: Bearbeitet durch Moderator
von Purzel H. (hacky)


Lesenswert?

Ich arbeit auch mit Logs. Ein kWord als Buffer, wo man periodisch was 
reinschreibt und per Protokol ausliest.
Wenn die Vermutung, die Kommunikation sei zustaenig in der luft liegt, 
wuerd ich fehlerhafte Kommunikation einspeisen. Erst mal den 
Kommunikationsbuffer erhoehen. Und dann immer laengere Meldungen senden. 
Bis ans zulaessige Maximum.

Die Meldungen enthalten die Laenge selbst ?
Wie lang darf eine Meldung sein ?
Wird das ueberprueft ?
Was geschieht in diesem Fall, wo die Laenge in der Meldung als zu lange 
angegeben wird ?
Wird die Meldung als Block oder byte fuer byte, dh Zustandmaschine, 
verarbeitet ?

von Peter D. (peda)


Lesenswert?

Anton schrieb:
> Immer dasselbe, 28 Bytes, an derselben Stelle wild und quer über zwei
> von mehreren Datenpuffern (deren Zeiger hintereinander an die
> Senderoutine übergeben werden).

Bei 28 Bytes sollte doch eigentlich herauszukriegen sein, welche Task 
diese erzeugt hat.

von Anton (Gast)


Lesenswert?

Peter D. schrieb:
> Bei 28 Bytes sollte doch eigentlich herauszukriegen sein, welche Task
> diese erzeugt hat.

Das wäre vermutlich nicht mal mit den vermissten Data Breakouts 
gelungen.
Nachdem in einem Teil des Hauptprogramms dessen vielverwendetes Register 
R16 wie von Zauberhand zuweilen einen unerklärlichen Wert bekam... naja, 
der Profi wird sich das Ende der Geschichte denken können. Sowas ist 
mindestens so übel in der Analyse wie unübersehbar in den Auswirkungen 
und peinlich beim gestehen ;-)

von rbx (Gast)


Lesenswert?

Anton schrieb:
> naja,
> der Profi wird sich das Ende der Geschichte denken können.

Kennt der Profi nicht auch Circuit- oder System-Simulatoren, die 
teilweise sogar auf einem Apple laufen?

von Peter D. (peda)


Lesenswert?

Anton schrieb:
> Nachdem in einem Teil des Hauptprogramms dessen vielverwendetes Register
> R16 wie von Zauberhand zuweilen einen unerklärlichen Wert bekam...

Ja, das ist ein Problem von Assembler, man ist für die Registerrettung 
selber zuständig.
Ich hab ~10 Jahre Assembler benutzt, ich weiß also ganz genau, warum ich 
auf keinen Fall dahin zurück will. Ich weiß auch, daß der Wechsel schwer 
fällt.

In C übernimmt alle Variablenverwaltung der Compiler und der kann das 
viel besser als ein Mensch. Z.B. die Overlaytechnik beherrscht er 
perfekt, d.h. Nutzung des selben Registers für verschiedene lokale 
Variablen. Damit kann man sich in Assembler leicht ein Bein stellen.

von Anton (Gast)


Lesenswert?

Peter D. schrieb:
> Ja, das ist ein Problem von Assembler...

Ja, ein besseres Beispiel als meines hättest Du zur Begründung nicht 
wählen können. Gutes Programmieren kann aber, insbesondere wenn die 
Produktivität (im Hobby) nicht an Nummer 1 steht, sehr viel mehr sein 
als das bloße Vermeiden von Unachtsamkeiten. Es ist vielmehr eine 
hochindividuelle Angelegenheit: Während der eine die maximale 
Gestaltungsfreiheit bei minimalen Mitteln schätzt, liebt der andere 
engere, dafür sichere Leitplanken. Viel mehr als mein 
Flüchtigkeitsfehler ärgert mich, daß das UPDI Debugging der neuen AVRs 
offensichtlich einen Rückschritt gemacht hat. So schön es auch ist, 
dafür nur noch einen Pin opfern zu müssen.

von Walter T. (nicolas)


Lesenswert?

Jörg W. schrieb:
> Habe ich schon vor Jahren mit dem GDB genutzt, als irgendwelche Studios
> das noch lange nicht konnten.

Das finde ich jetzt hochinteressant! Unterstützt der GDB immer 
Data-Breakpoints? Sprich: Könnte ich mit dem GDB in der Konsole bei 
jedem Debug-Adapter diese Breakpoints verwenden?

Das wäre mal der Ausschlag, sich mit der GDB-Konsole 
auseinanderzusetzen. Letzte Jahr habe ich mal mit großer Verzweiflung 
danach gesucht, welches Ereignis einen Wert in einem Register gesetzt 
hat.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Anton schrieb:
> Gutes Programmieren kann aber, insbesondere wenn die
> Produktivität (im Hobby) nicht an Nummer 1 steht, sehr viel mehr sein
> als das bloße Vermeiden von Unachtsamkeiten.

Naja, im Alter wird man bequemer und behält nicht mehr jedes Detail im 
Kopf. Auch hat man noch andere Verpflichtungen und das Hobby bleibt mal 
längere Zeit liegen.
Da ist es dann schön, wenn einem der Compiler viele monotone Arbeiten 
abnimmt und man sich auf die eigentlichen Programmfunktionen und Abläufe 
konzentrieren kann. Man kann dann auch leichter das Programm komplett 
umstellen, wenn man in einer Sackgasse gelandet ist.

Anton schrieb:
> Während der eine die maximale
> Gestaltungsfreiheit bei minimalen Mitteln schätzt

Das kann man aber auch anders sehen. Ich habe unter C mehr Freiheiten, 
etwas zu realisieren, was ich mich in Assembler nicht getraut hätte, 
weil es zu komplex würde. Z.B. meinen Scheduler möchte ich nicht in 
Assembler schreiben, obwohl ich es könnte.

: Bearbeitet durch User
von Anton (Gast)


Lesenswert?

Peter D. schrieb:
> Das kann man aber auch anders sehen. Ich habe unter C mehr Freiheiten,
> etwas zu realisieren, was ich mich in Assembler nicht getraut hätte,
> weil es zu komplex würde. Z.B. meinen Scheduler möchte ich nicht in
> Assembler schreiben, obwohl ich es könnte.

Das kann ich gut nachvollziehen.
Aber auch mit Assembler kann man sich an komplexere Dinge herantasten. 
Das gelingt durch eine durchdachte funktionelle Grundstruktur und 
konsequente Wiederverwendung bewährten Codes (namentlich zur 
Schnittstellen-Bedienung). Aber zugegeben: Es braucht schon etwas mehr 
Überlegung und Umsicht, fortgeschrittenes Alter ist da womöglich ein 
wesentlicher Kontraindikator, ich spür's ja selber ;-)

Walter T. schrieb:
> Könnte ich mit dem GDB in der Konsole bei jedem Debug-Adapter diese
> Breakpoints verwenden?

Würde mich persönlich auch interessieren.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Walter T. schrieb:
> Unterstützt der GDB immer Data-Breakpoints?

Der GDB erst einmal immer, nennt sich "watchpoint".

Inwiefern er es aber in Hardware abbilden (lassen) kann, das braucht 
natürlich entsprechende Unterstützung durch die Hardware selbst. Auf dem 
PC muss dafür das OS die Möglichkeiten der Hardware nach oben reichen 
(habe ich zusammen mit dem Autor von AVRDUDE, Brian Dean, mal vor vielen 
Jahren für FreeBSD gebaut, weil ich in irgendwelchem Tcl/Tk-Code nicht 
anders eine data corruption zu finden in der Lage war), oder aber eben 
bei einem Embedded-Target muss das der entsprechende Adapter zur 
Anbdindung ans Target bieten.

Hat man das nicht, wie beschrieben, gibt's einen Software-Watchpoint. 
Wenn er es in Hardware abbilden kann, wird es beim Einrichten auch als 
"hardware watchpoint" ausgewiesen. Je nach Hardware muss man u.U. mit 
etwas Zeiger-Jongliererei herumopern um den zu überwachenden Bereich in 
eine Größe zu zwängen, die die Hardware unterstützt (meist nur 2^N Bytes 
mit N <= 3 oder so).

von Stefan F. (Gast)


Lesenswert?

Ohne Hardwaresupport muss man sich halt selbst was basteln.

Ich empfehle log Meldungen. An allen Stellen, wo die Variable geändert 
wird logge ich "update x from a to b, because ...".

Wenn sich die Variable unerwartet ohne Logmeldung ändert, habe ich 
entweder einen Zeiger der aus dem Ruder gelaufen ist, oder einen 
Speicherüberlauf. Speicherüberlauf kann man durch zyklische Kontrollen 
und Logging erkennen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Stefan ⛄ F. schrieb:
> Ich empfehle log Meldungen.

Wenn das zu langsam ist, "Meldungen" über Bitmuster an freien GPIO-Pins 
ausgeben und mit dem LA überwachen.

von Anton (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> An allen Stellen, wo die Variable geändert wird

Hier ging es aber um Amok im Speicher und keine geordnete Änderung einer 
fixen Variable von wohlbekannten Codestellen.

Jörg W. schrieb:
> Wenn das zu langsam ist, "Meldungen" über Bitmuster an freien GPIO-Pins
> ausgeben

Zum Glück hatte ich zwei freie Pins und ein schnelles Picoscope. Das 
ermöglicht zwar immer noch keine Echtzeit-Überwachung einer 
Speicherstelle aber man kann sich so immerhin an merkwürdige Aktivitäten 
herantasten. Ist der Fehler dann noch so plump wie in meinem Fall fallen 
die Tomaten ganz schnell von den Augen.

von Stefan F. (Gast)


Lesenswert?

Anton schrieb:
> Hier ging es aber um Amok im Speicher

Dann logge hat alle schreibenden Speicherzugriffe, wo Pointer und 
Array-Indexe verwendet werden.

von Anton (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Dann logge hat alle schreibenden Speicherzugriffe, wo Pointer und
> Array-Indexe verwendet werden.

Theoretisch ja aber praktisch kann das bei größeren Programmen ganz 
schnell einen riesigen Aufwand bedeuten. Hast Du den Log-Speicher nicht 
im System wirds noch grauenvoller. Von den Timing-Verlusten ganz 
abgesehen. Data-Brakpoints gibts schon nicht ganz umsonst finde ich.

von Stefan F. (Gast)


Lesenswert?

Anton schrieb:
> Data-Brakpoints gibts schon nicht ganz umsonst finde ich.

Wenn man keine hat, nützt es nichts, sich welche zu wünschen. Dann muss 
man eben nutzen, was da ist.

von Anton (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Wenn man keine hat, nützt es nichts, sich welche zu wünschen. Dann muss
> man eben nutzen, was da ist.

Da hast Du Recht obwohl ich nach Beitrag 2 von Lothar noch guter Dinge 
war. Da hat man schon modernste AVRs, den besten Debugger und die 
entsprechenden Menüpunkte im MicrochipStudio- und dann bleibt trotzdem 
alles grau.

von rbx (Gast)


Lesenswert?

Anton schrieb:
> Data-Brakpoints gibts schon nicht ganz umsonst finde ich.

Manchmal kann man auch anrufen, oder email schreiben. Bei so 
Treibergeschichten sind wohl eher Anrufe besser.
..oder eben die Aussschau nach Alternativen, oder nach Möglichkeiten der 
Prävention, wie z.B. bei Assembler, eine gute Fehlerliste. Bei C ist die 
nicht so nötig, da nimmt man die Probleme eher beim Aufnehmen mit, denn 
sonst kommt man ja beim Lernen kaum auf einen grünen Zweig.

GDB und radare sind auch so eine Sache. Besser eine Liste mit 
Arbeitstechniken und Befehlen erstellen, und die Liste sollte nicht 
allzuweit weg vom Workflow sein.
Auf YT gibt es ein nettes Video vom radare-Entwickler:
https://www.youtube.com/watch?v=fnpBy3wWabA

von Hermann W. (hermannw)


Lesenswert?

Anton schrieb:
> Ich möchte doch nur den kurzen Moment
> aufklären an dem etwas falsches an besagten Speicher geschrieben wird

Ich habe ein ähnliches Problem in einem Windows-Programm gehabt. Für 
eine Betriebsdatenerfassung senden viele Maschinen ihre Daten, die in 
der Entwicklungsphase zu unerwarteten Fehlern führten. Ein 
Windows-Programm stürzt leider bei nicht abgefangenden Fehlern einfach 
ab.
Zur Analyse habe ich eine "Trace-Datei" geschrieben, die den Weg des 
zyklischen Programms aufzeichnet. Nach jedem Zyklus wird die Datei 
gelöscht. Im Fehlerfall sehe ich dann wie weit das Programm fehlerfrei 
gelaufen ist.
Die Übertragung der Trace-Aufzeichnung auf den AVR hängt von deinen 
Möglichkeiten ab. Als erstes muss die Aufzeichnung im Fehlerfall 
gestoppt werden. So ist der letzte Weg durch alle Interrups 
festgehalten. Je nach Ausgabemöglichkeit kann man den Trace in einen 
intakten RAM-Bereich schreiben oder über eine serielle Schnittstelle 
senden.
Ich sehe meistens einen Menübereich im Display vor, in dem ich 
Analysedaten ausgebe.

von Anton (Gast)


Lesenswert?

Hermann W. schrieb:
> Die Übertragung der Trace-Aufzeichnung auf den AVR hängt von deinen
> Möglichkeiten ab. Als erstes muss die Aufzeichnung im Fehlerfall
> gestoppt werden. So ist der letzte Weg durch alle Interrups
> festgehalten.

Zwischen Windows-Programmen am PC und einem auf kleinen Controller-Chips 
liegen Welten. Vielleicht könntest Du genauer erläutern, wie sich der 
Programmlauf im Detail, über jeden Befehl und Speicherzugriff 
praktikabel aufzeichnen lassen soll. Ich sehe hier höchstens die 
Möglichkeit einzelne Wegmarken an verschiedenen Stellen des Programms zu 
postieren und von dort den Status zu loggen. Das dürfte bei 
verschiedenen Störungen aber oft zu grobkörnig sein, bei meinem 
Fehlerbild hier sogar eher verwirrend. Da hilft manchmal

rbx schrieb:
> eine gute Fehlerliste

schon besser, wenn man schon nicht alles mehr im Kopf halten kann.

Hermann W. schrieb:
> Ich sehe meistens einen Menübereich im Display vor, in dem ich
> Analysedaten ausgebe.

Gute Idee. In meinem Fall ist mit der richtigen Display-Ausgabe aber 
bereits die beste Rückmeldung vorhanden, es geht ja hier nur um eine 
solche.

von Hermann W. (hermannw)


Lesenswert?

Anton schrieb:
> Ich sehe hier höchstens die Möglichkeit einzelne Wegmarken

Genau das meine ich. Damit ist man zuerst grob an der Fehlerstelle. Man 
sieht schon mal die Abfolge der Interrupts. Danach kann man das 
schrittweise verfeinern. Bis man am Schluss (wenn es denn sein muss) am 
kritischen Assemblerbefehl ist.

von Hermann W. (hermannw)


Lesenswert?

Anton schrieb:
> In meinem Fall ist mit der richtigen Display-Ausgabe aber
> bereits die beste Rückmeldung vorhanden

Das verstehe ich nicht. Die beste Rückmeldung kann es nicht sein, sonst 
hättes du die Fehlerstelle. Wichtig ist natürlich vor jedem 
Trace-Eintrag den korrupten RAM-Bereich zu prüfen und im Fehlerfall die 
Aufzeichnung zu stoppen, damit sicher ist, das bis zum letzten Trace 
alles ok ist.

von Hermann W. (hermannw)


Lesenswert?

Anton schrieb:
> dort den Status zu loggen
?? nichts loggen
Ich meine das so:
-RAM prüfen
-wenn korrupt, Trace stoppen (Stop=1)
-wenn Stop=0 Trace schreiben

Das jeweils erst an groben Wegmarken, dann an der kritischen Stelle 
immer feiner. Der Trace endet dann an vor der kritischen Stelle.

von Anton (Gast)


Lesenswert?

Hermann W. schrieb:
> Man
> sieht schon mal die Abfolge der Interrupts.

Zu diesem Zweck und für Fehler die damit zusammenhängen wirklich gut.

Hermann W. schrieb:
> Bis man am Schluss (wenn es denn sein muss) am
> kritischen Assemblerbefehl ist

Wenn es diesen einen Befehl aber gar nicht gibt?
Die eine fehlerhafte Codestelle?
Bereits ein Fehler bei der Register-Rettung kann auf einem komplexen 
System mit vielen unregelmäßigen Interrupts zu hoffnungslos chaotischen 
Fehlerbildern führen. Wenn viele Einflüsse von außen hinzukommen von dem 
Programmzweige und Datenzugriffe abhängen bliebe eigentlich nichts 
anderes übrig als zu versuchen, dieses Gesamt-System zu "loggen".

Hermann W. schrieb:
> Die beste Rückmeldung kann es nicht sein, sonst
> hättes du die Fehlerstelle

Insofern die beste Rückmeldung als daß sich quasi alles um die 
Display-Ausgabe dreht und dort jedwede Störung sofort ersichtlich wäre.

von Rainer V. (a_zip)


Lesenswert?

Anton schrieb:
> Wenn viele Einflüsse von außen hinzukommen von dem
> Programmzweige und Datenzugriffe abhängen bliebe eigentlich nichts
> anderes übrig als zu versuchen, dieses Gesamt-System zu "loggen".

War mein Vorschlag schon vor einiger Zeit. Trotzdem kannst du ja auch 
versuchen, sinnvolle Teilprogramme zu "isolieren". Das es einfach gehen 
sollte, hat ja keiner gesagt :-)
Gruß Rainer

von Hermann W. (hermannw)


Lesenswert?

Anton schrieb:
> Wenn es diesen einen Befehl aber gar nicht gibt?

Dann ist es eben kein Programmfehler. Wenn es denn bei der 
Registerrettung passiert, dann siehst du ja, dass zu Beginn der 
Interruptroutine der Fehler da ist und du weißt, die Registerrettung 
geht schief. Dann ist also der Stack nicht richtig dimensioniert.

von Anton (Gast)


Lesenswert?

Hermann W. schrieb:
> Ich meine das so:
> -RAM prüfen
> -wenn korrupt

So einfach ist das an dieser Stelle nicht.
Im Grunde wäre dafür der zulässige Wertebereich jeder RAM-Zelle zu 
prüfen.
Der auch wieder zeitabhängig sein kann. Das klingt nicht gerade 
praktikabel.

Rainer V. schrieb:
> War mein Vorschlag schon vor einiger Zeit.

Nun ja, dafür gilt gleiches. Ein hoher Aufwand.

Rainer V. schrieb:
> versuchen, sinnvolle Teilprogramme zu "isolieren".

Klar kann man das. Das würde bei diesem und jenem Fehlerbild ganz 
sinnvoll sein. Nur eben lange nicht bei jedem.

von Anton (Gast)


Lesenswert?

Hermann W. schrieb:
> Dann ist es eben kein Programmfehler. Wenn es denn bei der
> Registerrettung passiert, dann siehst du ja, dass zu Beginn der
> Interruptroutine der Fehler da ist und du weißt, die Registerrettung
> geht schief. Dann ist also der Stack nicht richtig dimensioniert.

Nein. Ein einzelnes Register nicht bei Eintritt in den Interrupt, wo 
es dann wiederverwendet wird zu sichern ist sowohl ein kapitaler 
Programmfehler als auch nirgendwo konkret "sichtbar"- außer in 
chaotischen Programmläufen. Das hat rein gar nichts mit der 
Dimensionierung des Stacks zu tun. Hier hilft nur Augen offenhalten und 
solche Dinge schlicht vermeiden.

von Hermann W. (hermannw)


Lesenswert?

Anton schrieb:
> Im Grunde wäre dafür der zulässige Wertebereich jeder RAM-Zelle zu
> prüfen

Kennst du nicht wenigstens den Bereich im RAM, der überschrieben wird? 
Dann könntest du den Bereich durch verschieben deiner Variablen frei 
halten und dann einfach prüfen, ob was geschrieben wird. Du musst 
irgendwie den Fehler erkennen, sonst geht die Methode nicht.

von Anton (Gast)


Lesenswert?

Hermann W. schrieb:
> Kennst du nicht wenigstens den Bereich im RAM, der überschrieben wird?

Ja. Der war sogar fix und mit immer den gleichen/ähnlichen Inhalten. Das 
kann jedoch bloßer Zufall sein. Ich kann und will das jetzt auch nicht 
mehr nachvollziehen nachdem besagter Register-Fehler behoben ist.

von Peyer (Gast)


Lesenswert?

Peter D. schrieb:
> Anton schrieb:
>> Nachdem in einem Teil des Hauptprogramms dessen vielverwendetes Register
>> R16 wie von Zauberhand zuweilen einen unerklärlichen Wert bekam...
> Ja, das ist ein Problem von Assembler, man ist für die Registerrettung
> selber zuständig.

Vor einigen Jahren hab ich mir ein Programm geschrieben, das alle 
verwendeten Register auflistet und ob sie gepoppt und gepusht wurden.
Hat mich gewundert, dass es sowas nicht gab, bzw. dass es nicht 
verbreitet ist. Bis ich dann ASM endlich hinter mir gelassen habe.

> Ich hab ~10 Jahre Assembler benutzt, ich weiß also ganz genau, warum ich
> auf keinen Fall dahin zurück will. Ich weiß auch, daß der Wechsel schwer
> fällt.

von Anton (Gast)


Lesenswert?

Peyer schrieb:
> Vor einigen Jahren hab ich mir ein Programm geschrieben, das alle
> verwendeten Register auflistet und ob sie gepoppt und gepusht wurden.

Das seh ich jetzt (überraschenderweise) eigentlich als geringes Problem 
an.
Mit einem Mindestmaß an Übersicht sollte das bei den paar Registern 
nicht passieren. So einen blöden Fehler hat man nur einmal, dann ist man 
geheilt ;-)

Kritisch ist vor allem, wenn einzelne Programmteile register-unbesehen 
von Main nach Interrupt verlagert werden, so wie es mir passiert ist.

von Thomas (kosmos)


Lesenswert?

eigentlich sollte man wissen welche Register eine Interruptroutine 
verwendet, dann pushed und popt man eben nur diese. Ich nehme mir in der 
Interruptroutine soviel Zeit und lege die Ergebnisse an eine feste 
Stelle im SRAM ab um nicht unnötig Register dafür zu benutzen die ich 
später wiederum pushen/poppen muss. Klar wenn man sich unsicher ist kann 
man alle 32 Register auf den Stack legen und später wieder herstellen. 
Deaktiviertst du die Intterupts wärend du in einer Interruptroutine 
bist? Wenn nicht funkt dir vielleicht ein anderer Interrupt dazwischen.

Ich würde auch schauen, das Programm so zu gestallten, dass ein paar 
Statusmeldungen ausgegeben werden, wie schon jemand empfohlen hat. z.B. 
einen Zahler wie oft ein Interrupt schon aufgetreten ist. Oder sogar 
über einige Pins das Auswählbar zu machen also mit einem kleinen DIP 
Schalter vorzugeben was du sehen möchtest.

von Anton (Gast)


Lesenswert?

Thomas O. schrieb:
> eigentlich sollte man wissen welche Register eine Interruptroutine
> verwendet, dann pushed und popt man eben nur diese.

Sowieso.
Hier war aber das Problem daß ein Register nicht gesichert wurde, im 
Interrupt verwendet und dann (heimlich) verändert wieder im 
Hauptprogramm auftauchte.

Thomas O. schrieb:
> Deaktiviertst du die Intterupts wärend du in einer Interruptroutine
> bist?

Bei Interrupts mit nur einer Prioritätsstufe braucht man das nicht.
Jeder Interrupt wird vollständig abgearbeitet und bleibt bis reti für 
weitere gesperrt. Bei mehreren Prioritätsstufen kann der höhere den 
niedrigeren Interrupt unterbrechen. Das wird man nicht verhindern wollen 
da die höheren Interrupts ja vom Programmierer nicht ohne Grund 
eingesetzt werden. Entweder sind die verwendeten Register dabei wiederum 
auf dem Stack zu sichern oder man wählt dafür separate Register.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Anton schrieb:
> Da hat man schon modernste AVRs

Nun ja, habe mir die Datenblätter gerade mal angesehen.

UPDI stammt von der vorhergehenden Tiny-Familie (Tiny817 etc.). Tinys 
sollen billig sein und dafür macht man den Chip halt klein. Da werden 
dann eben auch mal Features "abgespeckt", und so sind für UPDI nur noch 
zwei Hardware-Breakpoints beschrieben statt früher (beim JTAG der 
klassischen Megas und beim PDI der Xmegas) vier. Für einen data 
breakpoint muss man jedoch stets ein Paar Breakpoint-Register benutzen 
bei der AVR-Architektur (eins für die Adresse, das zweite für die 
Länge). Damit ist klar, dass mit den zwei Breakpoint-Registern des UPDI 
keine data breakpoints gehen.

Warum man nun für die dann wieder "Mega" genannte Weiterentwicklung bei 
den Limitierungen geblieben ist, werden dir nur Insider verraten können. 
Vermutung: so ließ sich durch Weiterbenutzung existierender 
Hardwareblöcke Entwicklungszeit sparen, auch die existierenden Tests 
lassen sich 1:1 weiter verwenden, genauso die Softwareblöcke im Debugger 
des Studios. "Time to market" ist in der Halbleiterei ohnehin schon 
immer eine gefühlte Ewigkeit (allein ein Fab-Durchlauf dauert oft schon 
ein Vierteljahr), ein paar eingesparte Wochen können da schon relevant 
sein und der Grund, auf ein paar seltener genutzte Features zu 
verzichten.

Ähnliche "als Mega getarnte Tinys" gab es auch schon zuvor: ATmega88 & 
Verwandte. Auch die haben beispielsweise kein JTAG bekommen sondern nur 
debugWIRE. Da sie aber andererseits die Multiplikationsbefehle der Megas 
bekommen haben, hat man sie wohl auch "Mega" nennen wollen.

Bliebe für den aktuellen Fall noch die Frage, ob man den gleichen Code 
auch auf älteren, "klassischen" Megas oder Xmegas laufen lassen könnte, 
auf denen man die nötige Hardwareunterstützung hat.

von Stefan F. (Gast)


Lesenswert?

Anton schrieb:
> Wenn es diesen einen Befehl aber gar nicht gibt?
> Die eine fehlerhafte Codestelle?

Und wenn doch?

Solange man keinen besseren Plan hat, ist der Versuch 
erfolgversprechender als gar nichts zu tun.

von Anton (Gast)


Lesenswert?

Jörg W. schrieb:
> Bliebe für den aktuellen Fall noch die Frage, ob man den gleichen Code
> auch auf älteren, "klassischen" Megas oder Xmegas laufen lassen könnte

Natürlich. Alles eine Frage des Aufwands, was ein neues PCB mit 
einschließt.
Die neuen leistungsfähigeren AVRs haben aber schon zuviele Vorteile und 
neue Features als daß ich

> Da werden
> dann eben auch mal Features "abgespeckt"

für tragfähig halte. Aber was ist das schon anderes als Rumstochern im 
Nebel. Es wird schon so sein, der UPDI samt seiner Debug-Hardware hats 
nicht drauf, wurde bei seinem zentralen "nur 1 Leitung" Vorteil aber 
dennoch von den billigeren Tinys übernommen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Anton schrieb:
> wurde bei seinem zentralen "nur 1 Leitung" Vorteil aber dennoch von den
> billigeren Tinys übernommen.

Das muss keineswegs der einzige Vorteil sein. Dazu müsste man sich die 
Entscheidungsträger anhören …

von Peter D. (peda)


Lesenswert?

Anton schrieb:
> Mit einem Mindestmaß an Übersicht sollte das bei den paar Registern
> nicht passieren. So einen blöden Fehler hat man nur einmal, dann ist man
> geheilt ;-)

Aus Erfahrung kann ich sagen, solche Fehler passieren immer wieder.
Man müßte sich ein Tool schreiben, was solche Fehler aufdecken hilft. 
Einen schönen Fehler hatte ich mal, indem ich die Push/Pop Reihenfolge 
vertauschte, d.h. 2 Register waren nach dem Interrupt vertauscht. Da 
grübelt man auch ewig.

Die Fehlermöglichkeiten in Assembler sind also ungleich höher, als in C.
Es passiert schon mal, daß ein Compiler Fehler macht. Aber der Vorteil 
ist, daß Millionen Leute ihn benutzen und solche Fehler schnell 
auffallen. Ich meine, auch der WINAVR hatte mal einen Registerfehler.

von Anton (Gast)


Lesenswert?

Peter D. schrieb:
> Aus Erfahrung kann ich sagen, solche Fehler passieren immer wieder.

Das vermeidet man durch

Anton schrieb:
> eine durchdachte funktionelle Grundstruktur

was z.B. eine Spezialisierung einzelner Register auf bestimmte Aufgaben 
bedeuten kann. "Standard" Interrupt-Rümpfe bestehen bei mir 
beispielsweise aus einem fixen Register zur Flag-Sicherung und der 
Sicherung von bis (alle) 3 PointerRegister in 6 weitere fixe Register. 
Braucht man im Interrupt wirklich noch mehr Register sichert man in 
diesem i.d.R. besonderen Fall auf den Stack, behält sie in dieser 
seltenen Verwendung aber auch im Hinterkopf. Obigen "Verbrauch" von 7 
fixen Registern kann man sich leisten da der AVR eigentlich mehr als 
genug davon hat. Sinnvollerweise sind das welche mit sonst 
eingeschränkter Funktionalität, im Bereich von 3-15.
Gefährlich wirds nur wenn nun einfach irgendwelcher Code in Interrupts 
kopiert wurde ohne die Register-Verwendung genau zu prüfen.

von Ozvald K. (Firma: Privat) (ozvaldk)


Lesenswert?

Anton schrieb:
> welche Möglichkeiten gibt es beim AVR-Debugging, eine konkrete
> Speicherstelle zu überwachen und beim Schreiben dorthin mit einem Halt
> abzubrechen damit man ermitteln kann welcher Code dazu führte?

Vielleicht so:

Am Anfang als erstes und am Ende (vor reti) aus jedem Interrupt eine 
kleine Routine aufrufen. (rcall check_Speicherstelle). Hat sich der 
Inhalt geändert, Rücksprungadresse von Stack holen, anzeigen (LCD) und 
stop.
Damit würdest du zumindest die Stelle bekommen, wo die Änderung 
detektiert wurde. Ist das vorne beim Interrupt, dann hat das 
Hauptprogramm die Speicherstelle geändert. Wurde das vor reti entdeckt, 
dann hat die Interruptroutine reingeschrieben. Damit könnte man den 
Fehler wenigstens eingrenzen und dort weiter suchen. Wäre das ein Weg?

von Anton (Gast)


Lesenswert?

Ozvald K. schrieb:
> Am Anfang als erstes und am Ende (vor reti) aus jedem Interrupt eine
> kleine Routine aufrufen... Wäre das ein Weg

Ein Anfang allemal. Ausgeschlossen bleiben die Aktivitäten des 
Hauptprogramms. Wenn dann aber nur vergessen wurde ein Register des 
Hauptprogramms vor Weiterverwendung im Interrupt zu sichern haben wir 
eine ganz neue Fehler-Qualität, die sich nicht mit dem Aufspüren einer 
bestimmten faulen Code-Stelle bewältigen lässt. Jenes nicht gesicherte 
R16 ist in meinem Fall im Hauptprogramm z.B. auch Teil eines Pointers 
geworden. Damit sind wilden Schreibereien im SRAM Tür und Tor geöffnet.

von Oliver S. (oliverso)


Lesenswert?

Anton schrieb:
> Jenes nicht gesicherte
> R16

Du wolltest maximale Freiheit, du hast sie bekommen.

Oliver

von Anton (Gast)


Lesenswert?

Oliver S. schrieb:
> Du wolltest maximale Freiheit, du hast sie bekommen.

So schauts aus. Über die Kehrseite einer schönen Medaille darf man sich 
nicht beschweren.

von Rainer V. (a_zip)


Lesenswert?

Anton schrieb:
> So schauts aus. Über die Kehrseite einer schönen Medaille darf man sich
> nicht beschweren.

Immerhin konntest du zumindest die Fehlerursache finden. Die 
Auswirkungen sind natürlich verhehrend und durch einfaches 
"Rückschließen" wohl kaum aufzuspüren. Es hätte aber auch ein 
sporadischer, wirklich ekliger Fehler ala Störungen auf irgendwelchen 
Pins oder gar auf der Versorgungsspannung sein können! Deshalb kann man 
wohl mit Recht sagen, is noch immer joot gejangen :-)
Gruß Rainer

von Anton (Gast)


Lesenswert?

Rainer V. schrieb:
> Es hätte aber auch ein sporadischer, wirklich ekliger Fehler ala
> Störungen auf irgendwelchen Pins oder gar auf der Versorgungsspannung
> sein können!

Vor dem Problem stünden dann alle Programmiersprachen. Meine Erfahrung 
mit den AVRs ist aber, daß sie recht robuste, verlässliche Teile sind.

von Rainer V. (a_zip)


Lesenswert?

Anton schrieb:
> Vor dem Problem stünden dann alle Programmiersprachen

Ja klar...genau genommen jeder beliebiger Controller...Ich hatte gerade 
nur im Sinn: ekliger Programmierfehler gegen eklige Hardwareprobleme...
Gruß Rainer

von Anton (Gast)


Lesenswert?

Zwar hätte es hier wenig geholfen, aber für die allgemeine Fehlersuche 
bei der Ausführung von Interrupts und grober Einkreisung von 
Speicherfehlern hab ich basierend auf der Idee von

Ozvald K. schrieb:
> Am Anfang als erstes und am Ende (vor reti) aus jedem Interrupt eine
> kleine Routine aufrufen. (rcall check_Speicherstelle). Hat sich der
> Inhalt geändert, Rücksprungadresse von Stack holen, anzeigen (LCD) und
> stop.
> Damit würdest du zumindest die Stelle bekommen, wo die Änderung
> detektiert wurde. Ist das vorne beim Interrupt, dann hat das
> Hauptprogramm die Speicherstelle geändert. Wurde das vor reti entdeckt,
> dann hat die Interruptroutine reingeschrieben. Damit könnte man den
> Fehler wenigstens eingrenzen und dort weiter suchen.

jetzt eine kleine AVR128DBxx Routine
1
intlog:         lds     ZL,LOGP
2
                lds     ZH,LOGP+1               ;SAVE CURRENT INT NUMBER
3
                st      Z+,XL
4
                lds     XL,(MEMADDR)
5
                st      Z+,XL                   ;SAVE (MONITORED MEMORY)
6
                lds     XL,TCA0_SINGLE_CNT
7
                lds     XH,TCA0_SINGLE_CNT+1
8
                st      Z+,XL
9
                st      Z+,XH
10
                cpi     ZH,$70
11
                brne    intlog1   
12
                ldi     ZH,$50
13
intlog1:        sts     LOGP,ZL
14
                sts     LOGP+1,ZH
15
                ret        
16
17
.DSEG
18
LOGP:           .BYTE 2                 ;LOG POINTER
19
20
.org $5000
21
LOGBUF:         .BYTE 8192              ;2000H LOG MEMORY

im Einsatz die zusammen mit einem 1 MHz UpCounter in TCA0 
(TCA0_SINGLE_CTRLA =7 bei 8MHz) und an Anfang und Ende jedes Interrupts 
aufgerufen jetzt folgendes leistet:

- Überwachung einer Speicherstelle in jedem Interrupt und zuvor in Main
- Überwachung welche Interrupts wann auftreten
- Überwachung der Länge der Interrupts und des zuvor durchlaufenen 
Main-Abschnitts in ca. 1us Einheiten.

Der hier zugewiesene (Ring)Speicher hätte dann Platz für die letzten 
8192/4/2= 1024 Interrupts und kann beim Debugging eingesehen oder 
zyklisch nach außen gesendet werden. Eventuell könnte man den gefüllten 
Puffer gleich noch im System nach eigenen Kriterien auswerten!

P.S. Logpointer am Anfang noch mit LOGBUF initialisieren und auf die 
Sicherung der verwendeten Register im Interrupt achten ;-)

von Anton (Gast)


Lesenswert?

Anton schrieb:
> kleine AVR128DBxx Routine

mit Eingangsparameter XL= Interruptnummer

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.