Dividing through 2/4/8/16/32 in Timers is faster.... why?

Hey there,
I have a huge project and must save every byte and bit. I have changed some code that I could even use Timer0 for some things.
When I must divide something in Timer0, Timer1 or Timer2 I have found out that when I divide through 2/4/6/8/16 and so on, it is really fast. When I change it to another number like 1/3/5/7/9... the division gets really slow.
Another strange behaviour: When I multiply the divided result through an uneven number afterwards it didn't slowing down the timer enormusly.
Does someone know why this happens?

What do you mean "divide sommething in timerX"? Are you referring to the prescalers?

If you're referring to ordinary division, it's probably because the compiler optimizes divisions by any 2^x operands to bitshifts.

Its about the division directly in the timer routine (Timer division is :1):

ISR(TIMER0_OVF_vect) {
  phaccu=phaccu+tword_m;
  icnt=phaccu >> 24;
  OCR0A=(wave[icnt]*amplitude)/128; //Only division through 2/4/8/16/32/64/128 and so on is fast
}

fast compared to what?

the division gets really slow

How do you know how much time "division" takes?

Compared to any other values... :confused:

What you're observing makes sense. 128 = 2^7 which the compiler can optimize to 7 right bitshifts. Bitshifts are typically faster than division.

Sorry, this still does not make sense. What, exactly, are you "timing"?

nicolajna:
What you're observing makes sense. 128 = 2^7 which the compiler can optimize to 7 right bitshifts. Bitshifts are typically faster than division.

Awesome that really could make sense.
Doesn't know a lot about bitshifting but if this is true I could change the division through 128 by this or am I wrong?

OCR9A=(wave[icnt]*amplitude) >> 128

I would suppose he's timing the execution time of interrupt routine.

nicolajna:
I would suppose he's timing the execution time of interrupt routine.

Thats true :slight_smile:

mufufischer:
Awesome that really could make sense.
Doesn't know a lot about bitshifting but if this is true I could change the division through 128 by this or am I wrong?

OCR1A=(wave2[icnt1]*velocityTone2) >> 128

No it would be:

OCR1A=(wave2[icnt1]*velocityTone2) >> 7

Doing a bitshift to the right is the same is dividing by two.
But you should leave it to the compiler to do these kinds of optimizations.

Are you doing some sort of volume control? Any way you can precompute the values?

nicolajna:
Are you doing some sort of volume control? Any way you can precompute the values?

Yep, some volume must be controlled ^^
Precompute the wavetable array is sadly not an option ->too slow.

I had to do something similar for a project. What i ended up doing was settling for "steps" in volume, calculating all the values in an Excel sheet and storing it in a two dimensional lookup table in flash.

That way I could fetch the calculated value like this: precalculatedValues[volume][sampleValue];

When using a processor as a DSP, it is much faster to do scaled multiplication than to do actual division by a constant. Division by powers of 2 is an exception but it obviously can't always be used. The catch is - you can't just do multiplication of two variables that way because first you have to actually divide something to make the scaling value. So it's not a saving. If you have multiple values to scale with one variable, you only have to manufacture the scaling variable once, so it's a saving.

So in consideration of that, @mufufischer, my question would be, is your divisor a constant or a variable?

Another thought. You speak of dividing a timer. This is a little strange. Normally you allow timer hardware to perform the division itself. A periodic event is effectively divided by a simple counter, no software division is necessary for that. Software timers can be implemented with a very frequent timer event triggering updates to counter variables that perform frequency division in the time domain.

It is not clear exactly what you are doing. Notwithstanding, the problem of frequency generation generally depends on the fout = fref / n. The timer hardware can do that but you need one timer to produce each frequency, or else you have to subdivide in software from a fref that is a very high frequency, to provide adequate resolution.

aarg:
So in consideration of that, @mufufischer, my question would be, is your divisor a constant or a variable?

It's a variable that will change. Don't get me wrong I am absolute happy with division or bitshift, its working fine fine fine :slight_smile:

Just need to explain why because it is for a study project and these need some proper documentation.
If you divide something with bitshift >> could you multiply the other way around with << ?

Yes. You would double the value for every left bitshift.

0b110 = 6
0b110 >> 1 = 0b011 = 3
0b011 << 1 = 0b110 = 6

But as you can see you can only double and halve. So it works for any number that is a power of two.

Awesome, thanks again :slight_smile:

You're welcome. Good luck with your project!

If you divide something with bitshift >> could you multiply the other way around with << ?

Yes, that's what happens. One thing to keep in mind, when you scale down (divide) you lose information (i.e. resolution), when you scale up, you do not gain any resolution. This is something you have to consider when you're constructing a digital audio signal chain because truncation introduces noise.

Trivially, floating point seems to avoid this problem automatically, but it does so at the expense of extra software overhead.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.