Forum: Mikrocontroller und Digitale Elektronik Denkbare Möglichkeiten: Prorgamm "spinnt"


von Daniel Mader (Gast)


Lesenswert?

Hallo,

um eine Frage gleich vorweg zu nehmen: Leider kann/darf ich das Programm 
nicht veröffentlichen, da ich es für meinen Arbeitgeber ist. Dennoch 
wäre ich um Hilfe dankbar.

Prozessor: Atmega8
Compiler: GCC
Programmiersprache: C

Randaten:
Atmega Flash-Speicher ist nach dem compilieren zu 80-<90% voll (also 
noch Luft)
Atmega SRAM nach dem compilieren zu 12% voll.

Auch während der Programmlaufzeit ändert sich der SRAM-Vebrauch nur 
geringfügig*
*geprüft nach folgender Methode:
http://www.rn-wissen.de/index.php/Speicherverbrauch_bestimmen_mit_avr-gcc
Sonst finde ich im Programm auch keine verschachtelten Funktionen. 
Arrays verwende ich im Programm nicht, außer einem im EEPROM. Diesen 
Programmteil/das Modul benutze ich aber in anderen Programmen 
fehlerfrei.

Folgendes Problem:
Zum Debuggen verwende ich ein LCD. Um auch hier die Frage vorweg zu 
nehmen: Strings sind per PROGMEM im Flash ausgelagert. Je mehr Zeilen 
bzw. Inhalt ich auf dem LCD ausgebe, desto mehr der Programmverbrauch im 
Flash (wegen PROGMEM). Ab einem gewissen Programmgröße (jedoch kleiner 
max. und SRAM bleibt unverändert), bekomme ich auf dem LCD nur wirre 
Zeichen angezeigt von den Strings und das Progarmm läuft nicht richtig. 
Kommentiere ich etwas andere Programmteile aus (nicht die LCD Ausgabe) 
und verringere damit die Programmgröße, funktioniert die Ausgabe 
einwandfrei und das Programm auch. Aber ich habe schon sukzessive 
verschiedene Stellen auskommentiert, um herauszufinden, ob es an 
irgendeiner bestimmten hakt, aber nein. Es ist scheinbar rein von der 
Größe abhängig.

Das gleiche ist übrigens auch, wenn ich das LCD weglasse, dafür mehr 
Programmmodule mit hinzu nehme, um den Speicher so hoch zutreiben. Aber 
einem gewissen Punkt, läuft das Programm nicht zuverlässig und wie es 
soll. Das LCD macht das Problem eigentlich nur direkt „sichtbar“, wenn 
die Daten/Strings eben „wirr“ angezeigt werden.

Nun stellt sich für mich die Frage, wo ich anfangen soll nach Fehler zu 
suchen oder wo Fehler sein könnten. Speicher ist nach dem compilieren zu 
keiner Zeit größer 90% und der SRAM wie oben geschrieben ca. 12%. Auch 
bei der Programmlaufzeit stelle ich keine großen SRAM Verbräuche fest.

Danke an alle, die es lesen und sich Gedanken machen.

VG
Daniel

von Conny G. (conny_g)


Lesenswert?

Bei diesen Effekten würde ich normalerweise zuerst am Probleme mit dem 
Stack denken, der am Ende des RAM sitzt. Dazu müsste das RAM aber fast 
voll sein oder der Stackbedarf sehr hoch (lokale Variablen in 
Funktionen).

Zweite Möglichkeit: Murks bei Pointer-Operationen.

Dritte Möglickeit: der Flash-Speicher hat Fehler. Anderen Atmega8 
versuchen.

von Daniel Mader (Gast)


Lesenswert?

Erst einmal danke für die Antwort.

ad 1)
Dürfte ja durch die im roboternetz ausgeführte Variante von mir 
abgeprüft sein.
Lokale Variablen habe ich nicht übermäßig, dass es ins Auge fallen 
würde. Globale volatile deklarierte sind es ein paar, da im Programm 
viele Interrupts vorkommen:
- Timer1 OVF
- Timer 1 CompA
- Timer 1 CompB
- Int0
- ICP


ad 2)
Pointer verwende ich im Programm explizit nicht, es sei denn, Sie sind 
durch vorhandene Bibliotheken eingebunden und werden implizit durch den 
Compiler angewandt.

ad 3)
Leider bereits auch schon versucht (habe die Schaltung hier 5x aufgebaut 
gelötet).

von Cyblord -. (cyblord)


Lesenswert?

Daniel Mader schrieb:
> Erst einmal danke für die Antwort.
>
> ad 1)
> Dürfte ja durch die im roboternetz ausgeführte Variante von mir
> abgeprüft sein.
> Lokale Variablen habe ich nicht übermäßig, dass es ins Auge fallen
> würde. Globale volatile deklarierte sind es ein paar, da im Programm
> viele Interrupts vorkommen:
> - Timer1 OVF
> - Timer 1 CompA
> - Timer 1 CompB
> - Int0
> - ICP


Beschreibst du jetzt allen ernstes in Prosa dein Programm, anstatt es zu 
posten? Zeig deinen Code.

von Peter II (Gast)


Lesenswert?

cyblord ---- schrieb:
> Beschreibst du jetzt allen ernstes in Prosa dein Programm, anstatt es zu
> posten? Zeig deinen Code.

einfach erst mal lesen?

> Leider kann/darf ich das Programm
> nicht veröffentlichen

von nurmal so (Gast)


Lesenswert?

schwer etwas zu sagen wenn von dem code so wenig bekannt ist,
aber mal eine Idee.
Vieleicht ist ja gar nicht der Speicher das Problem, sondern irgend 
welche Timings, die ab einer gewissen menge von eingebundenen Modulen 
nicht mehr eingehalten werden können.

von Cyblord -. (cyblord)


Lesenswert?

Peter II schrieb:
> cyblord ---- schrieb:
>> Beschreibst du jetzt allen ernstes in Prosa dein Programm, anstatt es zu
>> posten? Zeig deinen Code.
>
> einfach erst mal lesen?
>
>> Leider kann/darf ich das Programm
>> nicht veröffentlichen

Jo, aber ohne Code kann hier niemand helfen. So einfach ist das.

Wie soll so ein diffuses problem, was sowohl aus einer winzigen 
Kleinigkeit resultieren könnte, als auch aus dem gesamten Konzept 
heraus, ohne Code gefunden werden?

Alle wahrscheinlichen Ursachen (Stacküberlauf, wilde Pointer usw.) 
werden ja kategorisch ausgeschlossen.

: Bearbeitet durch User
von porter (Gast)


Lesenswert?

cyblord ---- schrieb:
> Peter II schrieb:cyblord ---- schrieb:Beschreibst du jetzt allen ernstes
> in Prosa dein Programm, anstatt es zu posten? Zeig deinen Code.einfach
> erst mal lesen?Leider kann/darf ich das Programm nicht veröffentlichenJo
> dann kann auch niemand helfen. So einfach ist das.

NIEMAND nicht. Aber vllt. JEMAND ;-)

von Arsenico (Gast)


Lesenswert?

Titel für ein hermetisches Drama:  Denkbare Möglichkeiten

von Peter D. (peda)


Lesenswert?

Daniel Mader schrieb:
> Kommentiere ich etwas andere Programmteile aus (nicht die LCD Ausgabe)
> und verringere damit die Programmgröße, funktioniert die Ausgabe
> einwandfrei und das Programm auch.

Schreib diese Teile als Funktion und rufe sie mal auf und mal nicht.
D.h. sie bleiben im Flash als toter Code.

von Peter II (Gast)


Lesenswert?

wenn es wirklich nachvollziehbar ist, sollte man es doch auch debuggen 
können. Einfach schrittweise durchgehen und schauen was in den Variablen 
steht.

von m.n. (Gast)


Lesenswert?

cyblord ---- schrieb:
> Alle wahrscheinlichen Ursachen (Stacküberlauf, wilde Pointer usw.)
> werden ja kategorisch ausgeschlossen.

Es ist eben ein fehlerfreies Programm und mich wundert, dass noch 
niemand die Abblockkondensatoren moniert hat oder die Anschlußleitung 
zum LCD, die bestimmt länger als 2cm ist :-)

Im Ernst: eine Woche lang liegen lassen, um noch einmal in Ruhe alles 
durchzutesten oder komplett neu schreiben, was bei klarer Zielsetzung 
und einem ATmega8 kein großes Problem sein sollte.

von c-hater (Gast)


Lesenswert?

Daniel Mader schrieb:

> Folgendes Problem:
> Zum Debuggen verwende ich ein LCD. Um auch hier die Frage vorweg zu
> nehmen: Strings sind per PROGMEM im Flash ausgelagert. Je mehr Zeilen
> bzw. Inhalt ich auf dem LCD ausgebe, desto mehr der Programmverbrauch im
> Flash (wegen PROGMEM). Ab einem gewissen Programmgröße (jedoch kleiner
> max. und SRAM bleibt unverändert), bekomme ich auf dem LCD nur wirre
> Zeichen angezeigt von den Strings

Handelt es sich um einen µC mit mehr als 64kByte Flash? Dann ist das mit 
hoher Wahrscheinlichkeit die Ursache des Problems. Sobald eine 
Zeichenkette oder eine im flash abgelegte Tabelle oberhalb der 
64k-Grenze zu liegen kommen, passiert Mist.

Soweit ich weiß, ist das aber in neueren Versionen des avrgcc behoben, 
da braucht man dann auch dieses PROGMEM-Zeuchs nicht mehr.

Überflüssig zu erwähnen, daß es in Assembler nie ein Problem dargestellt 
hat...

von tex (Gast)


Lesenswert?

Durch Deine Interrupts und Dein sehr großes Programm verursachst Du 
Stack-Überläufe.
Das läßt sich ggf. verhindern, indem Du auf Strings und Arrays 
verzichtest.
- Lade die Zeichen einzeln aus dem EEPROM wenn Du sie ausgibst-
- Überprüfe die Zykluszeiten Deiner Interrups und vermeide Interrups, wo 
immer es geht.
- Sei sparsam mit Variablen. Statt 6 oder 8 zu deklarieren, die alle nur 
1 Mal gebraucht werden, kann man bisweilen mit weniger auskommen, indem 
man kleinere Zwischenergebnisse berechnet und die selben Variablen 
mehrfach verwendet.

von Oliver S. (oliverso)


Lesenswert?

c-hater schrieb:
> Handelt es sich um einen µC mit mehr als 64kByte Flash?

Daniel Mader schrieb:
> Prozessor: Atmega8

In diesem Sinne...

Oliver

von Cyblord -. (cyblord)


Lesenswert?

Oliver S. schrieb:
> c-hater schrieb:
>> Handelt es sich um einen µC mit mehr als 64kByte Flash?
>
> Daniel Mader schrieb:
>> Prozessor: Atmega8
>
> In diesem Sinne...

Jo, schau doch mal, wers schreibt. Der hater-boy. Was erwartest du da?

von oldmax (Gast)


Lesenswert?

Hi
Die Aussage "Programm spinnt" find ich gut. Alle wissen, ein Programm 
macht genau das was der Programmierer programmiert hat. Nicht mehr und 
nicht weniger... eben genau das. Soviel zum Thema.
Aber vielleicht hab ich auch was nützliches beizutragen.
Es ist die Rede von "wenigen" globalen Variablen, aber von vielen 
lokalen. Na ja, auch lokale Variablen belasten den SRAm, also auch den 
Bereich Stack. Und wenn verschachtelte Aufrufe den Stack des öfteren 
bemühen, ist es leicht möglich, irgendwann ein paar Zeiger mal zu 
verbiegen. Ob das ein gepushtes Register ist, ein zerschossener Stack 
oder eine unsinnig überschriebene lokalvariable ist da völlig wurscht.
Ach ja, und wil's der Proggrammierer ausschließt, heißt es, das Programm 
spinnt.....
Gruß oldmax

von Conny G. (conny_g)


Lesenswert?

tex schrieb:
> Durch Deine Interrupts und Dein sehr großes Programm verursachst Du
> Stack-Überläufe.
> Das läßt sich ggf. verhindern, indem Du auf Strings und Arrays
> verzichtest.
> - Lade die Zeichen einzeln aus dem EEPROM wenn Du sie ausgibst-
> - Überprüfe die Zykluszeiten Deiner Interrups und vermeide Interrups, wo
> immer es geht.
> - Sei sparsam mit Variablen. Statt 6 oder 8 zu deklarieren, die alle nur
> 1 Mal gebraucht werden, kann man bisweilen mit weniger auskommen, indem
> man kleinere Zwischenergebnisse berechnet und die selben Variablen
> mehrfach verwendet.

Ja, überlappende Interrupts könnte noch was sein!

von Oliver S. (oliverso)


Lesenswert?

Wer "überlappende" Interrupts auf einem AVR einsetzt, stellt solche 
Fragen erst gar nicht.

Oliver

von Peter D. (peda)


Lesenswert?

tex schrieb:
> Durch Deine Interrupts und Dein sehr großes Programm verursachst Du
> Stack-Überläufe.

Unwarscheinlich.
Der AVR kann keine nestet Interrupts.

Und den Flash kann man zu 100% ausnutzen, da läuft nichts über.
Flash kann ja nicht zur Laufzeit dynamisch allokiert werden.

von Karl H. (kbuchegg)


Lesenswert?

Das einzige was man sagen kann

So ein Vorgehen ...

>  und verringere damit die Programmgröße, funktioniert die
> Ausgabe einwandfrei und das Programm auch. Aber ich habe
> schon sukzessive verschiedene Stellen auskommentiert, um
> herauszufinden, ob es an irgendeiner bestimmten hakt,
> aber nein. Es ist scheinbar rein von der Größe abhängig.

... ist sehr wahrscheinlich nicht zielführend.
Es ist sicher nicht die Programmgröße im Flash, die für das Problem 
verantwortlich ist, sondern da steckt noch irgendwo ein Bug drinnen. 
Indem du Programmteile auskommentierst, veränderst du die 
Programmausführung, wodurch sich der Bug mal zeigt und mal nicht zeigt.

Da du aber den Code nicht zeigen kannst/willst, kann dir aber das 
4-Augen Prinzip auch nicht weiterhelfen.
Entweder du springst über deinen Schatten und zeigst das Programm oder 
hier kann dir keiner konkret weiter helfen. Dann musst du dir in deiner 
Firma eben jemanden suchen, der mit dir das Programm Zeile für Zeile 
durchgeht und nach Auffälligkeiten sucht.
Du selbst, und das ist keineswegs negativ gemeint, bist höchst 
wahrscheinlich zu betriebsblind um es zu sehen.

: Bearbeitet durch User
von PittyJ (Gast)


Lesenswert?

Immer mehr Teile weglassen (auskommentieren). Wenn das Programm dann 
plötzlich wieder geht, dann ist des letzte auskommentierte Teil am 
Fehler beteiligt.


Ansonsten: mit Kupferpyramiden gegen Erdstrahlen sichern.

von Fpgakuechle K. (Gast)


Lesenswert?

Ich tippe auf compiler-prob oder unsaubere programmierung. Alle warnings 
anschalten (-Wall), alle Optimierungen aus (-O0) und die compiler/linker 
logs genau durchlesen und alle warnings verstehen und die durch sauberes 
Coding vermeidbaren durch Codeänderung beseitigen.

MfG,

PS:
Posten der Compilerlogs verletzten keine Copyrights des Arbeitsgebers.

von Peter II (Gast)


Lesenswert?

PittyJ schrieb:
> Immer mehr Teile weglassen (auskommentieren). Wenn das Programm dann
> plötzlich wieder geht, dann ist des letzte auskommentierte Teil am
> Fehler beteiligt.

so einfach ist das leider nicht. Bei einem Überschreiber im Speicher, 
kann das auskommentieren von variabel das Problem schon verschwinden 
lassen ohne das der Fehler an dieser Stelle ist.

von avr (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Der AVR kann keine nestet Interrupts.

Das kann er wohl (sei im Interrupt).

Zum Problem:

Sollte ein Bootloader vorhanden sein, ist der nutzbare Flash natürlich 
auch kleiner. Das hört sich für mich noch am logischten an, wenn man 
grobe Programmierfehler ausschließt.

von Oliver S. (oliverso)


Lesenswert?

avr schrieb:
> Peter Dannegger schrieb:
>> Der AVR kann keine nestet Interrupts.
>
> Das kann er wohl (sei im Interrupt).

Je nun, wer das macht, ist entweder selber schuld, oder er fragt solche 
Fragen wie der TO erst gar nicht.

Oliver

von Martin H. (marrtn)


Lesenswert?

Wie verlässlich sind denn Deine "Füllstände"?
Poste doch mal das Mapfile, da ist kein Code drin...

von Peter D. (peda)


Lesenswert?

avr schrieb:
> Das kann er wohl (sei im Interrupt).

Das ist ne Krücke, aber kein nested Interrupt. Man kann sich dabei schön 
selber ins Knie schießen (unendliche Rekursion).

Bei nested Interrupts kann ein Interrupt nur von einem mit höherer 
Priorität unterbrochen werden.
Z.B. beim 8051 mit 4 Prioritätslevel können nur max 3 Interrupts 
gleichzeitig einen niederen unterbrechen.

von Mark B. (markbrandis)


Lesenswert?

Daniel Mader schrieb:

> um eine Frage gleich vorweg zu nehmen: Leider kann/darf ich das Programm
> nicht veröffentlichen, da ich es für meinen Arbeitgeber ist.

Ist meines Erachtens kein Argument. Wenn Du kategorisch verweigern 
willst, den Code zu zeigen, dann ist ein öffentliches Forum der falsche 
Ort um nach Hilfe zu suchen. Wie weiter oben schon gesagt: Schnapp Dir 
einen Kollegen von Deiner Firma und geh das mit ihm zusammen durch.

Alternativ:
Gibt der Compiler Warnungen aus (mit -Wall -Wextra)? Dann behebe diese 
auf sinnvolle Art und Weise.
Verwendest Du ein Tool zur statischen Codeanalyse? Wenn nein, dann mach 
das mal. Ist erstaunlich was man da so finden kann ;-)

von Cyblord -. (cyblord)


Lesenswert?

Peter Dannegger schrieb:
> avr schrieb:
>> Das kann er wohl (sei im Interrupt).
>
> Das ist ne Krücke, aber kein nested Interrupt.
Und JA und DOCH.

> Man kann sich dabei schön
> selber ins Knie schießen (unendliche Rekursion).
Stimmt.

> Bei nested Interrupts kann ein Interrupt nur von einem mit höherer
> Priorität unterbrochen werden.

Nested ist nested. Das ist zwar eine schönes Feature, aber keine 
Bedingung für nested interrupts.

gruß cyblord

von oldmax (Gast)


Lesenswert?

Hi
Eigentlich ist es ja egal, ob das Programm läuft oder nicht... ist ja 
nicht von mir und alles was ich kaufe und nicht funktioniert wird 
reklamiert. Zugegeben, immer nur so ne Montagsproduktion macht keien 
Spaß, aber man kann ja das Produkt wechseln.
Was ich damit sagen will, eigentlich ist's ja schon vielfältig gesagt, 
ein unveränderbarer Teil des Controllers wird ja wohl nicht die Ursache 
sein, also ist der änderbare Teil, (SRAM) maßgeblich dranbeteiligt. Auch 
Register sind veränderbar, sonst könnt der Controller ja gar nix machen. 
Nun kommt die Frage: Anfangs läuft das Programm und irgendwann steigt es 
aus, liefert Müll. Na, immer noch bei Flash-Grenzen?
Wenn der TO lesen kann, dann hat er bestimmt mitbekommen, das gefühlte 
70% den Stack verdächtigen. Auch ohne das Programm zu kennen. Auch ich 
seh da das Problem und an der Aussage, das ja nur lokale Variablen in 
größerer Zahl benutzt werden. Vielleicht ist es nicht angekommen, daher 
noch einmal der Hinweis: Eine Variable ist eine veränderbare 
Speicherzelle, entweder ein Register oder ein Stück SRAM. ( Ich weiß, 
Register sind auch SRAM)
Und die werden bei lokal angelegten variablen auch auf dem Stack 
angelegt. Ein rekursi´ver Aufruf mit lokalen VAriablen füllt sehr wohl 
relativ schnell den Stack. Das muss noch nicht einmal von einem 
Interrupt kommen.
Also, noch viel Spaß beim heiteren Rätselraten.
Gruß oldmax

von Wolfi (Gast)


Lesenswert?

Ein Programm sollte immer mit einer Debugfunktionalitaet geschrieben 
werden, denn Debugging ist Teil der Entwicklung. Nicht irgednwas, das 
dummerweise in schlechten Fallen noch eingebaut werden muss. Also lieber 
einen naechst groesseren Controller mit einem UART mehr einbauen.

Dasselbe gilt auch fuer Hardware.

Der Rest wurde alles gesagt. Die fehlerhafte Funktionalitaet eingrenzen. 
Was kann man alles weglassen bis der Fehler nicht mehr auftritt.

von Daniel Mader (Gast)


Lesenswert?

oldmax schrieb:
> Auch ich
> seh da das Problem und an der Aussage, das ja nur lokale Variablen in
> größerer Zahl benutzt werden.

Danke für alle, die den Blick in die Glaskugel gewagt haben.
Obige Aussage habe ich aber eher umgekehrt getroffen. Es sind 
überschaubar lokale Variablen, aber etwas mehr global volatile 
deklarierte.

von Mark B. (markbrandis)


Lesenswert?

Globale Variablen belegen über die Laufzeit hinweg konstant die gleiche 
Menge an Speicher. Den Stack damit zu zerschießen wird schwierig ;-)

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Daniel Mader schrieb:
> Es sind
> überschaubar lokale Variablen, aber etwas mehr global volatile
> deklarierte.

Zusammenfassend lässt sich sagen, daß alles richtig ist, niemand eine 
Fehler gemacht hat, kein Programmierfehler vroliegt, und auch sonst 
alles in Ordnung ist.

Nur blöd, daß das Programm trotzdem nicht läuft.

Woher weisst du, ob deine Speicherprüfroutine richtig funktioniert, wenn 
der Rest des Programms Amok läuft?

Denn alle Hinweise deuten auf einen unbeansichtigt überschriebenen 
Speicherbereich hin. Entweder ein Stacküberlauf, Array out of bounds, 
oder ein fehlgeleiteter Pointer.

Oliver

von Logger (Gast)


Lesenswert?

Oliver S. schrieb:
> Woher weisst du, ob deine Speicherprüfroutine richtig funktioniert, wenn
> der Rest des Programms Amok läuft?

Irgend eine Macke wird das Programm schon haben, sonst würde da
ja nicht so ein Murks raus kommen. Da bleibt einem doch ohnehin
nichts anderes überig, als das Programm Schritt für Schritt
abzuarbeiten, entweder simuliert, per Debugging oder emulieren
(wegen der IRQs).
Würde da der Einsatz eines STK500/600 nicht was bringen?
(Hab damit leider keine Erfahrung).

von oldmax (Gast)


Lesenswert?

Hi
>Danke für alle, die den Blick in die Glaskugel gewagt haben.
>Obige Aussage habe ich aber eher umgekehrt getroffen. Es sind
>überschaubar lokale Variablen, aber etwas mehr global volatile
>deklarierte.
Sorry, hab ich anders gelesen, aber trotzdem, die global deklarierten 
kennst du. Lokal, ist im Prinzip auch klar, es sei denn du hast 
rekursive Aufrufe...... Und dann sind das schon nicht mehr 
"überschaubare". Aber egal, du weißt, es ist ok, wir nicht.
Gruß oldmax

von Walter T. (nicolas)


Angehängte Dateien:

Lesenswert?

Den Trick mit der Speicherbelegung aus dem Roboternetz kann man übrigens 
auch noch weiter treiben. Den SRAM am Anfang mit 0xAAs füllen und dann 
eine kleine Routine schreiben, die wahlweise die SRAM-Belegung einfach 
auf dem Display darstellt (siehe Bild). Bei einem Grafik-Display geht 
das direkt, beim Text-Display sollte zumindest sichtbar sein, wo noch 
0xAAs stehen.

Auf dem Bild kann man schön erkennen, wie groß mein Sicherheitsabstand 
zwischen Head (oben) und Stack (unten) noch ist.

Und man kann sehr gut vor und nach dem Aufruf einer Funktion prüfen, ob 
sich der Abstand verringert hat.

Die Methode funktioniert natürlich auch für den Flash. Im zweiten Bild 
der Blick in eine kaputte Zeichensatztabelle.

Nur als Anregung.

Edit: Und bevor die Frage aufkommt, warum das so leer/mit lauter Nullen 
gefüllt ist ist: Es ist ein ATmega32 und auf dem LCD ist gerade der 
SRAM-Bereich oberhalb 1kB.

[Edit:] Ich glaube, einige Tasten sind schon nachmittagsmüde

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Mir hat mal folgende Methode geholfen:

Ich habe zwei globale Variablen zum Test eingebaut, und sie mit einem 
bestimmten Wert intialisiert. Vor und nach dem Aufruf verdächtiger 
Funktionen habe ich diese Variablen über den seriellen Port ausgegeben:
1
int test1=12345;
2
... andere variablen
3
int test2=11111;
4
5
int main() {
6
  initserial();
7
  int i;
8
  while(1) {
9
    printf("i=%i, 1=%i, 2=%i",i,test1,test2);
10
    verdaechtige_funktion(parameter);
11
    printf("i=%i, 1=%i, 2=%i",i,test1,test2);
12
    i++;
13
  }
14
}
Dazu habe ich eine bewährte Library eingebunden, die den seriellen Port 
an stdout bindet.

Irgendwann nach einer scheinbar zufälligen Anzahl von 
Schleifendurchläufen wurde eine der beiden Test-Variablen unerwartet 
verändert. Also lag die Vermutung nahe, dass irgendein unregeläßiges 
Ereignis den Fehler auslöst. In meinem Fall war ein externer Interrupt. 
Die Interruptroutine war zwar Ok, aber die Vorgänge, die NACH dem 
Interrupt aus der Hauptschleife heraus ausgeführt wurden, brachten den 
Speicher durcheinander.

Nachdem ich nun wusste, welche Funktion innerhalb der Hauptschleife der 
Übeltäter war, konnte ich entsprechende printf Ausgaben in eben diese 
Funktion einbauen.

Die eigentliche Ursache war dann schnell gefunden (es wurden Daten von 
einem externen Chip in ein Array geladen, das zu klein war).

Versuche es mal mit dieser Methode. Falls Du keine serielle Library 
hast, der du vertraust, dann nimm das:
1
#include <stdint.h>
2
#include <stdio.h>
3
#include <avr/io.h>
4
#include <util/setbaud.h>
5
6
// The serial bitrate and CPU clock frequency is usually set in the Makefile
7
// #define BAUD 115200
8
// #define F_CPU 20000000
9
10
static int serial_write(char, FILE *);
11
static FILE serialPort = FDEV_SETUP_STREAM(serial_write, null, _FDEV_SETUP_WRITE);
12
13
// Write a character to the serial port
14
static int serial_write(char c, FILE *f) {
15
    // wait until transmitter is ready
16
    loop_until_bit_is_set(UCSRA, UDRE);
17
    UDR = c;
18
    return 0;
19
}
20
21
// Initialize the serial port
22
void initserial(void) {
23
    // set baudrate
24
    UBRRH = UBRRH_VALUE;
25
    UBRRL = UBRRL_VALUE;
26
    #if USE_2X
27
        UCSRA |= (1 << U2X);
28
    #else
29
        UCSRA &= ~(1 << U2X);
30
    #endif
31
    // framing format 8N1
32
    #ifdef URSEL
33
        UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);
34
    #else 
35
        UCSRC = (1<<UCSZ1) | (1<<UCSZ0);
36
    #endif
37
    // enable transmitter
38
    UCSRB = (1<<TXEN);
39
    // Bind stdout to the serial port
40
    stdout = &serialPort;
41
}
Dieser Code kommt ohne Interrupts und Pufferspeicher aus. Die 
Warscheinlichkeit, dass die Textausgabe versagt, weil der Speicher 
durcheinander geraten ist, wird so minimiert.
Du must beim Programmstart einmal die Funktion initserial() aufrufen. 
Danach kannst Du mit sämtlichen Ausgabe-Funktionen der standard Library 
arbeiten (printf, puts, putc und so weiter).

von Wolfi (Gast)


Lesenswert?

printf() auf einen AVR? Wuerd ich mir nie antun. Viel zu klotzig.

Das einfachste und kleinste zum debuggen ist wahrscheinlich ein 
einzelner Pin, den man als ausgang definiert und hoch-runter zieht. Die 
naechst bessere loesung ist ein zweiter Pin, auf den man die Aenderung 
signalisiert. zB auf dessen steigende Flanke sind auf dem ersten pin die 
daten gueltig.

Falls das laeuft kann man den UART in betrieb nehmen. Beim UART muss man 
beachten, dass man nur soviele Daten rausschicken kann wie die Baudrate 
schnell ist.

von Stefan F. (Gast)


Lesenswert?

> Beim UART muss man beachten, dass man nur soviele Daten
> rausschicken kann wie die Baudrate schnell ist.

Wie meinst du das? Darf man bei 9600 Baud nur 9600 Zeichen senden? Und 
was passiert danach?

von Stockki (Gast)


Lesenswert?

9600  Baud bedeutet 9600 Bit, inkl. Start, Stop, Parity. Dh sind dann 
max 960 Bytes/sek. Wenn man mehr auf das UART schreibt kommt nur noch 
Muell.

von oldmax (Gast)


Lesenswert?

Hi

Stockki schrieb:
> 9600  Baud bedeutet 9600 Bit, inkl. Start, Stop, Parity. Dh sind dann
> max 960 Bytes/sek. Wenn man mehr auf das UART schreibt kommt nur noch
> Muell.

Nun bin auch ich sprachlos...
Leute, lest doch bitte erst mal das was ihr da schreibt. Es soll hier 
Teilnehmer geben, die glauben das dann auch und verkünden es weiter. Und 
wenn das zufällig eine Lehrkraft mit dem Ehrgeiz seinen Schülern 
Mikrocontrollern beizubringen ist, multipliziert sich das Ganze Wissen 
und wir können uns in Zukunft von den Ausflügen Richtung Weltall 
verabschieden.
Gruß oldmax

von Wolfi (Gast)


Lesenswert?

>Nun bin auch ich sprachlos...

Was stimmt denn nicht?

von Cyblord -. (cyblord)


Lesenswert?

Stockki schrieb:
> 9600  Baud bedeutet 9600 Bit, inkl. Start, Stop, Parity. Dh sind dann
> max 960 Bytes/sek. Wenn man mehr auf das UART schreibt kommt nur noch
> Muell.

Wie soll man denn "mehr auf den UART schreiben"? Der UART wird mit einer 
festen Taktrate (=Baudrate) betrieben und tackert so alle Daten raus die 
er bekommt. Bekommt er schneller Daten, als er senden kann, so läuft 
irgendwann der Sendepuffer voll. Auf die eigentliche Übertragung hat das 
natürlich keinen Einfluss und somit kommt da auch kein "Muell" an.

> printf() auf einen AVR? Wuerd ich mir nie antun. Viel zu klotzig.

Ahah

> Falls das laeuft kann man den UART in betrieb nehmen.
Genau, und da ist printf dann eine gute Möglichkeit schnell und einfach 
kurze Texte und Variableninhalte rauszuschicken. Ohne umständliches 
formatieren mit itoa und zusammenbauen der Daten.

> Beim UART muss man
> beachten, dass man nur soviele Daten rausschicken kann wie die Baudrate
> schnell ist.
Was bei Debug Ausgaben ja auch echt ein Problem ist. Da hat man ja auch 
Megabyteweise Daten pro Sekunde....

gruß cyblord

von Martin H. (marrtn)


Lesenswert?

> Stockki schrieb:
>> 9600  Baud bedeutet 9600 Bit, inkl. Start, Stop, Parity. Dh sind dann
>> max 960 Bytes/sek. Wenn man mehr auf das UART schreibt kommt nur noch
>> Muell.

cyblord ---- schrieb:
> Wie soll man denn "mehr auf den UART schreiben"? Der UART wird mit einer
> festen Taktrate (=Baudrate) betrieben und tackert so alle Daten raus die
> er bekommt. Bekommt er schneller Daten, als er senden kann, so läuft
> irgendwann der Sendepuffer voll. Auf die eigentliche Übertragung hat das
> natürlich keinen Einfluss und somit kommt da auch kein "Muell" an.

Ach, mit genügend Phantasie beim "Programmieren" bekommt man das 
sicherlich hin - hier laufen eine ganze Reihe solcher Spezialisten rum 
;).
Ein Sendepuffer ist ja nicht immer vorhanden, viele werfen die Daten 
einfach so in die Register. Und vorher nachschauen, ob das letzte Byte 
schon komplett raus ist, ist ja auch nicht soo wichtig...

: Bearbeitet durch User
von MWS (Gast)


Lesenswert?

oldmax schrieb:
> Hi
>
> Stockki schrieb:
>> 9600  Baud bedeutet 9600 Bit, inkl. Start, Stop, Parity. Dh sind dann
>> max 960 Bytes/sek.
>
> Nun bin auch ich sprachlos...
> Leute, lest doch bitte erst mal das was ihr da schreibt. Es soll hier
> Teilnehmer geben, die glauben das dann auch und verkünden es weiter. Und
> wenn das zufällig eine Lehrkraft mit dem Ehrgeiz seinen Schülern
> Mikrocontrollern beizubringen ist, multipliziert sich das Ganze Wissen
> und wir können uns in Zukunft von den Ausflügen Richtung Weltall
> verabschieden.
> Gruß oldmax

Nun, der erste Teil ist ja richtig. Wenn etwas kritikwürdig wäre, dann 
das hier:
>> Wenn man mehr auf das UART schreibt kommt nur noch
>> Muell.

Bei korrekter Programmierung schafft man es auf Seite des µC nicht, mehr 
Bytes pro Sekunde zu schreiben, da kommt dann auch kein Müll.

Der entsteht nur wenn: der Code Murks ist, die Übertragungsraten von 
Sender und Empfänger nicht stimmen, oder der Empfänger beschäftigt ist 
und die Bytes nicht schnell genug abholt.

Ob dieser kleine Fehler es verdient hat, mit dem Geschwurbel über den 
Untergang des Abendlandes beantwortet zu werden, darf bezweifelt werden.

Außerdem, wenn Du schon im belehrenden Tonfall loslegst, dann schreib' 
halt hin, was Deiner Meinung nach richtig wäre, damit Zillionen anderer 
Schüler nicht irre gehen.

von oldmax (Gast)


Lesenswert?

Hi

MWS schrieb:
> Nun, der erste Teil ist ja richtig. Wenn etwas kritikwürdig wäre, dann
> das hier:
>>> Wenn man mehr auf das UART schreibt kommt nur noch
>>> Muell.
>
> Bei korrekter Programmierung schafft man es auf Seite des µC nicht, mehr
> Bytes pro Sekunde zu schreiben, da kommt dann auch kein Müll.

Es mag sein, das der erste Teil der Aussage richtig ist und dennoch ist 
die Antwort schlichtweg falsch. Auch deine Antwort hinkt gewaltig. Wie 
bitteschön sieht denn eine unkorrekte Programmierung aus, die einen mit 
9600 Byte betriebenen UART in die Lage versetzt, mehr als 960 Bytes in 
der Sekunde zu senden? Sicherlich ist es durchaus machbar, mehr als 960 
Bytes in einer Sekunde in einem Sendepuffer abzulegen. Na und, dann 
dauert die Übertragung eben mehr als eine Sekunde. Wenn der Puffer groß 
genug und nach einer Sendung entsprechen Zeit bis zur nächsten Datenflut 
ist, kommt da auch nix durcheinander.
Mir braucht ihr über Datentransfer keine Belehrung zukommen lassen, ich 
weiß wie's funktioniert, aber der TO hat ein Problem mit ganz anderen 
Ursachen. Nun kommt hier noch tief fundierte die Diskussion über UART 
hinzu. Bravo
Gruß oldmax

von MWS (Gast)


Lesenswert?

oldmax schrieb:
> Wie bitteschön sieht denn eine unkorrekte Programmierung aus

In's UDR schreiben, ohne zu überprüfen ob's leer ist.

> die einen mit
> 9600 Byte betriebenen UART in die Lage versetzt, mehr als 960 Bytes in
> der Sekunde zu senden?

Diese Vermutung hat niemand in den Raum gestellt, außer Dir jetzt 
vielleicht. Denn so lautete das ursprünglich:

Stockki schrieb:
> Wenn man mehr auf das UART schreibt kommt nur noch
> Muell.

Das trifft bei falschem Code, s.o. zu, welche Form "Muell" wurde nicht 
näher definiert.

oldmax schrieb:
> Mir braucht ihr über Datentransfer keine Belehrung zukommen lassen, ich
> weiß wie's funktioniert

Den Eindruck hatte ich nicht. Hättest Du's gewusst, wäre es Dir ein 
Leichtes gewesen, den Fehler in einem Satz zu berichtigen, statt in drei 
Sätzen und mit vielen Worten das vermeintliche Nichtwissen des 
Schreibers im Rundumschlag zu kritisieren.

oldmax schrieb:
> wir können uns in Zukunft von den Ausflügen Richtung Weltall
> verabschieden.

M.E. bist Du da der Einzige, der auf der Erde sitzenbleibt. :D

oldmax schrieb:
> Nun kommt hier noch tief fundierte die Diskussion über UART
> hinzu. Bravo

Ist doch egal, Threads hier haben durchaus den Reiz, dass die mal 
abdriften, deswegen sind sie nicht weniger interessant. Das Ansinnen des 
TEs per Glaskugel in Ferndiagnose eine Lösung seines Problems zu 
erhalten, ist eh' nicht machbar. Eine Diskussion über UART ändert daran 
nichts und kann deshalb auch nicht schaden.

von Stefan F. (Gast)


Lesenswert?

Hi alle,
ihr seid mir zuvor gekommen. Ich musste mich erstmal im stillen 
kämmerlein abregen.

Mein primitiver Beispiel-Code sendet Zeichen so:
1
static int serial_write(char c, FILE *f) {
2
    // wait until transmitter is ready
3
    loop_until_bit_is_set(UCSRA, UDRE);
4
    UDR = c;
5
    return 0;
6
}

Ich habe also bereit vor Wolfis Kommentar gezeigt, wie man es richtig 
macht. Abgesehen davon sind die entsprechenden Erlärungen im Datenblatt 
meiner Meinugn nach nicht zu übersehen.

von Martin H. (marrtn)


Lesenswert?

Stefan us schrieb:
> Abgesehen davon sind die entsprechenden Erlärungen im Datenblatt
> meiner Meinugn nach nicht zu übersehen.

Hehe, der war gut. Wie viele der hier im Forum fragenden haben jemals 
ein Datenblatt über das Pinout hinaus gelesen?

---

OK, ich weiß das ist OT und gemein, aber das musste raus...

: Bearbeitet durch User
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.