Problem med AVR

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
nodanolo
EF Sponsor
Inlägg: 90
Blev medlem: 25 mars 2009, 23:05:38
Ort: Järfälla

Problem med AVR

Inlägg av nodanolo »

Någon som har en hjärna till övers? För min egen verkar inte fungera...

Bygger en batteritestare för 24V. Den lägger på en konstant last tills polspänningen understiger ett visst värde som jag kallar 'CutOffVoltage', varvid testet är klart och avslutas.

Processorn är en ATMEAG168 programmerad med ICCAvr v8.

CurrentValues[CurrentVoltage] innehåller polspänningen i mV och uppdateras via interupt ett antal gånger per sekund.
CurrentValues[CurrentTime] innehåller det antal minuter testet pågått och uppdateras via interup varje hel minut.
TestSetup[] innehåller de testparametrar jag vill att testaren skall använda sig av. Dessa laddas ner innan testet påbörjas. TestSetup[CutOffVoltage] ligger på 20400 mV

Jag vill att polspänningen skall understiga 'CutOffVoltage' minst en minut i sträck för att testet skall avslutas.

Kod: Markera allt

#define CurrentVoltage 9
#define CutOffVoltage 8
#define CurrentTime 2

unsigned int TempTime;
unsigned int CurrentValues[18];
unsigned int TestSetup[30];

main(void)
{
...
...
...
if(CurrentValues[CurrentVoltage] > TestSetup[CutOffVoltage])
  TempTime = CurrentValues[CurrentTime]; 
...
...
...
if(CurrentValues[CurrentTime] > TempTime + 2)
  //Skriv ut CurrentValues[CurrentTime], CurrentValues[CurrentVoltage] och TempTime och gå därefter till klart.

}
Problemet är att var tionde till femtonde test så går testaren till klart för tidigt, dvs. innan polspänningen understiger 'CutOffVoltage'.
De värden som skrivs ut kan typiskt vara "CurrentValues[CurrentTime]= 512 CurrentValues[CurrentVoltage]=23890 TempTime=511

Så vitt min defekta hjärna anbelangar så borde inte '512 > 511+2' utvärdera som sant...någonsin....eller???

Alla gånger det faktiskt fungerar som jag tänkt mig så ligger värdena typiskt som "CurrentValues[CurrentTime]= 560 CurrentValues[CurrentVoltage]=20983 TempTime=557", dvs. 3 minuter mellan CurrentValues[CurrentTime] och TempTime.

Det som är lite intressant är att de gånger det inte fungerar så är CurrentValues[CurrentTime] = 256 eller 512 eller 1024. Det kan inte vara en slump. Jag har observerat problemet ett tiotal gånger och det har följt detta mönster VARJE gång.

De flesta test jag kört så har testet pågått till runt 1000 minuter, alltså passerat både 256, 512 minuter utan problem. En del tester har också passerat 1024, och inte haft några problem med det.

Jag lurar på att eftersom det är relativt sällan som det inte fungerar så kanske det är så att det går åt skogen om interupten går in och ökar CurrentValues[CurrentTime] efter att TempTime tilldelats men före jämförelsen "if(CurrentValues[CurrentTime] > TempTime+2)" eftersom det alltid skiljer 1 minut mellan CurrentValues[CurrentTime] och TempTime på utskriften i de fall det inte fungerar.

Kollade manualen för ICCAvr och naturligtvis står det att '+' har högre prioritet än '>'.

Visst skulle jag kunna testa mig fram som man brukar göra, men det blir lite tidsödande efter som jag kommer att få köra i genomsnitt 7-10 test innan felet uppenbarar sig, och varje test bör gå åtminstone 1030 minuter. Sedan måste batterierna laddas upp igen mellan varje test vilket kommer att göra att provkörningen efter varje programändring kommer att ta åtminstone en vecka.
Man skulle kanske kunna göra något "snabbprogram", men jag tycker det är en bättre lösning att faktiskt reda ut vad som händer.


Så, vart har jag klantat till det?

Edit: Ändrade 'temptime' till 'TempTime'
Senast redigerad av nodanolo 25 januari 2014, 15:25:51, redigerad totalt 1 gång.
void
Inlägg: 119
Blev medlem: 8 juli 2007, 11:06:50
Ort: Enköping

Re: Problem med AVR

Inlägg av void »

Vet inte om det är ditt problem men C är skiftläges-känsligt så temptime och TempTime är inte samma sak.
Användarvisningsbild
nodanolo
EF Sponsor
Inlägg: 90
Blev medlem: 25 mars 2009, 23:05:38
Ort: Järfälla

Re: Problem med AVR

Inlägg av nodanolo »

Sant. "Stavfel" av mig nu när jag skrev ner koden här. Rättade till det.

Det står dock rätt i programmet och ICCAvr släpper inte igenom det om jag hade skrivit fel.

Så tyvärr är det inte det som är felet, hade varit rätt skönt om det hade varit det.
void
Inlägg: 119
Blev medlem: 8 juli 2007, 11:06:50
Ort: Enköping

Re: Problem med AVR

Inlägg av void »

CurrentValues skall deklareras volatile unsigned int CurrentValues[18]; om den ändras av interrupt-rutinen.
sodjan
EF Sponsor
Inlägg: 43236
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Problem med AVR

Inlägg av sodjan »

> om interupten går in och ökar...

Du kan kanske stänga av interrupt under tiden så vet du om det är det.
En koll på den genererade koden kan kanske också vara intressant.
Att det verkar bli problem just vid 256 eller 512 eller 1024 kan tyda på
att det kanske krockar vid uppdateringar/läsningar av 2 st bytes. Intrruptet
kanske sker när main-koden har läst halva variablen, såden kommer ISR'en
in och uppdaterar och när main läser andra halvan så är det hela förstört.

T.ex att 000F => 0100 läses som 0000 eftersom uppräkninger sker "i mitten".

Notera att alla 16-bit variabler kommer att hanteras som två delar på en 8-bit processor.

Ja, du förstår nog hur jag menar... :-)

Alltså något i stil med:

Kod: Markera allt

CLI(); //disable all interrupts
if(CurrentValues[CurrentTime] > TempTime + 2)
SEI(); //re-enable interrupts
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Problem med AVR

Inlägg av jesse »

Läs inte av CurrentTime direkt, utan lägg den först i en separat variabel. Men när du ska läsa av en variabel som uppdateas i ett interrupt måste du också stänga av interruptet precis när du läser av den. Det gör du med cli(); och sätter på interrupt igen med sei();

En variant är att du i interruptet bara sätter en flagga, dvs en varaibel som sätts till etta. Sedan kollar du den variabeln i huvudprogrammet - och när du läser av en etta så vet du att minuterna ska uppdateras och du har en variabel i main till det.

exempel 1: stänga av interruptet

Kod: Markera allt

#define CurrentVoltage 9
#define CutOffVoltage 8
#define CurrentTime 2

unsigned int TempTime;
unsigned int CurrentValues[18];
unsigned int TestSetup[30];

main(void)
{
...
...
...
cli();
TempTime = CurrentValues[CurrentTime]; 
sei();
if(CurrentValues[CurrentVoltage] > TestSetup[CutOffVoltage])
  OldTempTime = TempTime; 
...
...
...
if(TempTime > OldTempTime + 2)
  //Skriv ut TempTime, CurrentValues[CurrentVoltage] och OldTempTime och gå därefter till klart.

}
exempel 2:

Kod: Markera allt

#define CurrentVoltage 9
#define CutOffVoltage 8
#define CurrentTime 2

unsigned int TempTime;
unsigned int CurrentValues[18];
unsigned int TestSetup[30];

main(void)
{
...
...
...
if (timerFlag) 
{
  CurrentValues[CurrentTime]++;
}
if(CurrentValues[CurrentVoltage] > TestSetup[CutOffVoltage])
  TempTime = CurrentValues[CurrentTime]; 
...
...
...
if(CurrentValues[CurrentTime] > TempTime + 2)
  //Skriv ut CurrentValues[CurrentTime], CurrentValues[CurrentVoltage] och TempTime och gå därefter till klart.

}
Och bara ett tips:
Om du vill samla en grupp med värden så skapa en struct istället för att lägga dem i en array. Det är lite snyggare, tycker jag. Men om du ska läsa igenom alla variabler för att skicka som data kan det ju finnas en fördel med array då man kan loopa igenom alla med ett index.
Användarvisningsbild
nodanolo
EF Sponsor
Inlägg: 90
Blev medlem: 25 mars 2009, 23:05:38
Ort: Järfälla

Re: Problem med AVR

Inlägg av nodanolo »

Sådärja. Nu finns det hopp igen!

När jag kollar genererade koden så ser man ju att processorn laddar CurrentValues[CurrentTime] i två steg, hög byte och låg byte. Naturligtvis, hur skulle det annars gå till...
Kommer då interupten för minuträkningen mitt i detta så blir det ju fel precis som Sodjan påpekar, så detta är mycket troligt mitt problem.

Jag hade tänkt "halvvägs" och insett problemet om interupten kom efter att TempTime tilldelats sitt värde men före jämförelsen. Därav lade jag till +2 till TempTime för att råda bot på problemet.

Men att stänga av interupt när man läser av CurentValues[CurrentTime]? Blir det verkligen bra? Kommer jag då inte att "missa" just den interupten? Därmed kommer tidsräkningen att missa en minut varje gång det händer. Idag får jag problem vid vart 20:e test, men det är ju bara vid tidpunkterna 256, 512, 768 och 1024 som det blir strul, vid övriga tidspunkter märker jag ju inget. Eftersom ett genomsnittligt test ligger på runt 1000 minuter så kommer detta att inträffa 250 gånger oftare, dvs. 12 gånger per test. Är då interupten avslagen så blir tiden 12 minuter för kort.

Så jag har nu ändrat enligt Jesse's förslag med en flagga och sedan får Main-rutinen uppdatera CurrentValues[CurrentTime]. Det här tror jag starkt på.

Och en struct är betydligt "prydligare", absolut. Men värden och parametrar skickas upp och ner via serieport och då blir det enkelt med array.

Men 'volatile' har jag nog inte riktigt grepp om. Jag har trott att det bara påverkar kompilatorn att inte komprimera en volatile för mycket, utan att alltid "spara tillbaka" variabeln till minnet eftersom den kan ändras oförutsägbart från andra delar av programmet. Och eftersom min kompilator är en "snålvariant" har kan jag inte aktivera komprimeringen, så jag har trott att det inte spelar någon roll med volatile. Men när jag nu provar att kompilera med och utan volatile så blir kodstorleken olika, så det gör någon skillnad!
Det här måste jag kolla upp noggrannare.
Finns det någon tumregel för detta? Ska t.ex. variabler som kan ändras i en interupt alltid vara volatile? Det känns lite luddigt eftersom man har svårt att veta vad kompilatorn "hittar på".

Hur som helst. Jag har uppdaterat programmet och inom ett par veckor vet jag om det lyckades. Men det känns bra.

Så ett STORT TACK för hjälpen. Helt ovärderligt!

/Daniel
Senast redigerad av nodanolo 26 januari 2014, 15:02:51, redigerad totalt 1 gång.
sodjan
EF Sponsor
Inlägg: 43236
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Problem med AVR

Inlägg av sodjan »

> Men att stänga av interupt när man läser av CurentValues[CurrentTime]?
> Blir det verkligen bra? Kommer jag då inte att "missa" just den interupten?

Kommer det att vara avstängt lägre tid en intervallet mellan två interrupt?
Notera att interruptet bara *fördröjs* tills du slår på det igen, du kommer inte
att missa ett interrupt som sker under tiden, det triggas bara inte. Utom ifall
det är avstängt längre tid än intervallet, enbart då kommer två interrupt att
uppfattas som ett enda.

> men det är ju bara vid tidpunkterna 256, 512, 768 och 1024 som det blir strul...

Exakt, det är enbart då som det sker en ändring av *både* höga och låga delen!
Det är enbart då som det blir konflikt mellan uppräkningen och avläsningen...
void
Inlägg: 119
Blev medlem: 8 juli 2007, 11:06:50
Ort: Enköping

Re: Problem med AVR

Inlägg av void »

Det finns en bra beskrivning av ditt problem i manualen (https://www.imagecraft.com/help/PDF/ICCAVR.pdf) på sidan 75. "volatile" gör att kompilatorn inte använder ett cache-värde för variabeln, utan hämtar det varje gång.
sodjan
EF Sponsor
Inlägg: 43236
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Problem med AVR

Inlägg av sodjan »

> "volatile" gör att kompilatorn inte använder ett cache-värde för variabeln,
> utan hämtar det varje gång.

Ja, det stämmer ju, men det har inget med det aktuella problemet att göra.

Det intressanta finns i "Access Atomicity and Interrupts":
"To work around these problem, you should either not use a multi-byte variable in this
manner, or you must explicitly disable and enable interrupt around accesses to the
variable to guarantee atomic access."
void
Inlägg: 119
Blev medlem: 8 juli 2007, 11:06:50
Ort: Enköping

Re: Problem med AVR

Inlägg av void »

Ja, det var det stycket "Access Atomicity and Interrupts" jag syftade på. Ville bara förtydliga vad "volatile" innebär eftersom nodanolo frågade om det. Yes, jag var lite otydlig :)
sodjan
EF Sponsor
Inlägg: 43236
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Problem med AVR

Inlägg av sodjan »

Ah, OK... :-)
Ja, det stämmer ju. Det undertrycker vissa optimeringar som
i sig kan vara ett problem vid t.ex en ISR. Det är samma sak med
register som kan ändras "utifrån" utan att det syns i koden.
Skriv svar