Problem med Interrupt AtMega168 @ 16MHz

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
myrek
Inlägg: 38
Blev medlem: 7 april 2009, 09:52:15

Problem med Interrupt AtMega168 @ 16MHz

Inlägg av myrek »

Hej allihop. jag håller på med ett litet projekt där jag spelar musik med stegmotorer. Jag har dock ett problem med min kod som jag hoppas någon kan hjälpa mig med.
Lite bakgrund. Jag använder mig av en AtMega168-20 samt en extern oscillator med en klockfrekvens på 16Mhz.

Programmet fungerar som så att jag kör en interrupt med extremt hög frekvens (prescaler 1, 8bitar. 1/16MHZ * 256)
Timern har en frekvens på 16uS. Inuti denna interrupt har jag en räknare som räknar antalet interrupts som har utförts och kontrollerar hela tiden interrupt numret mot en array som innehåller de toner jag vill spela.

Tonerna är alltså lagrade i en array där deras frekvens (tonen som skall spelar) står i direkt relation till antalet interrupts.

Om interrupt talet är korrekt så stegar jag motorn. Efter varje steg kontrollerar jag ytterligare en array som innehåller den paus som skall vara efter varje spelad ton. även denna är hårdkodad.

Mitt problem är följande. Låten spelar som den ska vissa stunder för att sedan stanna av någon sekund och fortsätta. Jag trodde detta berodde på att jag hade för hög interruptfrekvens men precis samma sak händer när jag ökar prescalern.
Jag provade också att byta uC till AtMega8515 men precis samma fel kvarstår. Jag körde lite simulering i avrstudio då jag misstänkt att interrupten kanske tog för god tid på sig och avbröt sig själv eller något liknande (om det är möjligt) men hela ISR:en han slutföras i god tid innan nästa.

Jag har förmodligen något fel i min kod. hoppas någon kan ta sig tid att kolla igenom lite. Jag vet att koden är något ostrukturerad... och att variabelnamnen är kassa men jag har experimenterat så mycket med detta fram och tillbaka att det har blivit så :)

när jag kollar med oscilloskopet ser jag att alla frekvenser är korrekta men plötsligt bara dör allt och pinnen ställer sig antingen låg eller hög för att sedan fortsätta efter några sekunder. Koden rullar på som vanligt eftersom jag plötsligt befinner mig på "rätt" ställe i musikstycket.
Senast redigerad av myrek 10 april 2010, 23:47:12, redigerad totalt 1 gång.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Problem med Interrupt AtMega168 @ 16MHz

Inlägg av sodjan »

Jag försökte läsa ditt inlägg men det var praktiskt taget omöjligt p.g.a
formatteringen av din kod (långa rader). V.v fixa det så får vi se...
Användarvisningsbild
tlvb
Inlägg: 132
Blev medlem: 13 januari 2009, 00:40:17
Ort: Lund
Kontakt:

Re: Problem med Interrupt AtMega168 @ 16MHz

Inlägg av tlvb »

Är inte säker på att detta är felet, men:
1) Kolla upp hur/när volatile behövs i interrupt/variabelsammanhang, t.ex. Part 5: Things you Need to Know: Parentes 2
2) Om du använder progmem så måste ändå värdena laddas in i ramminnet innan användning vilket kan ta tid (och i det här fallet kanske för mycket rammine), (det var kommentarmarkerat här men kan vara värt att nämna)
Användarvisningsbild
jesper
Inlägg: 722
Blev medlem: 12 juni 2006, 16:04:08
Ort: Laem Mae Phim, Thailand

Re: Problem med Interrupt AtMega168 @ 16MHz

Inlägg av jesper »

Ser inte något fel sådär rakt av, men om du får en såpass lång paus, låter det som att något index eller räknare får overflow och du inte kommer igång igen innan den wrappat runt.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Problem med Interrupt AtMega168 @ 16MHz

Inlägg av sodjan »

Symptomen är like likt när man har WDT påslaget av misstag.
Användarvisningsbild
Swech
EF Sponsor
Inlägg: 4750
Blev medlem: 6 november 2006, 21:43:35
Ort: Munkedal, Sverige (Sweden)
Kontakt:

Re: Problem med Interrupt AtMega168 @ 16MHz

Inlägg av Swech »

Skulle det vara Watchdog så borde väl musiken starta om, inte fortsätta där den borde vara?

Swech
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Problem med Interrupt AtMega168 @ 16MHz

Inlägg av sodjan »

Möjligt, men som sagt, första inlägget var lite svårläst så jag
kollade inte alla detaljer...
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Problem med Interrupt AtMega168 @ 16MHz

Inlägg av jesse »

om du först har if (pause == 1) så behöver du inte senare skriva else if (pause == 0) väl? Det räcker med else ... För det finns väl inte fler alternativ? men det var inte själva problemet.

kommer pausen ofta på samma ställe i melodin eller på slumpartade ställen?
kommer pausen alltid i ett skifte från en låg ton till en högre ton?
Är pausen på 1.048 sekunder?

(jag skriver lite frågor eftersom jag inte orkar ta reda på allt själv);

jag tror att det är så att när du byter ton så hänger inte "step" med.
Har jag rätt att du har en paus mellan varje ton?
vad händer med variabeln "step" under en paus?

Du kanske borde nollställa variabeln "step" när en ton ska börja spelas, risken är att när du i programmet sätter paus = 1 så råkar step ha ett värde som är högre än maxvärdet på nästa ton.

Du fixar det antingen genom att nollställa step vid paus , eller att du i interrupten inte skriver if(step == track1) utan iställetif(step >= track1)

orsaken till pauserna är att när en ton med nr 239 tar slut (dvs. pause sätts till 1) och nästa ton är t.ex. 150 , så kan det råka slumpa sig så att variablen step råkar ha värdet 220 när detta sker. Vad händer då när den ska börja spela tonen 150? Jo den jämför step med tonen: (220 == 150) = false - och ökar sedan step till 221.... detta pågår i 1.048 sekunder - tills step räknat till 65535 och sedan slårt över till 0.

Jag har inte läst din kod, bara snabbt ögnat igenom den, så detta är bara en kvalificerad gissning.

Annars var din kod grymt smart. :tumupp:
myrek
Inlägg: 38
Blev medlem: 7 april 2009, 09:52:15

Re: Problem med Interrupt AtMega168 @ 16MHz

Inlägg av myrek »

Jag har städat lite i koden. hoppas det blir lite lättare att se vad som pågår nu.

Kod: Markera allt


#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>


volatile unsigned int step;  
volatile unsigned int duration;	
volatile unsigned int i=0;
volatile unsigned int p=0;

volatile unsigned int pause=0;
volatile unsigned long int PauseCounter=0;


//This array contains the number of interrupts needed to produce the correct note at interrupt frequency 16Mhz
volatile unsigned char track1[299] = {
47,47,47,60,47,40,60,80,95,71,63,67,71,80,47,40,36,45,40,47,60,53,63,60,80,95,71,63,67,71,80,47,40,36,45,40,
47,60,53,63,40,42,45,50,47,75,71,60,71,60,53,40,42,45,50,47,30,30,30,40,42,45,50,47,75,71,60,71,60,53,50,53,
60,40,42,45,50,47,75,71,60,71,60,53,40,42,45,50,47,30,30,30,40,42,45,50,47,75,71,60,71,60,53,50,53,60,60,60,
60,60,53,47,60,71,80,60,60,60,60,53,47,60,60,60,60,53,47,60,71,80,47,47,47,60,47,40,60,80,95,71,63,67,71,80,
47,40,36,45,40,47,60,53,63,60,80,95,71,63,67,71,80,47,40,36,45,40,47,60,53,63,47,60,80,75,71,45,45,71,63,36,
36,36,40,45,47,60,71,80,47,60,80,75,71,45,45,71,63,45,45,45,47,53,60,47,60,80,75,71,45,45,71,63,36,36,36,40,
45,47,60,71,80,47,60,80,75,71,45,45,71,63,45,45,45,47,53,60,60,60,60,60,53,47,60,71,80,60,60,60,60,53,47,60,
60,60,60,53,47,60,71,80,47,47,47,60,47,40,47,60,80,75,71,45,45,71,63,36,36,36,40,45,47,60,71,80,47,60,80,75,
71,45,45,71,63,45,45,45,47,53,60};


// This array contains all the delays between the notes
volatile unsigned char pause1[298] = {
8,32,32,8,32,176,56,56,56,32,32,8,32,16,16,16,32,8,32,32,8,8,56,56,56,56,32,32,8,32,16,16,16,32,8,32,32,8,8,
104,8,8,8,32,32,8,8,32,8,8,56,8,8,8,32,32,32,8,128,8,8,8,32,32,8,8,32,8,8,56,56,56,224,8,8,8,32,32,8,8,32,8,
8,56,8,8,8,32,32,32,8,128,8,8,8,32,32,8,8,32,8,8,56,56,56,176,8,32,32,8,32,8,32,8,80,8,32,32,8,	8,200,8,32,32,
8,32,8,32,8,80,8,32,32,8,32,176,56,56,56,32,32,8,32,16,16,16,32,8,32,32,8,8,56,56,56,56,32,32,8,32,16,16,16,32,
8,32,32,8,8,56,8,32,56,32,8,32,8,80,16,16,16,16,16,16,8,32,8,80,8,32,56,32,8,32,8,80,8,32,8,16,16,16,176,8,32,
56,32,8,32,8,80,16,16,16,16,16,16,8,32,8,80,8,32,56,32,8,32,8,80,8,32,8,16,16,16,176,8,32,32,8,32,8,32,8,80,
8,32,32,8,8,200,8,32,32,8,32,8,32,8,80,8,32,32,8,32,176,8,32,56,32,8,32,8,80,16,16,16,16,16,16,8,32,8,80,8,32
,56,32,8,32,8,80,8,32,8,16,16,16};

int main(void)
{

	TCCR0B = 1;		// Prescler = 1 --> counter frequency 62,5kHz (8bit counter)
	TIMSK0 = 1;		// Enable timer/counter0 overflow interrupt
	
	DDRD = 0xFF;	// All pins outputs
	DDRB = 0xFF;
	
	sei();			//enable interrupts
	
	while(1)
	{
					//infinite loop to keep interrupts running.
	}	

}


//interrupt overflow vector. This interrupt has a frequency of 16 MHz / 256 = 62500 Hz.
//The period is 16uS. (prescaler = 1, 8 bit register)

ISR(TIMER0_OVF_vect)			
{


	if (pause == 1)							//if pause=1 pause between notes
	{
		PauseCounter++;
		
		if(PauseCounter==pause1[p]*100)	//the end of pause has been reached.
		{
			pause=0;						//Clear pause flag
			PauseCounter=0;
			p++;							//jump to next pause element
			
			if(p==297)
			{
				p=0;						//if end of array has been reached. restart.
			}
		}
	
	}
	else if(pause == 0)	//if pause=0 we should play notes
	{
	
		//This loop toggles the pin to the correct frequency. the track array contains the number of 
		//interrupts to be played. This is based on an interrupt freq of 62,5 kHz.
		
		if(step == track1[i])
		{
			PORTD ^= (1<<0);
			step=0;				//clear counter.
		}
		
		step++;					//increase interrupt counter
		
		duration++;				//Increase duration counter.
		
		if(duration == 35625)	//Every note should be played for 0,57s --> 35625 * 0,16us = 0.57s 
		{
			i++;				//Go to the next tone
			duration = 0;		//Cclear duration counter
			pause=1;			//set the pause flag to pause between notes
			
			if (i==298)
			{
				i=0; 			//if end of track has been reached. restart.
			}
		}

	}	
	
}


sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Problem med Interrupt AtMega168 @ 16MHz

Inlägg av sodjan »

Men har du gjort något åt *radlängderna" ??

Kod: Markera allt


#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>


volatile unsigned int step; 
volatile unsigned int duration;   
volatile unsigned int i=0;
volatile unsigned int p=0;

volatile unsigned int pause=0;
volatile unsigned long int PauseCounter=0;


// This array contains the number of interrupts needed to produce the
// correct note at interrupt frequency 16Mhz
volatile unsigned char track1[299] = {
47,47,47,60,47,40,60,80,95,71,63,67,71,80,47,40,36,45,40,47,60,53,63,60,
80,95,71,63,67,71,80,47,40,36,45,40,47,60,53,63,40,42,45,50,47,75,71,60,
71,60,53,40,42,45,50,47,30,30,30,40,42,45,50,47,75,71,60,71,60,53,50,53,
60,40,42,45,50,47,75,71,60,71,60,53,40,42,45,50,47,30,30,30,40,42,45,50,
47,75,71,60,71,60,53,50,53,60,60,60,60,60,53,47,60,71,80,60,60,60,60,53,
47,60,60,60,60,53,47,60,71,80,47,47,47,60,47,40,60,80,95,71,63,67,71,80,
47,40,36,45,40,47,60,53,63,60,80,95,71,63,67,71,80,47,40,36,45,40,47,60,
53,63,47,60,80,75,71,45,45,71,63,36,36,36,40,45,47,60,71,80,47,60,80,75,
71,45,45,71,63,45,45,45,47,53,60,47,60,80,75,71,45,45,71,63,36,36,36,40,
45,47,60,71,80,47,60,80,75,71,45,45,71,63,45,45,45,47,53,60,60,60,60,60,
53,47,60,71,80,60,60,60,60,53,47,60,60,60,60,53,47,60,71,80,47,47,47,60,
47,40,47,60,80,75,71,45,45,71,63,36,36,36,40,45,47,60,71,80,47,60,80,75,
71,45,45,71,63,45,45,45,47,53,60};


// This array contains all the delays between the notes
volatile unsigned char pause1[298] = {
8,32,32,8,32,176,56,56,56,32,32,8,32,16,16,16,32,8,32,32,8,8,56,56,56,56,
32,32,8,32,16,16,16,32,8,32,32,8,8,104,8,8,8,32,32,8,8,32,8,8,56,8,8,8,32,
32,32,8,128,8,8,8,32,32,8,8,32,8,8,56,56,56,224,8,8,8,32,32,8,8,32,8,8,56,
8,8,8,32,32,32,8,128,8,8,8,32,32,8,8,32,8,8,56,56,56,176,8,32,32,8,32,8,32,
8,80,8,32,32,8,8,200,8,32,32,8,32,8,32,8,80,8,32,32,8,32,176,56,56,56,32,
32,8,32,16,16,16,32,8,32,32,8,8,56,56,56,56,32,32,8,32,16,16,16,32,8,32,
32,8,8,56,8,32,56,32,8,32,8,80,16,16,16,16,16,16,8,32,8,80,8,32,56,32,8,
32,8,80,8,32,8,16,16,16,176,8,32,56,32,8,32,8,80,16,16,16,16,16,16,8,32,
8,80,8,32,56,32,8,32,8,80,8,32,8,16,16,16,176,8,32,32,8,32,8,32,8,80,
8,32,32,8,8,200,8,32,32,8,32,8,32,8,80,8,32,32,8,32,176,8,32,56,32,8,
32,8,80,16,16,16,16,16,16,8,32,8,80,8,32,56,32,8,32,8,80,8,32,8,16,16,16};

int main(void)
{

   TCCR0B = 1;      // Prescler = 1 --> counter frequency 62,5kHz (8bit counter)
   TIMSK0 = 1;      // Enable timer/counter0 overflow interrupt
   
   DDRD = 0xFF;   // All pins outputs
   DDRB = 0xFF;
   
   sei();         //enable interrupts
   
   while(1)
   {
               //infinite loop to keep interrupts running.
   }   

}


//interrupt overflow vector. This interrupt has a frequency of 16 MHz / 256 = 62500 Hz.
//The period is 16uS. (prescaler = 1, 8 bit register)

ISR(TIMER0_OVF_vect)         
{


   if (pause == 1)                     //if pause=1 pause between notes
   {
      PauseCounter++;
      
      if(PauseCounter==pause1[p]*100)   //the end of pause has been reached.
      {
         pause=0;                  //Clear pause flag
         PauseCounter=0;
         p++;                     //jump to next pause element
         
         if(p==297)
         {
            p=0;                  //if end of array has been reached. restart.
         }
      }
   
   }
   else if(pause == 0)   //if pause=0 we should play notes
   {
   
      // This loop toggles the pin to the correct frequency. the track array contains
      // the number of interrupts to be played. This is based on an interrupt freq
      // of 62,5 kHz.
      
      if(step == track1[i])
      {
         PORTD ^= (1<<0);
         step=0;            //clear counter.
      }
      
      step++;               //increase interrupt counter
      
      duration++;            //Increase duration counter.
      
      if(duration == 35625)   //Every note should be played for 0,57s --> 35625 * 0,16us = 0.57s
      {
         i++;            //Go to the next tone
         duration = 0;      //Cclear duration counter
         pause=1;         //set the pause flag to pause between notes
         
         if (i==298)
         {
            i=0;          //if end of track has been reached. restart.
         }
      }

   }   
   
}
EDIT: OK, ser nu att det verkar vara lite kortare i ditt andra försök, men jag får i
alla fall scrolla vänster/höger fortfarande. Lite mindre dåligt, men inte bra... :-)

Skit samma, det är inte helt avgörande, du har fått en del andra frågor/tips som du kanske
ska jobba med istället. Men ta med det till nästa gång, så att du fixar formatteringen då... :-)
myrek
Inlägg: 38
Blev medlem: 7 april 2009, 09:52:15

Re: Problem med Interrupt AtMega168 @ 16MHz

Inlägg av myrek »

om du först har if (pause == 1) så behöver du inte senare skriva else if (pause == 0) väl? Det räcker med else ... För det finns väl inte fler alternativ? men det var inte själva problemet.
Det har du nog rätt i :) skall ändra det.
kommer pausen ofta på samma ställe i melodin eller på slumpartade ställen?
Pauserna dyker alltid upp på samma ställe när koden körs. Just var de dyker upp beror på om jag har ändrat nåt i koden. När jag väl laddat över koden till processorn stannar den alltid på samma ställe. just nu stannar den efter 18 toner.

Pauserna är inte alltid exakt lika långa men verkar ligga mellan 1.1-1.2sekunder ungefär

Det verkar vara så att pauserna dyker upp vid skifte från lägre till högre toner ja!

Jag orkar inte skriva klart detta meddelande. Jag testade lösningen du föreslog och det funkar perfekt! tusen tack!
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Problem med Interrupt AtMega168 @ 16MHz

Inlägg av jesse »

Grattis! :bravo:

Jag kände nämligen igen problemet från timers... där får man se upp om de ska slå om vid ett visst värde till ett lägre.. timern kan då "missa" vid jämförelse på samma sätt som din rutin missade. Därför skriver jag alltid > "mer än" istället för "lika med" == när jag ska jämföra saker som räknar upp... för säkerhets skull.

Får vi höra hur det låter nu då? :razz:
myrek
Inlägg: 38
Blev medlem: 7 april 2009, 09:52:15

Re: Problem med Interrupt AtMega168 @ 16MHz

Inlägg av myrek »

Jag skall lägga upp det på nätet så fort allt är klart. Det problem jag står inför just nu är att den ena "stämman" är klar det är två stycken till som skall med :)
Jag har dock fullt i SRAM. Var bör jag lagra alla arrayerna för att få plats? Kan jag lagra dem i flash och fortfarande ha dem som globala variabler eller är detta omöjligt?

Hur bör jag göra?
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Problem med Interrupt AtMega168 @ 16MHz

Inlägg av jesse »

Kod: Markera allt

static unsigned int track3[291] PROGMEM
Du kanske skulle ha char även på track3?

Det går att lagra både i EEPROM och i FLASH.
Antar att du använder AVR-GCC. I biblioteken där finns koder för detta.

Men båda dessa är mycket långsammare än SRAM, så i så fall får du ladda en char (i SRAM) med tonens värde i början av varje ton, så att du läser ur arrayen endast en gång per ton och inte som nu 62500 ggr/sekund.
Men du har ju redan lagt vissa arrayer i PROGMEM...?

kolla:
<avr/eeprom.h>: EEPROM handling och <avr/pgmspace.h>: Program Space Utilities

Hoppas du hinner med alla tre stämmorna... det kan funka, men det finns en liten risk att interrupten inte hinner med. Men det är väl bara att testa.
myrek
Inlägg: 38
Blev medlem: 7 april 2009, 09:52:15

Re: Problem med Interrupt AtMega168 @ 16MHz

Inlägg av myrek »

tack för snabbt svar. track3 innehåller flera element som är större än 256 så jag måste ha den som int :/ väldans slöserie med utrymme ..

Jag satt och testade lite med progmem tidigare, jag var dock inte helt säker på hur jag skulle läsa ut datat från flash dock.
att lagra det var inga problem.

har du nåt exempel på hur jag kan läsa från flash? Skall försöka läsa på lite i biblioteket.
Skriv svar