Forum: Mikrocontroller und Digitale Elektronik Unterschied AVR Simulation - Realität


von Hermann E. (hermann_e)


Angehängte Dateien:

Lesenswert?

Einen "Guten Morgen" an die uC Community !

Nach vielen Stunden probieren und  Atmega644 heisslaufen lassen weiss 
ich einfach nicht mehr weiter:
Eigentlich geht es mir nur um einen Timer den ich in zwei Zeitbasen 
unterteilen will. Dazu löse ich alle 100ms ("T_RESOLUTION") einen 
Overflow Interrupt aus der mir die schnelle Zeitbasis liefern soll. Zum 
Überprüfen habe ich den PD7 als Ausgang definiert und mit "PORTD ^= 
(1<<PD7)" toggle ich den Ausgang mit den erwarteten 50Hz - soweit so 
gut, das Oszi gibt mir genau den erwarteten Wert.
Um jede Sekunde langsamere Aufgaben zu erledigen ist die Idee mit der 
Variablen "Tick Counter" bis auf 100 zu zählen um dann per:

if(TickCounter >= 100)
  {
    TickCounter = 0;
    PORTD ^= (1<<PD6);
  }

eine Unterteilung in Sekunden zu erzielen. Zum Überprüfen toggle ich 
PD6.
In der Simulation läuft alles wie es soll, sobald ich das Programm aber 
auf meinen Atmega644 aufspiele ist Schluss. PD7 toggelt nach wie vor, 
aber es ist tote Hose auf PD6. Interessanterweise funktioniert's wenn 
ich anstatt 100 nur 2 verwende, also anstatt "if(TickCounter >= 100)" 
die IF Konstruktion:  "if(TickCounter >= 2)". In diesem Fall zeigt das 
Oszi keine Halbierung der Frequenz sondern eine Änderung des 
Tastverhältnisses (immer noch 50Hz auf PD6 aber zwei Drittel der Zeit 
ist der Ausgang 0 und ein Drittel der Periode auf 1). In der Simulation 
verhält es sich aber wie's soll.

Ich benutze das AVR studio 6 (mit letztem Patch) der Quarz ist ein 
11.0592MHz Baud Quarz.

Den Code habe ich in einem File versammelt, ich häng' den mal an.
Ich denke dass ich irgendwo Tomaten auf den Augen habe, das Problem 
erscheint mir so primitiv dass ich mir keinen "Kompilerfehler" 
vorstellen kann.

Hätte jemand eine Idee dazu ??

Vielen Dank:  Hermann

von Georg G. (df2au)


Lesenswert?

Am Anfang der ISR setzt du den Tick-Counter auf 0, bei jedem Aufruf. Das 
ist suboptimal. Weil er dann nur schwer auf 100 kommen kann.

Und noch ein Hinweis: 100ms und 50Hz widersprechen sich. Vermutlich 
meinst du 10ms. Das würde auch zu %100 für 1s passen.

von Hmm (Gast)


Lesenswert?

>Am Anfang der ISR setzt du den Tick-Counter auf 0, bei jedem Aufruf.

Nein. Bei einer static Variablen wird diese Initialiserung nur einmal 
ausgeführt, nämlich beim ersten Ausführen der Funktion.

Und bei dem Stichwort "Funktion" bimmelts irgendwie bei mir.
Eine Interrupt-Service-Routine ist keine herkömmliche Funktion. Sie 
bekommt keine Parameter. Zwar hat sie für lokale Variablen wohl einen 
Stack-Frame, aber ich hätte nicht vorausgesetzt, das der Compiler auch 
statische Variablen in ISRs wie in Funktionen behandelt. In der Tat ist 
das die erste ISR die ich sehe in der eine static-Variable deklariert 
ist.

Ich nehme an, das der Compiler das Ding wie eine lokale Variable 
behandelt und das (unter Annahme verschiedener Nebenumstände) der Stack 
im Simulator zufällig noch diesen Wert behielt. Warum das nun im realen 
Prozessor nicht so ist, kann ich im Moment nicht erklären. Der 
Assemblercode könnte das klären.

Ich empfehle Dir die Variable ausserhalb jeder Funktion zu deklarieren. 
Entferne das static und füge ein volatile hinzu.

von Hermann (Gast)


Lesenswert?

Danke Georg !

Die 50Hz sind logisch da die ISR alle 100ms ausgeführt wird.
In jeder ISR wird PD7 getoggelt. Dh. PD7 ist 100ms "high"
und dann 100ms "low" das ergibt eine Periode von 200ms und damit 50Hz.

Was die Initialisierung von TickCounter angeht so habe ich die Variable
als "Statisch" definiert, damit wird nach meinem (vielleicht falschen 
??) Kenntissstand die Variable nur einmal am Programmanfang 
initialisiert und dann nicht mehr, sie müsste also ihren Wert von dann 
an beibehalten ?!

Grüsse aus dem sonnigen Frankreich:  Hermann

von Hmm (Gast)


Lesenswert?

Das mit 100ms toggle eine 50Hz Frequenz erreicht wird, beruht meiner 
Ansicht nach, auf einem Rechenfehler. Es sind 5Hz.
Für 50Hz bräuchtest Du 10ms.

von Hermann E. (hermann_e)


Lesenswert?

Oups,

in der Zwischenzeit ist ja noch ein weiterer Beitrag gekommen, nochmals 
"Danke".
Ich hab' das sofort getestet und außerhalb von "main(){}" die Variable 
TickCounter  mit "volatile uint8_t  TickCounter = 0;" als global 
definiert.
In der ISR führe ich die Variable mit "extern uint8_t  TickCounter;" 
ein.

Jetzt ist es aber so dass das Programm auch mit "if(TickCounter >= 2)" 
keinerelei Aktivität an PD6 mehr ergibt (gescheige denn mit Werten 
grösser als 2) Immerhin zeigt sich eine Veränderung des Verhaltens was 
mich vermuten lässt dass das Problem in dieser Richtung zu suchen ist.

Grüsse:  Herman

von Hmm (Gast)


Lesenswert?

Also, ich habe mal ein bisschen gegoogelt und nachgedacht.
Theoretisch spricht eigentlich nichts dagegen, in einer ISR eine 
statische Variable zu haben. Ich finde auch Beispiele dazu.

Mein mein "dummes Gefühl" dabei mag also unbegründet sein. Das ich das 
noch nie so gemacht habe, ist ja nicht ausschlaggebend. Vielleicht magst 
Du aber doch mal ausprobieren, die Variable global und volatile zu 
deklarieren.

von Hmm (Gast)


Lesenswert?

>In der ISR führe ich die Variable mit "extern uint8_t  TickCounter;"
>ein.

Das ist unnötig und sogar falsch, wenn der Code wie oben gezeigt, in 
einer Datei enthalten ist. Jedenfalls fehlt das volatile.

Lösch die Deklaration "extern uint8_t  TickCounter;" einfach.

von Hermann E. (hermann_e)


Lesenswert?

"Für 50Hz bräuchtest Du 10ms."

Das ist völlig richtig, war ein Denkfehler von mir da ich durch 100 
teile in
"#define T_RESOLUTION   100" !
(aber 1000/100 ist wie du richtig bemerkst 10 und nicht 100)

von Hmm (Gast)


Lesenswert?

Das "extern" ist nur dann nötig, wenn Du zwei C-Dateien hast von denen 
eine die Definition der Variablen enthält (nicht static) und die andere 
C-Datei diese Variable referenzieren will. Wenn nur eine Datei vorhanden 
ist, dann ist das "extern" falsch.

von Hermann E. (hermann_e)


Lesenswert?

hm,

Hab' im gleichen File die ISR unter den "main" -Abschnitt verschoben so 
dass
TickCounter in der ISR bekannt ist. (und nur noch "volatile uint8_t 
TickCounter = 0;" überhalb von main())
Das praktische Resultat ist aber leider unverändert.

Nochmals Grüsse:  Hermann

von Georg G. (df2au)


Lesenswert?

Poste doch bitte mal den ASM-Code, den der GCC baut. Dann sieht man 
vermutlich, was passiert.

von Hermann E. (hermann_e)


Lesenswert?

Hallo Georg,

jetzt erwischt du mich an meiner weichen Stelle - ich weiss nicht wie 
ich an den Assembler Code rankomme !

von Hmm (Gast)


Lesenswert?

Um jedes Missverständnis auszuschliessen, bitte ich Dich, den momentanen 
Code zu posten und das nunmehr beobachtete Verhalten zu beschreiben.

Die Reihenfolge von main und der ISR spiel keine Rolle. Besonders nicht 
in Bezug auf darin verwendete Variablen. In Bezug auf Variablen würde 
die Reihenfolge der Variablen-Definitionen/Deklarationen und der 
Funktionen welche sie verwenden ein Rolle spielen. Aber das ist ein 
anderes Thema.

von Hermann E. (hermann_e)


Angehängte Dateien:

Lesenswert?

Ha das müsste es sein ...

von Hermann E. (hermann_e)


Angehängte Dateien:

Lesenswert?

Fühl mich ein wenig komisch dich mit "Hm" anzusprechen aber ich finde es 
Klasse von euch dass ihr mir wirklich versucht zu helfen !! also 
nochmals Danke.

Den code hab' ich so wie er ist angeheftet.
Das Verhalten ist so dass PD7 nach wie vor dass tut was es soll, in
"if(TickCounter >= 2)" aber mit PD6 Schluss ist wenn 2 durch einen 
höheren Wert ersetzt wird.

von Georg G. (df2au)


Lesenswert?

ASM sieht so weit unauffällig aus. Muss aber erst einmal SN machen. Wenn 
es dann immer noch unklar ist, geht es weiter.

von tut nichts zur sache (Gast)


Lesenswert?

Watchdog?

von Hmm (Gast)


Lesenswert?

>Fühl mich ein wenig komisch dich mit "Hm" anzusprechen...

Ich nenne mich ja auch "Hmm". :-)

Also ich sehe an dem Code nichts, warum das nicht gehen sollte.
Bleiben also die üblichen Verdächtigen:

Hast Du
1. im Simulator
2. beim Compiler
3. beim Programmier-Dialog
jeweils den richtigen Prozessor eingestellt?

Hast Du dir richtigen Fuses eingestellt?
1. Taktquelle
2. CKDIV8

Du kannst ja mal sicherheitshalber das lss file schicken wenn Du für den 
Vergleichswert 100 einsetzt. Aber ich denke nicht, das sich da was Neues 
ergibt.

Welche Frequenz ergibt sich an PD6 solange Du auf >= 2 testest?

von Hermann (Gast)


Lesenswert?

Nee, kein Watchdog aktiviert,

meine Antworten werden in den nächsten Minuten etwas unregelmässiger da 
meine Freundin mich zum Essen machen verdonnert hat ...

von Georg G. (df2au)


Lesenswert?

Tja... wie sag ich es am schonendsten...

Auf meinem STK500 mit einem 1284 (sollte keinen Unterschied machen, war 
zu faul zum wechseln) mit "alle 100" funktioniert es wunderbar. Kein 
Fehler feststellbar.

(Ehefrau macht ausnahmsweise das Essen)

von Hermann E. (hermann_e)


Lesenswert?

aaalso:

zu "Welche Frequenz ergibt sich an PD6 solange Du auf >= 2 testest?"
Frequenz an PD6 mit ">= 2" nach wie vor 50Hz aber mit verandertem 
Tastverhältniss
1/4 auf '1' 3/4 auf '0' d.h. PD6 über eine 20ms Periode: 5ms "an" 15 ms 
"aus"
F_CPU=11059200UL

Der Compiler ist bei mir standardmässig auf C++ gesetzt
(in "ALT+F7" -> AVR/GNU Compiler habe ich:

-funsigned-char -funsigned-bitfields -DF_CPU=11059200UL  -O0 
-fpack-struct -fshort-enums -g2 -Wall -c -gdwarf-2  -x c++ -std=gnu++98 
-MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -MT"$(@:%.o=%.o)" 
-mmcu=atmega644

wo's von den Standard Settings abweicht ist der Zusatz:
"-x c++ -std=gnu++98" um alles mit C+ zu compiliern (schreibe viel in 
C++ und hatte soweit keine Probleme damit)
Der Prozessor ist ein 644A, da sagt er aber dass er den io?? File nicht 
findet. Ich habe ihn deshalb als 644 (ohne A) definiert, hoffe das es 
nicht daran liegt.

Taktquelle/CKDIV8: Sicher nicht, die im Oszi angegeben Frequenz stimmt 
(50Hz)

von Hmm (Gast)


Lesenswert?

>... mit einem 1284 (sollte keinen Unterschied machen ...

Um ein mögliches Missverständnis zu vermeiden. Es ist dennoch nötig zu 
kontrollieren ob Du die Optionen zum simulieren, kompilieren und 
programmieren im AVRStudio wegen des Prozessortyps richtig und gleich 
eingestellt hast.

von Hermann E. (hermann_e)


Lesenswert?

Hab soeben auch noch alle Atmega644 mit "Change Device" durchgespielt 
und aufgflasht - (A,PA,P, 644 ohne Endung) leider keine Änderung im 
Problem...

von Hmm (Gast)


Lesenswert?

Jetzt muss ich doch mal ein bisschen "strenger" werden. ;-)

Nicht einfach irgendwas rumprobieren. Das hilft in der Technik nicht und 
kann bis zur Zerstörung von Teilen führen.
Du hast einen bestimmten Prozessortyp, nämlich 644A und den stellst Du 
in den Dialogen ein. Es gibt keinen Grund da irgendwas 
"herumzuprobieren".

Deine Aussage
>zu "Welche Frequenz ergibt sich an PD6 solange Du auf >= 2 testest?"
>Frequenz an PD6 mit ">= 2" nach wie vor 50Hz aber mit verandertem
>Tastverhältniss
>1/4 auf '1' 3/4 auf '0' d.h. PD6 über eine 20ms Periode: 5ms "an" 15 ms
>"aus"
>F_CPU=11059200UL

deutet auf irgendwas Oberfaules hin. Es kann nicht sein, das bei einer 
Veränderung des Vergleichskriterium von 100 auf 2 die Frequenz gleich 
bleibt und sich das Tastverhältnis ändert.

Prüfe bitte zusätzlich ob Du auch die richtige Hex-Datei programmierst.
Wohlgemerkt, nachdem Du den richtigen Prozessortyp eingestellt hast.

von Georg G. (df2au)


Lesenswert?

644 rausgesucht und eingebaut. Neu compiliert. Programm tut das 
gewünschte.
Allerdings nicht c++ sonder als c (normal) gebaut. Da keine c++ Features 
verwendet werden, sollte es nichts ändern.

von Hmm (Gast)


Lesenswert?

>644 rausgesucht und eingebaut.
Hey, nett von Dir. Ich seh keinen Grund warum das nicht bei ihm spielen 
sollte. Irgendwas ist da im Setup faul.

von Georg G. (df2au)


Lesenswert?

Auch als c++ compiliert spielt es sauber. Bin ratlos.

von Hermann (Gast)


Lesenswert?

Super von euch dass ihr euch die Mühe macht !

Was die HEX Datei angeht so bin ich mir sicher das es die Richtige ist,
beim Verändern des Codes  wegen ">= 2" habe ich ja die Änderung gesehen 
und auch den Path mehrfach überprüft.

"deutet auf irgendwas Oberfaules hin" - Dem kann ich leider nur 
zustimmen !
Ich muss jetzt leider weg da der Famileinfrieden ernsthaft bedroht ist !
Heute Abend nach 20:00 bin ich zurück.

Da ich noch andere Prozessoren hier rumliegen habe werd' ich's mal mit 
denen versuchen und auch den Kompi wechseln wo ich noch die "Urform" von 
AVR-Studio6 bzw Studio4 installiert (nix C++) habe.

Ich halt' euch auf dem Laufenden ...

Hermann

von Georg G. (df2au)


Lesenswert?

Stell die HEX Datei auch mal rein. Dann flashe ich die auf meine 
Hardware und teste.

von Peter II (Gast)


Lesenswert?

Hmm schrieb:
> Ich empfehle Dir die Variable ausserhalb jeder Funktion zu deklarieren.
> Entferne das static und füge ein volatile hinzu.

das ist total unsinn. volatil ist hier nicht notwendig und wenn man es 
vermeiden kann macht man keine globalen Variablen!

von Hmm (Gast)


Lesenswert?

>das ist total unsinn. volatil ist hier nicht notwendig und wenn man es
>vermeiden kann macht man keine globalen Variablen!

Wenn ich auch Deine Ausdrucksweise nicht mag: Ich stimme Dir zu, das 
volatile nicht nowendig ist. Ob man globale Variablen vermeidet, ist 
aber Geschmackssache. "Unsinn" ist hier nur das volatile.
Ich finde Du hättest noch eine Begründung hinzufügen sollen. Da Du es 
unterlassen hast, tue ich das für Dich.

volatile ist hier nicht notwendig, weil es nur eine Stelle, nämlich in 
der ISR gibt, in der die Variable geschrieben und gelesen wird. D.h. der 
Compiler trifft auf keine andere Codestelle an der er die Möglichkeit 
hätte einen noch in einem Register gespeicherten Wert der Variablen 
weiterzuverwenden, während er potentiell in der ISR verändert werden 
könnte.

Zur Verwendung oder Nicht-Verwendung von globalen Variablen gibt es eine 
Reihe von Standpunkten mit unterschiedlichem Schwerpunkt.
Z.B. die möglicherweise unbeabsichtigte Verwendung einer Variablen in 
einem Modul, die in einem anderen Modul definiert ist. Wenn man aber die 
Variable auch ein zweites Mal definiert dann gibt es bei den heutigen 
C-Compilern eine Warnung. Trifft hier nicht zu, weil es nur ein Modul 
gibt.
Ob da die Kritik an einer globalen Variable überhaupt angebracht ist, 
bezweifle ich.

von Hermann E. (hermann_e)


Angehängte Dateien:

Lesenswert?

Hier einmal mit ">= 2" und einmal mit ">= 10" zum Vergleich,

muss jetzt los...

von Georg G. (df2au)


Lesenswert?

Schlechte Nachrichten... beide Files funktionieren. Kein Fehler zu 
finden.
Also muss es deine Hardware sein. Kurzschluss zwischen zwei 
Prozessorbeinen?

von Hmm (Gast)


Lesenswert?

Au weia!

von Hermann E. (hermann_e)


Lesenswert?

Wow, Super Georg !

Auch wenn du das als schlechte Nachrichten bezeichnest so schränkt es 
doch die Fehlermöglichkeiten weiter ein und hilft insoweit echt weiter.
Bevor ich weg ging habe ich noch den geposteten File mit Studio 4 
compiliert und aufgespielt - leider ohne Veränderung. Im Licht von 
deinem Bericht ist dies auch kein Wunder - der .Hex scheint ja zu 
stimmen.
Ich schraub jetzt mal den 644A raus und ersetz ihn durch 'nen anderen.

Mehr gleich ..

Hermann

von Hermann E. (hermann_e)


Lesenswert?

Na sowas hab' ich bislang noch nie gesehen.
Ich habe den Atmega644 rausgehebelt und durch einen 8535 ersetzt (im 
gleichen Board). Im Programm musste ich noch TIMSK1 durch TIMSK ersetzen 
da dies der 8535 nicht kennt, compilieren, aufspielen  und siehe da es 
funzt !
Damit kann es auch kein Kurzschluss gewesen sein (hätte eh' keine 
unabhängigen Signale an PD6 und PD7 erlaubt).
m.a.W. das Problem war/ist wahrscheinlich im Atmega644 selbst !
Zum Glück hab ich noch ein ganzes Packet an Atmega644's, ich versuchs 
mal mit dem nächsten...

Als letztes an "Hmm" im Grunde hast du Recht was das "rumspielen" mit 
den
644(A/P etc.) Endungen angeht. Ich muss zu meiner Verteidigung aber 
einwenden dass das Studio4 den 644A nicht in der Liste hat und auch 
Studio6 mir mitgeteilt hat das es den iom644A.h nicht hat; auf meinen 
Chips (Quelle: Radiospares) ist aber ein dickes 644A aufgedruckt !

Gut jetzt geht's ans rumschrauben !

Muchas Grazias: Hermann
Falls alles so geht geb' ich noch ein letztes Update ...

von Hermann E. (hermann_e)


Lesenswert?

dad war's

genauer gesagt der Atmega selbst. Keine Ahnung warum es ihn zersemmelt 
hat und noch weniger warum er noch so getan hat als ob er funktionieren 
würde,
ich dachte ich hatte ihn schonend behandelt.
Es bleibt mir nur noch ein wenig das frustrierende Gefühl dass ich immer 
noch nicht verstehe was da eigentlich im Innern schief lief, aber dazu 
müsste ich wohl jemand von Atmel bestechen um mit deren Methoden das 
Teil zu analysieren (schliesslich arbeite ich ja zur Hälfte für die Uni 
Trondheim wo die ja herkommen)

Klasse, ihr (i.B. Georg und "Hmm" (auch wenn ich mit dem Namen immer 
noch ein Problem habe) wart wirklich ein echte Hilfe !

Jetzt kann's mit meinem Projekt endlich mit Volldampf weitergehen, zumal 
meine Freundin eh' gerade im Flieger nach Paris sitzt.

von Paul Baumann (Gast)


Lesenswert?

Herrmann schrob:

>Jetzt kann's in meinem Projekt endlich mit Volldampf weitergehen zumal
>meine Freundin gerade im Flieger nach Paris sitzt

Hoffentlich hat sie den Lötkolben da gelassen....
;-)
MfG Paul

von Hermann E. (hermann_e)


Lesenswert?

Keine Bange,

sie ist normalerweise eher tolerant was das angeht, da sie aber über 
500km von mir weg wohnt und wir uns nur am WE sehen wird sie manchmal 
etwas ungeduldig wenn ich die wenige Zeit auch noch mit Programmieren 
und Rumschrauben verbringe.
Is ja nachvollziehbar ...

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.