Yahoo Groups archive

AVR-Chat

Index last updated: 2026-04-28 22:41 UTC

Thread

Optimization levels in WinAVR, wierd problem.

Optimization levels in WinAVR, wierd problem.

2009-04-30 by David VanHorn

Bear with me, this isn't simple.

I have two sensors, each outputs a square wave.
I need to accurately measure the period of each, and determine the
difference in the two periods.

Depending on how I set the optimization, I get different results.

At -Os, I see values like 292, 304, 316.
The values are spaced by 12!
I won't ever see 305, 306, 307...

If I recompile with -O0, the spacing between the values is different,
but still mostly three discrete steps in values with nothing in
between.

I'm using an M644 at 20 MHz, T1 is running at CK/1

The basics are that I stop the clock to T1, and clear it.. Then I wait
till I see a low, then wait till I see a high, then I start the timer.
 With the timer running, I wait till I see low, high, low high... till
five periods have passed, then I stop the clock to T1, and take the
data.

Having done that, I do the same thing for the other sensor, then
subtract the second sensor from the first, which should give me some
small-ish value. The exact number isn't important, but what is
puzzling me is that the intermediate values are missing. Like somehow
I'm loosing low bits, but the delta is 12, which makes no sense from a
binary perspective.



// Prep for aquisition
TCCR1B &= ~(1<<CS10);				
// Stop T1 (should already BE stopped,
// but it's cheap insurance)

TCNT1=0;			
// Clear T1	
		
// Sync to the A channel
while (  Sensor_Pin & (1<<ChannelA));
// Wait for a low, so we know we're not seeing
// a high level yet
while (!(Sensor_Pin & (1<<ChannelA))); 	
// Wait for the high edge

TCCR1B |=(1<<CS10);// START the clock to T1

// T1 is now counting the period width.
// That can be as little as 25us
// (5 periods *  5us * 20 MHz =  500 counts)
// or as much as 138 uS
// (5 periods * 23uS * 20 MHz = 2300 counts)

while (  Sensor_Pin & (1<<ChannelA));
// Wait for a low on PD2
while (!(Sensor_Pin & (1<<ChannelA)));
//  Wait for a high on PD2	
// One pulse has gone
while (  Sensor_Pin & (1<<ChannelA));
while (!(Sensor_Pin & (1<<ChannelA)));		
// Now two
while (  Sensor_Pin & (1<<ChannelA));
while (!(Sensor_Pin & (1<<ChannelA)));		
// Now three
while (  Sensor_Pin & (1<<ChannelA));
while (!(Sensor_Pin & (1<<ChannelA)));	
// Now four
while (  Sensor_Pin & (1<<ChannelA));
while (!(Sensor_Pin & (1<<ChannelA)));	
// Now five

TCCR1B &= ~(1<<CS10);	
// Stop T1
A_Sensor_Raw = TCNT1;	
// Grab the data
TCNT1=0;		
// Clear T1 for the next measurement.

// Sync to the B channel, and proceed as above
while (  Sensor_Pin & (1<<ChannelB));
while (!(Sensor_Pin & (1<<ChannelB)));
TCCR1B |=(1<<CS10);
while (  Sensor_Pin & (1<<ChannelB));
while (!(Sensor_Pin & (1<<ChannelB)));
while (  Sensor_Pin & (1<<ChannelB));
while (!(Sensor_Pin & (1<<ChannelB)));
while (  Sensor_Pin & (1<<ChannelB));
while (!(Sensor_Pin & (1<<ChannelB)));
while (  Sensor_Pin & (1<<ChannelB));
while (!(Sensor_Pin & (1<<ChannelB)));
while (  Sensor_Pin & (1<<ChannelB));
while (!(Sensor_Pin & (1<<ChannelB)));
TCCR1B &= ~(1<<CS10);	
Temp2 = TCNT1;
TCNT1=0;					

//**********
// Condition according to sensor
// Scale to fit the histogram array
// Take the difference, and add half
  A_Sensor_Raw = ((A_Sensor_Raw - Temp2) + (Sample_Bins/2));
 // If the value is out of range then wrap it
 A_Sensor_Raw = (A_Sensor_Raw & 0x01FF);


Why do I not see output like 290,291,292... ?

-- 
There is no computer problem which cannot be solved by proper
application of a sufficiently large hammer.

Re: [AVR-Chat] Optimization levels in WinAVR, wierd problem.

2009-05-01 by A & T Schrum

With the timer running at CK/1, then does it not run at the CPU clock 
speed? That would mean
that instructions that take a couple of cycles to execute will allow for 
a couple of cycles on the
timer to pass.

The sequence of steps you do in finding the 5 wave forms are very 
repeatable. The final transition
on the fifth cycle to where you detect it and stop happens between where 
you last read the signal
(and it is false) to where you read it and it is true. Then you stop the 
timer. The resolution that you
will get is essentially the size of your last "while" statement check 
for the last transition of your waveform.
That loop is a bit test and branch not equal or equal which is probably 
three cycles (and three counts on
the timer). All the rest in front is essentially ignored and the 
instructions stopping the timer are a fixed
constant relative to the granularity of the timer values.

Optimization of -Os reduces space at the loss of efficient processing in 
the code. It may be
that the last "while" statement is done in a manner that is less 
efficient in time than the other and
you end up with 12 clocks.

Check the assembly code of that last loop and that should correspond to 
the granularity of your
timer value.

If you want greater accuracy, either sample more waveforms (how about 15 
since you have a
multiple of three in your timer value), or use an external trigger to 
stop the counter (if possible).

Does this seem reasonable?

-Allan

David VanHorn wrote:
Show quoted textHide quoted text
> Bear with me, this isn't simple.
>
> I have two sensors, each outputs a square wave.
> I need to accurately measure the period of each, and determine the
> difference in the two periods.
>
> Depending on how I set the optimization, I get different results.
>
> At -Os, I see values like 292, 304, 316.
> The values are spaced by 12!
> I won't ever see 305, 306, 307...
>
> If I recompile with -O0, the spacing between the values is different,
> but still mostly three discrete steps in values with nothing in
> between.
>
> I'm using an M644 at 20 MHz, T1 is running at CK/1
>
> The basics are that I stop the clock to T1, and clear it.. Then I wait
> till I see a low, then wait till I see a high, then I start the timer.
>  With the timer running, I wait till I see low, high, low high... till
> five periods have passed, then I stop the clock to T1, and take the
> data.
>
> Having done that, I do the same thing for the other sensor, then
> subtract the second sensor from the first, which should give me some
> small-ish value. The exact number isn't important, but what is
> puzzling me is that the intermediate values are missing. Like somehow
> I'm loosing low bits, but the delta is 12, which makes no sense from a
> binary perspective.
>
>
>
> // Prep for aquisition
> TCCR1B &= ~(1<<CS10);				
> // Stop T1 (should already BE stopped,
> // but it's cheap insurance)
>
> TCNT1=0;			
> // Clear T1	
> 		
> // Sync to the A channel
> while (  Sensor_Pin & (1<<ChannelA));
> // Wait for a low, so we know we're not seeing
> // a high level yet
> while (!(Sensor_Pin & (1<<ChannelA))); 	
> // Wait for the high edge
>
> TCCR1B |=(1<<CS10);// START the clock to T1
>
> // T1 is now counting the period width.
> // That can be as little as 25us
> // (5 periods *  5us * 20 MHz =  500 counts)
> // or as much as 138 uS
> // (5 periods * 23uS * 20 MHz = 2300 counts)
>
> while (  Sensor_Pin & (1<<ChannelA));
> // Wait for a low on PD2
> while (!(Sensor_Pin & (1<<ChannelA)));
> //  Wait for a high on PD2	
> // One pulse has gone
> while (  Sensor_Pin & (1<<ChannelA));
> while (!(Sensor_Pin & (1<<ChannelA)));		
> // Now two
> while (  Sensor_Pin & (1<<ChannelA));
> while (!(Sensor_Pin & (1<<ChannelA)));		
> // Now three
> while (  Sensor_Pin & (1<<ChannelA));
> while (!(Sensor_Pin & (1<<ChannelA)));	
> // Now four
> while (  Sensor_Pin & (1<<ChannelA));
> while (!(Sensor_Pin & (1<<ChannelA)));	
> // Now five
>
> TCCR1B &= ~(1<<CS10);	
> // Stop T1
> A_Sensor_Raw = TCNT1;	
> // Grab the data
> TCNT1=0;		
> // Clear T1 for the next measurement.
>
> // Sync to the B channel, and proceed as above
> while (  Sensor_Pin & (1<<ChannelB));
> while (!(Sensor_Pin & (1<<ChannelB)));
> TCCR1B |=(1<<CS10);
> while (  Sensor_Pin & (1<<ChannelB));
> while (!(Sensor_Pin & (1<<ChannelB)));
> while (  Sensor_Pin & (1<<ChannelB));
> while (!(Sensor_Pin & (1<<ChannelB)));
> while (  Sensor_Pin & (1<<ChannelB));
> while (!(Sensor_Pin & (1<<ChannelB)));
> while (  Sensor_Pin & (1<<ChannelB));
> while (!(Sensor_Pin & (1<<ChannelB)));
> while (  Sensor_Pin & (1<<ChannelB));
> while (!(Sensor_Pin & (1<<ChannelB)));
> TCCR1B &= ~(1<<CS10);	
> Temp2 = TCNT1;
> TCNT1=0;					
>
> //**********
> // Condition according to sensor
> // Scale to fit the histogram array
> // Take the difference, and add half
>   A_Sensor_Raw = ((A_Sensor_Raw - Temp2) + (Sample_Bins/2));
>  // If the value is out of range then wrap it
>  A_Sensor_Raw = (A_Sensor_Raw & 0x01FF);
>
>
> Why do I not see output like 290,291,292... ?
>
>

Re: [AVR-Chat] Optimization levels in WinAVR, wierd problem.

2009-05-01 by David VanHorn

On Thu, Apr 30, 2009 at 8:54 PM, A & T Schrum <agschrum@mindspring.com> wrote:
> With the timer running at CK/1, then does it not run at the CPU clock
> speed?

Yes, that's what I intended.

> That would mean that instructions that take a couple of cycles to execute will allow for
> a couple of cycles on the timer to pass.

Correct, and I would still expect to get different readings in integer "ticks".
I described this to someone earlier as like measuring bricks with a
ruler that only does inches.
If I pile 10 bricks into a line, and get 95 inches, then I know each
brick is 9.5 inches.

In my case, I'm also measuring another "pile of bricks" and finding
out how much difference there is between the length of bricks from the
two sources, if you follow.

> The sequence of steps you do in finding the 5 wave forms are very repeatable. The final transition on the fifth cycle to where you detect it and stop happens between where you last read the signal (and it is false) to where you read it and it is true. Then you stop the timer. The resolution that you will get is essentially the size of your last "while" statement check for the last transition of your waveform.

Correct, but this is true for both measurements. So I expect that it
will all come out in the wash.

Also, this problem did not surface when I was taking readings from
each sensor individually, it's only when I subtract the second one
from the first that I see this behavior.


> That loop is a bit test and branch not equal or equal which is probably three cycles (and three counts on the timer). All the rest in front is essentially ignored and the instructions stopping the timer are a fixed constant relative to the granularity of the timer values.

Right..

> Optimization of -Os reduces space at the loss of efficient processing in the code. It may be that the last "while" statement is done in a manner that is less efficient in time than the other and you end up with 12 clocks.

hmm.. Again, I did not see this until I started subtracting one sensor
from the other.

> Check the assembly code of that last loop and that should correspond to the granularity of your timer value.

I'll be looking at that tomorrow.

> If you want greater accuracy, either sample more waveforms (how about 15 since you have a multiple of three in your timer value), or use an external trigger to stop the counter (if possible).

This is a road that I'd rather not go any farther down.  My sample
routine happens inside an ISR, so that it is atomic, and it can take a
fair amount of time.  I'd love to find a more effective way to do
this.  The input capture hardware is tempting, but I'd have to add
external hardware since I only have one input that I can use that way,
but two sensors.  Another method would be an external counter, but
again more hardware.


> Does this seem reasonable?

That's pretty much the lines I've been thinking down, but why would I
get smooth integer values then for each sensor taken individually?

-- 
There is no computer problem which cannot be solved by proper
application of a sufficiently large hammer.

Re: [AVR-Chat] Optimization levels in WinAVR, wierd problem.

2009-05-01 by David VanHorn

AH!  I see it now!...

No matter how I slice it, the counts can only be different by integer
multiples of three ticks.
Interesting..

I'll probably have to rework this routine. As is, it runs every 50mS..
I think I'll have to run it every mS, and only take one sample of each
waveform, and then subtract those two large numbers, getting a larger
delta, then rotate right once to make the quantization disappear.

Move to quarantaine

This moves the raw source file on disk only. The archive index is not changed automatically, so you still need to run a manual refresh afterward.