Hi,
ich habe ein kleines aber lästiges Problemchen...
folgender ISR-Code liest einen Rotary-encoder aus:
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
4
#include"globals.h"
5
#include"abstractions.h"
6
7
#include"ui/ui.h"
8
9
volatileuint8_ttest=0;
10
ISR(INT0_vect){// SIG_A from encoder
11
LED_TOG
12
if(SIG_A){
13
if(SIG_B){
14
g_ui_cursor++;
15
test+=1;/// NOTE: DEBUG
16
uart_putc('a');/// NOTE: DEBUG
17
g_ui_status|=uistat_CursorINC;
18
}else{
19
g_ui_cursor--;
20
test-=1;/// NOTE: DEBUG
21
uart_putc('b');/// NOTE: DEBUG
22
g_ui_status|=uistat_CursorDEC;
23
}
24
}else{
25
if(SIG_B){
26
g_ui_cursor--;
27
test-=1;/// NOTE: DEBUG
28
uart_putc('c');/// NOTE: DEBUG
29
g_ui_status|=uistat_CursorDEC;
30
}else{
31
g_ui_cursor++;
32
test+=1;/// NOTE: DEBUG
33
uart_putc('d');/// NOTE: DEBUG
34
g_ui_status|=uistat_CursorINC;
35
}
36
}
37
38
uart_putc((char)test);/// NOTE: DEBUG
39
uart_puts("\n");/// NOTE: DEBUG
40
}
Dabei soll die globale Variable g_ui_cursor (volatile int8_t) erhöht
oder vermindert werden. Das Erkennen der Richtung etc. funktioniert
alles, das LED_TOG Makro lässt auch mit jedem Schritt des Encoders meine
LED toggeln.
Das Problem ist, dass g_ui_cursor nur bis +16 (manchmal auch nur bis
+15) inkrementiert, und dann wieder bei 0 zurückgesetzt wird, statt bis
+127 weiterzuzählen.
Ich dachte mir es könnte an der etwas komplexen (und zugegebenermaßen
verbogenen) Variablendeklaration liegen, die in einer anderen .c-Datei
als volatile uint_8 definiert, aber in einem header-file als extern
uint8_t deklariert wird. Daher habe ich eine extra zu debugzwecken
definierte volatile uint8_t Variable in der ISR-Datei eingefügt, mit der
das Problem aber genauso auftritt. Es schient, als würden nur mit den
unteren 4 Bit der Variable gezählt, was ja eigentlich keinen Sinn macht.
Mit der extra Testvariable habe ich auch das
'es-könnte-auch-anderer-code-auf-den-Speicher-zugreifen'-Problem
ausgeschaltet, denn die test-Variable wird nur und ausschließlich in der
ISR verwendet (habe gesamtes Projekt durchsucht!).
Ich habe das Programm dann mal ohne optimization (vorher -Os)
compiliert, woraufhin das Problem auf wundersame Weise verschwand.
Ich verwende den AVR Toolchain von Atmel:
1
C:\avrtoolchain\bin>avr-gcc --version
2
avr-gcc (AVR_8_bit_GNU_Toolchain_3.4.2_939) 4.7.2
3
Copyright (C) 2012 Free Software Foundation, Inc.
4
This is free software; see the source for copying conditions. There is NO
5
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Das Witzige ist, dass wenn ich den guten alten WinAVR von 2010 zum
Compilieren verwende, der Code auch mit -Os funktioniert.
...was ist da denn jetzt das Problem ?!
Ich danke euch,
73 Tobi
Tobias Schlegel schrieb:> Das Witzige ist, dass wenn ich den guten alten WinAVR von 2010 zum> Compilieren verwende, der Code auch mit -Os funktioniert.
Tja, mitlerweile haben wir das Jahr 2014 und dinge haben sich
weiterentwickelt, so auch der compiler.
Tobias Schlegel schrieb:> optimization + volatile = Problem
volatile schließt praktisch jede optimierung durch den compiler für
diese variable aus! Ergo, kann es da auch kein Problem geben!
Was sind SIG_A und SIG_B?
Tobias Schlegel schrieb:> Mit der extra Testvariable habe ich auch das> 'es-könnte-auch-anderer-code-auf-den-Speicher-zugreifen'-Problem> ausgeschaltet, denn die test-Variable wird nur und ausschließlich in der> ISR verwendet (habe gesamtes Projekt durchsucht!).
Nö, hast du nicht.
Nur weil die Variable nur an dieser Stelle verwendet wird, heißt das ja
nicht, das da sonst niemand an diese Speicheradresse schreiben könnte.
Tobias Schlegel schrieb:> Das Problem ist, dass g_ui_cursor nur bis +16 (manchmal auch nur bis> +15) inkrementiert, und dann wieder bei 0 zurückgesetzt wird, statt bis> +127 weiterzuzählen.inc schrieb:> Woher weißt du das?Tobias Schlegel schrieb:> uart_putc((char) test); /// NOTE: DEBUG> uart_puts("\n"); /// NOTE: DEBUG
Debugging mittels printf...tja, zur not frisst der Teufel fliegen.
Tobias Schlegel schrieb:> ...was ist da denn jetzt das Problem ?!
Ist echt nicht böse gemeint, aber:
Das du offenischtlich keinen Debugger hast,... ist ja auch voll unnötig
und uncool. Damit könnte man ja in den Speicher gucken, den
Programmablauf anhalten usw. und Problem viel leichter finden... aber
wer will das schon.
Ich behaupte mal ganz dreist, das Problem liegt in Code, den wir hier
nicht zu sehen bekommen... so wie is in 99% der Fälle der fall ist, in
denen gerne dem Compiler die Schuld in die schuhe geschoben wird.
Böser Compiler aber auch... und leg dir einen ordentlichen programmer
zu, dann kannst du auch gleich debuggen, z.B. den Atmel JTAG-ICE3 oder
gleich den Atmel-ICE. Richtig, kosten geld die Dinger, dafür spart man
zeit.
Tobias Schlegel schrieb:> Ich dachte mir es könnte an der etwas komplexen (und zugegebenermaßen> verbogenen) Variablendeklaration liegen, die in einer anderen .c-Datei> als volatile uint_8 definiert, aber in einem header-file als extern> uint8_t deklariert wird.
Das ist Hack. Das sollte einen Fehler vom Compiler geben weil sich
Definition und Deklaration widersprechen. Wenn es keinen Fehler gibt
dann trifft mindestens einer der folgenden Punkte zu:
- es stimmt was mit deinen Headern / Includes nicht
- du verwendest zwei unterschiedliche Variablen gleichen Namens (z.B.
eine static)
- dein Code hat Undefined Behaviour
> Ich habe das Programm dann mal ohne optimization (vorher -Os)> compiliert, woraufhin das Problem auf wundersame Weise verschwand.> Ich verwende den AVR Toolchain von Atmel:
Nachdem man den Zoo von benötigten Makros und Deklarationen nachgeflickt
hat, so daß sich der Code übersetzen lässt, erzeugen folgende Compiler
mit -Os -mmcu=atmega168 exakt den gleichen Code:
- avr-gcc 4.3.3 (WinAVR-20100110)
- avr-gcc 4.6.3
- avr-gcc 4.7.2
- avr-gcc 4.8.0
- avr-gcc 4.9.2
Wie in 99% der Fälle liegt das Problem nicht im gezeigten Code —
bestenfalls evtl. darin, daß durch das Debug-Geraffel die ISR zu lange
dauert, daher rekursiert, daher der RAM ausgeht, daher Unsinn passiert
bzw. der µC resettet und nicht weiter kommt als 16.
Erste Hausaufgabe ist, den Code aufzuräumen und die "etwas komplexen
(und zugegebenermaßen verbogenen) Variablendeklaration" zu korrigieren.
Weiters ist sicherzustellen, daß der Encoder adäquat entprellt ist.
Ansonsten gibt's eine Flut von ISRs mit o.g. Folgen.
Hi,
Peter II schrieb:> was kommen denn für ausgaben wenn das Programm läuft?
Ich habe gerade für die Ausgabe das Problem zu reproduzieren versucht
und den (gleichen) Code nochmal mit dem AVR-Toolchain und -Os
compiliert. Eigentlich habe ich ja das selbe Spielchen erwartet,
allerdings war das Zählen diesmal komplett wild und konfus. Das habe ich
dann zum Anlass genommen, das Problem doch wo anders zu suchen und die
Hardware nochmals in Augenschein zu nehmen. Es scheint, als sei die
Stromversorgung über den Programmer das Problem gewesen, über ein
Labornetzteil funktioniert der Code jetzt tadellos. Ich habe da auch
schon einen Verdacht... (wobei man eigentlich schon erwarten könnte,
dass ein LT1117-3.3 auf dem Programmer 80mA 3,3V liefern kann...)
Trotzdem interessant, dass man mit dem Optimizing die Hardwarestabilität
beeinflussen kann.
Trotzdem Vielen Dank für eure Mühe!
Tobi
Hi,
Johann L. schrieb:> Das ist Hack. Das sollte einen Fehler vom Compiler geben weil sich> Definition und Deklaration widersprechen.
Stimme ich dir voll und ganz zu. Wenn du mir sagst, wie ich eine globale
Variable volatile deklarieren kann, sodass ich sie in meinen restlichen
20 c-Files benutzen kann ohne davon einen vom Compiler übergezogen zu
bekommen mache ich es so!
Johann L. schrieb:> Nachdem man den Zoo von benötigten Makros und Deklarationen nachgeflickt> hat, so daß sich der Code übersetzen lässt
Tut mir leid; das Projekt hat ca. 1000 Zeilen reinen Code und ca. 4000
Zeilen insgesamt, verteilt auf 29 Files. Ich wollte es so übersichtlich
wie möglich halten.
Johann L. schrieb:> Weiters ist sicherzustellen, daß der Encoder adäquat entprellt ist.> Ansonsten gibt's eine Flut von ISRs mit o.g. Folgen.
Es scheint als hätte eines meiner RC-Glieder am Encoder irgendwo einen
Kurzschluss nach GND; ein Kontakt braucht nämlich ca. 10mA mehr Strom
als der andere...
Tobias Schlegel schrieb:> Johann L. schrieb:>> Das ist Hack. Das sollte einen Fehler vom Compiler geben weil sich>> Definition und Deklaration widersprechen.>> Stimme ich dir voll und ganz zu. Wenn du mir sagst, wie ich eine globale> Variable volatile deklarieren kann, sodass ich sie in meinen restlichen> 20 c-Files benutzen kann ohne davon einen vom Compiler übergezogen zu> bekommen mache ich es so!
1) In dem Modul, zu dem die Variable / Funktion natürlicherweise gehört,
wird sie definiert / implementier.
2) In den zum Modul gehörenden Header kommt die Deklaration bzw.
Prototyp.
3) Alle Module, die die Variable / Funktion benötigen, includen diesen
Header.
Und das ist unabhängig davon, ob es eine Variable ist oder eine Funktion
oder volatile oder nicht.
Wenn 20(!) C-Module die gleiche volatile-Variable brauchen scheint was
konzeptionell nicht zu stimmen.
Tobias Schlegel schrieb:> Johann L. schrieb:>> Das ist Hack. Das sollte einen Fehler vom Compiler geben weil sich>> Definition und Deklaration widersprechen.>> Stimme ich dir voll und ganz zu. Wenn du mir sagst, wie ich eine globale> Variable volatile deklarieren kann, sodass ich sie in meinen restlichen> 20 c-Files benutzen kann ohne davon einen vom Compiler übergezogen zu> bekommen mache ich es so!
Ich verstehe nicht, wo das Problem sein soll. Das geht ganz genauso wie
mit einer nicht-volatile-Variablen, nur daß eben volatile vor dem Typ
steht. Bei der Definition bekommst du das doch auch hin.
Tobias Schlegel schrieb:> volatile uint8_t test = 0;
Deklaration:
Johann L. schrieb:> 1) In dem Modul, zu dem die Variable / Funktion natürlicherweise gehört,> wird sie definiert / implementier.>> 2) In den zum Modul gehörenden Header kommt die Deklaration bzw.> Prototyp.>> 3) Alle Module, die die Variable / Funktion benötigen, includen diesen> Header.
Ja. So ist das ja auch umgesetzt...
Rolf Magnus schrieb:> Deklaration:extern volatile uint8_t test;
...und so ist es auch konform finde ich.
Ich glaube nur mich dunkel zu erinnern dass das mir mal eine Warning
eingebracht hat, kann aber auch sein dass ich mich da täusche.
Johann L. schrieb:> Wenn 20(!) C-Module die gleiche volatile-Variable brauchen scheint was> konzeptionell nicht zu stimmen.
Es sind natürlich nicht 20, ich wollte nur die Pluralität
unterstreichen. Es sind unterm Strich vllt. 2..3 (je nach dem was ich
mir noch einfallen lasse).
Nur mal so nebenbei: gibt es nicht gut funktionierende
Software-Entprellung für Drehgeber? Ich kann ja verstehen, daß man gern
alles selber schreiben will, aber mal anschauen ist nicht verboten.
http://www.mikrocontroller.net/articles/Drehgeber