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
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
Danke Lothar, das schaut doch schon mal gut aus. Ich hoffe es ist so mit einem AVR128DBx Asm-programmiert möglich. Anton
Ich wuerd Funktionalitaeten abschalten und schauen, ob's immer noch passiert. Allenfalls einen Pin toggeln um zu erkennen, wo der Code durchgeht.
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.
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
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.
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.
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.
>>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.
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.
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.
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
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.
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.
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
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.
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.
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.
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.
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
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.
Anton schrieb: > Es ist Assembler Code. > Daher weiß ich genau und selbstbestimmt was wo ist. YMMD ;) Oliver
Anton schrieb: > Daher weiß ich genau und selbstbestimmt was wo ist. Deswegen läuft's ja auch so gut ....
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
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.
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.
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.
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...
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
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.
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.
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
Anton schrieb: > zumal die seriellen Daten über Funk reinkommen Also brauchst Du erstmal ein ordentliches Protokoll mit CRC, um die Störungen rauszufiltern.
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.
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.
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.
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.
Da es um Assembler geht, ist’s letztendlich eh egal. Oliver
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.
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.
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".
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
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
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 ;-)
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.
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
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.
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.
Vielleicht läuft das ja unter MPLAB-X und dem neuen ICE4 Debugger...
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
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.
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...
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.
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
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?
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.
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
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.
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.
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.
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
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.
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
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.
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
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.
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.
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.
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.
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.
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.
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.
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
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).
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.
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).
Anton schrieb: > Die alten Megas/XMegas beherrschen Data > Breakpoints via PDI ja angeblich Die alten ATmegas haben kein PDI.
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...
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.
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
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 ?
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.
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 ;-)
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?
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.
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.
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
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
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.
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).
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.
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.
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.
Anton schrieb: > Hier ging es aber um Amok im Speicher Dann logge hat alle schreibenden Speicherzugriffe, wo Pointer und Array-Indexe verwendet werden.
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.
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.
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.
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
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.
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.
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.
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.
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.
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.
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
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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 …
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.
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.
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?
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.
Anton schrieb: > Jenes nicht gesicherte > R16 Du wolltest maximale Freiheit, du hast sie bekommen. Oliver
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.
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
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.
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
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 ;-)
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.