Guten Abend!!!
Ich bin gerade auf ein kleines Problem mit einer Globalen Variable für
eine ISR gestoßen.
Und zwar speichert GCC diese auf dem flash. nun dauert ein einziger
zugriff auf die variable geschlagene 10 zyklen. die isr sollte aber
nicht länger als 20 zyklen dauern. wie kann ich dem compiler sagen, das
er diese in einem register speichern soll? - das attribut "register"
scheint ja nichtmehr zu funktionieren.
und mit dem timer 2 hab ich ein problem mit dem ctc-modus. und zwar
springt das ding direkt nach dem einschreiben in "timsk" in die isr.
nach einigen ähnlichen beiträgen mit vielen tipps zu reihenfolge etc.
pp. komme ich einfach auf keinen grünen zweig. oder liegt hier ein bug
des avr-studios vor? - das gleiche problem hatte ich allerdings auch
schon unter assembler und habe mich damit unschön arrangiert.
dann danke ich euch schonmal und wünsche eine gute nacht.
hier noch ein kleiner codeschnipsel:
1
// für die ISR
2
volatileunsignedcharzaehler_timer2=0;
3
4
// MAIN
5
voidmain(void)
6
7
{
8
/* lcd_init();
9
// Startbildschirm
10
lcd_string("Temperbox-Steuerung");
11
lcd_cursor(0,2);
12
lcd_string("by Toni Krulikowski");
13
lcd_cursor(0,3);
14
lcd_string("Software v1.0");
15
lcd_cursor(0,4);
16
lcd_string("21.09.2010");
17
_delay_ms(4000); // 4 Sekunden warten
18
*/
19
20
uint8_tzeit_aus_timer;
21
//tempsensor ansteuerung
22
//Sensor starten und auf fallende flanke warten
23
DDRB=((1<<PB1)|(1<<PB0));// PB0, PB1 = eingang
24
PORTB|=(1<<PB1);// Sensor einschalten
25
sei();// interrupt frei
26
while((PINB&(1<<PB2)));// warte auf fallende Flanke
27
TCCR2|=(1<<CS00);// dann Timer2 start
28
while(!(PINB&(1<<PB2)));// auf steigende Flanke warten
29
TCCR2&=~(1<<CS00);// Timer2 stopp
30
zeit_aus_timer=(TCNT2-10);// gemessenen wert in Var schreiben
31
zeit_aus_timer>>=1;// x:2
32
OCR2=zeit_aus_timer;// und ins vergleichsregister schieben
33
TCNT2=0;// zählregister nullen
34
TCCR2=((1<<CS00)|(1<<WGM21));// dann Timer2 start und CTC-mode
Toni schrieb:> Und zwar speichert GCC diese auf dem flash.
Die Variable wird vom Startupcode im RAM angelegt. Stichwort .DATA
Variablenbereich. Im Flash ist lediglich der erste Wert (0) mit dem die
Variable initialisiert wird.
Was soll dein Programm machen? Soweit ich sehe, benutzt du den Inhalt
von zaehler_timer2 überhaupt nicht.
Toni schrieb:> Und zwar speichert GCC diese auf dem flash.
Das glaube ich eher nicht. Die liegt im RAM.
> nun dauert ein einziger zugriff auf die variable geschlagene 10 zyklen.
Hast du evtl. vergessen, die Optimierung einzuschalten?
Bei mir braucht der Zugriff nur 5 Zyklen.
> und mit dem timer 2 hab ich ein problem mit dem ctc-modus. und zwar> springt das ding direkt nach dem einschreiben in "timsk" in die isr.
In deinem Code sehe ich keinen Zugriff auf TIMSK oder irgendwelchen
anderen Timer-Setup-Code. Das macht es etwas schwierig, zu ermitteln,
was daran falsch sein könnte. Mein Wahrsager ist gerade im Urlaub ;-)
Übrigens: C ist case-sensitiv, und die meisten Leser hier auch.
Angemessene Verwendung der Shift-Taste wird mit mehr und mit
freundlicheren Antworten belohnt.
Stefan B. schrieb:> Die Variable wird vom Startupcode im RAM angelegt. Stichwort .DATA> Variablenbereich. Im Flash ist lediglich der erste Wert (0) mit dem die> Variable initialisiert wird.
0-initialisierte Variablen landen eigentlich nicht dort, sondern in
.BSS, das beim Starten einfach komplett genullt wird.
Die ISR soll 20 Zyklen dauern:
- Einsprung 4
- Rücksprung 4
- save / restore r1 4
- save / restore SR 6
- save / restore r0 4
-----------------------
Gesamt 22 Zyklen für "Housekeeping".
So geht das nicht.
Bernhard
BTW: Die Anzahl Zyklen pro Instruktion kommen aus meinem Gedächtnis,
nicht aus dem Datenblatt. Sie können also etwas danebenliegen.
Toni schrieb:> und mit dem timer 2 hab ich ein problem mit dem ctc-modus. und zwar> springt das ding direkt nach dem einschreiben in "timsk" in die isr.
Yep.
Was du ignorierst.
Die Vergleiche des OCR Registers mit dem Timer Register finden ständig
statt und nicht nur, wenn du den Interrupt dazu freigibst.
Dein Timer ist davor ja schon gelaufen und das OCR Register wird dort
noch den Wert 0 haben. Den hat aber TCNT2 auch schnell schon mal selber.
Konsequenterweise wird daher das Flag gesetzt, welches den Match
anzeigt, denn es liegt ja tatsächlich einer vor.
Mit dem Interrupt Flag im TIMSK erlaubst du nur, dass ein ISR Aufruf
ausgelöst wird wenn ein Match auftritt. Aber auch dann wenn du das nicht
tust (wie zb bei deiner ersten Timer Verwendung) wird der Match
selbstverständlich registriert.
Tja. Bis du dann den zugehörigen Interrupt freigibst, der natürlich auf
den bereits vorher aufgetretenen Match reagiert.
Guten Morgen!
Ich werde mich bemühen, case-sensitive zu schreiben :)
Zurück zum Thema:
Das Problem mit dem Timer liegt in der vorletzten Zeile von main().
1
TIMSK=(1<<OCIE2);// Timer 2 interrupt
Ab hier springt der debugger direkt in die ISR, weobei schon alle
Register wie OCR usw. geladen sind.
Ich habe schon probiert, das TISMK-Register reltiv mittig zu laden, aber
dann springt er in die ISR, sobald der Timer gestartet wird, blödes Ding
:).
Die Variable zaehler_timer2 wird testweise in der ISR um eins erhöht:
1
ISR(TIMER2_COMP_vect)
2
{
3
zaehler_timer2++;
4
}
Hier ist mir auch aufgefallen, das für diesen Schritt über 10 Zyklen
benötigt werden. Aber wenn er die Var. ins EEPROM schreibt, ist das
natürlich klar.
Wie kann ich nun verhindern, das er diese nichtmehr ins EEPROM schreibt
und dafür ein festes Reigster bereit hält?
Danke nochmal und nen schönen Tag noch.
Ich würde die Interruptroutine in Assembler schreiben, wenn sie so
zeitkritisch ist. Erfahrungsgemäß lässt sich gerade bei so kurzen
Routinen noch eine beträchtliche Anzahl Zyklen sparen (so sichert und
bereitet der Compiler r1 auch dann vor, wenn es gar nicht gebraucht wird
und wenn ich's richtig in Erinnerung habe).
Die Assembler-Routine könnte so aussehen:
1
#include <avr/io.h>
2
.global __vector_4 ; ggfs. anpassen
3
__vector_4:
4
push r24
5
in r24,_SFR_IO_ADDR(SREG)
6
push r24
7
lds r24, zaehler
8
subi r24, -1
9
sts zaehler, r24
10
pop r24
11
out _SFR_IO_ADDR(SREG),r24
12
pop r24
13
reti
Das dürfte in etwa das Minimum für diese Aufgabe darstellen. (Das
Zyklen-Zählen überlasse ich aber Dir).
Toni schrieb:> Hier ist mir auch aufgefallen, das für diesen Schritt über 10 Zyklen> benötigt werden. Aber wenn er die Var. ins EEPROM schreibt, ist das> natürlich klar.> Wie kann ich nun verhindern, das er diese nichtmehr ins EEPROM schreibt> und dafür ein festes Reigster bereit hält?
Troll, es wird nicht ins EEPROM geschrieben.
ouh man, da hatte ich wohl einen kleinen hänger, mit dem Flash meinte
ich natürlich den RAM :)
aber meinen und schreiben sind natürlich 2 paar Schuhe...
Ok, ich werds mal mit Inline-Assembler probieren. Die Timer-Geschichte
werde ich auch noch irgendwie hinbiegen können :).
>> Ab hier springt der debugger direkt in die ISR, weobei schon alle> Register wie OCR usw. geladen sind.
Klar, du musst ja vorher auch die Flags löschen, wie dir Karl Heinz
schon in Beitrag "Re: Problem mit globaler Variable und dem CTC-modus" schrieb.
Also entweder bin ich zu blöd, oder ich sehe einfach schlecht; aber den
scheiß Timer bekomme ich nicht anständig zum laufen...
Obwohl das OCF2 - Flag im TIFR Register von mir gelöscht wurde, spingt
er nach dem setzen des OCIE2 im TIMSK ständig in die ISR, ich könnte
brechen. Egal welche Reihenfolge ich anwende, entweder der TIMSK oder
das starten des Timers löst einen Interrupt aus.
Eigentlich dürfte er doch nur springen, sobald das Flag OCF2 im TIFR
Register gesetzt ist, oder?
An der Hardware habe ich es leider noch nicht getestet.
Einen Code hab ich nun auch nichtmehr, da ich den Timer nun nichtmehr
verwende :) - somit habe ich 2 Fliegen mit einer Klappe geschlagen.
Toni schrieb:> Eigentlich dürfte er doch nur springen, sobald das Flag OCF2 im TIFR> Register gesetzt ist, oder?
Genau deswegen sollst Du das blöde Flag ja auch zurücksetzen, bevor Du
TIMSK anfasst!.
Jörg hat Dir sogar schon die passende Codezeile dafür gepostet.
Toni schrieb:> Obwohl das OCF2 - Flag im TIFR Register von mir gelöscht wurde, spingt> er NACH dem setzen des OCIE2 im TIMSK ständig in die ISR.
Ich habe es doch gelöscht, bevor ich das TIMSK angefasst habe, Mensch.
Laut debugger war/ist es ebenfalls gelöscht.
Obwohl dieses scheiß OCF2 = 0 war, wurde in die ISR gesprungen. Das kann
doch nicht sein?!
Toni schrieb:> An der Hardware habe ich es leider noch nicht getestet.
Sag doch gleich, dass du nur so tust als ob.
Einen solchen "Fehler" in der Simulation nimmt doch niemand ernst.
> Einen Code hab ich nun auch nichtmehr, da ich den Timer nun nichtmehr> verwende :)
Klar, wenn man das Loch für den Zündschlüssel nicht findet, wird das
Auto halt geschoben, auch eine Lösung.