Timer overflow ISR execution is delayed - precise timing needed.

Go To Last Post
105 posts / 0 new

Pages

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

It's worth noting that if you really need 'to-the-clock-cycle' timing precision you need external hardware, because the AVR will finish executing what might be a multi-cycle instruction before branching to the interrupt handler, and you have no way of knowing where you were in that multi-cycle instruction when the interrupt fires.  Probably not a big problem for audio frequency work.   S.

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

tellSlater wrote:
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?

This is very confusing. If each sample takes more time to calculate than the ISR period then it would not help to do the calculation in the ISR - you'd still fail to supply samples at the rate you are trying to achineve! Obviously if you do the calculation in the ISR then a new interrupt would trigger before the ISR is done. If you do the calculation in the main loop then it would not matter how large the FIFO is - the main loop still would not be able to produce samples quickly enough.

 

So I think you have misunderstood something.

 

You only have one CPU and it can only do one thing at a time. For each sample to produce it must execute a bunch of instructions. That can either be done in the main loop (using FIFO) or in the ISR. The amount of CPU time required is the same for both solutions - they are equally efficient in that respect. However in general you want as short ISR as possible so the former solution (main loop) would be preferred in my opinion. Obviously your solution may still work as long as the application is designed to tolerate the longer interrupt latency.

 

/Jakob Selbing

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

These were some great reads, thanks. Now then, I wonder why making my variables non-volatile solved the ISR timing 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

tellSlater wrote:

These were some great reads, thanks. Now then, I wonder why making my variables non-volatile solved the ISR timing problem

Maybe the ISR became too slow to execute that it would not complete before next interrupt triggered. Did you check that?

/Jakob Selbing

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

I would appreciate if you could send me a small FIFO sampling example, I don't think I have understood how it should be used

 

It is necessary that this part of the sample is calculated in the ISR - the calculation needs to be executed at 39K times a sec to get the right note. I cannot omit this part of the sample calculation from the ISR.

However calculations calculations regarding envelope volumes vibratos etc are calculated in main about 1000 times a sec.

 

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

No that was not it - as I stated in previous post the ISR was executed 35% of the CPU time. It exited when the TCNT0 was 177 and upcounting. Therefore 177/510 = 35% give or take (510 timer ticks until overflow because phase-correct mode is used)

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: Wed. Oct 14, 2020 - 05:40 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

tellSlater wrote:
It is necessary that this part of the sample is calculated in the ISR - the calculation needs to be executed at 39K times a sec to get the right note.

But you don't really need to calculate the sample just at the specific time at which it is needed. You could calculate a bunch of samples and between each increment just increment the time variable. 

 

Using pseudo-code, you could go from this

ISR
{
   level = calculate_sample(t); // takes long time!
   PWM = level;
   t++;
}

 

to this

ISR
{
   level = fifo_read(); // takes short time
   PWM = level;
}

main
{

  while(1)
  {
      while (fifo_not_full())
      {
        sample = calculate_sample(t);
        fifo_write(sample)
        t++;
      }

      // do other stuff here...

  }
}

 

/Jakob Selbing

Last Edited: Wed. Oct 14, 2020 - 06:01 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

tellSlater wrote:

These were some great reads, thanks. Now then, I wonder why making my variables non-volatile solved the ISR timing problem


Suggest you re-read #27
.
https://www.avrfreaks.net/comment/3011266#comment-3011266

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

I get it now, thanks for taking the time to explain

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 already read that many times! I did exactly that.

But I thought that even if a calculation involving volatile variables was taking place, the ISR call still should not have been delayed - which it did (most probably anyways, since the sound pitched down).

Also when I removed the volatile from the appropriate variables that delay disappeared. This is why I am a bit baffled

I wish I knew how to read assembly - maybe then I could get a better understanding on this. I was looking for some tutorials on AVR assembly or assembly in general?(I dunno the difference)

If anyone knows a good source please link it for me

 

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

This example is extreme but:

#include <avr/io.h>

int value() {
	int a, b, c;
	a = 57;
	b = 31;
	c = a * b;
	return c;
}

int main(void) {
	PORTB = value();
	while (1) {
	}
}

When I don't use volatile:

0000007a <value>:
	int a, b, c;
	a = 57;
	b = 31;
	c = a * b;
	return c;
}
  7a:	87 ee       	ldi	r24, 0xE7	; 231
  7c:	96 e0       	ldi	r25, 0x06	; 6
  7e:	08 95       	ret

You don't have to be an Asm expert to recognise (I hope) that all that is happening here is that the compiler has already calculated what 57 * 31 is. It is 1767 which is 0x06E7 so this code just returns the R25:24 pair with 0x06 and 0xE7 in it.

 

Now I make them volatile:

int value() {
	volatile int a, b, c;
	a = 57;
	b = 31;
	c = a * b;
	return c;
}

which results in:

0000007a <value>:
#include <avr/io.h>

int value() {
  7a:	cf 93       	push	r28
  7c:	df 93       	push	r29
  7e:	00 d0       	rcall	.+0      	; 0x80 <value+0x6>
  80:	00 d0       	rcall	.+0      	; 0x82 <value+0x8>
  82:	00 d0       	rcall	.+0      	; 0x84 <value+0xa>
  84:	cd b7       	in	r28, 0x3d	; 61
  86:	de b7       	in	r29, 0x3e	; 62
	volatile int a, b, c;
	a = 57;
  88:	89 e3       	ldi	r24, 0x39	; 57
  8a:	90 e0       	ldi	r25, 0x00	; 0
  8c:	9a 83       	std	Y+2, r25	; 0x02
  8e:	89 83       	std	Y+1, r24	; 0x01
	b = 31;
  90:	8f e1       	ldi	r24, 0x1F	; 31
  92:	90 e0       	ldi	r25, 0x00	; 0
  94:	9c 83       	std	Y+4, r25	; 0x04
  96:	8b 83       	std	Y+3, r24	; 0x03
	c = a * b;
  98:	49 81       	ldd	r20, Y+1	; 0x01
  9a:	5a 81       	ldd	r21, Y+2	; 0x02
  9c:	2b 81       	ldd	r18, Y+3	; 0x03
  9e:	3c 81       	ldd	r19, Y+4	; 0x04
  a0:	42 9f       	mul	r20, r18
  a2:	c0 01       	movw	r24, r0
  a4:	43 9f       	mul	r20, r19
  a6:	90 0d       	add	r25, r0
  a8:	52 9f       	mul	r21, r18
  aa:	90 0d       	add	r25, r0
  ac:	11 24       	eor	r1, r1
  ae:	9e 83       	std	Y+6, r25	; 0x06
  b0:	8d 83       	std	Y+5, r24	; 0x05
	return c;
  b2:	8d 81       	ldd	r24, Y+5	; 0x05
  b4:	9e 81       	ldd	r25, Y+6	; 0x06
}
  b6:	26 96       	adiw	r28, 0x06	; 6
  b8:	0f b6       	in	r0, 0x3f	; 63
  ba:	f8 94       	cli
  bc:	de bf       	out	0x3e, r29	; 62
  be:	0f be       	out	0x3f, r0	; 63
  c0:	cd bf       	out	0x3d, r28	; 61
  c2:	df 91       	pop	r29
  c4:	cf 91       	pop	r28
  c6:	08 95       	ret

You don't have to try and decode that to know you don't want it !!!

 

Imagine the same thing happening all over your code because you made all your principle variable "volatile" ! It doesn't just make it "big and bloaty", It's also hundreds if not thousands of extra machine cycles to execute all that additional stuff.

Last Edited: Thu. Oct 15, 2020 - 08:33 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

tellSlater wrote:
the ISR call still should not have been delayed - which it did

Did it? What makes you think that?

 

If the rest of the code was too bloated and slow to keep up with the interrupts, couldn't that also have caused the problem ... ?

 

Note that making variables (and functions) static can give the compiler some extra optimisation opportunities ...

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...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You could always take a different approach and ditch the whole idea of main() plus an ISR, and just do everything in the ISR. You can write code that guarantees no jitter on your output.

 

Timer_ISR() {

    //Reload Timer

    //Do timing critical stuff

    //Do non-timing critical stuff

    //Ditch return address

    //SEI

    //SLEEP

    While (1) {
        ;
    }

}

main() {

    Initialise();
    
    start_timer();

    SEI;

    while (1) {
        ;
    }

}

 

#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

Yeah that is a hell of a difference. I am only concluding the ISR was delayed by the sound which was pitched down. I don't really have good evidence yet and am not 100% sure that it was delayed

 

So I should make static functions - only visible to the current main.cpp?

And also prefer using static local variables rather than global variables?

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 bringing that example up.

Truth is I already read one of your posts on this forum on the subject and was pretty helpful in understanding 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!

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

The interrupt call would need to happen during

//Do non-timing critical stuff.

where the interrupt flag is not yet set in your psudo-code thus probably causing timing problems again.

I see where you're going with this though

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:

The interrupt call would need to happen during...

 

I think you misunderstand, you do the non-critical stuff in the ISR after the critical stuff. Nothing is done in main() (in fact, once the ISR has fired it NEVER returns to main().

 

My proposal guarantees a fixed, and non-varying, response time to the timer interrupt; there can be no jitter.

#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

Brian Fairchild wrote:

tellSlater wrote:

The interrupt call would need to happen during...

 

My proposal guarantees a fixed, and non-varying, response time to the timer interrupt; there can be no jitter.

 

I really cannot see how this can happen. The interrupt would take more than 510 clock cycles to execute the non time critical stuff which is more time than the demanded ISR call period

 

Timer_ISR() {

    //Reload Timer

    //Do timing critical stuff

    //Do non-timing critical stuff !!!Secont ISR call needs to happen here but interrupt flag is disabled

    //Ditch return address

    //SEI

    //SLEEP

    While (1) {
        ;
    }

}

main() {

    Initialise();
    
    start_timer();

    SEI;

    while (1) {
        ;
    }

}

 

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

You split up the non-critical stuff. Do some of it one time through the ISR, and something different the next time. By doing it in the ISR you automatically have a timebase to do things like ADSR.

 

If you can't do that then you have a more fundamental problem with not enough CPU cycles per unit-time to do what needs to be done.

#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

Hmm yeah if you split the non-critical it is doable. Would you say this method is better? I mean putting all the code into the ISR.. and if so why?

I like your #5 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!

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

tellSlater wrote:

Would you say this method is better? I mean putting all the code into the ISR.. and if so why?

 

It's the method I use to generate accurate, predictable, jitter-free signals. It's the way I have generated video timing signals which are 100% correct and have absolutely zero timing jitter.

 

Is it the best method? I think so but YMMV.

#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

Brian Fairchild wrote:

Timer_ISR() {

    :
    :

    //Ditch return address

How do you do that in 'C' ?

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...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Brian Fairchild wrote:
fundamental problem with not enough CPU cycles per unit-time to do what needs to be done

That was the point I was trying to make in #63 - and others had also said previously.

 

Not sure OP has (fully) grasped it yet?

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...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:
How do you do that in 'C' ?

SP += 2;

perhaps? (well OK you'd have to examine the stack frame but as ISR entry is naked I think it's just removing the stacked PC by an adjustment of 2 to SP).

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

clawson wrote:

perhaps? (well OK you'd have to examine the stack frame but as ISR entry is naked I think it's just removing the stacked PC by an adjustment of 2 to SP).

 

Exactly that, or whatever syntax your compiler supports.

#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 just don't understand how some bloated code in main could be the reason of a delayed interrupt call

when it was earlier mentioned that whatever calculation happens in main atm the interrupt is supposed to be called immediately - no delay.

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

Would you mind explaining or linking some reads on this matter? I mean ditching return address and what that SP register is

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

SP = Stack Pointer. It's a fairly universal thing. Most CPU architectures have one (sometimes several).

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

http://www.avr-asm-tutorial.net/...

 

For some reason Assembler has the aura of magic runes only to be conjured by the high priests. Reality is that it is stunningly simple. Like building a house from Lego bricks - each instruction does a very simple operation. Even having a basic idea of how the C code is being translated is useful especially when you need to do things fast.

 

The main reason us oldies know assembler is simply because when we started, C compilers were inefficient, stupid expensive and besides the micros we had might have been lucky to have 256 bytes. 4K on a ZX80- luxury! And, we didn't have a PC as we know them today that had the resources to run a compiler.

 

You might want to seek out other AVR projects where they have done synthesis - 

https://create.arduino.cc/projec...

 

There the whole gamut from very simple to ones that blow my mind where the designer has pulled some weird ass tricks and made them work. Or you get a 600MHz processor like Cliff has. One channel of DDS can be done at over 100MHz. Also being a 32bit cpu helps.

 

 

 

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

If the ISR needs 60% of the CPU and the main line needs 50%, something will give.

Absent disabling interrupts, the main line cannot delay an

interrupt by more than the few cycles required for an instruction.

What will happen is that the main line will not get its work done.

If the ISR relies on the main line getting its work done,

the ISR will produce the wrong results.

Iluvatar is the better part of Valar.

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

Something is nagging me about this, I may be wrong and need to think more but...

 

for DDS you run the accumulation at a constant clock speed and do something when it overflows, or you simply use the upper n bits to address a LUT. You say that you are running your timer in phase correct pwm mode which means the interrupt/accumulation rate will vary along with the PWM width. It just feels wrong.

#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

tellSlater wrote:
I just don't understand how some bloated code in main could be the reason of a delayed interrupt call

Again, who says that the interrupt call is being delayed ?

 

That's the point.

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...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Do you have a 'scope?

 

Two output pins, even if temporarily repurposed, one which goes high at the start of main and one at the start of the ISR which clear sat the end of it. Each clears the other.

#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

No the OVF happens constantly every 510 CLK cycles and has no relation to the PWM width - OCR0A. Is LUT a lookup table? I think I am using one LUT for every wave form but I am only accessing it in the OVF interrupt where the final sample calculations happen before outputting.

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 don't remember seeing your code which sets up the timers. Can you post it?

#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

jaksel also suggested I use a similar trick to make sure I know what is going on. I am going to use this in the future if I get more timing problems and make a more detailed post about it.

Right now I am not really in the mood of re-writing all the code as it was 4 days ago just to see what was going on

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
inline void setupTIMERS() //Sets up TIMER0 overflow interrupt and PWM
{
	OCR0A  = 0;
	TIMSK0 = (1 << TOIE0);   //overflow interrupt - timer0
	TCCR0A = (1 << COM0A1) | (1 << WGM00);   //PWM and timer modes - timer0
	
	TIMSK1 = (0 << TOIE1);   //overflow interrupt - timer1 (I am not using timer1 anymore but kept the commands here for future use)
 	TCCR1A = (0 << WGM10);   //timer mode - timer1
	
	TCNT0 = 0x00;
	TCNT1 = 0xff;
	TCCR0B = (1 << CS00);   //clock source = CLK, start PWM - timer0
	TCCR1B = (0 << CS10);   //clock source = CLK, start PWM - timer1
}

 

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

Again, I concluded that from the sound which I realize is not hard evidence. But still strong enough IMO to give it a 80% chance that it actually was due to ISR delayed execution. I may revisit this in the future and use jaksel - Brian method to ensure and post results.

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

Brian Fairchild wrote:
You say that you are running your timer in phase correct pwm mode which means the interrupt/accumulation rate will vary along with the PWM width. It just feels wrong.

I don't think the interrupt rate will vary in phase-correct PWM. Unless you change the top value, of course...

/Jakob Selbing

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

tellSlater wrote:
Right now I am not really in the mood of re-writing all the code as it was 4 days ago just to see what was going on

I assume you are not using any version control software? I would strongly recommend to do so!

 

Take a look at e.g. tortoise SVN: https://tortoisesvn.net/

/Jakob Selbing

Last Edited: Sun. Oct 18, 2020 - 06:01 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks! I will

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:

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

This is not safe.  Here is an example of a failure sequence.

 

// assume wait is 1 here

load wait into register

interrupt occurs, setting wait to 0

test register 

if register == 1 (which it does), set wait to 1

// at this point, the setting of wait to 0 by the ISR is lost

 

Perhaps you meant

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

 

Last Edited: Sun. Oct 18, 2020 - 09:29 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, thank you for bringing it up. In an earlier post it was proposed that I change it to:

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

Would you say this form is ok? This is what I am using 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

tellSlater wrote:

Yes, thank you for bringing it up. In an earlier post it was proposed that I change it to:

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

Would you say this form is ok? This is what I am using now.

What if wait is false when you enter the function?  You will miss it.  Problems like this are why many computer instruction sets had instructions like test-and-set, where you could get the value of a flag and set it in the same instruction, so you would never miss a valid setting.

 

The best thing to do is to set wait = true once, as soon as possible after you detect that it is false, and no other time.  Then you have more assurance that the ISR has very recently set wait to false.  So actually this is better, because wait is set back to true immediately after you detect that it is false:

void waitForSample()
{
    while(wait)
        ;           // I always put ; here to make it more visible
    wait = true;
}

 

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

But if wait is false when you enter waitForSample, the first assignment turns it to true.. I don't think you can miss it.

On the contrary wait could be assigned false outside the function. Then after the function is called and wait is false, the "waiting" does not happen at all.

That is something we were talking about here on a previous post. Because I am changing the value of wait in an ISR the assignment must happen before the while loop in the function.

If I set wait to true after the while loop there is no guarantee that it wont change to false before the next call of the function.

If I set wait to 1 right before the while loop it is guaranteed that the execution will stall between this assignment and inside the while loop until wait is changed to false in the 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

tellSlater wrote:

But if wait is false when you enter waitForSample, the first assignment turns it to true.. I don't think you can miss it.

You just did miss it.  On entering waitForSample, either wait will be true or it will be false.  It seems to me that those are not the same situations, and you should not treat them the same.

Quote:
That is something we were talking about here on a previous post. Because I am changing the value of wait in an ISR the assignment must happen before the while loop in the function.

If I set wait to true after the while loop there is no guarantee that it wont change to false before the next call of the function.

If I set wait to 1 right before the while loop it is guaranteed that the execution will stall between this assignment and inside the while loop until wait is changed to false in the ISR.

The only guarantee you can have is if you set wait to true immediately after the ISR sets it to false.  If you wait a long time before setting wait to true, it may get set to false by the ISR just before you set it to true, and then you missed it getting set to false.

 

The sequence you generally want is this

while (1)
{
    wait_for_ISR_signal();
    reset_ISR_signal();  // do as soon as possible after receiving signal
    do_stuff();
}

What you seem to be doing is this

 

while (1)
{
    reset_ISR_signal();  // do as soon as possible after receiving signal
    wait_for_ISR_signal();
    do_stuff();
}

I'm not saying your sequence won't work, I'm just saying it gives you less timing margin and that makes it more fragile.

 

Last Edited: Mon. Oct 19, 2020 - 07:25 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I picked testandclear instead of tesetandset because avr-gcc keeps zero in R1.

uint8_t testandclear(volatile uint8_t *ptr) {
    uint8_t sreg=SREG;
    SREG &= ~_BV(SREG_I);  // i.e. cli
    uint8_t retval= *ptr;
    // SREG=sreg, if brave or hand-compiling
    *ptr=0;     // should be a single machine insntruction
    SREG=sreg;  // here if neither brave nor hand-compiling
    return retval;
}  // testandclear

Except for the return, all statements are volatile accesses and may not be reordered.

Iluvatar is the better part of Valar.

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

I was curious so I looked at the AVR instruction set.  AVR has XCH, which exchanges (Z) and some register r.  This will give the same safe result as a test-and-set, or test-and-clear, depending on what value you load into r before executing the instruction.  

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

kk6gm wrote:
On entering waitForSample, either wait will be true or it will be false.  It seems to me that those are not the same situations, and you should not treat them the same.

 

Ok then I really am missing something big I have not understood:

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

a) If wait is false, true will be assigned to it and then execution will continue to while loop.

b) If wait is true, true will be assigned to it and then execution will continue to while loop.

ISR could be called at any point, setting wait to false. But this is ok - the while loop will be skipped and that is the whole purpose of it anyways.

 

What am I missing? Is this not how it will work? I am not a programmer nor computers engineer so please help me understand - if you have a source please link it

Is this code in #98 equivalent?

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 19, 2020 - 09:08 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I drew this diagram to try and explain the difference in the two versions of waitForSample in #95.  Yours is the top code there, mine is the bottom code.

 

The diagram assumes timer interrupts every 10ms, hence the marks at 0ms, 10ms, 20ms, etc.  For each figure A, B, C and D, the line is high when main code is running, then goes low while looping in waitForSample before resynchronizing with the timer at point X, where main code runs its next pass.

 

In figure A, main code runs for 6ms, then calls waitForSample which waits for 4ms until the timer ISR sets wait = false, which causes waitForSample to return and main code begins running again (at X).

 

In figure B, main code runs for 9ms, then calls waitForSample which waits for 1ms until the timer ISR sets wait = false, which causes waitForSample to return and main code begins running again (at X).  In both A and B, main code begins running again at 10ms point (plus a few microseconds to return from waitForSample).  In both examples A and B, the code behaves the same (and as desired) for either version of waitForSample.  But now comes the problem (examples C and D).

 

In figure C, which uses my version of waitForSample, main code runs for 11ms, running past the timer interrupt at 10ms.  This is not an ideal situation, but in many systems it might happen.  Now when waitForSample is called at 3A it sees that wait has been set to false (at 10ms) and returns immediately, and main code runs slightly late but still within the interval of 10ms-20ms.

 

In figure D, which uses your version of waitForSample, main code runs for 11ms, running past the timer interrupt at 10ms.  Now when waitForSample is called at 3B it misses the fact that wait was set to false at 10ms, so it waits all the way until the next tick at 20ms before main code resumes.  The entire interval 10ms-20ms has been lost.  An entire slot of work has not occurred.  If you were maintaining a tick counter in main code, in figure D you have lost a tick count, while in figure C you would not lose a tick count.

 

 

Last Edited: Tue. Oct 20, 2020 - 07:03 AM

Pages