gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

DS development > Timer/Freezing

#169429 - Synthetic - Fri Jul 10, 2009 9:17 am

So I've been having problems with timers since the last libnds update, and I'm having a weird problem now that I'm not quite sure what to make of.

I'm setting up a ~millisecond timer using the following code:


Code:

volatile long time0=0;//global millisecond timer
void timer0_function(void){time0++;}

//blah blah blah, code inbetween

TIMER0_DATA = TIMER_FREQ_64(1000);
TIMER0_CR = TIMER_ENABLE | TIMER_IRQ_REQ | TIMER_DIV_64;
irqSet(IRQ_TIMER0, timer0_function);
irqEnable(IRQ_TIMER0);



The timer is enabled first thing in main, and happily chugs along working until time0 reaches ~65100 and then the program freezes. I've looked around, and it seems to freeze in a slightly different place in my code every time, which implies its not an overflow in any of my time calculations causing a freeze, and the fact that its freezing so close to 65535 ticks is very suspicious. I've tried calling the timer init code again after ~65000 ticks but that doesn't do anything.

Is there a way that the hardware timer could be overflowing into other memory, or maybe I'm overlooking something in the setup? I'm afraid I don't know very much about the timer internals, so I have no idea what the problem could be.

Thanks in advance for any help.

#169430 - Echo49 - Fri Jul 10, 2009 12:49 pm

Is there any reason why you need to call an interrupt nearly 17 times per frame? If you can, you could just set a vblank interrupt that adds (1 / 59.8261) to a variable.

#169433 - elhobbs - Fri Jul 10, 2009 1:53 pm

I am not sure that you need an interrupt handler to increment a value. In any case calling one that frequently cannot be good.

this is the code that I use for keeping track of time.

setup:
Code:

TIMER0_CR = TIMER_ENABLE|TIMER_DIV_1024;
TIMER1_CR = TIMER_ENABLE|TIMER_CASCADE; 


read time:
Code:

/*returns the elapsed seconds since the timer started*/
double Sys_FloatTime (void) {
    return ((TIMER1_DATA*(1<<16))+TIMER0_DATA)/32728.5;
}

though I doubt you need the value as a double precision floating point value...

#169434 - Miked0801 - Fri Jul 10, 2009 3:50 pm

Perhaps your interrupts are stacking on top of each other or getting in the way of VBlank or something. Still, calling an interrupt that often will drag performance way, way down. You have to trigger the interrupt, push all regs, jump to the interrupt vector, run the interrupt code (crt0), jump to your code and push more registers, run your code, then worm your way back out. Doing a whole bunch of times per frame will hurt. We had a similiar issue a long time ago on DMG/GB. Fired an interrupt every scan-line to copy info to VRAM. It took nearly the entire frame to copy a 16 bytes of info. Turned out we were using 90% of our available time just entering and exiting the interrupts. Spreading the copy across multiple scan lines allowed us to do the same copy in 3 lines. Moral: Don't interrupt unless you really need to.

#169435 - Synthetic - Fri Jul 10, 2009 5:08 pm

Thats a good point, I didn't really think about all the overhead behind such frequent interrupts. I've been using it for profiling a lot, which is why I started calling it so frequently, but I certainly don't need it to be that precise.

I'll try doing the interrupt less frequently, and see what happens.

#169436 - elhobbs - Fri Jul 10, 2009 6:05 pm

mike - is there a downside to not setting the timer to interrupt and just reading the value from TIMER0_DATA? particularly if it is only used measuring time?

#169439 - Synthetic - Fri Jul 10, 2009 8:43 pm

EDIT: Actually, I was wrong, it does have something to do with the timing. Very bizzare bug.

Last edited by Synthetic on Sat Jul 11, 2009 10:45 pm; edited 1 time in total

#169442 - Miked0801 - Fri Jul 10, 2009 10:07 pm

As long as nothing else is playing with the timer (big if), it would probably work. Still, I'd not go that route. I'd either count VBlanks for high(er) precision or the RTC for lower value, longer duration stuff.