Globala variabler och interrupt
Globala variabler och interrupt
Jag har en liten undran om interrupt och globala variabler.
Jag kör nämligen en timer interrupt för att uppdatera en tickräknare och en interrupt för att sampla värden från AD omvandlaren.
Dessa variabler som uppdateras är globala, så flera andra funktioner kan nå dem samtidigt.
Min fråga är: Finns det någon risk för att det kan bli kollision i processorn när 2 olika processer försöker använda samma variabel ung samtidigt??
Vissa funktioner tar nämligen lite tid (t.ex omvanlding mellan flyttal till string). Finns det risk för att man kan få felaktiga resultat om man inte stänger av interrupten under tiden man använder de globala variablerna??
Mvh/ Daniel Grafström
Jag kör nämligen en timer interrupt för att uppdatera en tickräknare och en interrupt för att sampla värden från AD omvandlaren.
Dessa variabler som uppdateras är globala, så flera andra funktioner kan nå dem samtidigt.
Min fråga är: Finns det någon risk för att det kan bli kollision i processorn när 2 olika processer försöker använda samma variabel ung samtidigt??
Vissa funktioner tar nämligen lite tid (t.ex omvanlding mellan flyttal till string). Finns det risk för att man kan få felaktiga resultat om man inte stänger av interrupten under tiden man använder de globala variablerna??
Mvh/ Daniel Grafström
För det första, det var en liten miss att inte tala om vad det var för processor du talar om. Jag utgår här att det är någon slags enklare processor (PIC, AVR o.s.v.) och inte någon avancerad sak med flera kärnor eller liknande.
> "Dessa variabler som uppdateras är globala, så flera andra funktioner kan nå dem samtidigt."
Nej, nej, aldrig *samtidigt*. Däremot skulle ju den ena rutiner kunna bli avbryten av den andra på ett sätt som inte är "bra" för de globala variablera. Med det är ju enbart om du (som programmerare) tillåter det !
> "Min fråga är: Finns det någon risk för att det kan bli kollision i processorn när 2 olika processer försöker använda samma variabel ung samtidigt?? "
Det beror lite på vad du menar med "kollision", men om du menar att processorn automatiskt skulle "se" att en variabel används från två håll, så är svaret absolut nej. Processorn har inte ens en aning om vilka variabler som är globala eller lokala. De finns bara i det högnivåspråk du använder.
Sen är också frågan vad "ung samtidigt" är...
Och "processorn" vet ingenting om "processer" eller "funktioner", den gör en sak i taget som den blir ombedd om av dig som programmerare.
> " Vissa funktioner tar nämligen lite tid (t.ex omvanlding mellan flyttal till string). Finns det risk för att man kan få felaktiga resultat om man inte stänger av interrupten under tiden man använder de globala variablerna?? "
Ja, det gör det. Om du har en kod snutt där det är kritiskt att inte vissa data ändras plötsligt, så ska/bör interrupten stängas av under tiden.
Obs att detta mycket väl kan vara en *mycket kort* tid, då man t.ex helt enkelt gör en kopia av de globala variablerna. Dessa kopior kan sedan användas utan att de riskerar att ändras även om "originalen" uppdateras.
Det hela beror mycket på vilken grad av "synkning" du behövr mellande olika rutinerna.
Och hur länge som interrupten kan vara avstängda.
Så svaret är väll att använda de globala variablerna så lite och så snabbt som möjligt, samt att stänga av interrupt under tiden (åtminstånde de interrupt som påverkar variablerna, andra kan ju fortfarande få rulla på.)
> "Dessa variabler som uppdateras är globala, så flera andra funktioner kan nå dem samtidigt."
Nej, nej, aldrig *samtidigt*. Däremot skulle ju den ena rutiner kunna bli avbryten av den andra på ett sätt som inte är "bra" för de globala variablera. Med det är ju enbart om du (som programmerare) tillåter det !
> "Min fråga är: Finns det någon risk för att det kan bli kollision i processorn när 2 olika processer försöker använda samma variabel ung samtidigt?? "
Det beror lite på vad du menar med "kollision", men om du menar att processorn automatiskt skulle "se" att en variabel används från två håll, så är svaret absolut nej. Processorn har inte ens en aning om vilka variabler som är globala eller lokala. De finns bara i det högnivåspråk du använder.
Sen är också frågan vad "ung samtidigt" är...
Och "processorn" vet ingenting om "processer" eller "funktioner", den gör en sak i taget som den blir ombedd om av dig som programmerare.
> " Vissa funktioner tar nämligen lite tid (t.ex omvanlding mellan flyttal till string). Finns det risk för att man kan få felaktiga resultat om man inte stänger av interrupten under tiden man använder de globala variablerna?? "
Ja, det gör det. Om du har en kod snutt där det är kritiskt att inte vissa data ändras plötsligt, så ska/bör interrupten stängas av under tiden.
Obs att detta mycket väl kan vara en *mycket kort* tid, då man t.ex helt enkelt gör en kopia av de globala variablerna. Dessa kopior kan sedan användas utan att de riskerar att ändras även om "originalen" uppdateras.
Det hela beror mycket på vilken grad av "synkning" du behövr mellande olika rutinerna.
Och hur länge som interrupten kan vara avstängda.
Så svaret är väll att använda de globala variablerna så lite och så snabbt som möjligt, samt att stänga av interrupt under tiden (åtminstånde de interrupt som påverkar variablerna, andra kan ju fortfarande få rulla på.)
Tack för svaret!
Det är en DSPic processor jag använder.
Jag ska försöka förklara vad jag menar med kollision.
Eftersom en float är på 4byte (enligt C30 kompilatorn) och processorn är på 16 bitar så fixar inte processorn att göra en uträkning på en enda klockcykel. Jag vill inte att min funktion skall börja göra en uträkning och börjar räkna på t.ex de 16 första bitarna och därefter kommer en interrupt och ändrar värdet så att nästa 16 bitar kommer från det nyaste samplade värdet. (hoppas ni hängde med där
)
Jag styr hyffsat långsamma processer (senorn har t.ex en responstid på 6 sek) och behöver inte ha det absolut senaste samplade värdet från AD omvandlaren. Det jag kräver är att funktionen som använder den globala variabeln håller sig till samma värde genom hela uträkningen även om en interrupt skulle avbryta.
Vilka kan felen bli om jag inte stänger av interrupten?
Det är en DSPic processor jag använder.
Jag ska försöka förklara vad jag menar med kollision.
Eftersom en float är på 4byte (enligt C30 kompilatorn) och processorn är på 16 bitar så fixar inte processorn att göra en uträkning på en enda klockcykel. Jag vill inte att min funktion skall börja göra en uträkning och börjar räkna på t.ex de 16 första bitarna och därefter kommer en interrupt och ändrar värdet så att nästa 16 bitar kommer från det nyaste samplade värdet. (hoppas ni hängde med där

Jag styr hyffsat långsamma processer (senorn har t.ex en responstid på 6 sek) och behöver inte ha det absolut senaste samplade värdet från AD omvandlaren. Det jag kräver är att funktionen som använder den globala variabeln håller sig till samma värde genom hela uträkningen även om en interrupt skulle avbryta.
Vilka kan felen bli om jag inte stänger av interrupten?
dsPIC (inte DSPic
)
Kul ! vad använder du för verktyg ? C30 har du sagt, men för programmeringen ?
En fråga, varför kör du med float ?
Är inte det lite overkill för att läsa in ett värde från ADC'n ? Den har väll
bara 10 eller 12 (beroende på vilken dsPIC det är) bitar i alla fall ?
Det finns lite olika "skolor" här, bl.a de som anser att man *aldrig* behöver float i en microcontroller. Generellt sätt, så används float ofta lite av slentrian när man lika gärna (och med betydligt bättre prestanda) skulle kunna köra fixed point.
Nog om det, jag kan ju inte veta om det är genomtänkt eller inte
Problemet är kristallklart, för övrigt.
Om C kompilatorn är smart nog, så borde den se till att interrupt är avstängda medan en float hanteras. Annars får du väll göra det själv.
Mitt tidigare svar byggde på (eftersom det var lite dåligt beskrivet) att du körde assembler och alltså har full koll på allt.
> "Vilka kan felen bli om jag inte stänger av interrupten?"
Det du besriver, att du får en float där ena halvan är från förra avläsningen och den andra från den senaste. Beroende på de aktuella värderna kan du få kraftiga fel om du ligger på et tröskelvärde.
Men, det beror ju även på vad C30 gör åt saken, det måste du fråga C30 om...
Du får nog kolla med C30 dokumentationen, antar jag...

Kul ! vad använder du för verktyg ? C30 har du sagt, men för programmeringen ?
En fråga, varför kör du med float ?
Är inte det lite overkill för att läsa in ett värde från ADC'n ? Den har väll
bara 10 eller 12 (beroende på vilken dsPIC det är) bitar i alla fall ?
Det finns lite olika "skolor" här, bl.a de som anser att man *aldrig* behöver float i en microcontroller. Generellt sätt, så används float ofta lite av slentrian när man lika gärna (och med betydligt bättre prestanda) skulle kunna köra fixed point.
Nog om det, jag kan ju inte veta om det är genomtänkt eller inte

Problemet är kristallklart, för övrigt.
Om C kompilatorn är smart nog, så borde den se till att interrupt är avstängda medan en float hanteras. Annars får du väll göra det själv.
Mitt tidigare svar byggde på (eftersom det var lite dåligt beskrivet) att du körde assembler och alltså har full koll på allt.
> "Vilka kan felen bli om jag inte stänger av interrupten?"
Det du besriver, att du får en float där ena halvan är från förra avläsningen och den andra från den senaste. Beroende på de aktuella värderna kan du få kraftiga fel om du ligger på et tröskelvärde.
Men, det beror ju även på vad C30 gör åt saken, det måste du fråga C30 om...

Du får nog kolla med C30 dokumentationen, antar jag...
Nu är jag kanske lite trög eller annat så jag inte förstår problemet men om du är så rädd bör du göra såhär:
1: stoppa alla interrupt
2: kopiera variablen i fråga till en arbetsvariabel
3: tillåta interrupts igen
4: räkna i lugn o ro med din arbetsvariabel.
Detta förfarande gör att interrupten blir minimalt förskjuten samt ger stor säkerhet.
I den C-kompiler jag använder kan man ge kommandon:
__DI();
och
__EI();
Jag använder dom på enstaka ställen där en interrupt ville vara förödande om den flyttade den ena av de 2 variabler jag fibblar med där och det har fungerat klockrent genom åren.
1: stoppa alla interrupt
2: kopiera variablen i fråga till en arbetsvariabel
3: tillåta interrupts igen
4: räkna i lugn o ro med din arbetsvariabel.
Detta förfarande gör att interrupten blir minimalt förskjuten samt ger stor säkerhet.
I den C-kompiler jag använder kan man ge kommandon:
__DI();
och
__EI();
Jag använder dom på enstaka ställen där en interrupt ville vara förödande om den flyttade den ena av de 2 variabler jag fibblar med där och det har fungerat klockrent genom åren.
Precis !
Som jag skrev i mitt *första* inlägg...
Problemet i sig är väll uppenbart, en standard "race condition" kring en gemensam resurs.
Om det handar om assembler så får man hantera det själv. I detta fall får man undersöka om C30 har något inbyggt skydd kring access av variabler, eller fixa det själv.
Man kan också ha någon slags "flaggor" som visar att resursen är upptagen (ungefär som skylten på dassdörren med "ledig"/"upptaget" på var sida...
).
Som jag skrev i mitt *första* inlägg...

Problemet i sig är väll uppenbart, en standard "race condition" kring en gemensam resurs.
Om det handar om assembler så får man hantera det själv. I detta fall får man undersöka om C30 har något inbyggt skydd kring access av variabler, eller fixa det själv.
Man kan också ha någon slags "flaggor" som visar att resursen är upptagen (ungefär som skylten på dassdörren med "ledig"/"upptaget" på var sida...

Jag håller helt med Icecap. Stäng av interrupt, kopiera till en temporär variabel som du aldrig använder i något interrupt, och slå sedan på interrupt igen.
En annan liknande sak som jag hade huvudbry med var att interruptskalet som är med "default" när du skapar ett nytt projekt i MPLAB och använder en mall (template) sparar inte FSR registret. Jag använde nämligen indirekta registret både i interrupt-rutiner och i övrigt. Detta orsakade mycket konstiga fel ibland, så det var inte uppenbart vad som var fel förräns noggran genomgång av koden.
Mats
En annan liknande sak som jag hade huvudbry med var att interruptskalet som är med "default" när du skapar ett nytt projekt i MPLAB och använder en mall (template) sparar inte FSR registret. Jag använde nämligen indirekta registret både i interrupt-rutiner och i övrigt. Detta orsakade mycket konstiga fel ibland, så det var inte uppenbart vad som var fel förräns noggran genomgång av koden.
Mats
Jag ska stänga av interrupten. Men nu är jag mer nyfiken på vilka typer av fel man kan få om man inte gör det
>>Kaggen, jag förstod inte riktigt din beskrivning av problemet..
FSR registret, är det FlagStatusRegister?
Såhär ser min interrupt funktion ut, säg gärna till om du ser några fel
Jag använder MPlab tillsammans med C30 när jag skriver min C-kod till dsPICen (Märk stavningen! man lär sig nått nytt varje dag
)
Det där med fixed point beräkningar verkar intressant. Det verkar gå mycket snabbare. Klockade mina flyttals beräkningar till ca 500 klockcykler på en rads uträkningar.
Anledningen till att jag använder flyttal är att jag inte lyckades räkna fram något vettigt värde med hjälp av heltal.
Har ni något exempel på hur man kan göra det smidigare, så är jag idel öga!
eller är det bara att skriva om det som:
Och få resultatet en faktor på 1000 ggr större?
jag hade helst viljat få mitt beräknade tal med 2 decimaler
ex: po2 = 1.42;
Jag behöver mina stora konstanter för att inte resultatet på uträkningen skall driva iväg.

>>Kaggen, jag förstod inte riktigt din beskrivning av problemet..
FSR registret, är det FlagStatusRegister?
Såhär ser min interrupt funktion ut, säg gärna till om du ser några fel
Kod: Markera allt
void __attribute__((__interrupt__, __shadow__)) _T5Interrupt(void)
{
(*iTicks)++; //step time
IFS1bits.T5IF = 0; //clear flag
}
Jag använder MPlab tillsammans med C30 när jag skriver min C-kod till dsPICen (Märk stavningen! man lär sig nått nytt varje dag

Det där med fixed point beräkningar verkar intressant. Det verkar gå mycket snabbare. Klockade mina flyttals beräkningar till ca 500 klockcykler på en rads uträkningar.
Kod: Markera allt
po2 = 0.0449*(float)t1[0]+8.7860;
Har ni något exempel på hur man kan göra det smidigare, så är jag idel öga!
eller är det bara att skriva om det som:
Kod: Markera allt
po2 = (449*t1[0]+87860 );
jag hade helst viljat få mitt beräknade tal med 2 decimaler
ex: po2 = 1.42;
Jag behöver mina stora konstanter för att inte resultatet på uträkningen skall driva iväg.
Mycket här... 
(Notera att Kaggen sannolikt *inte* talar om en dsPIC...)
Sedan, dsPIC'en är så pass annorlunda än de "vanliga" PIC16/PIC18 modellerna, och jag skulle gissa att det inte är många här (inkl mig) som har skrivit något kod för dom. Jag har i alla fall *läst* på lite om dom...
OK, så med det sagt kör vi vidare...
> "Klockade mina flyttals beräkningar till ca 500 klockcykler"
Det är nog rimligt för floating point. Fixed point kommer att gå på allt från ett par cyckler (för 16 bit prec) till ett tiotal (för 32 bit prec).
> "Anledningen till att jag använder flyttal är att jag inte lyckades räkna fram något vettigt värde med hjälp av heltal."
Ja, *heltal* är något annat en "fixed point". Det hela handlar om att skala sina värden och att tänka sig decimalpunkten på ett lämpligt ställe, allt eftersom vad applikationen kräver.
> "po2 = (449*t1[0]+87860 );"
Svårt att säga något om när man inte vet vad t.ex "449" och "87860" står för.
> "Jag hade helst viljat få mitt beräknade tal med 2 decimaler ex: po2 = 1.42; "
*DU* ja !!
PICen har inte en aning om vad decimaler är !! Den kan lika gärna räkna med 142 eller i princip vad som helst, bara *du* vet hur det skall konverteras vid presentationen (t.ex på LCD eller liknande).
Och dessutom, vad är po2 ? Motsvarar "1.42" någonting i verkligheten ? T.ex "1.42 dm", "1.42 Kg" eller något liknande liknande ?
Det är inte alls säkert att det är optimalt att hela tiden försöka representera de verkliga värderna med exakt samma siffror i applikationen. Det är ju bara vid t.ex en presentation på en LCD (bara som exempel!) som det behöver stå "1.42 Kg". Sedan spelar det ju ingen roll om 1.42 är lagrat som 142, 1420, 387 eller i princip vad som helst i applikationen. Det beror på vad som är effektivast att hantera/bearbeta.
Genom att tala om "decimaler" försöker du föra in begrepp som en PIC/dsPIC i alla fall inte har en aning om vad det är ! Spara alla "decimaler" till det är dags för presentation (eller överföring till andra system).
Så, för att sammanfatta, så handlar det till stor del om att göra en analys av de verkliga egenskaper som man vill representera i applikationen. Vilken spännvidd (t.ex 0-50 deg C) har de ? Vilken upplösning (t.ex 0.5 deg C) behöver jag ? Då kanske det är enklast att låta 0 deg C = 0 och 50 deg C = 100.
Sedan får man även ta hänsyn till ackumulerade fel (det du kallar "driva iväg", men float är inte bättre en fixed point på den punkten. Skillnaden är bara att man själv i förväg måste bestämma var (den tänkta) decimalpunkten skall vara, floating point har en viss automatik för detta. Däremot ger floating point en del svårberäknerliga avrundnings fenomen. Kom ihåg att ett floating point värde nästan *alltid* är ett avrundat närmevärde, det ligger liksom i definitionen av dom...
Nu får det vara bra...

(Notera att Kaggen sannolikt *inte* talar om en dsPIC...)
Sedan, dsPIC'en är så pass annorlunda än de "vanliga" PIC16/PIC18 modellerna, och jag skulle gissa att det inte är många här (inkl mig) som har skrivit något kod för dom. Jag har i alla fall *läst* på lite om dom...

OK, så med det sagt kör vi vidare...
> "Klockade mina flyttals beräkningar till ca 500 klockcykler"
Det är nog rimligt för floating point. Fixed point kommer att gå på allt från ett par cyckler (för 16 bit prec) till ett tiotal (för 32 bit prec).
> "Anledningen till att jag använder flyttal är att jag inte lyckades räkna fram något vettigt värde med hjälp av heltal."
Ja, *heltal* är något annat en "fixed point". Det hela handlar om att skala sina värden och att tänka sig decimalpunkten på ett lämpligt ställe, allt eftersom vad applikationen kräver.
> "po2 = (449*t1[0]+87860 );"
Svårt att säga något om när man inte vet vad t.ex "449" och "87860" står för.
> "Jag hade helst viljat få mitt beräknade tal med 2 decimaler ex: po2 = 1.42; "
*DU* ja !!
PICen har inte en aning om vad decimaler är !! Den kan lika gärna räkna med 142 eller i princip vad som helst, bara *du* vet hur det skall konverteras vid presentationen (t.ex på LCD eller liknande).
Och dessutom, vad är po2 ? Motsvarar "1.42" någonting i verkligheten ? T.ex "1.42 dm", "1.42 Kg" eller något liknande liknande ?
Det är inte alls säkert att det är optimalt att hela tiden försöka representera de verkliga värderna med exakt samma siffror i applikationen. Det är ju bara vid t.ex en presentation på en LCD (bara som exempel!) som det behöver stå "1.42 Kg". Sedan spelar det ju ingen roll om 1.42 är lagrat som 142, 1420, 387 eller i princip vad som helst i applikationen. Det beror på vad som är effektivast att hantera/bearbeta.
Genom att tala om "decimaler" försöker du föra in begrepp som en PIC/dsPIC i alla fall inte har en aning om vad det är ! Spara alla "decimaler" till det är dags för presentation (eller överföring till andra system).
Så, för att sammanfatta, så handlar det till stor del om att göra en analys av de verkliga egenskaper som man vill representera i applikationen. Vilken spännvidd (t.ex 0-50 deg C) har de ? Vilken upplösning (t.ex 0.5 deg C) behöver jag ? Då kanske det är enklast att låta 0 deg C = 0 och 50 deg C = 100.
Sedan får man även ta hänsyn till ackumulerade fel (det du kallar "driva iväg", men float är inte bättre en fixed point på den punkten. Skillnaden är bara att man själv i förväg måste bestämma var (den tänkta) decimalpunkten skall vara, floating point har en viss automatik för detta. Däremot ger floating point en del svårberäknerliga avrundnings fenomen. Kom ihåg att ett floating point värde nästan *alltid* är ett avrundat närmevärde, det ligger liksom i definitionen av dom...
Nu får det vara bra...