1/1024th of a second

I want to use units of 1/1024th of a second instead of milliseconds for a project that has to do a bunch of math in an ISR so I can do the math with bitshifts instead of division and modulo steps. I could use 1/1048576th of a second for microsecond scale measurements. I guess I'm talking about using base 2 to keep time instead of base 10.

The timing needs to be precise enough that I can't just leave the little bit of error in there. But I can do the math to convert the user input into those units as they're entered and let the entire program run in different time units.

It seems like the kind of thing that has probably been done so many times it has a name. So before I start trying to reinvent the wheel, I thought I would ask here first.

The timing needs to be precise enough that I can't just leave the little bit of error in there.

Hmm. You might want to check your Arduino clock with a good frequency counter before you lock onto any high-precision strategy. I suspect that before anyone can offer practical help, you'll need to provide at least some range/domain info for your calculations...

[edit - i did the math wong the first time, and coding badly's advice is much better]

Delta_G:
I want to use units of 1/1024th of a second instead of milliseconds…

#include <util/atomic.h>

extern volatile unsigned long timer0_overflow_count;

unsigned long get1024th( void )
{
  unsigned long rv;

  ATOMIC_BLOCK( ATOMIC_RESTORESTATE )
  {
    rv = timer0_overflow_count;
  }
  return( rv );
}

It only works on a 16 MHz processor and there is a very very tiny chance that a change in the core will invalidate it.

The timing needs to be precise enough that I can't just leave the little bit of error in there.

What little bit of error?

The error introduced if I just call 1/1024th a millisecond or say that x/1000 = x>>10. There’s a 2% error there. So my plan was to just change units. Instead of keeping track of a number of milliseconds, I’ll keep track of a number of a number of 1/1024ths of a second. That math can be done in the loop. When I go into my ISR, the numbers are already in those units and all my math dissolves into a few bitshift operations.

I am curious what your project is doing with this, why it need the math and why the "normal" clock is not suitable. Can you tell more about what you try to achieve? TIA

No, you’ve got your maths wrong, the timer0 overflow counter goes at 0.001024Hz, which is not the same as 1/1024

You need to divide the 16MHz system clock by 15625 rather than 16384 to get 1/1024 second output.

The normal clock is fine. It's the math that I don't want to do with division. I want to use the normal clock, I just want to shorten the maths. The clock will be the same, the only difference will be how many pieces I divide up a second into.

I'll have to post some code when I get off work. I'm moving a motor based on user input in seconds and then trying to do that with millisecond resolution. Basically, I have to keep up with a number of milliseconds and a remainder. Currently the math has two steps.

x = Switch_time / 1000 r = Switch_time % 1000

That takes a long time to perform compared to:

x = Switch_time >> 10 r = Switch_time & 0x03FF

But dividing seconds by 1024 and calling that milliseconds creates an error. There aren't 1024 milliseconds in a second, there are 1000. But why do I have to use milliseconds in the first place. It's just a unit. There's nothing special about it. And computers work so well with powers of 2 compared to powers of 10. So I want to keep track of my time variables as 1024ths of a second. Then, to turn that into a counter value and set OCR1A for my next interrupt, the math can all be done without any division.

MarkT:

[quote author=Coding Badly link=topic=94506.msg709613#msg709613 date=1330589415]

Delta_G:
I want to use units of 1/1024th of a second instead of milliseconds…

#include <util/atomic.h>

extern volatile unsigned long timer0_overflow_count;

unsigned long get1024th( void )
{
  unsigned long rv;

ATOMIC_BLOCK( ATOMIC_RESTORESTATE )
  {
    rv = timer0_overflow_count;
  }
  return( rv );
}




It only works on a 16 MHz processor and there is a very very tiny chance that a change in the core will invalidate it.

No, you’ve got your maths wrong, the timer0 overflow counter goes at 0.001024Hz, which is not the same as 1/1024

You need to divide the 16MHz system clock by 15625 rather than 16384 to get 1/1024 second output.
[/quote]

No no no, let’s not change the clock. I would have to redo my math. Leave the clock alone. It’s already working in binary. I’m not happy with the human part that requires all the math to be in neat powers of 10. Id rather have a unit, lets call it a foo-second. It will make my code a little harder for a human to understand, but the computer should love it. I want to leave the clock alone and just change the number I am comparing the clock to.

Equivalent to keeping military time. The actual time doesn’t change and neither does the clock. Only the numerical representation of that time changes.

On a 16MHz atmega even "ms resolution" leaves time for 16 000 instructions.. Is this just for fun?

http://c2.com/cgi/wiki?OptimizeLater

Yeah its for fun. The program works as is. I just wanted to try to eliminate the use of the division operator when my isr converts seconds to milliseconds. There isnt a timing issue. Just an isr that takes longer than it should.

The math works too and i can implement it all by myself. My only reason for bringing it up is because i figured the unit might be common enough to have a name.

Think of it this way. I could talk about distance in feet, yards, and miles but i don't. The metric system is easy on the base 10 processor in my head. Makes the math work faster than using 12, 36, and 5280. I was thinking of applying that same sort of thinking to programming.

I think the common thing to do is to move the calculation outside the interrupt (set a flag)

Or maybe you can scale the number you are dividing to be more bit-shifting friendly? Haven't given this much thought, but would switch_time * 1.024 work?

MarkT: No, you've got your maths wrong, the timer0 overflow counter goes at 0.001024Hz, which is not the same as 1/1024...

So I did. Sorry about that.

An understandable error - I just happened to remember the PWM frequencies are just under 500Hz and 1kHz, which made me spot it.

To divide by 15625 simply takes timer1 setup with TOP set to this value… Then the hardware can do the work (if you’re happy programming the timer units).