Timer set macros not accurate
Timer set macros not accurate
I had trouble with timer accuracy over the weekend and found the cause was the "TIMER_FREQ_xxx(n)" macros.
They don't return the correct "Ticks" value for critical timing use.
So I ended up using my own formula to calculate the "Ticks" value needed when calling the timerStart() function:
For ClockDivider_1: Ticks = 0x10000 - (TIMER_HZ / n)
For ClockDivider_64: Ticks = 0x10000 - (TIMER_HZ / (n * 64))
For ClockDivider_256: Ticks = 0x10000 - (TIMER_HZ / (n * 256))
For ClockDivier_1024: Ticks = 0x10000 - (TIMER_HZ / (n * 1024))
Also I made a function to return the "Ticks" value and matching "ClockDivider" for the timerStart() function:
unsigned int FreqtoTicks(unsigned int Hz, unsigned int *Divider)
{
unsigned int Ticks;
*Divider = ClockDivider_1;
if ((Ticks = (TIMER_HZ / Hz)) <= 0x10000)
return (0x10000 - Ticks);
*Divider = ClockDivider_64;
if ((Ticks = (TIMER_HZ / (Hz << 6))) <= 0x10000)
return (0x10000 - Ticks);
*Divider = ClockDivider_256;
if ((Ticks = (TIMER_HZ / (Hz << 8))) <= 0x10000)
return (0x10000 - Ticks);
*Divider = ClockDivider_1024;
if ((Ticks = (TIMER_HZ / (Hz << 10))) <= 0x10000)
return (0x10000 - Ticks);
return 0;
}
Returns the 'Ticks" value need for the desired frequency "Hz". "*Divider" is a pointer to an unsinged int to fill with the ClockDivider value.
Many thanks,
laser
They don't return the correct "Ticks" value for critical timing use.
So I ended up using my own formula to calculate the "Ticks" value needed when calling the timerStart() function:
For ClockDivider_1: Ticks = 0x10000 - (TIMER_HZ / n)
For ClockDivider_64: Ticks = 0x10000 - (TIMER_HZ / (n * 64))
For ClockDivider_256: Ticks = 0x10000 - (TIMER_HZ / (n * 256))
For ClockDivier_1024: Ticks = 0x10000 - (TIMER_HZ / (n * 1024))
Also I made a function to return the "Ticks" value and matching "ClockDivider" for the timerStart() function:
unsigned int FreqtoTicks(unsigned int Hz, unsigned int *Divider)
{
unsigned int Ticks;
*Divider = ClockDivider_1;
if ((Ticks = (TIMER_HZ / Hz)) <= 0x10000)
return (0x10000 - Ticks);
*Divider = ClockDivider_64;
if ((Ticks = (TIMER_HZ / (Hz << 6))) <= 0x10000)
return (0x10000 - Ticks);
*Divider = ClockDivider_256;
if ((Ticks = (TIMER_HZ / (Hz << 8))) <= 0x10000)
return (0x10000 - Ticks);
*Divider = ClockDivider_1024;
if ((Ticks = (TIMER_HZ / (Hz << 10))) <= 0x10000)
return (0x10000 - Ticks);
return 0;
}
Returns the 'Ticks" value need for the desired frequency "Hz". "*Divider" is a pointer to an unsinged int to fill with the ClockDivider value.
Many thanks,
laser
Last edited by laser on Thu Aug 26, 2010 9:14 am, edited 2 times in total.
Re: Timer set macros not accurate
IIRC, the TIMER_FREQ_xxx(n) are inaccurate because of the division. therefore they use more wellrounded numbers because they are more easily dividable, else the division with TIMER_HZ would cause those inaccuracies. not sure what would be more accurate tho.
there is also a slight inaccuracy in the clock per system that causes errors in accuracy on one system, while it works on another.
there is also something off with your formulas, the 0x10000 is unneeded.
I'm also not sure about what FreqtoTicks() should do. usally you would know what divider to use.
there is also a slight inaccuracy in the clock per system that causes errors in accuracy on one system, while it works on another.
there is also something off with your formulas, the 0x10000 is unneeded.
I'm also not sure about what FreqtoTicks() should do. usally you would know what divider to use.
Re: Timer set macros not accurate
The "0x10000" value represents the overflow count the timer needs to reach to trigger the interrupt - it's a 16 bit register (i.e 0xffff + 1 = 0x10000).
The formula is correct - I get no timer lag now. I multiply the frequency (n) with the ClockDivider instead of dividing the TIMER_HZ with ClockDivider to minimize divide round off errors. The current macro is dividing twice and getting double round off errors. At the very least the macros should be based on "TIMER_HZ" not "0x2000000".
The function "FreqtoTicks()" is because I need to actively change the timer frequency in my program. I agree you don't need it if the timer frequency is fixed at the time of the build.
laser
The formula is correct - I get no timer lag now. I multiply the frequency (n) with the ClockDivider instead of dividing the TIMER_HZ with ClockDivider to minimize divide round off errors. The current macro is dividing twice and getting double round off errors. At the very least the macros should be based on "TIMER_HZ" not "0x2000000".
The function "FreqtoTicks()" is because I need to actively change the timer frequency in my program. I agree you don't need it if the timer frequency is fixed at the time of the build.
laser
-
- Site Admin
- Posts: 1986
- Joined: Tue Aug 09, 2005 3:21 am
- Location: UK
- Contact:
Re: Timer set macros not accurate
Define timer lag to start with, I'm still not entirely clear on the usage scenario for your code.
Also TIMER_HZ isn't constant, if you're relying on the timers being absolute on all DS consoles you're in for a big surprise. 0x2000000 is a good approximation for most uses.
The specified bus clock is 33513982Hz, we use 33554432Hz which is 40450Hz above that. For the audio DACs that makes the 32768Hz we set using our approximation 32728.498046875Hz in reality, assuming that the bus clock is really absolutely spot on spec. In the real world there's a tolerance on the bus clock and it varies with ambient conditions.
Power of 2 constants are much better to work with when you're dealing with integer arithmetic and, since everything is relative to that bus clock, it's reasonably straightforward to compensate under most normal uses of the timers.
I also threw together some code to check the bus clock, here are some results from the units I have around :-
DSi: min: 01ff25be, max: 01ff99c7
DSi: min: 01ff4c54, max: 01ff6524
DS Lite: min: 01ff5f39, max: 01ff6454
DS Phat: min: 01ff5292, max: 01ff67d9
DSi XL: min: 01ff5f4f, max 01ff70d0
335139282 is 01ff61fe and in the bus clock section of http://nocash.emubase.de/gbatek.htm#dsmemorytimings Martin says his unit is ~ 1ff6231
tester nds attached.
Also TIMER_HZ isn't constant, if you're relying on the timers being absolute on all DS consoles you're in for a big surprise. 0x2000000 is a good approximation for most uses.
The specified bus clock is 33513982Hz, we use 33554432Hz which is 40450Hz above that. For the audio DACs that makes the 32768Hz we set using our approximation 32728.498046875Hz in reality, assuming that the bus clock is really absolutely spot on spec. In the real world there's a tolerance on the bus clock and it varies with ambient conditions.
Power of 2 constants are much better to work with when you're dealing with integer arithmetic and, since everything is relative to that bus clock, it's reasonably straightforward to compensate under most normal uses of the timers.
I also threw together some code to check the bus clock, here are some results from the units I have around :-
DSi: min: 01ff25be, max: 01ff99c7
DSi: min: 01ff4c54, max: 01ff6524
DS Lite: min: 01ff5f39, max: 01ff6454
DS Phat: min: 01ff5292, max: 01ff67d9
DSi XL: min: 01ff5f4f, max 01ff70d0
335139282 is 01ff61fe and in the bus clock section of http://nocash.emubase.de/gbatek.htm#dsmemorytimings Martin says his unit is ~ 1ff6231
tester nds attached.
- Attachments
-
[The extension nds has been deactivated and can no longer be displayed.]
Re: Timer set macros not accurate
Hi,
Sorry, I fail to understand why this post is causing so much confusion.
I'm not ready to take a screw driver to my new DSi XL unit which is still under warranty to confirm the clock crystal used is 33513982Hz. I assume whoever wrote "Timers.h" has already done this.
Therefore I have to trust that according to "Timers.h" the hardware timers are clocked at TIMER_HZ which is defined as 33513982 (Hz).
This should be the fixed bus clock that all DS units use and is based on a crystal locked clocking circuit.
Sure, crystals will have a manufacture tolerance (normally around +/- 30Hz per 1MHz at -20 to +70 degrees C) but this is no reason to round up a fixed hardware clock from 33513982Hz to 33554432Hz (0x2000000).
As for the "lag" question. I did not want to give away to much yet but it seems I might need to in order to help make devkitPro work for my application.
The FTP program I wrote was only a warm up and a necessary tool for my main project. I am porting my Laser Controller software from the Coldfire platform to the DS.
This is me:
http://www.uclinux.org/ports/coldfire/laser/index.htm
The port is complete and currently only simulated on the DS LCD for now. I still need to design a DAC interface board to plug in to slot-2 to drive the laser scanners and other hardware. This is just a hobby interest for me so I really don’t care how long it takes.
So back to the lag question... running the ported code on the DS using the TIMER_FREQ_xxx macros for timing caused the simulated laser output on the DS's LCD to "lag" or "go too slow" compared to the Coldfire platform.
In other words the timer counter was being set to count too many times before overflowing to trigger my main time base function. This is because the base clock used in the macros has been rounded up 40450Hz higher than the actual real hardware clock causing a 0.12% accumulating lag when running side by side. After using my formula to set the timer's overflow counter both platforms now run perfectly in sync over several minutes. This is significant when trying to sync a laser show with music. This proves my formula is correct and the DS hardware clock is indeed 33513982Hz. Fluctuations in manufacture’s clock tolerance is insignificant compared to the rounding up being done in the macros.
Maybe my FreqtoTicks() function has no interest to a game creator (nor is the 0.12% clock round up) but was given to help explain the problem I’m trying to report in this post.
Many thanks,
laser
Sorry, I fail to understand why this post is causing so much confusion.
I'm not ready to take a screw driver to my new DSi XL unit which is still under warranty to confirm the clock crystal used is 33513982Hz. I assume whoever wrote "Timers.h" has already done this.
Therefore I have to trust that according to "Timers.h" the hardware timers are clocked at TIMER_HZ which is defined as 33513982 (Hz).
This should be the fixed bus clock that all DS units use and is based on a crystal locked clocking circuit.
Sure, crystals will have a manufacture tolerance (normally around +/- 30Hz per 1MHz at -20 to +70 degrees C) but this is no reason to round up a fixed hardware clock from 33513982Hz to 33554432Hz (0x2000000).
As for the "lag" question. I did not want to give away to much yet but it seems I might need to in order to help make devkitPro work for my application.
The FTP program I wrote was only a warm up and a necessary tool for my main project. I am porting my Laser Controller software from the Coldfire platform to the DS.
This is me:
http://www.uclinux.org/ports/coldfire/laser/index.htm
The port is complete and currently only simulated on the DS LCD for now. I still need to design a DAC interface board to plug in to slot-2 to drive the laser scanners and other hardware. This is just a hobby interest for me so I really don’t care how long it takes.
So back to the lag question... running the ported code on the DS using the TIMER_FREQ_xxx macros for timing caused the simulated laser output on the DS's LCD to "lag" or "go too slow" compared to the Coldfire platform.
In other words the timer counter was being set to count too many times before overflowing to trigger my main time base function. This is because the base clock used in the macros has been rounded up 40450Hz higher than the actual real hardware clock causing a 0.12% accumulating lag when running side by side. After using my formula to set the timer's overflow counter both platforms now run perfectly in sync over several minutes. This is significant when trying to sync a laser show with music. This proves my formula is correct and the DS hardware clock is indeed 33513982Hz. Fluctuations in manufacture’s clock tolerance is insignificant compared to the rounding up being done in the macros.
Maybe my FreqtoTicks() function has no interest to a game creator (nor is the 0.12% clock round up) but was given to help explain the problem I’m trying to report in this post.
Many thanks,
laser
Re: Timer set macros not accurate
Well, correct me if I'm wrong, but the gist of it is, DS / DSi units, individually, have wide differences among them in their clock frequencies. Probably the hardware is to blame here.
Remember these are gaming consoles, not high-precision industrial equipment for critical-equipment usage.
And speaking of which... using a DS to control a laser... totally cool, don't get me wrong... but... not sure if that's a wise choice.
Remember these are gaming consoles, not high-precision industrial equipment for critical-equipment usage.
And speaking of which... using a DS to control a laser... totally cool, don't get me wrong... but... not sure if that's a wise choice.
-
- Site Admin
- Posts: 1986
- Joined: Tue Aug 09, 2005 3:21 am
- Location: UK
- Contact:
Re: Timer set macros not accurate
Because you probably haven't dealt with too many homebrewers before :p A lot of people get caught up in accuracy they don't need and probably can't obtain anyway, I think we're probably all data points in the autistic spectrum somewherelaser wrote:Hi,
Sorry, I fail to understand why this post is causing so much confusion.
Nobody was asking you to, that's why I knocked up a quick timer test against RTC irq.I'm not ready to take a screw driver to my new DSi XL unit which is still under warranty to confirm the clock crystal used is 33513982Hz. I assume whoever wrote "Timers.h" has already done this.
But since for most normal purposes the error doesn't matter and nice round numbers are significantly easier to deal with it seemed like a reasonable trade off at the time.Sure, crystals will have a manufacture tolerance (normally around +/- 30Hz per 1MHz at -20 to +70 degrees C) but this is no reason to round up a fixed hardware clock from 33513982Hz to 33554432Hz (0x2000000).
Well, if you'd actually said you were controlling real world systems and suffering from the 0.12% accumulating error then it might have helped.Maybe my FreqtoTicks() function has no interest to a game creator (nor is the 0.12% clock round up) but was given to help explain the problem I’m trying to report in this post.
I'm likely to get all sorts of grief from people if I change things that haven't changed in 5 years is all, I just need a good justification for it. "I'm controlling lasers with a DS" is so cool I don't even care now :p
wide is probably overstating the case quite a lot, effectively we're shifting the error from around +/- 0.005% to +0.12% which is obviously quite significant for this use case.Izhido wrote:Well, correct me if I'm wrong, but the gist of it is, DS / DSi units, individually, have wide differences among them in their clock frequencies. Probably the hardware is to blame here.
I did a spreadsheet with the measured clocks on my collection of consoles - https://spreadsheets.google.com/ccc?key ... l=en#gid=0
The 29KHz range is obviously an outlier probably caused by a bit of an omission in the cpu timing functions, I'll see if I can get a better test framework & update those.
Sure but we're not talking about performing eye surgery here ( not on purpose anyway )Remember these are gaming consoles, not high-precision industrial equipment for critical-equipment usage.
Re: Timer set macros not accurate
I just tried running my laser software on some other DS units.
The main problem I found was trying to pry the DS lites out of my children's hands for an hour...
Tested on 2 x DSi XL and 2 x DS lite. 1 hour test time on each unit and saw no visible lag or difference on each unit.
Which was the result I expected - no significant difference in bus clock speeds between DS units.
Also I discovered a flaw in my plan - there is no slot-2 on DSi XL.
Will have to rethink how to do the DAC interface board now if I want access to 16MB RAM.
Many thanks,
laser
The main problem I found was trying to pry the DS lites out of my children's hands for an hour...
Tested on 2 x DSi XL and 2 x DS lite. 1 hour test time on each unit and saw no visible lag or difference on each unit.
Which was the result I expected - no significant difference in bus clock speeds between DS units.
Also I discovered a flaw in my plan - there is no slot-2 on DSi XL.
Will have to rethink how to do the DAC interface board now if I want access to 16MB RAM.
Many thanks,
laser
-
- Posts: 34
- Joined: Tue May 11, 2010 2:29 am
Re: Timer set macros not accurate
Hmm... Maybe you could encode the data into audio output and pump it out to the headphone jack? It'd be easier than designing a custom Slot-1 device to both play the game AND convert the digital signal...
However, you might want to look into designing a custom Slot-1 DAC interface, and simply use WifiMe or something similar to send the program to the DS... although I thought I heard that programs run via WifiMe weren't allowed to access the Slot-1 device.
You could crack open a DSi XL and set up a custom circuit, but that'd be really dangerous and totally not advisable. Plus, you already said you don't want to do that, so forget this option.
If you really wanted to, and you knew enough about the DS hardware, you could write some software to set up a section of the game card as virtual memory, but it would be extremely slow, not to mention it'd be going totally against the design of the hardware (aka it's a hack, don't do it).
I think your best bet is just to suck it up for now and stick with an earlier DS model with a GBA slot and less RAM. I mean, do you even really need 16MB of RAM for your laser control program?
However, you might want to look into designing a custom Slot-1 DAC interface, and simply use WifiMe or something similar to send the program to the DS... although I thought I heard that programs run via WifiMe weren't allowed to access the Slot-1 device.
You could crack open a DSi XL and set up a custom circuit, but that'd be really dangerous and totally not advisable. Plus, you already said you don't want to do that, so forget this option.
If you really wanted to, and you knew enough about the DS hardware, you could write some software to set up a section of the game card as virtual memory, but it would be extremely slow, not to mention it'd be going totally against the design of the hardware (aka it's a hack, don't do it).
I think your best bet is just to suck it up for now and stick with an earlier DS model with a GBA slot and less RAM. I mean, do you even really need 16MB of RAM for your laser control program?
Re: Timer set macros not accurate
Thank you for your suggestions. I am one step ahead of you. I have already got it running on the sound channels. Right channel is X axis and Left is Y axis. Works okay using the headphone jack and an external op-amp circuit but does not give DC offset. I will need to crack open the DS and tap off the audio output straight from the Audio/Power control chip , this should bypass the coupling caps and give me the DC offset I need. Still need an external op-amp circuit to centre the offset to zero volts and boost the output to + / -10 volts. Same trick I did with my Amiga "Lasermax" program many years ago, but the Amiga only had 8 bit audio.
Also picked up a cheap GBA cart. from cash converters today. Going to strip the board bare and run some wires out a hole in the back and basically use it as a slot-2 plug to tap off the signals I need. I need to measure write timings and then prototype the DAC board.
So the program will support both these output options. This seems to be the way to go.
Anyway this has gone way off topic. Should probably move this message to a new thread...
Thanks again for your ideas and support
laser
Also picked up a cheap GBA cart. from cash converters today. Going to strip the board bare and run some wires out a hole in the back and basically use it as a slot-2 plug to tap off the signals I need. I need to measure write timings and then prototype the DAC board.
So the program will support both these output options. This seems to be the way to go.
Anyway this has gone way off topic. Should probably move this message to a new thread...
Thanks again for your ideas and support
laser
Who is online
Users browsing this forum: No registered users and 0 guests