Forum: Mikrocontroller und Digitale Elektronik XMega bleibt "hängen"?


von Michael K. (mmike)


Lesenswert?

Hallo Leute,

ich bastel momentan an meinem Tricopter Regler mit dem µc XMega128A1. 
Entwickelt wird unter Ubuntu Linux 10.04 (32bit) mit dem Eclipse Plugin. 
Die Treiber für die Sensoren laufen mittlerweile schon, aber leider nur 
"einzeln". Beide Sensoren hängen über TWI an PORTE und PORTF (also TWIE 
und TWIF). Lasse ich nur den Beschleunigungssensor auslesen kappts. Wenn 
ich nur das Gyro auslese klappts auch. Werden beide Sensoren ausgelesen 
(alles interruptbasiert) bleibt der µC einfach stehen. Und das in 
Codeblöcken, in denen eigentlich nichts großes passiert, ausser ein paar 
Berechnungen. Folgendes konnte ich schon in Erfahrung bringen, bzw. 
ausschliessen:

* Main wird nicht mehr durchlaufen
* While Schleifen werden überwacht
* In einem Interrupt hängt er auch nicht fest
* Main wird nicht verlassen

So langsam gehen mir wirklich die Ideen aus und ich wäre über einen Tipp 
wirklich sehr sehr dankbar, wo ich noch suchen kann bzw. was die Ursache 
sein könnte ....

Grüße,
Michael

von gascht (Gast)


Lesenswert?

definitiv in zeite 42 ...
 da haste nen fehler

von Peterp (Gast)


Lesenswert?

Zeile 23 würd ich sowieso prüfen...

von Michael K. (mmike)


Angehängte Dateien:

Lesenswert?

Hallo gascht, Peterp,

:) ich hab schon verstanden, aber Projekt ist wirklich nicht klein! Mir 
gehts mehr darum, ob jemand sowas schon mal hatte und evtl. eine Lösung 
bzw. eine Strategie hat um den Fehler zu lokalisieren. Ich kann mir 
nicht vorstelle, dass sich jemand durch den Sourcecode wühlen will (rund 
25 Dateien, ich hab ihn trotzdem mal angehängt ...)

Grüße,
Michael

von Michael K. (mmike)


Lesenswert?

Hallo ich nochmal,

jetzt wirds spannend: Hab grad mal unter Windows gebootet und die 
aktuellen Sourcen ausgecheckt (svn) und unter Win kompiliert und 
geflasht ... und es läuft!?

Was ich festgestellt habe, ist eine unterschiedliche Kompilerversion:

Windows: avr-gcc 4.3.3 (WINAVR 20100110)
Linux:   avr-gcc 4.3.4

bitte jetzt keine Ratschläge ala "na dann prog halt unter Windows" ....

Grüße,
Michael

von Purzel H. (hacky)


Lesenswert?

Also. Debuggen, dh den Fehler finden ist Teil der Entwicklung, und 
sollte schon zu Begin eingeplant werden. Dh die Leiterplatte sollte die 
passenden Testpunkte enthalten. Der Code sollte hinreichend modular 
sein, um die Funktionalitaet einer jeden Komponente pruefen zu koennen. 
Dann beginnt man mit dem Laufenlaassen einer jeden Komponente. Ich 
bevorzuge das UART, denn damit kann man zur Laufzeit Variablen 
anschauen. Ich hatt auch schon Designs, da hatt ich einen 8x 8 bit DAC 
auf einem gesteckten Adapter, damit konnte man dann zum Debuggen ein 
paar schnelle Variablen aufm Scope anschauen.

von Michael K. (mmike)


Lesenswert?

Hallo hacky,

danke für Deine Antwort. Genau was Du beschreibst habe ich heute den 
ganzen Tag getrieben. Der Aufbau ist noch verkabelt und noch nicht auf 
einer Platine. Der Proz ist auf einem Headerboard von Alvidi und die 
Sensoren sind per Stiftleisten und mit angelöteten Kabeln verbunden. 
Stromversorgung und TWI Pegel sind mit Oszi und LA geprüft und da passt 
auch alles! Komischerweise läuft der Code ja, wenn unter Windows 
kompiliert ohne Probleme, was ich vorhin rausgefunden habe. Unter Linux 
treten seltsame Dinge auf, wie dass der Proz an manchen Stellen einfach 
eben stehen bleibt. Und das leider auch nicht reproduzierbar, sondern 
immer an einer anderen Stelle. Sogar innerhalb von Funktionen, wo 
eigentlich nichts ist, wo er stehen bleiben könnte. Ich hab sogar 
zwischen den Berechnungen in der Datei fc.c entsprechende Debug Ausgaben 
produzieren lassen und plötzlich geht nix mehr. Die Interrupts haben 
ALLE auch eine Debug Ausgabe, d.h. ich würde es mitbekommen, wenn da 
irgendwas schief läuft ....
Speicher bzw. Stack kanns eigentlich auch nicht sein. Das schreibt der 
Kompiler:

AVR Memory Usage
----------------
Device: atxmega128a1

Program:   12752 bytes (9.2% Full)
(.text + .data + .bootloader)

Data:        137 bytes (1.7% Full)
(.data + .bss + .noinit)


Build succeeded with 0 Warnings...


Wirklich sehr suspekt. Ideen ??

Grüße,
Michael

von Purzel H. (hacky)


Lesenswert?

-Vergleich mal die Hexfiles produziert unter Windows und von unter 
Linux. Sie sollten eigentlich identisch sein.

Falls unterschiede ausserhalb des Codes zu finden sind :

-Die Pfade zu den Libraries kontrollieren.
-Kann es sein, dass ein nicht expizit initialisierter Pin beim Einen auf 
Input steht, beim anderen auf Output ?

von Michael K. (mmike)


Lesenswert?

Hallo Hacky,

ich hab die Hexfiles mal verglichen. Die Dateigröße ist identisch, aber 
der offenbart einige Unterschiede (ist nur der Anfang ...):

diff Linux/Flightcontrol.hex Windows/Flightcontrol.hex
11,12c11,12
< :1000A0000C94390A0C94390A0C94390A0C94E41013
< :1000B0000C94390A0C94390A0C940F130C94390AD5
---
> :1000A0000C94390A0C94390A0C94390A0C947A0C81
> :1000B0000C94390A0C94390A0C94A50E0C94390A44
27,28c27,28
< :1001A0000C94390A0C94390A0C94390A0C947B1576
< :1001B0000C94B9130C94390A0C94390A0C94390A2A
---
> :1001A0000C94390A0C94390A0C94390A0C941111E4
> :1001B0000C944F0F0C94390A0C94390A0C94390A98

Lib Pfade sind bei beiden OS in Ordnung und die Dateien sind definitiv 
identisch (beide aus dem gleichen SVN ausgecheckt).

Wenn ich mich recht erinnere, stehen bei den XMegas nicht initialisierte 
IOs immer auf Eingang, wenn nicht explizit als Ausgang definiert. Da 
beide Sensoren ja an den TWIs hängen, wird die "DIR" Konfiguration ja 
vom TWI Modul überschrieben ... Das komische ist ja, dass beide 
Sensortreiber wunderbar laufen, wenn jeweils nur einer aktiviert ist. 
Sind beide aktiv, also sollen Daten von beiden Sensoren abgefragt 
werden, so tritt der Effekt mit dem "Freeze" auf, aber eben nur, wenn 
unter Linux kompiliert wurde. Echt strange ....

Grüße,
Michael

von Michael K. (mmike)


Angehängte Dateien:

Lesenswert?

Hi,

hier noch mal die beiden Hexfiles.

Grüße,
Michael

von Huch (Gast)


Lesenswert?

Hmm. Es müsste, denke ich, geklärt werden ob der Unterschied in Deinem 
Code liegt oder innerhalb einer der Libraries.
Vergleich doch mal die Assemblerlistings. Da siehst Du die Adresse und 
ob der fragliche Code Dein eigener ist oder nicht.

von Huch (Gast)


Lesenswert?

Du schreibst, das Du identlsche Libraries verwendet hast, aber mit zwei 
verschiedenen Versionen des Compilers.
Theoretisch sollte also Dein Code und der Code der Libraries im Listing 
bzw. Hex-File identisch sein.
Dennoch gibt es einen Unterschied. Jetzt ist die Frage was genau der 
Unterschied ist.
Das wird evtl. nicht unmittelbar zur Problemlösung führen, aber unter 
Umständen einen Ansatzpunkt liefern.
Es wäre auch interessant mal die Beschreibung der Releases anzuschauen, 
ob sich da ein Anhaltspunkt ergibt bzw. ob und wie die Neuerung bei dem 
späteren Release mit dem Unterschied im Listingfile korreliert.

Alles ein wenig mühsam und nicht einfach aber das ist der Weg, denke 
ich.

von Wat (Gast)


Lesenswert?

Hallo,

ich hatte mal das Problem, dass Objektdateien nicht neu gebaut wurden 
und deshalb alte Objektdateien gelinkt wurden. Lösche diese mal manuell 
und baue das Projekt neu. Denn dies ist vermutlich passiert, beim 
Auschecken unter Windows...

von Michael K. (mmike)


Lesenswert?

@Huch: Der Code stammt von mir und liegt auch in einem eigenen SVN 
Repos. Die Lib-Versionen sollten gleich sein, aber prüfe ich gleich noch 
mal und schau' ob da Unterschiede sind. Wie genau komme ich denn an die 
Assembler Listings?? Unter AVR Studio kannte ich, dass man beim 
Simulieren sich den ASM Code anzeigen lassen kann ... weißt Du wie das 
unter Linux geht??

@Wat: Beide OS Varianten wurden frisch kompiliert, also vorher 
"gecleaned" und dann gebaut ...

Danke für die Anregungen!! Ich halte Euch auf dem Laufenden!

Grüße,
Michael

von Huch (Gast)


Lesenswert?

>@Huch: Der Code stammt von mir und liegt auch in einem eigenen SVN
Repos.

Mir ist gerade nicht klar, was Du damit sagen willst.

Ich wollte darauf hinaus, dass es Code gibt den Du (oder wer auch immer) 
geschrieben hast und solchen der aus den Libraries stammt.
Wesentlich daran, ist folgendes: Liegt der Unterschied im resultierenden 
Hex-File in dem Bereich des Library-Codes so bedeutet das etwas anderes 
als wenn der Unterschied in "Deinem" Code liegt.

Was das Listing File mit gcc unter Linux betrifft muss man da eine 
Option hinzufügen, denke ich. Bin gerade zu faul selbst nachzusehen. 
Mach Du das bitte selbst.

von Michael K. (mmike)


Lesenswert?

Ah, verstehe. Ich hab grad nochmal die Libversionen gecheckt und die 
sind identisch (Linux sagt: avr-lib 1:1.6.7-1ubuntu2, WINAVR V.20100110 
sagt im WINAVR-User-Manual.txt unter Punkt 2.1 Manifest: 3. avr-libc 
1.6.7cvs). Fragt sich nur, ob gleiche Version = gleicher Code !?
Der Quellcode ist definitiv identisch .... hab die Dateien mal auf nen 
Stick gezogen und gedifft. Kein Unterschied.
Ich installier grad das Linux in einer VM um nicht dauern umbooten zu 
müssen. Dann checke ich mal die Listing Unterschiede. Wusste nicht, dass 
der gcc, respektive der avr-gcc direkt so ein Listing erzeugen kann...

DANKE!

Grüße,
Michael

von Huch (Gast)


Lesenswert?

>Fragt sich nur, ob gleiche Version = gleicher Code !?
>Der Quellcode ist definitiv identisch .... hab die Dateien mal auf nen
>Stick gezogen und gedifft. Kein Unterschied.

Also der Quellcode der Libraries ist identisch? Das wäre schon mal eine 
Information.

von Huch (Gast)


Lesenswert?

Wo wir schon über Optionen reden könntest Du auch mal die Optionen beim 
Bau mit der alten Compilerversion mit denen beim Bau mit der neuen 
Version vergleichen.

von Michael K. (mmike)


Lesenswert?

Was ich geprüft habe ist der Quellcode von meinem Code, nicht den der 
Libraries. Die liegen ja als .a vor und sind schon kompiliert ;-) Ausser 
ich zieh mir die sourcen ....
ich teste jetzt mal mit den Kompileroptionen ... -g -Wa,-adhlns=file.lst 
klingt schon vielversprechend ...

von Huch (Gast)


Lesenswert?

>Was ich geprüft habe ist der Quellcode von meinem Code, nicht den der
Libraries.

Ach so. Ich habe in den Sätzen:

>Ich hab grad nochmal die Libversionen gecheckt und die
>sind identisch (Linux sagt: avr-lib 1:1.6.7-1ubuntu2, WINAVR V.20100110
>sagt im WINAVR-User-Manual.txt unter Punkt 2.1 Manifest: 3. avr-libc
>1.6.7cvs). Fragt sich nur, ob gleiche Version = gleicher Code !?
>Der Quellcode ist definitiv identisch .... hab die Dateien mal auf nen
>Stick gezogen und gedifft. Kein Unterschied.

die Frage "ob gleiche Version = gleicher Code" als rethorisch 
verstanden, denn in dem nachfolgenden "Der Quellcode ist definitiv 
identisch..." wurde das Satzsubjekt nicht vollständig neu spezifiziert, 
so das sich "Quellcode" auf den Quellcode der Library zu beziehen 
schien.

Ich denke den Vergleich der Quellcodes der Library brauchst Du jetzt 
nicht zu durchzuführen. Das wesentliche ist erstmal, anhand des 
Listing-Files erstmal festzustellen wo der Unterschied liegt und zu 
welcher Quellcode-Zeile der Unterschied gehört.

Dann kann man weiter sehen.

von alibaba (Gast)


Lesenswert?

Als Ansatz:
1
%.lss: $(PROJECT).elf
2
  avr-objdump -h -S $< > $@
So sieht als Beispiel ein make target für das Listing aus.

Grüße

von Michael K. (mmike)


Angehängte Dateien:

Lesenswert?

@alibaba: Vielen Dank! Habs auch schon gefunden ;-)

Anbei die beiden Listings  .... ich hab die beiden auch mal gedifft und 
es gibt einige Unterschiede (mit Notepad++ über 
Erweiterungen->Compare->Compare).

Ich verstehe nur leider noch nicht ganz wonach ich suchen soll ...?? Und 
asm verstehe ich auch nur in den Grundzügen ... ich hoffe Ihr könnt 
daraus mehr lesen als ich!!

Grüße,
Michael

PS: In dem Linux listing sind anscheinend keine Debug Informationen drin 
... Ich versuch da mal welche reinzubekommen ....

von Purzel H. (hacky)


Lesenswert?

Aus dem Unterscheid der Hexfiles kann man die Adresse herausziehen. 
Siehe Aufhau von Hex-files. Dann im ASM Listing die Zeilennummer suchen.

von Michael K. (mmike)


Angehängte Dateien:

Lesenswert?

So der Vollständigkeit anbei noch das Linux Listing mit debug 
Informationen.
@hacky: Die Hexfiles unterscheiden sich ja schon in der ersten Zeile! 
Könntest Du bitte kurz ausführen, wonach ich suchen muss? Auch die 
Speicheraufteilung scheint zwischen Win und Lin unterschiedlich zu sein 
... Am Anfang stehen die Strings, die im Flash abgelegt worden sind. Da 
ist z.B. die Reihenfolge schon gänzlich anders ....

Grüße,
Michael

von Huch (Gast)


Lesenswert?

@ Michael K.

Kriegst Du das erste Listing (Linux) auch so hin, dass die 
C-Source-Zeilen mit in dem File stehen. Das wäre viel einfacher.


>Ich verstehe nur leider noch nicht ganz wonach ich suchen soll ...??

Das kann ich im voraus leider auch nicht genau sagen. Man sollte mal die 
C-Zeilen angucken bei denen im Assembler-Code ein Unterschied besteht.

Eine Vermutung wäre, das Du ein C-Statement etwas unglücklich formuliert 
hast. Es funktioniert zwar aber vielleicht aber nicht wenn ein Bug 
beseitigt wurde. Da gibt es viele Möglichkeiten C-Befehle zwar 
syntaktisch korrekt zu formulieren aber so, das es nur unter bestimmten 
Bedingungen geht, die im C-Standard als "implementierungsabhängig" 
gekennzeichnet sind.

von Michael K. (mmike)


Lesenswert?

@Huch: Meinst Du das Listing? 
(Beitrag "Re: XMega bleibt "hängen"?") In diesem sind die 
C-Source-Zeilen mit drin ...

Grüße,
Michael

von Huch (Gast)


Lesenswert?

>In diesem sind die C-Source-Zeilen mit drin ...
Oops. Habe ich nicht gesehen.

von Benni L. (sutter_cain)


Lesenswert?

Ist es möglich, dass es zu einem Stack Overflow kommt?

Es könnte z.B. sein, dass unter Windows in den Compileroptionen 
Optimierungen an sind, die den Code beschleunigen, so dass es nicht zum 
Stack Overflow kommt.

Ein Debugger hast du nicht, wenn ich das geschriebene richtig 
interpretiere?

von T.O. (Gast)


Lesenswert?

Hallo..

Sagt mal, den einfachsten aller Fälle, einen Programmierfehler, hat hier
noch keiner angenommen? (Die Frage, warum er unter Win geht und unter 
Lin
nicht, wäre mir zunächst egal, ich würde den Fehler suchen. Bestimmt 
nicht
in den Libs, eher in meinem Code...)

Stichworte wie "atomar" sollten da hellhörig machen..

Gruss, T.

PS: If stack full, erase stack.

von Huch (Gast)


Lesenswert?

>Die Dateigröße ist identisch, aber der offenbart einige Unterschiede

Also, ich habe mir "einige" Unterschiede anders vorgestellt. So drei bis 
20-40. Aber das hier ist doch eine etwas andere Dimension.

Deine sprachlichen Äusserungen darf man wohl nicht ganz ernst nehmen. 
Ist nicht böse gemeint, aber es ist natürlich wichtig zu wissen wie 
präzise Du Dich ausdrückst.

Ich habe ehrlich gesagt keine Lust die Unterschiede selbst zu suchen und 
würde ansgesichts der Menge doch erstmal versuchen den Fehler mittels 
Debugging einzugrenzen.

Du hast nun folgende Möglichkeiten, denke ich:

1. Suche die Unterschiede selbst heraus und präsentiert sie hier. Es 
geht um die C-Codezeilen, der zugehörigen Assemblerzeilen die 
unterschiedlich sind. Jedoch sind reine Unterschiede in den Sprungzielen 
dabei irrelevant.
- Ganz ehrlich, habe ich das Gefühl, das Du damit überfordert sein 
könntest.

2. Versuche den Fehler auf der Ebene des C-Codes zu finden.
Das scheint mir eher erfolgversprechend.

--------------------------------------

Solltest Du Alternative 2. wählen, dann erkläre doch mal folgendes aus 
Deinem ersten Posting. Ich kann damit wenig anfangen.

>* Main wird nicht mehr durchlaufen
Wie stellst Du das fest? Was meinst Du damit?

>* While Schleifen werden überwacht
Wie stellst Du das fest und was heisst hier "überwacht"? Von wem, mit 
welchen Mitteln, und welchen Ergebnissen?

>* In einem Interrupt hängt er auch nicht fest
Wie stellst Du das fest? Das ist ein Widerspruch zum ersten Punkt: Wenn 
der uC main nicht ausführt und keinen Interrupt, was macht er dann?

>* Main wird nicht verlassen
Das sollte so sein bei einem uC-Programm, was erscheint Dir daran 
bemerkenswert?

-----------------------------------------------------------------

Ich hoffe Du hast Verständnis dafür, dass ich Dich auf die besondere 
Bedeutung einer möglichst korrekten Beschreibung der Fakten hinweise. 
Falls Du Anfänger bist, haben wir durchaus Verständnis für unkorrekte 
Ausdrucksweise.

Ein Beispiel ist: " bleibt der µC einfach stehen."
Der uC bleibt nur dann stehen, wenn der Takt wegbleibt oder er abbrennt 
oder jemand drauftritt. Sonst läuft er immer weiter. Es ist ihm 
unmöglich "stehenbleiben". Das geht garnicht. Was also meinst Du damit?

In diesem Fall wäre zusätzlich die Angabe nützlich, auf welche Weise und 
anhand welcher Kriterien Du denn feststellst, das er "stehenbleibst". 
Daraus können wir uns dann wieder in passende Begriffe 'übersetzen' was 
Du damit meinst. Aus den Reaktionen kannst Du auch lernen wie man sich 
in dem Thema korrekt ausdrückt. Evtl. stellen wir aber auch fest, das 
Deine Kriterien oder die Verfahren verbessert werden können. Auch 
interessant.

von Michael K. (mmike)


Lesenswert?

Hallo zusammen,

@Benni L.:
* Stackoverflow: keine Ahnung ... wie könnte ich das feststellen?
* Debugger ist vorhanden (Atmel JTAG MKII). Als die Software unter Linux 
immer "stehen blieb" (dazu später mehr) wollte ich unter Windows 
debuggen (unter Linux geht debugging (noch) nicht). Da hab ich dann eben 
festgestellt, dass der, unter Win kompilierte Code druchläuft.
* Compileroptionen sind identisch und überprüft
Was ich als nächstes machen werde, ist den Code von Linux unter Windows 
flashen und vor allem debuggen ... vllt. sieht man dann wo er "hängen 
bleibt".

@T.O.:
* Programmierfehler schließe ich natürlich nicht aus! Ich hab schon 
wirklich "megabyteweise" debug Informationen über die USART rausgelassen 
und zudem mit dem LA Pinwakler gecheckt.

@Huch:
> Also, ich habe mir "einige" Unterschiede anders vorgestellt. So drei bis
> 20-40. Aber das hier ist doch eine etwas andere Dimension.

* stimmt ...leider!

> Deine sprachlichen Äusserungen darf man wohl nicht ganz ernst nehmen.
> Ist nicht böse gemeint, aber es ist natürlich wichtig zu wissen wie
> präzise Du Dich ausdrückst.

* Ich versuche daran zu arbeiten!

> Ich habe ehrlich gesagt keine Lust die Unterschiede selbst zu suchen und
> würde ansgesichts der Menge doch erstmal versuchen den Fehler mittels
> Debugging einzugrenzen.

Das erwarte ich auch gar nicht!! Ich will den Fehler schon selber 
finden! Bzgl. debugging: s.o.

> Du hast nun folgende Möglichkeiten, denke ich:
>
> 1. Suche die Unterschiede selbst heraus und präsentiert sie hier. Es
> geht um die C-Codezeilen, der zugehörigen Assemblerzeilen die
> unterschiedlich sind. Jedoch sind reine Unterschiede in den Sprungzielen
> dabei irrelevant.
> - Ganz ehrlich, habe ich das Gefühl, das Du damit überfordert sein
> könntest.

* Überfordert bin ich noch nicht ... ist halt viel Arbeit da 
Unterschiede zu finden und vor allem dauert es eifach ...

> 2. Versuche den Fehler auf der Ebene des C-Codes zu finden.
> Das scheint mir eher erfolgversprechend.

Bin dabei.

> --------------------------------------
>
> Solltest Du Alternative 2. wählen, dann erkläre doch mal folgendes aus
> Deinem ersten Posting. Ich kann damit wenig anfangen.
>
>>* Main wird nicht mehr durchlaufen
> Wie stellst Du das fest? Was meinst Du damit?

Ich hab in der main nen USART output drin gehabt, ala Debug_Str ("."); 
Wenn der µC "stehen" bleibt, dann kam über UART kein "." mehr. Meine 
Vermutung war dann, dass der µC in entweder ein Schleife hängt, oder ein 
Interrupt permanent auslöst wird und er darin "festhängt".

>>* While Schleifen werden überwacht
> Wie stellst Du das fest und was heisst hier "überwacht"? Von wem, mit
> welchen Mitteln, und welchen Ergebnissen?

Alle while - Schleifen haben eine Debug Ausgabe drin (gehabt). In keiner 
der Schleifen hing der µC länger als erwartet.

>>* In einem Interrupt hängt er auch nicht fest
> Wie stellst Du das fest? Das ist ein Widerspruch zum ersten Punkt: Wenn
> der uC main nicht ausführt und keinen Interrupt, was macht er dann?

Debug - Ausgaben am Anfang und am Ende der ISR.

>>* Main wird nicht verlassen
> Das sollte so sein bei einem uC-Programm, was erscheint Dir daran
> bemerkenswert?

Das ist eine der Möglichkeiten, wie der µC "stehen" bleiben kann ;-). 
Macht man im main ein return, ist Schluss mit "arbeiten" ....

> -----------------------------------------------------------------
>
> Ich hoffe Du hast Verständnis dafür, dass ich Dich auf die besondere
> Bedeutung einer möglichst korrekten Beschreibung der Fakten hinweise.
> Falls Du Anfänger bist, haben wir durchaus Verständnis für unkorrekte
> Ausdrucksweise.

Anfänger bin ich nicht mehr, ich hoffe das sieht man auch ein wenig am 
Code, aber Profi bin ich auch nicht. Ich programmiere hauptberuflich, 
aber eben nur auf PCs unter Linux. Wenn ich mich unkorrekt ausgedrückt 
habe, dann möchte ich mich dafür entschuldigen! Ich arbeite dran!

> Ein Beispiel ist: " bleibt der µC einfach stehen."
> Der uC bleibt nur dann stehen, wenn der Takt wegbleibt oder er abbrennt
> oder jemand drauftritt. Sonst läuft er immer weiter. Es ist ihm
> unmöglich "stehenbleiben". Das geht garnicht. Was also meinst Du damit?

Es kommen keine Debug Ausgaben über UART mehr. PC seitige Probleme kann 
ich dabei ausschließen. Zudem zeigt der LA keine Aktivität mehr an 
"Toggelpins" und die angeschlossene LED (die blinken sollte) bleibt 
entweder statisch an oder aus.

> In diesem Fall wäre zusätzlich die Angabe nützlich, auf welche Weise und
> anhand welcher Kriterien Du denn feststellst, das er "stehenbleibst".
> Daraus können wir uns dann wieder in passende Begriffe 'übersetzen' was
> Du damit meinst. Aus den Reaktionen kannst Du auch lernen wie man sich
> in dem Thema korrekt ausdrückt. Evtl. stellen wir aber auch fest, das
> Deine Kriterien oder die Verfahren verbessert werden können. Auch
> interessant.

s.o.

Grüße,
Michael

von Huch (Gast)


Lesenswert?

>* Ich versuche daran zu arbeiten!
> Anfänger bin ich nicht mehr, ich hoffe das sieht man auch ein wenig am
> Code, aber Profi bin ich auch nicht. Ich programmiere hauptberuflich,
> aber eben nur auf PCs unter Linux.

Gut. Ich werde das berücksichtigen. Aber vorerst werde ich Deine 
Antworten weiter hinterfragen.

>Wenn ich mich unkorrekt ausgedrückt habe, dann möchte ich mich dafür 
>entschuldigen!
Das ist wirklich und absolut unnötig. Ich mache Dir keine Vorwürfe, 
erwarte keine Zerknirschung, kein Bedauern, keine Unterwerfung oder 
Wiedergutmachung. Wenn ich darüber schreibe, dann allein deswegen weil 
diese sprachlichen "Eigenheiten" den Analyseprozess entstellend 
beeinflussen.

Ich will trotzdem versuchen Dir mit dem was ich weiss zu helfen. Gehe 
Dir mit dem sprachlichen Zeug wahrscheinlich ein paarmal auf die Nerven.

Das mit dem Debuggen der Windows-Variante unter Linux scheint mir ein 
guter Ansatz zu sein.

Denke daran, das das ausbleiben der Debug-Ausgabe kein "Anhalten" 
bedeutet sondern nur, dass der durchlaufene Code keine Ausgaben erzeugt. 
Genauso der Zustand in dem keine Änderungen an der LED oder den Ports 
mehr erfolgen.

Eine weiter Möglichkeit wäre die Debug-Ausgaben weiter zu 
differenzieren. Gib eine Kombination aus einem Buchstaben für die 
Funktion und einer Zahl für einen Schritt in der Funktion aus. (Nicht zu 
fein gliedern).

Was mir auffällt, ist das Du im Text von Debug-Ausgaben innerhalb des 
Interrupts sprichst. An sich ist das absolut tödlich, wenn etwa Ausgaben 
selbst auch über Ints laufen. Wenn Du das nicht komplett aus den ISRs 
entfernen willst dann kommentiere es mal aus. Eine durchaus reale 
Möglichkeit, das hier was knackt.

Ehrlich gesagt halte ich die Möglichkeit des Stacküberlaufs für 
wahrscheinlich. Um das zu erkennen kannst Du den Speicher mal mit einem 
Muster vollschreiben und hinterher sehen ob das Muster noch da ist.
Gab hier gerade vor ein paar Tagen eine Diskussion dazu. Suche einfach 
danach.
Falls es tatsächlich am Stacküberlauf liegt wirst Du mit den bisherigen 
Debugausgaben nur bedingt weiterkommen, weil der Code an sich korrekt 
ist aber zu viele Verschachtelungsebenen auftreten. Du kannst evtl. eine 
Debug-Ausgabe basteln die die die Aufrufebenen zurückgibt, bzw. den 
Stackpointer.

Du könntest auch mal im Code gucken ob irgendwo absichtlich oder 
unabsichtlich Rekursionen auftreten und ob die Abbruchbedingungen 
wirklich mit true bewertet werden.

Läuft der Code im Simulator? Kannst Du den Fehler im Simulator auch 
provozieren?

Eine gute Möglichkeit ist auch, einen Lint über Deinen Code laufen zu 
lassen. Es gibt da einige für Linux.

Falls noch nicht geschehen, lasse Dir alle Warnings ausgeben und 
beseitige alle (zeige die die Du meinst nicht beseitigen zu können).

So, das sind einige Vorschläge. Über die Reihenfolge könnte man noch 
gesondert reden, aber da Du schreibst das Du Programmiererfahrung hast, 
kannst Du das wahrscheinlich selbst gut entscheiden.

von Michael K. (mmike)


Lesenswert?

Huch schrieb:
>>* Ich versuche daran zu arbeiten!
>> Anfänger bin ich nicht mehr, ich hoffe das sieht man auch ein wenig am
>> Code, aber Profi bin ich auch nicht. Ich programmiere hauptberuflich,
>> aber eben nur auf PCs unter Linux.
>
> Gut. Ich werde das berücksichtigen. Aber vorerst werde ich Deine
> Antworten weiter hinterfragen.

Gerne!

>
>>Wenn ich mich unkorrekt ausgedrückt habe, dann möchte ich mich dafür
>>entschuldigen!
> Das ist wirklich und absolut unnötig. Ich mache Dir keine Vorwürfe,
> erwarte keine Zerknirschung, kein Bedauern, keine Unterwerfung oder
> Wiedergutmachung. Wenn ich darüber schreibe, dann allein deswegen weil
> diese sprachlichen "Eigenheiten" den Analyseprozess entstellend
> beeinflussen.

Alles klar. Nochmals danke an alle (und speziell an Dich!) !

> Ich will trotzdem versuchen Dir mit dem was ich weiss zu helfen. Gehe
> Dir mit dem sprachlichen Zeug wahrscheinlich ein paarmal auf die Nerven.

Klasse! Wenn ich dabei lerne, dann ists mir nur Recht!

> Das mit dem Debuggen der Windows-Variante unter Linux scheint mir ein
> guter Ansatz zu sein.

Das habe ich mittlerweile durchführen können mit folgendem Ergebnis:

1. Flashen des unter Linux kompilierten Hexfiles.
2. Laufen lassen --> µC stellt LED blinken, Pintogglen und Debugausgaben 
ein = "meine" Umschreibung für "hängen bleiben".
3. Debugger klar gemacht und versucht das Linux Hexfile zu debuggen. 
Also Debugger scharf gemacht und gestartet -> AVR Studio zeigt den 
ersten Eintrag in der Main, danach F5 (Run) ==> Läuft ... ????

Wirklich seltsam. Wenn der Debugger dran hängt und der µC per Run laufen 
gelassen wird, dann läufts wie soll. Debugausgaben kommen und die LED 
blinkt ...

Sobald ich das Programm ohne Debugger auf dem µC laufen lassen, bleibt 
er wieder "hängen".

> Denke daran, das das ausbleiben der Debug-Ausgabe kein "Anhalten"
> bedeutet sondern nur, dass der durchlaufene Code keine Ausgaben erzeugt.
> Genauso der Zustand in dem keine Änderungen an der LED oder den Ports
> mehr erfolgen.

Klar. Irgendwo ist das Ding in einer quasi "Endlosschleife" aus der er 
nicht mehr rauskommt ...

> Eine weiter Möglichkeit wäre die Debug-Ausgaben weiter zu
> differenzieren. Gib eine Kombination aus einem Buchstaben für die
> Funktion und einer Zahl für einen Schritt in der Funktion aus. (Nicht zu
> fein gliedern).

Hab ich verstanden und auch schon gemacht! Werde den morgigen Tag mal 
nutzen und das ausgiebig erweitern!!

> Was mir auffällt, ist das Du im Text von Debug-Ausgaben innerhalb des
> Interrupts sprichst. An sich ist das absolut tödlich, wenn etwa Ausgaben
> selbst auch über Ints laufen. Wenn Du das nicht komplett aus den ISRs
> entfernen willst dann kommentiere es mal aus. Eine durchaus reale
> Möglichkeit, das hier was knackt.

Verstehe. Die Debugausgaben werden nicht über Interrupts ausgegeben, 
sondern relativ straight forward:

Meine Debugfunktion ist diese hier (PSTR für das ablegen der Strings im 
PROGMEM):
#define Debug_Str(_str) ( dputsP (PSTR(_str)) )

die Funktion dputsP sieht folgendermassen aus:

inline void dputsP (const char * str)
{
  while (pgm_read_byte(str) != 0x00)
    Debug_ch(pgm_read_byte(str++));
}

und dann noch die Funktion Debug_ch:

inline void Debug_ch (char ch)
{
  USART_putc (&DEBUG, ch);
}

mit der USART_putc Funktion:

void USART_putc (USART_t * _usart, char ch)
{
  // Wait until data register empty interrupt flag is set
  while(!(_usart->STATUS & USART_DREIF_bm));
  // Write char to DATA register
  _usart->DATA = ch;
}

mir fällt grad auf, dass hier auch noch ne while Schleife ist, die noch 
nicht überprüft worden ist. Hole ich nach!

> Ehrlich gesagt halte ich die Möglichkeit des Stacküberlaufs für
> wahrscheinlich. Um das zu erkennen kannst Du den Speicher mal mit einem
> Muster vollschreiben und hinterher sehen ob das Muster noch da ist.
> Gab hier gerade vor ein paar Tagen eine Diskussion dazu. Suche einfach
> danach.
> Falls es tatsächlich am Stacküberlauf liegt wirst Du mit den bisherigen
> Debugausgaben nur bedingt weiterkommen, weil der Code an sich korrekt
> ist aber zu viele Verschachtelungsebenen auftreten. Du kannst evtl. eine
> Debug-Ausgabe basteln die die die Aufrufebenen zurückgibt, bzw. den
> Stackpointer.

Das klingt sehr möglich! Mehr dazu morgen. Hab mal nach Möglichkeiten 
gesucht den Stack / Speicherbedarf zu checken gesucht. Ist das hier eine 
Möglichkeit Beitrag "Re: ATMEGA32 Stackauslastung im AVR Studio anzeigen" ??

> Du könntest auch mal im Code gucken ob irgendwo absichtlich oder
> unabsichtlich Rekursionen auftreten und ob die Abbruchbedingungen
> wirklich mit true bewertet werden.

Mach ich morgen!

> Läuft der Code im Simulator? Kannst Du den Fehler im Simulator auch
> provozieren?

Unter Linux hab ich den Simulator noch nicht bemüht. Könnte man im 
Simulator auch die Kommunikation mit den Sensoren simulieren?? Denn das, 
denke ich ist Vorraussetzung für einen sinnvollen Test !?

> Eine gute Möglichkeit ist auch, einen Lint über Deinen Code laufen zu
> lassen. Es gibt da einige für Linux.

Lint kenne ich noch nicht. Ich mach mich mal schlau ...

> Falls noch nicht geschehen, lasse Dir alle Warnings ausgeben und
> beseitige alle (zeige die die Du meinst nicht beseitigen zu können).

Keine Warnings.

> So, das sind einige Vorschläge. Über die Reihenfolge könnte man noch
> gesondert reden, aber da Du schreibst das Du Programmiererfahrung hast,
> kannst Du das wahrscheinlich selbst gut entscheiden.

Klasse! Vielen Dank nochmals für die Vorschläge!


Grüße,
Michael

von Michael K. (mmike)


Lesenswert?

Hallo,

also die ersten Test haben folgendes ergeben:

0. Vorbedingungen:
LA an PORTA angeschlossen und alle 8 Leitungen von 0-7 angeklemmt.
PIN0 wird getoggelt, wenn main durchlaufen wird.
PIN1 wird getoggelt, wenn die "PinChange"-ISR des Gyros ausgeführt wird. 
Der Sensor setzt einen seiner Pins für 50µs auf high, wenn neue Daten 
vorliegen.
PIN2 wird gesetzt am Anfang der TWI-ISR des Gyros und am Ende davon 
wieder gecleared.

1. Test: Sensorwerte auslesen und nichts berechnen.
Dafür wurde in der Datei fc.c (hier läuft die Berechnung der Lagewinkel 
(phi, theta, psi - mit Filter) und deren Derivate (phi_dot, theta_dot, 
...). In der Funktion wurden alle Berechnungen auskommentiert. Zudem 
wurde bei jedem 10. neu gelesenen Sensorwert eine LED getoggelt (Gyro 
wird mit 100Hz ausgelesen).

ERGEBNIS:
Es läuft durch (hab 10 Minuten gewartet). Das sehe ich an einer 
blinkenden LED und den Pinwacklern.

Ich teste jetzt mal die Stackgeschichte speziell für die Funktion.

Grüße,
Michael

von Michael K. (mmike)


Lesenswert?

Also weiterer Test ist erfolgt:

0. Vorbedinungen:
Die Stackprüfung wurde mit eingebaut mit folgendem Code:

mem-check:
1
#ifndef _MEM_CHECK_H_
2
#define _MEM_CHECK_H_
3
4
extern unsigned short get_mem_unused (void);
5
6
#endif  /* _MEM_CHECK_H_ */

mem-check.c:
1
/*
2
 * mem_check.c
3
 *
4
 *  Created on: 29.12.2010
5
 *      Author: mkriegel
6
 */
7
8
#include <avr/io.h>  // RAMEND
9
#include "mem_check.h"
10
11
// Mask to init SRAM and check against
12
#define MASK 0xaa
13
14
// From linker script
15
extern unsigned char __heap_start;
16
17
unsigned short
18
get_mem_unused (void)
19
{
20
   unsigned short unused = 0;
21
   unsigned char *p = &__heap_start;
22
23
   do
24
   {
25
      if (*p++ != MASK)
26
         break;
27
28
      unused++;
29
   } while (p <= (unsigned char*) RAMEND);
30
31
      return unused;
32
}
33
34
/* !!! never call this function !!! */
35
void __attribute__ ((naked, section (".init8")))
36
__init8_mem (void)
37
{
38
   __asm volatile (
39
      "ldi r30, lo8 (__heap_start)"  "\n\t"
40
      "ldi r31, hi8 (__heap_start)"  "\n\t"
41
      "ldi r24, %0"                  "\n\t"
42
      "ldi r25, hi8 (%1)"            "\n"
43
      "0:"                           "\n\t"
44
      "st  Z+,  r24"                 "\n\t"
45
      "cpi r30, lo8 (%1)"            "\n\t"
46
      "cpc r31, r25"                 "\n\t"
47
      "brlo 0b"
48
         :
49
         : "i" (MASK), "i" (RAMEND+1)
50
   );
51
}

Sourcen sind von hier: 
Beitrag "Re: ATMEGA32 Stackauslastung im AVR Studio anzeigen"

In der Funktion Flightcontrol () aus der Datei fc.c wurde dann vor jeder 
Operation ein "Memory Debug" eingefügt:

das ganze sieht dann so aus:
1
/*
2
 * fc.c
3
 *
4
 *  Created on: Nov 6, 2010
5
 *      Author: mike
6
 */
7
8
#include "fc.h"
9
10
// Body fixed rates
11
#define            p        BodyRate_i32_m1024__deg_d_s[0]
12
#define            q        BodyRate_i32_m1024__deg_d_s[1]
13
#define            r        BodyRate_i32_m1024__deg_d_s[2]
14
// Euler rates
15
#define            phi_dot      EulerRate_i32_m1024__deg_d_s[0]
16
#define            theta_dot    EulerRate_i32_m1024__deg_d_s[1]
17
#define            psi_dot      EulerRate_i32_m1024__deg_d_s[2]
18
// Euler Angles (filter)
19
#define            phi        EulerAngle_Filtered_i32_m1024__deg[0]
20
#define            theta      EulerAngle_Filtered_i32_m1024__deg[1]
21
#define            psi        EulerAngle_Filtered_i32_m1024__deg[2]
22
// Euler Angles (accelerometer & magnetometer)
23
#define            phi_acc      EulerAngle_Accel_i32_m1024__deg[0]
24
#define            theta_acc    EulerAngle_Accel_i32_m1024__deg[1]
25
#define            psi_mag      EulerAngle_Accel_i32_m1024__deg[2]
26
// Trigonometric functions
27
#define            sini(_param)  ( sin_i32_m1024(_param) )
28
#define            cosi(_param)  ( cos_i32_m1024(_param) )
29
#define            tani(_param)  ( tan_i32_m1024(_param) )
30
31
// Variables
32
int16_t            AccelRaw_i16_m1024__1g[3];
33
int32_t            AccelVectorLength;
34
uint8_t            UseAccelForFilterFlag = 1;
35
int16_t            GyroRaw_i16_m14d375__deg_d_s[3];
36
37
int32_t            FilterWeight = 41;                    // Complementary filter weighting value
38
39
int32_t            BodyRate_i32_m1024__deg_d_s[3]      = {0, 0, 0};  // Body fixed rates, p (index 0), q, r
40
int32_t            EulerRate_i32_m1024__deg_d_s[3]      = {0, 0, 0};  // Euler rates, phi_dot, theta_dot, psi_dot
41
int32_t            EulerAngle_Accel_i32_m1024__deg[3]    = {0, 0, 0};  // Euler angles (from accelerometer) phi, theta, (psi)
42
int32_t            EulerAngle_Filtered_i32_m1024__deg[3]  = {0, 0, 0};  // Euler angles (filtered) phi, theta, (psi)
43
44
int16_t            Debug_BodyRate_i16_m8__deg_d_s[3];
45
int16_t            Debug_EulerRate_i16_m8__deg_d_s[3];
46
int16_t            Debug_EulerAngle_Accel_i16_m8__deg[3];
47
int16_t            Debug_EulerAngle_Filter_i16_m8__deg[3];
48
49
50
/*****************************************************************************************************************************************/
51
void FlightControl ()
52
{
53
  // Locals
54
  uint8_t      i;
55
  static uint8_t  count = 0;
56
  unsigned short     freemem;
57
58
  Debug_Str ("FC-start: ");
59
  freemem = get_mem_unused ();
60
  Debug_i16 (freemem);
61
  Debug_Str ("\n");
62
63
  // Check for new LIS values
64
  if (UpdateLISSensorValues ())
65
  {
66
    Debug_Str ("LIS: ");
67
    freemem = get_mem_unused ();
68
    Debug_i16 (freemem);
69
    Debug_Str ("\n");
70
71
    if ( (AccelVectorLength > (629146)) && (AccelVectorLength < 1468006))
72
    {
73
      FilterWeight = 41;
74
    }
75
    else
76
    {
77
      FilterWeight = 0;
78
    }
79
80
    Debug_Str ("LIS-end: ");
81
    freemem = get_mem_unused ();
82
    Debug_i16 (freemem);
83
    Debug_Str ("\n");
84
  }
85
86
  // Check for new ITG values
87
  if (UpdateITGSensorValues ())
88
  {
89
    Debug_Str ("ITG: ");
90
    freemem = get_mem_unused ();
91
    Debug_i16 (freemem);
92
    Debug_Str ("\n");
93
94
    if (count++ > 10)
95
    {
96
      LED_BLUE_TOGGLE;
97
      count = 0;
98
    }
99
100
    Debug_Str ("p: ");
101
    freemem = get_mem_unused ();
102
    Debug_i16 (freemem);
103
    Debug_Str ("\n");
104
105
    // Convert and scale body fixed rates p, q, r
106
    // GyroRaw_i16_m14d375__deg_d_s range: +-2000 * 14.375
107
    p      =  (int32_t)(((int32_t) GyroRaw_i16_m14d375__deg_d_s[2] * 8192L) / 115L);            // p [deg/s]
108
109
    Debug_Str ("q: ");
110
    freemem = get_mem_unused ();
111
    Debug_i16 (freemem);
112
    Debug_Str ("\n");
113
114
    q      =  (int32_t)(((int32_t)-GyroRaw_i16_m14d375__deg_d_s[0] * 8192L) / 115L);            // q [deg/s]
115
116
    Debug_Str ("r: ");
117
    freemem = get_mem_unused ();
118
    Debug_i16 (freemem);
119
    Debug_Str ("\n");
120
121
    r      =  (int32_t)(((int32_t)-GyroRaw_i16_m14d375__deg_d_s[1] * 8192L) / 115L);            // r [deg/s]
122
123
    Debug_Str ("phi_dot: ");
124
    freemem = get_mem_unused ();
125
    Debug_i16 (freemem);
126
    Debug_Str ("\n");
127
128
    // Calculate Euler rates from body rates (body fixed -> earth fixed)
129
    // Euler_vector_dot = Jacobi_Matrix * BodyRate_vector
130
    // Calculate Phi dot
131
    phi_dot      =    p +
132
        ((q * ((sini(phi) * tani(theta)) / 1024L)) / 1024L) +
133
        ((r * ((cosi(phi) * tani(theta)) / 1024L)) / 1024L);
134
135
    Debug_Str ("theta_dot: ");
136
    freemem = get_mem_unused ();
137
    Debug_i16 (freemem);
138
    Debug_Str ("\n");
139
140
    // Calculate Theta dot
141
    theta_dot    =  ((q * cosi(phi)) / 1024L) -
142
        ((r * sini(phi)) / 1024L);
143
144
    Debug_Str ("psi_dot: ");
145
    freemem = get_mem_unused ();
146
    Debug_i16 (freemem);
147
    Debug_Str ("\n");
148
149
    // Calculate Psi dot
150
    psi_dot      =  ((q * sini(phi)) / cosi(theta) ) +
151
        ((r * cosi(phi)) / cosi(theta) );
152
153
    Debug_Str ("phi_acc: ");
154
    freemem = get_mem_unused ();
155
    Debug_i16 (freemem);
156
    Debug_Str ("\n");
157
158
    // Calculate Euler angles from acceleration values
159
    phi_acc      =  atan2_i32_m1024 (-AccelRaw_i16_m1024__1g[1], AccelRaw_i16_m1024__1g[0]);
160
161
    Debug_Str ("theta_acc: ");
162
    freemem = get_mem_unused ();
163
    Debug_i16 (freemem);
164
    Debug_Str ("\n");
165
166
    theta_acc    =  atan2_i32_m1024 ( AccelRaw_i16_m1024__1g[2], AccelRaw_i16_m1024__1g[0]);
167
168
    Debug_Str ("psi: ");
169
    freemem = get_mem_unused ();
170
    Debug_i16 (freemem);
171
    Debug_Str ("\n");
172
173
    EulerAngle_Accel_i32_m1024__deg[2]    =   0;                                          // Value from magnetometer
174
175
    Debug_Str ("roll_int: ");
176
    freemem = get_mem_unused ();
177
    Debug_i16 (freemem);
178
    Debug_Str ("\n");
179
180
    int32_t RollIntegration_i32_m1024__deg  =  phi_dot    / CONTROL_FREQUENCY_HZ;
181
182
    Debug_Str ("nick_int: ");
183
    freemem = get_mem_unused ();
184
    Debug_i16 (freemem);
185
    Debug_Str ("\n");
186
187
    int32_t PitchIntegration_i32_m1024__deg  =  theta_dot  / CONTROL_FREQUENCY_HZ;
188
189
    freemem = get_mem_unused ();
190
    Debug_i16 (freemem);
191
192
    int32_t  YawIntegration_i32_m1024__deg  =  psi_dot    / CONTROL_FREQUENCY_HZ;
193
194
    Debug_Str ("phi_filt: ");
195
    freemem = get_mem_unused ();
196
    Debug_i16 (freemem);
197
    Debug_Str ("\n");
198
199
    // Complementary filter
200
    phi    =  ((4096L - FilterWeight)  * (phi + RollIntegration_i32_m1024__deg) +
201
        (FilterWeight)     * (phi_acc)) / 4096L;
202
203
    Debug_Str ("theta_filt: ");
204
    freemem = get_mem_unused ();
205
    Debug_i16 (freemem);
206
    Debug_Str ("\n");
207
208
    theta  =  ((4096L - FilterWeight)  * (theta + PitchIntegration_i32_m1024__deg) +
209
        (FilterWeight)     * (theta_acc)) / 4096L;
210
211
    Debug_Str ("psi_filt: ");
212
    freemem = get_mem_unused ();
213
    Debug_i16 (freemem);
214
    Debug_Str ("\n");
215
216
    psi    =  ((4096L - 2048L)    * (psi + YawIntegration_i32_m1024__deg) +
217
        (2048)         * (psi)) / 4096L;
218
219
    Debug_Str ("Debug: ");
220
    freemem = get_mem_unused ();
221
    Debug_i16 (freemem);
222
    Debug_Str ("\n");
223
224
    // Debug & Logging values
225
    for (i = 0; i < 3; i++)
226
    {
227
      Debug_BodyRate_i16_m8__deg_d_s[i]    = (int16_t) (BodyRate_i32_m1024__deg_d_s[i]      / 128L);
228
      Debug_EulerRate_i16_m8__deg_d_s[i]    = (int16_t)  (EulerRate_i32_m1024__deg_d_s[i]    / 128L);
229
      Debug_EulerAngle_Accel_i16_m8__deg[i]  = (int16_t) (EulerAngle_Accel_i32_m1024__deg[i]    / 128L);
230
      Debug_EulerAngle_Filter_i16_m8__deg[i]  = (int16_t) (EulerAngle_Filtered_i32_m1024__deg[i]  / 128L);
231
    }
232
233
    Debug_Str ("SDebug: ");
234
    freemem = get_mem_unused ();
235
    Debug_i16 (freemem);
236
    Debug_Str ("\n");
237
238
    //SensorDebug ();
239
  }
240
241
  Debug_Str ("FC-end\n");
242
}
243
244
/*****************************************************************************************************************************************/
245
void SensorDebug ()
246
{
247
  static uint8_t  count = 0;
248
249
  uint8_t  i, ascii = 1;
250
251
  if (count++ == 9)
252
  {
253
    count = 0;
254
    LED_BLUE_TOGGLE;
255
    PORTD.OUTTGL = (1 << PIN0);
256
  }
257
258
  if (ascii == 0)
259
  {
260
    Debug_ch (0xA6);
261
    Debug_ch (0x8C);
262
263
    for (i = 0; i < 6; i++)
264
      Debug_ch (((char *)Debug_BodyRate_i16_m8__deg_d_s)[i]);
265
266
    for (i = 0; i < 6; i++)
267
      Debug_ch (((char *)Debug_EulerRate_i16_m8__deg_d_s)[i]);
268
269
    for (i = 0; i < 6; i++)
270
      Debug_ch (((char *)AccelRaw_i16_m1024__1g)[i]);
271
272
    for (i = 0; i < 6; i++)
273
      Debug_ch (((char *)Debug_EulerAngle_Accel_i16_m8__deg)[i]);
274
275
    for (i = 0; i < 6; i++)
276
      Debug_ch (((char *)Debug_EulerAngle_Filter_i16_m8__deg)[i]);
277
  }
278
  else if (ascii == 1)
279
  {
280
    Debug_Str ("p,q,r: ");
281
    for (i = 0; i < 3; i++)
282
      Debug_i16 (Debug_BodyRate_i16_m8__deg_d_s[i] / 8);
283
284
    Debug_Str ("   ax,ay,az: ");
285
    for (i = 0; i < 3; i++)
286
      Debug_i16 (AccelRaw_i16_m1024__1g[i]);
287
288
    Debug_Str ("   AccelAngles: ");
289
    for (i = 0; i < 3; i++)
290
      Debug_i16 (Debug_EulerAngle_Accel_i16_m8__deg[i] / 8);
291
292
    Debug_Str ("   FilterAngles: ");
293
    for (i = 0; i < 3; i++)
294
      Debug_i16 ((int16_t)(Debug_EulerAngle_Filter_i16_m8__deg[i] / 8));
295
296
    Debug_Str ("\n");
297
  }
298
299
}
300
301
/*****************************************************************************************************************************************/
302
uint8_t UpdateLISSensorValues ()
303
{
304
  if (Get_LIS_LastActionStatus() == LIS_ACTION_GETXYZ)
305
  {
306
    Get_LISRawValues (AccelRaw_i16_m1024__1g);
307
308
    // Calculate resulting acceleration vector length²
309
    AccelVectorLength = ((int32_t)AccelRaw_i16_m1024__1g[0] * (int32_t)AccelRaw_i16_m1024__1g[0]) +
310
        ((int32_t)AccelRaw_i16_m1024__1g[1] * (int32_t)AccelRaw_i16_m1024__1g[1]) +
311
        ((int32_t)AccelRaw_i16_m1024__1g[2] * (int32_t)AccelRaw_i16_m1024__1g[2]);
312
313
    return 1;
314
  }
315
316
317
  return 0;
318
}
319
320
/*****************************************************************************************************************************************/
321
uint8_t UpdateITGSensorValues ()
322
{
323
  if (GetLastITGActionStatus() == ITG_ACTION_GETTEMPXYZ)
324
  {
325
    Get_ITGRawValues (GyroRaw_i16_m14d375__deg_d_s);
326
    return 1;
327
  }
328
329
  return 0;
330
}

Soweit so gut. Der Log der Debug Ausgaben ist dieser:
FC-start: + 7959<\n>
LIS: + 7959<\n>
LIS-end: + 7959<\n>
ITG: + 7959<\n>
p: + 7959<\n>
q: + 7959<\n>

Also der Speicher, wenn ich das Recht interpretiere, kann es nicht sein, 
dennoch gehts in folgender Zeile nicht "weiter" (µC bleibt stehen, keine 
ISRs mehr, keine Pinwackler am LA und main wird auch nicht mehr 
durchlaufen):
1
q      =  (int32_t)(((int32_t)-GyroRaw_i16_m14d375__deg_d_s[0] * 8192L) / 115L);            // q [deg/s]

Das Listing dazu schaut folgendermassen aus:
1
q      =  (int32_t)(((int32_t)-GyroRaw_i16_m14d375__deg_d_s[0] * 8192L) / 115L);            // q [deg/s]
2
    1b46:  60 91 44 20   lds  r22, 0x2044
3
    1b4a:  70 91 45 20   lds  r23, 0x2045
4
    1b4e:  70 95         com  r23
5
    1b50:  61 95         neg  r22
6
    1b52:  7f 4f         sbci  r23, 0xFF  ; 255
7
    1b54:  88 27         eor  r24, r24
8
    1b56:  77 fd         sbrc  r23, 7
9
    1b58:  80 95         com  r24
10
    1b5a:  98 2f         mov  r25, r24
11
    1b5c:  5d e0         ldi  r21, 0x0D  ; 13
12
    1b5e:  66 0f         add  r22, r22
13
    1b60:  77 1f         adc  r23, r23
14
    1b62:  88 1f         adc  r24, r24
15
    1b64:  99 1f         adc  r25, r25
16
    1b66:  5a 95         dec  r21
17
    1b68:  d1 f7         brne  .-12       ; 0x1b5e <FlightControl+0x18c>
18
    1b6a:  23 e7         ldi  r18, 0x73  ; 115
19
    1b6c:  30 e0         ldi  r19, 0x00  ; 0
20
    1b6e:  40 e0         ldi  r20, 0x00  ; 0
21
    1b70:  50 e0         ldi  r21, 0x00  ; 0
22
    1b72:  0e 94 63 1a   call  0x34c6  ; 0x34c6 <__divmodsi4>
23
    1b76:  20 93 0c 20   sts  0x200C, r18
24
    1b7a:  30 93 0d 20   sts  0x200D, r19
25
    1b7e:  40 93 0e 20   sts  0x200E, r20
26
    1b82:  50 93 0f 20   sts  0x200F, r21

Leider verstehe ich asm so gut wie überhaupt nicht, aber ich versuch 
mich mal einzuarbeiten! Vllt. fällt jemandem von Euch was auf !?

Grüße,
Michael

von Purzel H. (hacky)


Lesenswert?

Ein Controller bleibt nicht stehen...
Zu den Memorytests : Man sollte dynamisches Memory sowieso vermeiden.
Das einzige, was mir auffaellt ist das call _divmodsi4 ... ist das 
ueberhaupt vorhanden ? Die Adressen 0x2000 + x sind oberhalb 8k. Hat's 
soviel RAM ?

von Michael K. (mmike)


Lesenswert?

O.. oha Jetzt ! schrieb:
> Ein Controller bleibt nicht stehen...

Das dachte ich auch ;-) Er macht nur nach der Zeile nicht im 
geschriebenen Code weiter, sondern anscheinend irgendwo anders ....

> Zu den Memorytests : Man sollte dynamisches Memory sowieso vermeiden.

Wie genau meinst Du das?? Malloc verwende ich jedenfalls nicht und die 
verwendeten array sind alle statisch.

> Das einzige, was mir auffaellt ist das call _divmodsi4 ... ist das
> ueberhaupt vorhanden ? Die Adressen 0x2000 + x sind oberhalb 8k. Hat's
> soviel RAM ?

nope. Der XMega128A1 hat 8k ....

Bzgl. _divmodsi4 sagt das Listing
1
000034c6 <__divmodsi4>:
2
    34c6:  97 fb         bst  r25, 7
3
    34c8:  09 2e         mov  r0, r25
4
    34ca:  05 26         eor  r0, r21
5
    34cc:  0e d0         rcall  .+28       ; 0x34ea <__divmodsi4_neg1>
6
    34ce:  57 fd         sbrc  r21, 7
7
    34d0:  04 d0         rcall  .+8        ; 0x34da <__divmodsi4_neg2>
8
    34d2:  28 d0         rcall  .+80       ; 0x3524 <__udivmodsi4>
9
    34d4:  0a d0         rcall  .+20       ; 0x34ea <__divmodsi4_neg1>
10
    34d6:  00 1c         adc  r0, r0
11
    34d8:  38 f4         brcc  .+14       ; 0x34e8 <__divmodsi4_exit>

Ich denke Du meinst die Zeile: mit call  0x34c6

Ich kann zwar kein asm, aber ich denke _divmodsi4 ist ne "Funktion", die 
der Kompiler baut und auch im Flash ablegt, oder liege ich da falsch??

Grüße,
Michael

von Huch (Gast)


Lesenswert?

Hi Michael K.

tut mir leid, dass ich mich nicht früher gemeldet habe.
Gestern Abend ist bei mir ne Virusinfektion ausgebrochen und ich habe 
38,5 Fieber. Meine "Birne" ist dementsprechend "matschig".
Wenn ich wieder fitter bin, dann schau ich wieder rein.

Eines ist mir allerdings trotzdem aufgefallen, (wenn das keine 
Fieberphantasie ist):

In dem Codeschnipsel wo der Debugger nichts weiter anzeigt:
1
q      =  (int32_t)(((int32_t)-GyroRaw_i16_m14d375__deg_d_s[0] * 8192L) / 115L);            // q [deg/s]
2
                     ^^^^^^^^^

ist der erste Summand eine Typenbezeichnung und keine Variable.
Eigentlich bin ich ziemlich sicher, dass das eine Warnung, wenn nicht 
sogar einen Fehler zur Folge haben sollte. Wundere mich gerade wieso da 
keine kommt. (Kann aber auch an meiner Matschbirne liegen). Prüf das mal 
nach, bitte.

Hast Du wirklich alle Warnings eingeschaltet? Das sollte mit -Wall gehen 
(ohne Gewähr, guck nochmal nach).

Mehr in ein paar Tagen wenn ich wieder auf dem Damm bin (und Du das 
Problem noch nicht anderweitig lösen konntest).

Viel Erfolg

von Benni L. (sutter_cain)


Lesenswert?

Wenn er "irgendwo" weitermacht, dann riecht das verdammt nach nem Stack 
Overflow.

Und den kannst auslösen, indem du zu viele Funktionen aufrufst durch 
ISRs.

Evtl. kannst du noch den Call Stack anschaun. Und schaun wie viel da so 
drinsteht, bevor der Controller im Nirvana weitermacht. Bzw. schauen ob 
der Call Stack immer weiter wächst. Problem beim Debuggen ist halt, dass 
Wartzeiten auf Hardwareeinheiten wie UART durch nen Breakpoint 
verschwinden.

An deiner Stelle würde ich die Debugausgaben per UART mit ner 
Präprozessoranweisung versehen, so dass die nicht unbedingt im Programm 
sein müssen. So sind die alle schnell mal weg.

Desweiteren, versuch doch mal die Sachen in den ISRs zu verkleinern und 
evtl. falls du Timerinterrupts benutzt, die Intervalle zu vergrößern.

Falls nach ner Schlankheitskur dein Programm läuft war wohl tatsächlich 
ein Stack Overflow vorhanden.

von Huch (Gast)


Lesenswert?

Im Listing File taucht das mit dem Typnamen an mehreren Stellen auf.

von Purzel H. (hacky)


Lesenswert?

Ich haette die Zeilen gemeint :

  1b46:  60 91 44 20   lds  r22, 0x2044
  1b4a:  70 91 45 20   lds  r23, 0x2045
..
..
  1b76:  20 93 0c 20   sts  0x200C, r18
  1b7a:  30 93 0d 20   sts  0x200D, r19
  1b7e:  40 93 0e 20   sts  0x200E, r20
  1b82:  50 93 0f 20   sts  0x200F, r21

Das (: 0x20..) sind zugriffe oberhalb 8k. Sollte aber auch einen Fehler 
bringen.

von Michael K. (mmike)


Lesenswert?

Hallo,

na jetzt geht ja was vorwärts!

Huch schrieb:
> Hi Michael K.
>
> tut mir leid, dass ich mich nicht früher gemeldet habe.
> Gestern Abend ist bei mir ne Virusinfektion ausgebrochen und ich habe
> 38,5 Fieber. Meine "Birne" ist dementsprechend "matschig".
> Wenn ich wieder fitter bin, dann schau ich wieder rein.

Kein Problem und GUTE BESSERUNG!!

> Eines ist mir allerdings trotzdem aufgefallen, (wenn das keine
> Fieberphantasie ist):
>
> In dem Codeschnipsel wo der Debugger nichts weiter anzeigt:
>
>
1
> q      =  (int32_t)(((int32_t)-GyroRaw_i16_m14d375__deg_d_s[0] * 8192L)
2
> / 115L);            // q [deg/s]
3
>                      ^^^^^^^^^
4
>
>
> ist der erste Summand eine Typenbezeichnung und keine Variable.
> Eigentlich bin ich ziemlich sicher, dass das eine Warnung, wenn nicht
> sogar einen Fehler zur Folge haben sollte. Wundere mich gerade wieso da
> keine kommt. (Kann aber auch an meiner Matschbirne liegen). Prüf das mal
> nach, bitte.

Das soll eigentlich ein Typcast sein. Die Variable (respektive das 
Array) GyroRaw_i16_m14d375__deg_d_s ist vom Typ int16_t. Diesen Wert 
will ich nach int32 casten. Compiler schmeisst kein Warning!

>
> Hast Du wirklich alle Warnings eingeschaltet? Das sollte mit -Wall gehen
> (ohne Gewähr, guck nochmal nach).

Wall ist drin!

>
> Mehr in ein paar Tagen wenn ich wieder auf dem Damm bin (und Du das
> Problem noch nicht anderweitig lösen konntest).
>
> Viel Erfolg

Danke!

@Benni:
> Wenn er "irgendwo" weitermacht, dann riecht das verdammt nach nem Stack > 
Overflow.

Ich denke den kann ich ausschließen durch die Memory Prüfung.

> An deiner Stelle würde ich die Debugausgaben per UART mit ner
> Präprozessoranweisung versehen, so dass die nicht unbedingt im Programm
> sein müssen. So sind die alle schnell mal weg.

Kein Problem. Mach ich mal!

> Desweiteren, versuch doch mal die Sachen in den ISRs zu verkleinern und
> evtl. falls du Timerinterrupts benutzt, die Intervalle zu vergrößern.

Timerinterrupts sind so gut wie keine drin, bis auf das auslesen des 
Beschleunigungsensors. Das Auslesen der Sensorwerte produziert keine 
Fehler, wenn die Berechnung in der fc.c nicht durchgeführt wird. Ich 
prüfs und teste es trotzdem mal!

@hacky:

Das Datenblatt für den ATXMega128A1 sagt: SRAM Bereich von 0x2000 - 
0x3FFF


Grüße,
Michael

von Huch (Gast)


Lesenswert?

>Das soll eigentlich ein Typcast sein.

Aber Du siehst das Problem oder? Mit dem Minuszeichen danach ist das 
eine Subtraktion. Du subtrahierst sozusagen von dem Objekt int32_t das 
Gyro....
Das GyroRaw wird nicht gecastet.
1
q = 
2
   (int32_t)
3
   (
4
      (
5
         (int32_t)
6
         -
7
         GyroRaw_i16_m14d375__deg_d_s[0]
8
         *
9
         8192L
10
      )
11
      /
12
      115L
13
   );

von Michael K. (mmike)


Lesenswert?

Hallo,

hab grad nochmal folgende Änderung vorgenommen:
1
q = (int32_t)(((int32_t)-GyroRaw_i16_m14d375__deg_d_s[0] * 8192L) / 115L);

wurde geändert in:
1
q = (int32_t)(( -((int32_t)GyroRaw_i16_m14d375__deg_d_s[0]) * 8192L) / 115L);

um auszuschließen, dass hier ein Problem mit dem Cast und dem Vorzeichen 
vor der Variable auftritt ....

Effekt: Keiner.

Grüße,
Michael

von Huch (Gast)


Lesenswert?

Ach Sch.... Da wird nur das Vorzeichen geändert. Doch Matschbirne. 
Vergiss es.

von Michael K. (mmike)


Lesenswert?

> Aber Du siehst das Problem oder? Mit dem Minuszeichen danach ist das
> eine Subtraktion. Du subtrahierst sozusagen von dem Objekt int32_t das
> Gyro....

Hab ich ;-) sie Vorgängerpost ...

Grüße,
Michael

von Huch (Gast)


Lesenswert?

Dann lass ichs für heute lieber, sonst wird das noch ne Kaffeemaschine 
anstelle eines Copters. ;-)

von Michael K. (mmike)


Lesenswert?

:D ... gute Besserung!

von Huch (Gast)


Lesenswert?

>Wirklich seltsam. Wenn der Debugger dran hängt und der µC per Run laufen
>gelassen wird, dann läufts wie soll. Debugausgaben kommen und die LED
>blinkt ...

>Sobald ich das Programm ohne Debugger auf dem µC laufen lassen, bleibt
>er wieder "hängen".

Das ist wirklich bemerkenswert, wenn es (mir) zumindest keine weiteren 
Informationen liefert.

Aber der Weg ist auch nicht wirklich, den Debugger einfach laufen zu 
lassen. Vielmehr setzt Du an entscheidenden Stellen im Code einen 
Breakpoint und prüfst sowohl ob er erreicht wird und ob die Daten an der 
Stelle im Code konsistent sind, den Werten entsprechen die Du erwartest.

>> Denke daran, das das ausbleiben der Debug-Ausgabe kein "Anhalten"
>> bedeutet sondern nur, dass der durchlaufene Code keine Ausgaben erzeugt.
>> Genauso der Zustand in dem keine Änderungen an der LED oder den Ports
>> mehr erfolgen.

>Klar. Irgendwo ist das Ding in einer quasi "Endlosschleife" aus der er
>nicht mehr rauskommt ...
Möglich, aber das ist auch nicht mehr als eine Vermutung und damit ohne 
grösseren Wert. Du musst feststellen was er macht und nicht Vermutungen 
darüber anstellen.

>> Was mir auffällt, ist das Du im Text von Debug-Ausgaben innerhalb des
>> Interrupts sprichst. An sich ist das absolut tödlich, wenn etwa Ausgaben
>> selbst auch über Ints laufen. Wenn Du das nicht komplett aus den ISRs
>> entfernen willst dann kommentiere es mal aus. Eine durchaus reale
>> Möglichkeit, das hier was knackt.

>Verstehe. Die Debugausgaben werden nicht über Interrupts ausgegeben,
>sondern relativ straight forward:

Ich habe der Aussage nicht ganz getraut und habe selbst im Code 
nachgesehen. Und voilà: Du machst tatsächlich Ausgaben im Interrupt! 
Z.B. in der Datei: lis3lv02dq.c, gleich vorne in der ISR (LIS_TWI_INT) 
erfolgt tatsächlich eine Ausgabe "im" Interrupt. Ich muss bekennen, das 
ich selbst einmal von Ausgaben "im" Interrupt spreche und einmal von 
Ausgaben "über" Interrupts. Das ist nicht dasselbe. Ausgaben "über" 
(also im Sinne von "mittels") Interrupts sind hier nicht relevant. 
Sondern die Ausgaben "in" Interrupts. Diese können wegen der 
Warteschleife in USART_putc zu starken Verzögerungen führen. (Die 
bessere Technik ist eigentlich auch die Ausgabe in Buffer die per 
Interupt ausgegeben werden). Diese Verzögerungen können wiederrum 
Probleme verursachen wenn mehrere Int-Quellen aktiv sind.
Also, nehme die Ausgaben in den Ints raus. Dnke daran auch die 
Debug-Ausgaben aus den Funktionen herauszunehmen die von der ISR 
aufgerufen werden. Aufgrund von Anwenundunginterrupts darf keine 
Debugausgabe erfolgen! Allenfalls mal ein wackeln an nem Portpin für ne 
LED.

>> Du könntest auch mal im Code gucken ob irgendwo absichtlich oder
>> unabsichtlich Rekursionen auftreten und ob die Abbruchbedingungen
>> wirklich mit true bewertet werden.

>Mach ich morgen!
Was hat sich dabei herausgestellt?

>> Eine gute Möglichkeit ist auch, einen Lint über Deinen Code laufen zu
>> lassen. Es gibt da einige für Linux.

>Lint kenne ich noch nicht. Ich mach mich mal schlau ...
Und? Wie stehts damit?

>Also der Speicher, wenn ich das Recht interpretiere, kann es nicht sein,
>dennoch gehts in folgender Zeile nicht "weiter" (µC bleibt stehen, keine
>ISRs mehr, keine Pinwackler am LA und main wird auch nicht mehr
>durchlaufen):
Genau genommen ist das nicht so zu interpretieren. Schau Dir die 
Testroutine mal an. Sie beschreibt den Speicher mit einem festen Muster 
und prüft später bis wohin das Muster noch vorhanden ist. Es sehr wohl 
möglich das das Muster auch in den "normalen" Daten vorhanden ist, die 
beim Programmlauf auftreten. Insofern ist nur die Aussage wirklich 
relevant, das der Speicher nicht ausreicht. Die Aussage, das der 
Speicher reicht ist nur bedingt richtig. Es ist nützlich, die Routine 
mal mit noch einem oder zwei anderen Mustern mitlaufen zu lassen und die 
Ergebnisse zu vergleichen. Ausserdem sind auf diese Weise die Interrupts 
nicht abgedeckt. Du müsstet noch sicherstellen, das vor Aufruf von 
get_mem_unused alle Interrupts wenigstens einmal in allen Zweigen 
durchlaufen worden sind. Besser ist es, das im Simulator einmal 
durchzuspielen.

Aber was mir auffällt, ist das Du Dich von dem Gedanken, dass eine CPU 
stehenbleibt noch nicht verabschiedet hast. Streich das aus Deinem 
Denken. Sowas gibt es nicht. Er macht immer irgendwas. Und genau das ist 
wichtig! Was genau macht er anstelle des Codes der dasteht?
Setze einen Breakpoint auf die Codezeile. Bei erreichen stellst Du auf 
Anzeige des Assembler-Codes um und gehst im Einzelschritt weiter. Guck 
Dir den Stack an, ob die Return-Addressen gültig sind, insbesondere vor 
rets.
Berichte hier am besten im Detail darüber was Du festgestellt hast, 
auch wenn Dir nichts besonderes auffällt.


Ich möchte Dir an dieser Stelle empfehlen zunächst den Code durch einen 
Lint laufen zu lassen. Das Problem ist, das die anderen Methoden relativ 
viel Aufwand erfordern und Kenntnisse von Assembler und des uC. Der Lint 
hingegen findet relativ mühelos Probleme im Code auf. Erst wenn das 
nichts bringt würde ich mit dem Debuggen weitermachen.

Die Entfernung der Debug-Ausgaben aus den Interrupts ist wichtig. Mach 
das auf jeden Fall.

Dann erst wieder Debuggen bzw. Simulieren.

Hoffe das bringt Dich weiter.

Viel Erfolg.

von Michael K. (mmike)


Lesenswert?

Hallo

> Aber der Weg ist auch nicht wirklich, den Debugger einfach laufen zu
> lassen. Vielmehr setzt Du an entscheidenden Stellen im Code einen
> Breakpoint und prüfst sowohl ob er erreicht wird und ob die Daten an der
> Stelle im Code konsistent sind, den Werten entsprechen die Du erwartest.

Das hab ich gemacht. Debuggen geht zur Zeit leider nur unter Windows, 
und da läuft der Code ja ....

>
>>> Denke daran, das das ausbleiben der Debug-Ausgabe kein "Anhalten"
>>> bedeutet sondern nur, dass der durchlaufene Code keine Ausgaben erzeugt.
>>> Genauso der Zustand in dem keine Änderungen an der LED oder den Ports
>>> mehr erfolgen.
>
>>Klar. Irgendwo ist das Ding in einer quasi "Endlosschleife" aus der er
>>nicht mehr rauskommt ...
> Möglich, aber das ist auch nicht mehr als eine Vermutung und damit ohne
> grösseren Wert. Du musst feststellen was er macht und nicht Vermutungen
> darüber anstellen.

Stimmt. Bin dabei!

>
>>> Was mir auffällt, ist das Du im Text von Debug-Ausgaben innerhalb des
>>> Interrupts sprichst. An sich ist das absolut tödlich, wenn etwa Ausgaben
>>> selbst auch über Ints laufen. Wenn Du das nicht komplett aus den ISRs
>>> entfernen willst dann kommentiere es mal aus. Eine durchaus reale
>>> Möglichkeit, das hier was knackt.
>
>>Verstehe. Die Debugausgaben werden nicht über Interrupts ausgegeben,
>>sondern relativ straight forward:
>
> Ich habe der Aussage nicht ganz getraut und habe selbst im Code
> nachgesehen. Und voilà: Du machst tatsächlich Ausgaben im Interrupt!
> Z.B. in der Datei: lis3lv02dq.c, gleich vorne in der ISR (LIS_TWI_INT)
> erfolgt tatsächlich eine Ausgabe "im" Interrupt. Ich muss bekennen, das
> ich selbst einmal von Ausgaben "im" Interrupt spreche und einmal von
> Ausgaben "über" Interrupts. Das ist nicht dasselbe. Ausgaben "über"
> (also im Sinne von "mittels") Interrupts sind hier nicht relevant.
> Sondern die Ausgaben "in" Interrupts. Diese können wegen der
> Warteschleife in USART_putc zu starken Verzögerungen führen. (Die
> bessere Technik ist eigentlich auch die Ausgabe in Buffer die per
> Interupt ausgegeben werden). Diese Verzögerungen können wiederrum
> Probleme verursachen wenn mehrere Int-Quellen aktiv sind.
> Also, nehme die Ausgaben in den Ints raus. Dnke daran auch die
> Debug-Ausgaben aus den Funktionen herauszunehmen die von der ISR
> aufgerufen werden. Aufgrund von Anwenundunginterrupts darf keine
> Debugausgabe erfolgen! Allenfalls mal ein wackeln an nem Portpin für ne
> LED.

Der Unterschied ist mir klar. Momentan erfolgen keine Ausgaben im 
Interrupt. Die können über die tricopter_config.h ausgeschaltet werden:

#define    TWI_DEBUGGING          0
#define    LIS_DEBUGGING          0
#define    LIS_ERROR_DEBUGGING        0
#define    ITG_DEBUGGING          0
#define    ITG_ERROR_DEBUGGING        0

und in der lis3lv02dq.h:
1
#if (LIS_DEBUGGING == 1)
2
#define  LIS_Debug_Str(_str)  ( Debug_Str(_str) )
3
#define  LIS_Debug_u8(_u8)  ( Debug_u8(_u8) )
4
#else
5
#define LIS_Debug_Str(_str)
6
#define  LIS_Debug_u8(_u8)
7
#endif

>>> Du könntest auch mal im Code gucken ob irgendwo absichtlich oder
>>> unabsichtlich Rekursionen auftreten und ob die Abbruchbedingungen
>>> wirklich mit true bewertet werden.
>
>>Mach ich morgen!
> Was hat sich dabei herausgestellt?

Alle so wie es sein sollte ...

>
>>> Eine gute Möglichkeit ist auch, einen Lint über Deinen Code laufen zu
>>> lassen. Es gibt da einige für Linux.
>
>>Lint kenne ich noch nicht. Ich mach mich mal schlau ...
> Und? Wie stehts damit?

splint ist installiert und läuft ... bekomme leider relativ häufig:
Parse Error. Bin dabei das zu beheben.

>>Also der Speicher, wenn ich das Recht interpretiere, kann es nicht sein,
>>dennoch gehts in folgender Zeile nicht "weiter" (µC bleibt stehen, keine
>>ISRs mehr, keine Pinwackler am LA und main wird auch nicht mehr
>>durchlaufen):
> Genau genommen ist das nicht so zu interpretieren. Schau Dir die
> Testroutine mal an. Sie beschreibt den Speicher mit einem festen Muster
> und prüft später bis wohin das Muster noch vorhanden ist. Es sehr wohl
> möglich das das Muster auch in den "normalen" Daten vorhanden ist, die
> beim Programmlauf auftreten. Insofern ist nur die Aussage wirklich
> relevant, das der Speicher nicht ausreicht. Die Aussage, das der
> Speicher reicht ist nur bedingt richtig. Es ist nützlich, die Routine
> mal mit noch einem oder zwei anderen Mustern mitlaufen zu lassen und die
> Ergebnisse zu vergleichen. Ausserdem sind auf diese Weise die Interrupts
> nicht abgedeckt. Du müsstet noch sicherstellen, das vor Aufruf von
> get_mem_unused alle Interrupts wenigstens einmal in allen Zweigen
> durchlaufen worden sind. Besser ist es, das im Simulator einmal
> durchzuspielen.

OK. Ich werde das unter Windows mal durchführen.

> Aber was mir auffällt, ist das Du Dich von dem Gedanken, dass eine CPU
> stehenbleibt noch nicht verabschiedet hast. Streich das aus Deinem
> Denken. Sowas gibt es nicht. Er macht immer irgendwas. Und genau das ist
> wichtig! Was genau macht er anstelle des Codes der dasteht?

Ist gestrichen. Das "anhalten" ist mehr eine Umschreibung meinerseits 
für das Beobachtete, als eine konkrete Beschreibung! Das Problem ist, 
dass er nichts mehr macht, was im Code darsteht (also weder Pins wackeln 
noch LED blinken, noch Debug produzieren)

> Setze einen Breakpoint auf die Codezeile. Bei erreichen stellst Du auf
> Anzeige des Assembler-Codes um und gehst im Einzelschritt weiter. Guck
> Dir den Stack an, ob die Return-Addressen gültig sind, insbesondere vor
> rets.

OK.

> Berichte hier am besten im Detail darüber was Du festgestellt hast,
> auch wenn Dir nichts besonderes auffällt.

Mach ich.

> Ich möchte Dir an dieser Stelle empfehlen zunächst den Code durch einen
> Lint laufen zu lassen. Das Problem ist, das die anderen Methoden relativ
> viel Aufwand erfordern und Kenntnisse von Assembler und des uC. Der Lint
> hingegen findet relativ mühelos Probleme im Code auf. Erst wenn das
> nichts bringt würde ich mit dem Debuggen weitermachen.

s.o.

> Die Entfernung der Debug-Ausgaben aus den Interrupts ist wichtig. Mach
> das auf jeden Fall.

Ist schon passiert!

> Dann erst wieder Debuggen bzw. Simulieren.
>
> Hoffe das bringt Dich weiter.
>
> Viel Erfolg.

Vielen Dank nochmals an alle ... ich kämpfe weiter und gebe Feedback!

Grüße,
Michael

von Michael K. (mmike)


Lesenswert?

Soooo,

viel ist passiert und gleich vorweg ... ich scheine einen Bug 
unabsichtlich behoben zu haben, denn jetzt läufts. Warum -- weiss ich 
noch nicht genau ;-)

Der von mir eingesetzte Sensor ITG-3200 gibt an einem Pin für 50µs ein 
high Signal aus wenn neue Daten abgefragt werden können. Das hab ich mir 
einer PinChange ISR (rising edge) mitgekriegt und die Datenabfrage 
gestartet. Soweit so gut, aber mein anfängliches Problem war, dass mit 
dem Sensor relativ häuft der Busstate "ARB Lost" eingetreten ist, trotz 
sauberer I2C Beschaltung (Pullups, etc.). Stromversorgung war ok, die 
Pegel auch und trotzdem liefs einfach nicht so wirklich rund. Alle 1 - 2 
Sekunden hat sich der Bus verabschiedet. Mein Workaround war dann:

1. TWI abschalten und SDA als Input und SCL als Output konfigurieren.
2. SCL so lange toggeln bis SDA wieder hoch kommt
3. Wenn SDA wieder high ist, dann TWI wieder einschalten und 
konfigurieren und weiter gehts.

Das hat soweit auch recht gut funktioniert. Jetzt habe ich zu 
Testzwecken mal ne Debugausgabe vor dem Starten der Datenabfrage 
reingemacht und plötzlich waren die ARB-Lost Stati weg!? Mittlerweile 
wird die Datenabfrage gestartet, wenn das Data-Ready-Signal fällt, also 
50µs später und die ARB-Lost sind so gut wie verschwunden (1 - 2 in 10 
Minuten).

Zum Recovern wurde der TWI Bus Status im Interrupt abgefragt und wenn 
der State ARB Lost eingetreten ist, dann wurde die "Recoverfunktion" aus 
dem Interrupt heraus aufgerufen. Im Zuge der Einarbeitung Eurer 
Vorschläge (Ints schlank und schnell halten, ohne Debug Ausgaben) hab 
ich dann auch den Aufruf Funktion aus dem Interrupt genommen und statt 
dessen einfach ein Flag gesetzt, das eine Funktion prüft, die aus der 
main aufgerufen wird. Und ... jetzt rennts. Genau kann ich noch nicht 
sagen warum genau, aber ich habe die Vermutung, dass der µC dauerhaft im 
TWI Interrupt hängen geblieben ist und nicht mehr raus kam. Das hätte 
ich eigentlich mit dem LA sehen müssen - hab ich aber nicht ... ich 
teste weiter und immerhin hab ich schon mal nen Anhaltspunkt, wo die 
Ursache liegen könnte.

Ich halte Euch auf dem Laufenden!

Grüße,
Michael

von Michael K. (mmike)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

Leider ist die Zeit im Hinblick auf Neujahr leider ein wenig knapp und 
deshalb konnte ich weniger schaffen, als erwartet, aber es gibt wieder 
ein paar Neuigkeiten. Ich hab das vorgeschlagene Vorgehen von Huch mal 
durchgeführt und ausgiebigst gedebugged. Den Beschleunigungssensor hab 
ich mal "rausgenommen" und die Gyrowerte abgefragt und das Ganze im 
Debugger angeschaut. Breakpoints in den Interrupts vor und nach while 
Schleifen und mir auch den ASM Code angeschaut und die 
Rücksprungadressen kontrolliert. Dabei konnte ich keinen Fehler 
feststellen. Alles läuft wie gewollt.
Kompiliert, geflasht und gedebugged unter Windows. Soweit super. Ich 
wollte die Änderungen vom Gyro-"Treiber" auch für den 
Beschleunigungssensor (der soll mit 100Hz abgefragt werden) umsetzen, 
der nicht wie das Gyro per PinChange-Interrupt abgefragt wird, sondern 
per Timer-Interrupt.

0. Gyrosensor soll mit 400Hz ausgelesen werden.
1. Sensor gibt für 50µs ein High - Signal, wenn neue Daten verfügbar 
sind.
2. PinChange - Interrupt startet das Auslesen des Sensors per TWI
3. Gyro-Treiber arbeitet Interruptbasiert
4. LA Konfiguration:
-- 0: Pin toggle in der main
-- 1: Pin toggle in der Pin Change ISR (Gyro)
-- 2: am Anfang der TWI ISR wird Pin2 gesetzt und beim verlassen wieder 
gecleared
-- 4: Pin toggle in der Timer OVF ISR (Accelerometer)

Bild LA_WIN / LA_WIN2 ist ein Screener vom LA.
* Die weißen Blöcke auf Kanal 0 zeigen, wenn die main durchlaufen wird.
* Kanal 1 zeigt den Pin Toggle aus der PinChange ISR. Die 
"Toggle"-Frequenz entspricht den gewollten 400Hz.
* Kanal 2 zeigt die TWI ISR. Sobald neue Daten am Gyro verfügbar sind 
startet die Datenübertragung und die TWI ISR wird durchlaufen. Ein ISR 
Durchlauf dauert in der Regel 1-3µs. Und die komplette Datenabfrage vom 
Sensor ist nach ca. 0.2ms abgeschlossen.
* Kanal 4 zeigt die TimerOVF-ISR in der momentan nur ein Pin getoggelt 
wird.

Alles super.

Dann gings unter Linux weiter.  Also wieder LA dran und schon gab es die 
ersten seltsamen Ergebnisse.

Code ist der gleiche wie unter Windows.

Die Bilder LA_LINUX / LA_LINUX2 zeigen den gleichen Code, nur unter 
Linux kompiliert und geflasht. Das Gyro arbeitet wie erwartet, jedoch 
wird die Timer OVF ISR für den Beschleunigungssensor nicht so "sauber" 
ausgeführt (unregelmässiger PinToggle, vgl. Kanal4) wir mit dem unter 
Windows kompilierten Code. Der Beschleunigungssensor wird momentan noch 
nicht ausgelesen und ist somit inaktiv! Ich wollte nur kontrollieren, ob 
die Timer-ISR sauber ausgeführt wird und zu der Windows Version sind 
hier heftige Unterschiede!! Irgendwas ist mit dem Linux faul ....

Ich wünsche Euch dennoch ein gutes neues Jahr und einen guten Rutsch 
heute abend!! Ich melde mich dann bis ins neue Jahr ab, da langsam die 
Vorbereitungen für heute abend anlaufen ...

Grüße,
Michael

von Dietmar M. (Gast)


Lesenswert?

Michael K. schrieb:
> Soweit so gut, aber mein anfängliches Problem war, dass mit
> dem Sensor relativ häuft der Busstate "ARB Lost" eingetreten ist,

Das hatte ich auch. Hat mich ziemlich lang beschäftigt. Hat sich 
herausgestellt, dass ich einen Wackelkontakt am Weg von Xmega zu 
Steckbrett hatte. Gemessen habe ich mit dem Oszilloskop immer an den 
Pullups... Die so gesehene Spannung hat der Xmega an seinem SDA Pin 
allerdings nie zu spüren bekommen. Der war damit mehr oder weniger 
Floating... --> ARB Lost...

Sry, dass ich damit dieses alte Thema noch mal aufgreife... Habs aber 
mit Googel gefunden, da "gleiches Problem" und möchte zukünftige Sucher 
damit einen Lösungsweg aufzeigen. :)

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.