Sida 1 av 2

Kan inte skriva till en global variabel i ISR. C. ATMega48.

Postat: 11 oktober 2010, 16:13:46
av StRob
Varför kan jag inte skriva till en global "unsigned char" i avbrottet för TIMER1 Capture?
Jag har variabeln, MeasurementStatus, som flaggregister, där bit0 falggar för fel i mätningen, bit1 flaggar för att en ny mätning gjorts. Och i ISR (Interrupt Service Routine) vill jag sätta just biten som flaggar för att en ny mätning gjorts.
Så här ser de relevanta delarna av koden ut:

Kod: Markera allt

//Globala variabler och definitioner
#define NEW_MEASUREMENT 0b00000010
unsigned char MeasurementStatus = 0;

//ISR:
ISR(TIMER1_CAPT_vect)	//Rising edge on ICP1-pin (Flow Sensor Pulses) detected
{
	TCNT1 = 0;	//Clear Timer1 (16bit) for the following measurment
	MeasurementStatus |= NEW_MEASUREMENT;		//Flag for a complete period time measurment
//	PORTB ^= (1<<PORTB2);			             //BARA TESTRAD FÖR FELSÖKNING!! FUNGERAR DOCK!
}

//I main():
	if(MeasurementStatus & NEW_MEASUREMENT)			//Is the NEW_MEASUREMENT flag bit set from ISR?


Jag har provat att sätta en annan global variabel (unsigned char temp) temp = 1; i ISR och sedan bara kollat if(temp) i main, men den köper inte det heller!
Jag ser ju på togglingen (det som är bortkommenterat i ISR) att avbrotten fungerar fint, exakt när de ska, så ISR körs ju uppenbarligen!
Och jag har testat att sätta en negation i if(!temp) och då körs den ju så jag tycker att det är uppenbart att det är skrivningen av variabeln i ISR som inte fungerar, men varför???
Vad missar jag?? Jag har läst i databladet för ATM48 om interrupt och jag hittar iaf inget om detta..

Re: Kan inte skriva till en global variabel i ISR. C. ATMega

Postat: 11 oktober 2010, 16:25:52
av E85
Prova deklarera den som volatile, dvs "volatile unsigned char variabel;"

Re: Kan inte skriva till en global variabel i ISR. C. ATMega

Postat: 11 oktober 2010, 16:53:30
av jesper

Re: Kan inte skriva till en global variabel i ISR. C. ATMega

Postat: 12 oktober 2010, 09:12:30
av StRob
på länken ovan kan man läsa: "The problem is that the compiler has no idea that etx_rcvd can be changed within an ISR. As far as the compiler is concerned, the expression !ext_rcvd is always true, and, therefore, you can never exit the while loop. Consequently, all the code after the while loop may simply be removed by the optimizer." Men tittar man i lss-filens assemblerkod så hittar man i ISR:

Kod: Markera allt

	MeasurementStatus |= INVALID_MEASUREMENT;		//Flag for lost contact to sensor (Sensor freq to low)
  bc:	80 91 05 01 	lds	r24, 0x0105
  c0:	81 60       	ori	r24, 0x01	; 1
  c2:	80 93 05 01 	sts	0x0105, r24
Så den har alltså inte tagit bort koden iaf.. Skall givetvis testa ändå!
Och bra att det nämndes, för det hade jag glömt sen skoltiden :wink:

Re: Kan inte skriva till en global variabel i ISR. C. ATMega

Postat: 12 oktober 2010, 09:30:41
av sodjan
Att optimera bort kod syftade nog på main(), inte på en ISR.

Re: Kan inte skriva till en global variabel i ISR. C. ATMega

Postat: 12 oktober 2010, 10:02:28
av StRob
Jaha, just det. Så lär det nog vara ja..
Det fungerade med volatile iaf!
i ISR ändrade den adressen från 0x0105 till 0x0100. Main tittade jag inte på då jag fått för mig att det var själva skrivningen av variabeln som inte fungerade. Så artade sig ju felet. Men ack så galet det kan bli.
Nyttig läxa hur som! :)

Re: Kan inte skriva till en global variabel i ISR. C. ATMega

Postat: 12 oktober 2010, 10:49:58
av StRob
Jag fick samma fel när jag försökte skriva in en define i en global variabel. denna kodrad låg alltså i main() direkt efter initieringen:
unsigned int i = TIMER1_FLOW_LIMIT;
men la jag till volatile innan så fungerar det utmärkt. Ska jag alltid ha volatile på mina variabler alltså?

I texten i länken vi tidigare nämnde står det:
"C's volatile keyword is a qualifier that is applied to a variable when it is declared. It tells the compiler that the value of the variable may change at any time--without any action being taken by the code the compiler finds nearby."

Jag tolkar det som att variabeln kan då ändras när som helst utan att kompilatorn ska bry sig om närliggande kod. Är inte det vanliga kriterier för en global variabel? Kan någon komma med någon bra tumregel om när den ska deklareras som volatile? Kan man alltid använda volatile, eller vad får det för konsekvenser?

Re: Kan inte skriva till en global variabel i ISR. C. ATMega

Postat: 12 oktober 2010, 11:04:14
av AndLi
En global variabel kan inte ändra sig hur som helst, om den inte påverkas via en interrupt (eller via någon form av DMA, eller mappar en HW port) och då ska den vara volatile deklarerad.

Kompilatorn borde kunna ha rätt bra koll på hur den kommer ändras om den inte styrs via interrupt. Har du två funktioner som använder samma globala variabel kan ju kompilatorn räkna ut när den kommer att ändra sig och den behöver lägga in den i något register för att använda den till något. Så att volatile deklarera i onödan kan leda till sämre optimering då kompilatorn varje gång den ska använda den måste kopiera den från minnet.

Re: Kan inte skriva till en global variabel i ISR. C. ATMega

Postat: 12 oktober 2010, 11:28:37
av StRob
Okej. Låter logiskt.
Det sista problemet jag beskrev är endast relaterat till när man stegar genom programmet utan hänsyn till hårdvara. JAg kan inte se registret om jag inte skriver volatile. tycker det borde gå eftersom jag bara skriver in ett värde till det och det är en global char så "Watch-funktionen" borde se den. men "location not valid" får jag i value-fältet. trist men det är ju en värdslig sak.

Off topic: Kan någon rekomendera en bra debugger för AVR? Mega48 i huvudsak.

Re: Kan inte skriva till en global variabel i ISR. C. ATMega

Postat: 12 oktober 2010, 11:34:25
av AndLi
Det låter som att kompilatorn har optimerat runt med din globala variabel...

HW eller SW delen av debuggern? Kör själv Win AVR kitet och en jtagicemkII

Re: Kan inte skriva till en global variabel i ISR. C. ATMega

Postat: 12 oktober 2010, 13:41:35
av SvenW
[JAg kan inte se registret om jag inte skriver volatile.
unsigned char MeasurementStatus = 0;
Kompilatorn vet alltså att MeasurementStatus alltid är noll och därmed kan den optimeras bort. Kompilatorn är smart.
Men kompilatorn tar en funktion i taget och vet inget om att variabeln ändras i IRS när main() kompileras och vice versa.
Variabeln finns alltså inte heller i debuggern.
rekomendera en bra debugger för AVR? Mega48 i huvudsak.
Jag kör med avr-gdb och gnu toolchain. Fungerar alltid perfekt, i alla fall i Linux.

Re: Kan inte skriva till en global variabel i ISR. C. ATMega

Postat: 12 oktober 2010, 14:06:02
av AndLi
SvenW: det stämmer om variabeln inte används i koden, men även en rad som "unsigned char MeasurementStatus;" hade blivit borttagen av kompilatorn om den inte används i koden...

Man kan ju lägga till några MeasurementStatus++ och -- också och den blir fortfarande bortplockad... När den börjar användas i div if statement och dylikt kan man vara ganska säker på att den finns kvar.. Så att använda MeasurementStatus och bara sätta vilket mode den är i just nu och sen försöka använda den vid debugging lär inte ge önskat resultat...

Re: Kan inte skriva till en global variabel i ISR. C. ATMega

Postat: 12 oktober 2010, 14:19:15
av SvenW
AndLi,
Nja, jag har för mig att kompilatorn brukar plocka bort det mesta som inte har verkan. Men det kan bero på kompilator och version och givetvis vilken optimeringsflagga man använder.

Jag ville bara betona att kompilatorer ofta är smartare än man kan föreställa sig, vilket många gånger leder till problem både för nybörjare och andra.
Speciellt vid debuggning.

Re: Kan inte skriva till en global variabel i ISR. C. ATMega

Postat: 12 oktober 2010, 14:44:34
av AndLi
svenW. Ja, debugging med optimerad kod kan vara spännande, ofta försöker jag köra utan optimering påslagen då, vilket såklart ibland fixar buggen då det påverkar hela timeingen i koden...

Re: Kan inte skriva till en global variabel i ISR. C. ATMega

Postat: 12 oktober 2010, 15:26:58
av vfr
Precis så! Får man problem med kod genererad av en kompilator (i motsats till assembler), så ska man alltid prova att kompilera utan optimeringar först. Får man då skillnader, så är det läge att kolla närmare på såna saker.