Timer overflow ISR execution is delayed - precise timing needed.

Go To Last Post
105 posts / 0 new

Pages

Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am trying to produce some waveforms using the PWM and a timer interrupt. The problem is I am also doing envelope and LFO calculations in the main loop.

So, at certain points, I can listen to the note being produced bend towards a lower pitch. The only way this could be happening is if my interrupt was delayed and therefore the sample rate dropped.

What kind of CPU operation could be causing the delayed ISR execution? Is there a way to give higher priority to the ISR?

This topic has a solution.

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

Last Edited: Mon. Oct 12, 2020 - 01:54 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The only "delay" is that it has to finish the current opcode (which might be more than 1 cycle) then it takes 12..20 cycles to vector into the ISR.

 

So what kind if "delay" are you talking about?

 

BTW if you are a fan of LFOs/envelopes etc I can't recommend Teensy4 and its audio library high enough. 600MHz (more if overclocked) gives you a LOT of CPU headroom for all kinds of audio processing: LFO/modulated oscillators/envelopes/filters/flanger/chorus/delay/reverb/bitcrusher/S&H/panning/fader/etc, etc

 

I'm just toying with what's possible so far but already my design chain looks like...

It's like synth "Lego bricks" (of course you do need to add supporting code to manipulate each block).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I will definitely look into this in the future - I was thinking of working on a more powerful CPU in the future.

 

20 cycles just to initiate the ISR? I was not expecting that

So here is what happens right now with my code:

There is an audible pitch drop during the attack phase of the envelope but it goes away when I use some _delay_us(10) functions in those two spots.

It seems to me that it has to do with the time of execution of the attack calculations - if the calculations start right before the ISR is about to execute, the ISR is delayed and the pitch drops.

Could this be the problem?

 

inline void doEnvelope(uint8_t oscillator)
{
	switch (envelopeStage[oscillator])
	{
		case 0: //Attack
		_delay_us(10);
		if (button[0] && ((millisecsEnvelope[oscillator] << 4) / attack[oscillator] < 255))
		{
			_delay_us(10);
			volume[oscillator] = (millisecsEnvelope[oscillator] << 4) / attack[oscillator];		// millisecsEnvelope[oscillator] / (attack/16)
		}
		else if (button[0])
		{
			volume[oscillator] = 255;
			++envelopeStage[oscillator];
			millisecsEnvelope[oscillator] = 0;
		}
		else
		{
			++envelopeStage[oscillator];
			millisecsEnvelope[oscillator] = 0;
		}
		break;
		
		.......
		
	ISR (TIMER0_OVF_vect)
	{
	
  	if (notePlayingSum)
	{
 		phaccu[0] += tword[0];//738;440Hz
 		osc[0] = (pgm_read_byte( &waveTable[ waveKind[0] ][ phaccu[0] >> 8 ]) * 128) / 256;

		
phaccu[1] += tword[1]; 
 		osc[1] = (pgm_read_byte( &waveTable[ waveKind[1] ][ phaccu[1] >> 8 ]) * 128) / 256;

		OCR0A = (( osc[0] * volume[0] ) >> 8) + (( osc[1] * volume[1] ) >> 8); //;pgm_read_byte(&(waveTable[tremolo]))/0xff;
 	}
}

 

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Are you sharing variables between main() and your ISR? Are they volatile? Likewise, if you use anything other than 8-bit variables then you should look at atomic access.

#1 Hardware Problem? https://www.avrfreaks.net/forum/...

#2 Hardware Problem? Read AVR042.

#3 All grounds are not created equal

#4 Have you proved your chip is running at xxMHz?

#5 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand."

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If global interrupts are disabled then the execution of an ISR is delayed. I doubt this is the problem though.

 

Why do you think that a delay in the execution of an ISR would change the frequency of the PWM generated?

 

How is "volume" and "osc" declared? Are they volatile? Are they 8-bit values? Are you sure that all the variables used in the ISR are changed atomically? I.e. does your main loop ensure that all variables used by the ISR are consistent at all times that global interrupts are enabled?

 

 

/Jakob Selbing

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you have function calls in an ISR the compiler has to push/pop caller-saved registers (r18-r27,r30-r31) at least.

I'm not sure how pgm_read_byte is expanded.  Can you check the generated asm code?  (avr-objdump -d will do that.)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey I was searching around about atomic. Why should I use atomic in stead of using cli() before the command and sei() after the command? Is there something more to it?

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

We have no idea of what "command" is. We also have no idea of the types of your variables. You might want to time the isr code in the AS7 simulator. The results might surprise you.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

tellSlater wrote:

Hey I was searching around about atomic. Why should I use atomic in stead of using cli() before the command and sei() after the command? Is there something more to it?

You did not reply any of the questions asked. How is any one gonna be able to help you?

 

I am guessing that the problem here is that your main loop code modifies variables that are used by the ISR. You need to make sure to make access to those variables atomic.

 

But... you can also have a problem if your ISR accesses multiple variables that must be consistent with respect to each other. Having atomic access of each of those is not gonna be enough - you must change all those in one atomic block (or possibly use an duplicate set of variables that are updated atomically). I see you have at least two variables of this kind: volume[0] and volume[1].

 

It would help a lot if you showed some more context like variable declarations, the calling context of doEnvelope() etc.

 

EDIT: for more help regarding atomic access have a look here: https://www.nongnu.org/avr-libc/...

/Jakob Selbing

Last Edited: Mon. Oct 12, 2020 - 06:20 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

tellSlater wrote:

Hey I was searching around about atomic. Why should I use atomic in stead of using cli() before the command and sei() after the command? Is there something more to it?

 

The subtle difference is that 'atomic', on ending the block, will restore the interrupt state to how it was before you entered the block. So, if the interrupts were already disabled when you entered an atomic block they will still be disabled when you leave it. Using cli and sei does not do this.

#1 Hardware Problem? https://www.avrfreaks.net/forum/...

#2 Hardware Problem? Read AVR042.

#3 All grounds are not created equal

#4 Have you proved your chip is running at xxMHz?

#5 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand."

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am using Direct Digital Synthesis from PWM at ORC0A. One sample of the wave is being passed to OCR0A in every TOVF0 interrupt - in the OVF ISR.

Now when the sample rate drops, the pitch of the note drops - I can listen to the note dropping so I guessed that the ISR execution was delayed. I think that could be the only reason for a slower sample rate and therefore a pitch bend downwards on the note.

The frequency of the PWM is not altered, my sample rate is altered - this is how Direct Digital Synthesis works. Every sample (that is essentially a voltage level) is output through PWM in the ISR. ISR is called about 39K times a second so I get a 39KHz sample rate that drops if ISR execution is delayed.

 

volume and osc are volatile uint8_t. Also, after the first reply to this post I made sure the only variables shared between main code and ISR are volatile uint8_t.

If I have understood what is going on with shared variables in ISR and main code - now that only 8bit variables are shared, I don't need to use atomic... correct?

 

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I really don't know how to do this and where I am supposed to use this command.. I use AtmelStudio - can I export my code in assembly from there?

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you are doing DDS then that must be given the very highest priority and you shouldn't let anything interfere with it. I'd suggest that doing >>8 and *128 in the ISR is not a wise choice as these can be computationally expensive. For one thing >>8 generally just means (use higher byte(s) and ignore the lowest byte. Hopefully the compiler is smart enough to recognise this but an alternative is to make a union with phaccu and just pick out the relevant bytes to avoid the shift. But look at the generated Asm - perhaps the compiler spotted this already. 

 

Similarly for >>128, which is a 7 bit shift it might be "better" to <<1 and then use the next byte up.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Not necessarily. There maybe a relationship between a number of those variables that might create a problem.
Again, you might want to measure the execution time of your isr. It might be that you simply do not have enough time to complete the isr before the next interrupt comes along. Thus your ‘delay’. Everything takes a finite amount of time.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yeah Simulator really helps. I used it these last days to make sure that the ISR was not called while certain code was executing.

I also made a function that halted the main code in a while loop until the next ISR was called. That way I made sure that the complex calculations took place right after the ISR and not before it and the sound is ok now.

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for your help. Although I think I understood the importance of atomic and not letting a more-than-one-byte variable be mistreated I think that was not the my main problem here.

I asked above if it is ok not using atomic when accessing one byte variables and am waiting for your answer! Thanks again

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

Last Edited: Mon. Oct 12, 2020 - 03:37 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
const uint8_t wf_Width    = 84;
const uint8_t wf_Height   = 48;
const uint8_t PROGMEM wf_Bitmap[] = {
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x40, 0x40, 0x60, 0x20, 0x20, 0x20, 0x10, 0x90, 0xd0, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0x60, 0x30, 0xf8, 0x80, 0x00, 0x00, 0x80, 0xc0, 0x40, 0x60, 0x20, 0x30, 0x10, 0x18, 0x0c, 0x04, 0x06, 0x02, 0x03, 0x01, 0x01, 0x00, 0x80, 0xe0, 0x30, 0x1c, 0x06, 0x02, 0x03, 0x01, 0x01, 0x00, 0x00, 0x80, 0xc0, 0x60, 0x30, 0x18, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, 0x40, 0x60, 0x20, 0x20, 0x30, 0x10, 0x10, 0x18, 0x08, 0x08, 0x0c, 0x04, 0x04, 0x06, 0x82, 0x83, 0x41, 0x61, 0x30, 0x18, 0x08, 0x0c, 0x1f, 0xf2, 0x83, 0xe1, 0x38, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x7c, 0x07, 0x00, 0x80, 0x80, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x20, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x37, 0x1f, 0x80, 0x80, 0xb1, 0xef, 0xbe, 0xc3, 0x41, 0x3f, 0xf0, 0x90, 0x10, 0x08, 0x08, 0x04, 0x07, 0x3e, 0xf2, 0x01, 0x01, 0x00, 0x08, 0x08, 0x08, 0x78, 0xc0, 0x80, 0xc0, 0xc0, 0x80, 0xe0, 0x38, 0x00, 0xd0, 0x00, 0xc0, 0x80, 0x80, 0x00, 0xc0, 0x40, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40, 0x60, 0x20, 0x30, 0x10, 0x10, 0x18, 0x08, 0x08, 0x08, 0x08, 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x06, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0e, 0x18, 0x30, 0x20, 0x20, 0x30, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xc0, 0x79, 0x49, 0x48, 0x08, 0x00, 0xd1, 0x00, 0x41, 0x20, 0xa1, 0x00, 0xf1, 0x41, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x06, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

PROGMEM const unsigned char waveTable[5][256]  ={
	//Random numbers wave
	{156,164, 53, 27,167,174,146, 99,157, 61, 85, 46, 80, 79, 58,159,
	56,115,234,119,182,127,150,170,133,173,219, 66,227,249,  6, 57,
	203,255, 45,229, 29, 30, 19, 91,202,158,201, 98,172, 63, 69,235,
	106, 95,220, 35,131, 59,248, 81,154, 86, 31,243, 62,238,242,171,
	90,147,109, 60, 94,130, 43,103,122,132, 84,143, 22,247,105, 15,
	169,187,  3, 51,254,251,110,114,108, 49, 36, 13,181,225,188,104,
	230, 41,144,168,183,  9,252, 93,124,107,141,177,140,  1,175, 28,
	26,233,138,231,185,  8,221,214,  4, 89,208, 47,  0,237, 34,176,
	40,120,212,  2,236, 64,153,134,224,209, 44, 97, 16,218,200,165,
	178,180,102,137,118,125,161,245,226, 48, 12, 65, 83,101,190,116,
	217,198,142,192,199,155, 38,126,184, 25,189, 17,151,232,207,240,
	96,186, 74,128,196,211,129,163, 21, 73,117,135,197, 14, 24,179,
	20,113, 10,152, 77,160, 70,149,121, 33, 75,112, 88,195,194, 42,
	136,100, 78, 32,191,193, 68, 55,223,204,  7,215,162, 11, 52, 92,
	250,239, 23, 87,  5,205, 54,139, 71,228,222, 37,241,206,210,213,
	148,244, 67,253, 50, 76, 82, 18,246,166, 72, 39,111,216,145,123,},
	
	//square wave
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255},
	
	
	//left saw (negative slope)
	{255,254,253,252,251,250,249,248,247,246,245,244,243,242,241,240,239,238,237,236,235,234,233,232,231,230,229,228,227,226,225,224,223,222,221,220,219,218,217,216,215,214,213,
	212,211,210,209,208,207,206,205,204,203,202,201,200,199,198,197,196,195,194,193,192,191,190,189,188,187,186,185,184,183,182,181,180,179,178,177,
	176,175,174,173,172,171,170,169,168,167,166,165,164,163,162,161,160,159,158,157,156,155,154,153,152,151,150,149,148,147,146,145,144,143,142,141,
	140,139,138,137,136,135,134,133,132,131,130,129,128,127,126,125,124,123,122,121,120,119,118,117,116,115,114,113,112,111,110,109,108,107,106,105,104,103,102,101,100,99,98,97,96,95,94,93,92,91,90,
	89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,
	41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0},
	
	//triangle wave
	{1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,81,83,85,
	87,89,91,93,95,97,99,101,103,105,107,109,111,113,115,117,119,121,123,125,127,129,131,133,135,137,139,141,143,145,147,149,151,153,155,157,159,161,163,165,167,169,171,173,175,177,179,181,183,185,187,189,191,193,195,
	197,199,201,203,205,207,209,211,213,215,217,219,221,223,225,227,229,231,233,235,237,239,241,243,245,247,249,251,253,255,255,253,251,249,247,
	245,243,241,239,237,235,233,231,229,227,225,223,221,219,217,215,213,211,209,207,205,203,201,199,197,195,193,191,189,187,185,183,181,179,177,
	175,173,171,169,167,165,163,161,159,157,155,153,151,149,147,145,143,141,139,137,135,133,131,129,127,125,123,121,119,117,115,113,111,109,107,
	105,103,101,99,97,95,93,91,89,87,85,83,81,79,77,75,73,71,69,67,65,63,61,59,57,55,53,51,49,47,45,43,41,39,37,35,33,31,29,27,25,23,21,19,17,15,
	13,11,9,7,5,3,1},	
	
	//sine wave
	{0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,
	70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124,127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,217,219,
	221,223,225,227,229,231,233,234,236,238,239,240,242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254,254,
	253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,233,231,229,227,225,223,221,219,217,215,212,210,208,205,
	203,200,198,195,192,190,187,184,181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,111,108,105,
	102,99,96,93,90,87,84,81,78,76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,
	3,2,2,1,1,1,0,0,0} };
	


//Note frequencies

// PROGMEM float const keyFreq[88] = {
// 	27.5, 29.1352, 30.8677,																					   //Octave 0
// 	32.7032, 34.6478, 36.7081, 38.8909, 41.2034, 43.6535, 46.2493, 48.9994, 51.9131, 55, 58.2075, 61.7354,     //Octave 1
// 	65.4064, 69.2957, 73.4162, 77.7817, 82.4069, 87.3071, 92.4986, 97.9989, 103.826, 110, 116.541, 123.471,    //Octave 2
// 	130.813, 138.591, 146.832, 155.563, 164.814, 174.614, 184.997, 195.998, 207.652, 220, 233.082, 246.942,    //Octave 3
// 	261.626, 277.183, 293.665, 311.127, 329.628, 349.228, 369.994, 394.995, 415.305, 440, 466.164, 493.883,    //Octave 4
// 	523.251, 554.365, 587.330, 622.254, 659.255, 698.456, 739.989, 783.991, 830.609, 880, 932.328, 987.767,    //Octave 5
// 	1046.50, 1108.73, 1174.66, 1244.51, 1318.51, 1396.91, 1479.98, 1567.98, 1661.22, 1760, 1864.66, 1975.53,   //Octave 6
// 	2093.00, 2217.46, 2349.32, 2489.02, 2637.02, 2793.83, 2959.96, 3135.96, 3322.44, 3520, 3729.31, 3951.07,   //Octave 7
// 	4186.01                                                                                                    //Octave 8
// };

// PROGMEM uint16_t const twordNotes[88] = {
// 	46, 49, 52,																	//Octave 0
// 	55, 58, 62, 66, 69, 74, 78, 82, 87, 92, 98, 104,							//Octave 1
// 	110, 116, 123, 131, 138, 147, 155, 164, 174, 184, 195, 207,					//Octave 2
// 	219, 232, 246, 261, 276, 293, 310, 328, 348, 368, 390, 414,					//Octave 3
// 	438, 464, 492, 521, 552, 585, 619, 661, 695, 736, 780, 827,					//Octave 4
// 	876, 928, 983, 1041, 1103, 1169, 1238, 1312, 1390, 1472, 1560, 1653,		//Octave 5
// 	1751, 1855, 1965, 2082, 2206, 2337, 2476, 2623, 2779, 2944, 3119, 3305,		//Octave 6
// 	3501, 3709, 3930, 4163, 4411, 4673, 4951, 5245, 5557, 5888, 6238, 6609,		//Octave 7
// 	7002																		//Octave 8
// };


PROGMEM uint16_t const twordNotes[88] = {
	46, 49, 52,																	//Octave 0
	55, 58, 62, 66, 69, 74, 78, 82, 87, 92, 98, 104,							//Octave 1
	110, 116, 123, 131, 138, 147, 155, 164, 174, 184, 195, 207,					//Octave 2
	219, 232, 246, 261, 276, 293, 310, 328, 348, 368, 390, 414,					//Octave 3
	438, 464, 492, 521, 552, 585, 619, 661, 695, 735, 779, 826,					//Octave 4
	875, 927, 982, 1040, 1102, 1168, 1237, 1311, 1389, 1470, 1558, 1651,		//Octave 5
	1749, 1853, 1963, 2080, 2203, 2334, 2473, 2620, 2776, 2940, 3115, 3301,		//Octave 6
	3497, 3704, 3925, 4158, 4405, 4667, 4945, 5238, 5550, 5880, 6230, 6600,		//Octave 7
	6993																		//Octave 8
};


volatile uint16_t	refclk=39185;		// refclk=3906 = 20MHz / 510 ... increase to compensate for higher pitch
										// 510 comes from formula for calculating phase correct PWM frequency
																			
volatile uint16_t	phaccu[2] = {0, 0};
volatile uint16_t	tword[2] = {0, 0};
volatile uint16_t	twordcalc[2] = {0, 0};
volatile uint8_t	key[2] = {48, 48};
volatile uint8_t	osc[2] = {0, 0};

volatile uint8_t	waveKind[2] = {4, 4};

volatile uint16_t	dutyCycle;
volatile uint16_t	ADCinputs[INPsize];
volatile uint8_t	inputsi;
volatile uint32_t	rollingMeanADC;

volatile uint8_t	smallTimer = 0;				//Counts 1/40ms - every timer0 overflow interrupt - starts at 0
volatile uint8_t	wait = 1;					//A part of note calculations is done once after every small timer tick. After the calculation this is set to 0
volatile uint8_t	millisecs = 0;				//Counts 1 ms every 40 smallTimer clicks

volatile uint16_t	millisecsAutoButton = 0;	//Counts ms - used for AutoButton function
volatile uint16_t	millisecsSerial = 0;		//Counts ms - used for timing some serial debugging commands

volatile uint8_t	notePlaying[2] = {0, 0};	//Boolean  - enables oscillators if a note is playing
volatile uint8_t	notePlayingSum = 0;			//Boolean  - enables oscillators if a note is playing

volatile uint8_t	volume[2] = {0, 0};
volatile uint8_t	volumeRelease[2] = {0, 0};

volatile uint8_t	mainNoteADC[2] = {48, 48};		//INPUT - main note
volatile uint8_t	fine[2] = {127, 127};			//INPUT - fine
volatile uint16_t	finalNoteADC[2] = {550, 550};	//Note after sweep and vibrato are applied

volatile uint8_t	attack[2] = {80, 80};			//INPUT - Envelope attack
volatile uint8_t	decay[2] = {90, 90};			//INPUT - Envelope decay
volatile uint8_t	sustain[2] = {70, 70};			//INPUT - Envelope sustain
volatile uint8_t	release[2] = {150, 150};		//INPUT - Envelope release
volatile uint8_t	releaseMode[2] = {1, 1};		//INPUT - Release mode (0->linear or 1->nonlinear)

volatile uint8_t	envelopeStage[2] = {4, 4};		//Tracks the current stage of the envelope
volatile uint16_t	millisecsEnvelope[2] = {0, 0};	//Timer for the envelope incremented in ms

volatile uint8_t	sweepSpeed[2] = {0, 0};			//INPUT - Sweep speed (0->one semi a second, 255->fast!)
volatile uint8_t	sweepDirection[2] = {0, 0};		//INPUT - Sweep direction (0->down, 1->up, 2->from down, 3->from up)
volatile uint16_t	millisecsSweep[2] = {0, 0};		//Timer for the sweep incremented in ms

volatile uint16_t  vibratoSpeed[2] = {400, 400};	//INPUT - Vibration speed
volatile uint8_t   vibratoDepth[2] = {20, 20};		//INPUT - Vibration intensity
volatile uint8_t   vibratoWaveKind[2] = {4, 4};		//INPUT - Vibration
volatile uint16_t  vibratoPhacc[2] = {0, 0};		//Vibrato phase accumulator

volatile uint8_t   buttonPin[4] = {0x80, 0x04, 0x08, 0x10};
volatile uint8_t   button[4] = {0, 0, 0, 0};
volatile uint8_t   timerb[4] = {0, 0, 0, 0};

// volatile uint8_t buttonPin[4] = {1 << PORTB0, 1 << PORTB1, 1 << PORTB2, 1 << PORTB3};
// volatile uint8_t buttonState[4] = {0, 0, 0, 0};
// volatile uint8_t millisecsButton[4] = {0, 0, 0, 0};

//Display stuff
volatile uint8_t   millisecsFPS=0;				// Timer for 20FPS
volatile uint8_t   itemSelected[3]={0,0,0};		// Keeps track of selections across pages
volatile const uint8_t   pageItems[3]={1,5,5};	// Number of page items is +1 of the value of this variable. pageItems[0] has a value of 1 - therefore page 0 has 2 items
volatile uint8_t   page=0;						// Current page

declarations ^^^

 


inline void doEnvelope(uint8_t oscillator)
{
	waitForSample();
	switch (envelopeStage[oscillator])
	{
		case 0:
		waitForSample();
		if (button[0] && ((millisecsEnvelope[oscillator] << 4) / attack[oscillator] < 255))
		{
			volume[oscillator] = (millisecsEnvelope[oscillator] << 4) / attack[oscillator];		// millisecsEnvelope[oscillator] / (attack/16)
		}
		else if (button[0])
		{
			volume[oscillator] = 255;
			++envelopeStage[oscillator];
			millisecsEnvelope[oscillator] = 0;
		}
		else
		{
			++envelopeStage[oscillator];
			millisecsEnvelope[oscillator] = 0;
		}
		break;
	
		case 1:
		waitForSample();
		if (button[0] && volume[oscillator] > sustain[oscillator])
		{
			volume[oscillator] = 255 - ((millisecsEnvelope[oscillator] * 16) / decay[oscillator]) ;	// 255 - millisecsEnvelope[oscillator] / (decay/16);
		}
		else if (button[0])
		{
			volume[oscillator] = sustain[oscillator];
			++envelopeStage[oscillator];
			millisecsEnvelope[oscillator] = 0;
		}
		else
		{
			++envelopeStage[oscillator];
			millisecsEnvelope[oscillator] = 0;
		}
		break;
	
		case 2:
		waitForSample();
		if (!button[0] || (sustain[oscillator] == 0))
		{
			++envelopeStage[oscillator];
			millisecsEnvelope[oscillator] = 0;
		}
		break;
	
		case 3:
		waitForSample();
		if (volume[oscillator] <= 1)
		{
			volume[oscillator] = 0;
			millisecsEnvelope[oscillator] = 0;
			++envelopeStage[oscillator];
			notePlaying[oscillator] = 0;
		}
		else if (release[oscillator] > 253)
		{
			++envelopeStage[oscillator];
			break;
		}
		else
		{
			if (!volumeRelease[oscillator]) volumeRelease[oscillator] = volume[oscillator];
		
			if (!releaseMode[oscillator])
				if (volumeRelease[oscillator] > ((millisecsEnvelope[oscillator] << 4) / release[oscillator]))
					volume[oscillator] = volumeRelease[oscillator] - ((millisecsEnvelope[oscillator] << 4) / release[oscillator]); //Linear release
				else volume[oscillator] = 0;
			else
				volume[oscillator] = (volumeRelease[oscillator] * release[oscillator]) / ((millisecsEnvelope[oscillator] >> 1) + release[oscillator]) - (millisecsEnvelope[oscillator]/1000); //Non linear release
		}
	}
}

envelope function ^^^

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

here is the ISR 

 

ISR (TIMER0_OVF_vect)
{
  	if (notePlayingSum)
	{
 		phaccu[0] += tword[0];//738;440Hz
 		osc[0] = (pgm_read_byte( &waveTable[ waveKind[0] ][ phaccu[0] >> 8 ]) * 128) / 256;

		phaccu[1] += tword[1];
 		osc[1] = (pgm_read_byte( &waveTable[ waveKind[1] ][ phaccu[1] >> 8 ]) * 128) / 256;

		OCR0A = (( osc[0] * volume[0] ) >> 8) + (( osc[1] * volume[1] ) >> 8);
	}

	smallTimer++; //increment small timer 1
	if(smallTimer > 40)
	{
		smallTimer = 0;
		++millisecs;
	}
	wait = 0;
}

 

There was no problem with it until I started writing more code in my main so I kinda guessed the ISR was not the problem.

Using phase correct the 8bit timer upcounts then downcounts and interrupt flag is set at bottom. Timer clock is the CPU clock (prescale = 1). 20MHz external crystal and ISR called every 510 cycles. So ISR executed at 20MHz / 510 = 39216Hz

First ISR command is executed at TCNT0 = 32 and upcounting. Execution then leaves the ISR when TCNT0 = 177 and upcounting.

 

As I mentioned above I am now using a function that traps the execution of the main program in a while loop until the ISR is executed.

That way I can position pieces of my main code to be executed right after the ISR and not before it. The sound is fine again.

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

Last Edited: Mon. Oct 12, 2020 - 01:45 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You are using some terms that I am not familiar with. I was under the impression that a bit shift is the easiest operation and this is the reason why I am trying to as much as I can use it in my code.

For example - in stead of dividing by 9 I will prefer bit shifting >>3 is possible (I know it is equal to /8). I am very interested in learning how to make lighter code, could you point me to a source I could read?

I get what you mean by picking the higher byte, yeah that's all I want there. Union huh? I see it is some kind of.. container? Imma watch some tutorials on it

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

Last Edited: Mon. Oct 12, 2020 - 01:46 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So all in all my solution - I position my main code to be executed right after the ISR executed by trapping the execution of the main program in a while loop and freeing it from the while loop in the ISR. So it goes something like this:

 

void waitForSample()
{
    while(wait)
    wait = true
}

int main()
{
    waitForSample();
    //coomands
    //commands
    //coomands
    //commands
    waitForSample();
    //coomands
    //commands
    //coomands
    //commands
    waitForSample();
    //coomands
    //commands
    //coomands
    //commands
}

ISR(TIMER0_OVF_vect)
{
    //DDS commands
    //DDS commands
    //DDS commands
    
    //timing commands
    
    wait = false;
}

 

As Clawson said since I am using DDS this ISR needs to be on time at all costs and it wasn't. That was the problem

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Since you know about DDS would you also happen to know what are some acceptable rates of updating the envelope volumes pitch bend effects?

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

tellSlater wrote:
I asked above if you it is ok not using atomic when accessing one byte variables and am waiting for your answer! Thanks again

For single read or write, yes these are safe, but you still need to be careful with read-modifiy-write operations.  i.e. x |= (1<<y); or x = x + y;  as the value of x could change in the ISR() during the operation.

 

Jim

 

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Very helpful, thank you

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your isr is chewing up around 80% of cpu time. As for optimising your isr, it is a matter of looking at the generated code and finding ways to minimise the amount of computation in the isr - like indexing arrays. Bit shifts can be efficient, but if you need a number of them those cycles add up. Rather than do the amplitude calcs inthe isr, other methods might be to dothis in the analog domain and use another pwm for this.

The ppg wave synth used a 1ms timebase for adsr and modulation if iremember correctly. There’s also plenty of examples of mini synths using the avr, so you mightwant tolook at them to see how they approach the problem.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

80%? How did you come up with this number?

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you are making a DDS, maybe do your IRQ in assembler, you will have more finesses (control) over exactly what  is being done as efficiently as possible.

 

Here are some video examples...they also have some code postings

 

https://www.youtube.com/watch?v=...

 

if you pay a lot attention to what you are doing, you can generate 3D video at the same time

   ...both the video and audio are entirely generated using only the AVR.  

https://www.youtube.com/watch?v=...

 

 

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Mon. Oct 12, 2020 - 04:38 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Looking at #17 that is a LOT of volatile variables!! Remember that volatile really means "turn off optimisation for this thing and make the code as inefficient as you like". You should ONLY use "volatile" for the things that are shared between paths of execution and therefore MUST be volatile. For anything else you are just making the code bloated and slow.

 

So analyse the ISRs and just determine which globals in the ISRs are also accessed in main(), non-interrupt code and keep volatile on those - remove it from everything else or you are severely hampering the compiler's ability to optimize - never a great thing in time critical code.

 

(the only other use for volatile is when you are debugging and need to "see" something in the debugger that would otherwise have been optimised away - but when you are happy the code is working as intended remove volatile from any variable you hampered in this way - UNLESS it really is a shared variable).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Great stuff! Thanks

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have had the simulator and my MCU do very bizarre stuff when using non volatile variables in the past so I started only using volatiles without knowing why.

Truth is I don't exactly know where I can omit it without causing problems that would take me 3h to solve so I just kept all of them as volatile.

 

So am I only to use volatiles for variables that are --> (CHANGED in ISR) and (ACCESSED in main)?

 

If there is a global variable in ISR that is not changed in ISR but is accessed in main should I also make it a volatile?

 

If it is a constant does it automatically not need to be a volatile?

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

Last Edited: Mon. Oct 12, 2020 - 05:44 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

tellSlater wrote:

If there is a global variable in ISR that is not changed in ISR but is accessed in main should I also make it a volatile?

If it's not changed in ISR then it does not need to be volatile.

tellSlater wrote:

If it is a constant does it automatically not need to be a volatile?

Correct.

 

BTW I am still intrigued of how the frequency in your DDS can drop. The timer doesn't care what the CPU is doing; it will run at the configured rate at all times. Even if you have an interrupt latency that would not change the interrupt rate itself as long as you leave the timer running and don't manipulate the configuration (mode, prescaler, etc) or the timer value itself.

 

I have a DDS application that runs at 8192 Hz sample rate. It generates a sine wave with programmable amplitude superimposed on a linear ramp. Samples are written to a 12-bit D/A through timer interrupt. One trick I used to achieve fastest possible ISR was to have the main loop calculate the sample values and put them in a small (4 values or so) FIFO. All the ISR does is to fetch the next sample value and write to D/A. Maybe that trick could work in your application too?

/Jakob Selbing

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hmmm I see, thank you

I was thinking that the reason my ISR was delayed was that the interrupt flag was set while a 32bit calculation was executed in main or some other heavy calculation. Could that not be it?

Also, it could be a side effect of making all my variables volatile. I will comment again on this once I try to fix that

The reason why I couldn't use a fifo and wait for the ISR to fetch my samples is that it takes about 20-40 ISR cycles to calculate my envelope, note, fine, sweep and vibrato effects in main.

I don't have time-space to calculate every sample. But 40 ISR calls are about 1ms so updating the effects once a millisec is not bad

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

Last Edited: Mon. Oct 12, 2020 - 08:16 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I guessed based on the numbers you provided. It takes around 32 clocks to get in and out of your isr then add the clocks you measured. What value did you come up with?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would say 177 / 510 * 100 % of CPU time in the ISR. Timer OVF takes 510 CLK ticks (I am using the phase correct mode) and my ISR exits when TCNT0 = 177 and upcounting.. So I would guess my ISR occupies about 35% of CPU time and not 80%

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

Last Edited: Mon. Oct 12, 2020 - 08:52 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why guess when you can actually measure it? I had guessed at 256 clocks for the timer period, so that would explain my number being twice the value.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I said guess because I am not an expert and not sure if that method I used was the right way to measure it. If it is then yup - about 35%

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

tellSlater wrote:

I was thinking that the reason my ISR was delayed was that the interrupt flag was set while a 32bit calculation was executed in main or some other heavy calculation. Could that not be it?

Unless interrupts are disabled during that calculation, there should not be any extra latency. Also, as I pointed out, even if there is - it would not change the rate at which interrupts are triggered. Wouldn't you agree on that?

 

Having variable latency only means that there is some jitter in the actual time between ISR execution - it does not change the interrupt triggering rate.

 

It can be really helpful to hook up an oscilloscope to one of the I/O pins and have the ISR set the pin upon ISR entry and clear on ISR exit. This is a quick and easy way to check the interrupt rate and jitter. It also indicates the amount of CPU time consumed by the ISR (and thus how much left for main loop).

 

tellSlater wrote:

The reason why I couldn't use a fifo and wait for the ISR to fetch my samples is that it takes about 20-40 ISR cycles to calculate my envelope, note, fine, sweep and vibrato effects in main.

I don't have time-space to calculate every sample. But 40 ISR calls are about 1ms so updating the effects once a millisec is not bad

You mean that if the main loop is busy doing some processing then there is no "time slot" to do the sample calculation? Well, that is the whole point of using a FIFO. In this case you'd have to use a FIFO depth of at least 40 then. Main loop fills it first, then goes on with other processing. With a bigger FIFO you can have even longer processing in the main loop. Obviously you need to write all code in a non-blocking fashion (i.e. state machines). But you do that already, I hope? ;-)

 

 

/Jakob Selbing

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

tellSlater wrote:
I said guess because I am not an expert and not sure if that method I used was the right way to measure it. If it is then yup - about 35%

 

How to become an expert? Start off knowing f-all about something and some persistence - you'll be an expert in no time. As I've harped on earlier - the simulator can reveal many secrets. You just have to look.

 

Your isr as it is now will become a lot slower once you start selecting different waveforms etc - the compiler has optimised your fixed indexes into the tables. Give it a try and see if my expectation is valid.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I note a _delay_us(10) in the main loop.

_delay_us does not allow for interrupts.

How many interrupts can occur in 200 cycles?

Iluvatar is the better part of Valar.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In my usage of _delay_us(x) or _delay_ms(x), on those rare occasions where I do use them, I do not see them blocking interrupts in any fashion.

 

Indeed, interrupts executing during a _delay_Xs() serve only to increase the delay by whatever time is spent processing the interrupt(s).

David

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

frog_jr wrote:
In my usage of _delay_us(x) or _delay_ms(x), on those rare occasions where I do use them, I do not see them blocking interrupts in any fashion.
I think Michael's point was that with interrupts likely to go off at any moment something like _delay_us(10) does not do what it says on the tin. It could be a delay of 10us but is could be 53us or 2791us or 72894329430us (depending on how long the ISR held it from completing).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jaksel wrote:
rate at which interrupts are triggered. Wouldn't you agree on that?

 

Yeah I was thinking about that actually - even if the ISR was delayed, it should have been delayed by the same amount each iteration and therefore not drop in execution rate.

So after thinking that I arrived at the explanation that each one ISR call was delayed (for some reason I do not know (could be me having all variables volatile?)).

Each ISR would be called further and further delayed from normal execution and in the end one ISR would be skipped (TOVF0 would set while it was already high).

If interrupt timing gives me more problems I will use the method you provided (toggling a pin in ISR) to test that theory

 

jaksel wrote:
have the ISR set the pin upon ISR entry and clear on ISR exit

 

I will use this if I run into more ISR timing problems. Fortunately that while() trick really helped for now

 

jaksel wrote:
You mean that if the main loop is busy doing some processing then there is no "time slot" to do the sample calculation?

 

I mean that the sample takes more time to be calculated than the period of ISR callings so if I pop one sample from the FIFO in every ISR the FIFO would be emptied. Am I not getting something? Could you send me an example?

 

jaksel wrote:
Obviously you need to write all code in a non-blocking fashion 

 

Everything is written in a non blocking fashion except for my silenceOscilator() function that takes 2ms to execute and silence an oscillation. I didn't see no reason to make a more complicated, non-blocking implementation for this

 

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

Last Edited: Tue. Oct 13, 2020 - 10:57 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oh god... Not my ISR. I am starting to have some tremors just by thinking that. I will try it

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Only one. An interrupt triggers per 510 cycles. I was testing things out with that delay. It is not part of the code really.

Is it true that no ISRs are called during _delay_ms and _delay_us functions?

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Can I delete a post? I was just messing around trying to figure out how to quote

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

Last Edited: Tue. Oct 13, 2020 - 05:50 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
does not do what it says on the tin.
Oh that is ok then I am aware of this - I didn't need precise timing there.

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have been anxiously thinking about this the past hour but now I realize - this is the final form of the ISR. These indexes (0 and 1) represent the two oscillators I am running. This will be the final form of my ISR

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
void waitForSample()
{
    while(wait)
    wait = true
}

 

This bothers me, what if the interrupt occurs after the while statement, but before "wait = true".  In this case the wait flag is cleared by the interrupt, then set with "wait = true", and you miss that the interrupt occurred.

void waitForSample()
{
    wait = true
    while (wait)
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Very unlikely to happen but then again..

Yep! Much better - I fixed it, thanks

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

tellSlater wrote:
Only one. An interrupt triggers per 510 cycles. I was testing things out with that delay. It is not part of the code really.

Is it true that no ISRs are called during _delay_ms and _delay_us functions?

Those functions do not call other functions.

If by "called", you mean invoked by an interrupt, the answer is maybe.

Neither disables interrupts.  They will have little effect on the timing of interrupts.

In principle, ISRs can be called.

'Tis rarely, if ever, done.

If, for some reason, you choose to do so, be careful:

An ISR could include code that relies on interrupts being disabled.

An ISR ends with a RETI instruction that will enable interrupts.

That might not be what you want.

Iluvatar is the better part of Valar.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

After I removed the volatile keywords from all variables that were not shared with the ISR I discovered that I no longer have the sound problem - I don't need to use the waitForSample() function.

So my guess now is that the ISR was not called while a calculation that involved volatile variables took place.

Now that almost all variables in main are not volatile, the calculations that involve them are probably paused when the interrupt flag is set and the ISR is not delayed

TO THE FINDER... THE ISLE OF KOHOLINT, IS BUT AN ILLUSION... HUMAN, MONSTER, SEA, SKY... A SCENE ON THE LID OF A SLEEPER'S EYE... AWAKE THE DREAMER, AND KOHOLINT WILL VANISH MUCH LIKE A BUBBLE ON A NEEDLE... CAST-AWAY, YOU SHOULD KNOW THE TRUTH!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

tellSlater wrote:
After I removed the volatile keywords from all variables that were not shared with the ISR I discovered that I no longer have the sound problem

Doesn't sound like a surprise: the whole point of 'volatile' is to prevent certain compiler optimisations.

 

So if you use 'volatile' where it's not needed, it will unnecessarily slow down your code.

 

Edit: clawson already said this in #27

 

Nine ways to break your systems code using volatile

 

 

my guess now is that the ISR was not called while a calculation that involved volatile variables took place.

No, that's not how it works.

 

volatile just prevents the compiler from "caching" old values of a variable - it has nothing to do with blocking interrupts.

 

An important upshot of this is that 'volatile' does not give atomic access.

 

EDIT

 

clawson wrote a Tutorial on it: https://www.avrfreaks.net/forum/tutcoptimization-and-importance-volatile-gcc

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Thu. Oct 15, 2020 - 09:11 AM

Pages