trouble with timer overflow flags

Go To Last Post
13 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am testing a small timer program but it doesn't work properly. here is the program:


uint16_t overflow_counter = 0;
uint8_t  flag = 0;

ISR (TIMER0_OVF_vect )
{
	overflow_counter++ ;

	if ((overflow_counter & 500) == 500)
	{
		flag = 1;
	}

	TCNT0 = 256-125 ;
}

void timer0_init()
{
	TCNT0 = 256-125 ;
	TCCR0 = 0x02;  //prescaler 8 so for a 1MHz clock frequency--> 8*125*1us = 1000us = 1ms
	TIMSK |= 1;
	SREG |= 1 << 7;
}

void main()
{
	timer0_init();
	DDRA = 0xff;
	PORTA = 0;

	while (1)
	{
		if (flag)
		{
			PORTA = PORTA + 1;
			flag = 0;
		}

		_delay_us(100);

	}

}

the problem is that every 500ms PORTA doesn't increase by one, but instead it increases by 4 or more

This topic has a solution.
Last Edited: Tue. Feb 6, 2018 - 11:28 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I can see a few problems -
Shared variables must be declared volatile.
Eg: volatile uint8_t flag = 0;

ANDing overflow_count with 500 is going to give interesting results. Try it on paper to see what happens. Why did you not simply test it to be >= 500?
I’d suggest using the CTC mode the timer as this takes care of reloading the timer for you.

Last Edited: Tue. Feb 6, 2018 - 10:42 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I changed the flag test into this:

if ((overflow_counter % 500) == 0)

{

flag = 1;

}

and it worked finally!!! .. thank you sir.. but how did you know that the problem was in this part:

if ((overflow_counter & 500) == 500)
	{
		flag = 1;
	}

 logically it would work .. can you explain to me the wrong with this expression, please?

Last Edited: Wed. Feb 7, 2018 - 02:43 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ali_aw1995 wrote:
logically it would work .. can you explain it to me please?

Logically it wouldn't work.  Try for yourself.  Take the binary pattern for 500 -- 0x01f4.  So your test will be true for 0x1f4 and 0x1f5 and 0x1f6 and 0x1f7 to start.  And also with e.g. 0x3f4 and so on?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

% does a modulus which has a implied division. This is a reasonably expensive operation on an AVR considering what you want to do is count 500 ticks. Comparing with 500 then setting the value back to 0 is much easier for the AVR. Also note that using your method, the result is not correct when the value of overflow_count rolls over. Another reason for not using %

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

but the expression is not just an AND operation:

if ((overflow_counter & 500) == 500)

the last part (== 500) insures that all the bits of 500 must be high in the variable otherwise -like in the cases you've wrote- there are some bits that won't be set to 1  and the result of the AND operation won't == 500

Last Edited: Wed. Feb 7, 2018 - 02:57 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

actually in the real program there are 4 other flags with different counter values, that's why I can't clear it because other flags depend on it, the only way I see in this method is to use more than a counter which would waste memory, I was trying to find a an expression that could work without the need to clear the counter.

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

I tried another expression:

 

    if ((overflow_counter & 0x01ff) == 0x01f4)//500 ticks ---0x01f4 = 500, 0x01ff is masking all bits beneath 500

    {

        ship_shoot_flag = 1;

    }

 

and it worked solved the problem too, I don't exactly know why, but at least it's faster than % method

 

[EDITED]: this turned out it doesn't work properly too .. :(

Last Edited: Sun. Apr 15, 2018 - 01:00 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

I’d suggest you get a pencil and paper to work it out. Then you’ll understand it. Doing stuff you don’t understand will usually end up biting you.

ANDing as a form of modulus only works with binary 1bits. As well your modulus technique would give 131 flags of 500 then one of 532.

If you want four times, use four counters. Are you really pushed for ram?
And use CTC mode for your timer interrupt. It is much more accurate and requires less code.

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

If you must have 4 timings  from 1 variable, then set flag to the highest match so far.  So if you want to match at 500, 600, 750, 800(off), flag will be either  0 (no match/exceed), 500, 600, 750, or 800.   Then by polling flag you can determine how many times have elapsed:

In the irq, zero the overflow counter after it >= the max value (800)...so the overflow count endlessly cycles 0 to 800, very precisely

 

example for making variable pulse widths (not variable freq):

if flag>=500 turn on led1 ...the on time is from 500 to 800

also

if flag>=600 turn on led2 or other action           ...the on time is from 600 to 800

also

if flag>=750 turn on led3 or other action          ...the on time is from 750 to 800

also

if flag=800 turn off leds & clear flag...note flag should be cleared before overflow counter can get back to 500, to keep the 500 flag marker accurate 

 

So this sets a cycle time of approx. 800 counts (blurred by your polling time), with a few events happening along the way.  This assumes the shortest could can only occur once per the longest timing.

 

Perhaps get rid of the delay, since it lowers the precision of when you know (poll) the times have elapsed, creating some jitter in your outputs.

 

 

When in the dark remember-the future looks brighter than ever.

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

ali_aw1995 wrote:
I don't exactly know why,

Because you are doing a different test than your original approach.  You are just masking the lower 9 bits, and then doing a comparison of the result against a particular value.  Now, why you don't use >= as suggested for "defensive programming is a topic for another day.

 

ali_aw1995 wrote:
the last part (== 500) insures that all the bits of 500 must be high in the variable

True, but the result will still be a match if there are more bits set, as in the values I gave.

 

Kartman wrote:
I’d suggest you get a pencil and paper to work it out.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

The scheme is faulty. Any number xxxx xxx1 1111 x1xx  will produce a match, as long as the "500"  bits are set .  Also, since overflowcounter just wraps around you'd get poor results if you actually wanted multiple matches in that interval...they'd need to be equally spaced, or you'll have timing jitter.  For example, saying give a pulse every 100 counts, will fail when the count rolls over at 655535, since they are not multiples.  For example, if the rollover were 15  (16 states), you could find 4  equally spaced intervals (3,7,11,15, or 1,5,9, 13, etc).  However 3 intervals would not work.

 

Is your final goal to produce a certain pulse width or a certain pulse frequency?

When in the dark remember-the future looks brighter than ever.

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

Most often you get better help by specifying the problem you are trying to solve, rather than trying to debug the code you have written to solve the problem.

David (aka frog_jr)