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.

C/C++ > My timer doesn't want to work.

#22268 - expos1994 - Wed Jun 16, 2004 3:52 pm

Hello,

I needed a wait() function in my game, so the player can have a moment to take in some info. Well I am using ThePernProject's Wait(seconds) function since it seemed to be somewhat simple.

Well I added in a for.. loop so it would wait(1) second each time through. Well a one-second wait doesn't happen. It just zips through the loop. I am wondering if I'm doing something dumb, but it seems that the Wait() function resets the timer. And everything should be ok. Plus, I added this to the end of my main game loop (just on a whim really). And my game pauses for a second each time through the loop. So why won't it pause in this for() loop? Does anyone have any ideas?

Here's how I define the registers:

Code:

#define REG_TM3D          (*(volatile u16*)0x400010C)
#define REG_TM3CNT        (*(volatile u16*)0x400010E)


Here's the Wait() function:
Code:

void Wait(int seconds)
{
   //Start the timer
   REG_TM3CNT = TIME_FREQUENCY_1024 | TIME_ENABLE;
   //zero the timer
   REG_TM3D = 0;
   while(seconds--)
   {
      while(REG_TM3D <= 16386){} //wait
      REG_TM3D = 0; //reset the timmer
   }
   
}


Here's where I call it and it doesn't work:
Code:

void simulate_days(u16 numofdays)
{
   u16 loop;
   u16 loop2;
   char day_string[6];
   
   for (loop = 0; loop < numofdays; loop++)
   {
      update_date();
      if (selecteditem == 6)
      {
         PlotTextBG3((char *)month[monthno],5,1);  //Prints the date
         sprintf(day_string,"%d",day);
         if (day < 10) //moves ", 1848" based on the day
         {
            PlotTextBG3(day_string,8,1);
            PlotTextBG3((", 1948"),9,1);
         }else
         {
            PlotTextBG3(day_string,8,1);
            PlotTextBG3((", 1948"),11,1);
         }
      }
      update_food();
      WaitForVsync();
      Wait(1);
   }
}



Is there something I'm doing wrong? I like to think that I can call Wait() how ever many times I need to in this simulate_days() function, but I could be wrong...

Thanks for any help you can provide.

--Chris

#22270 - poslundc - Wed Jun 16, 2004 4:48 pm

Well, you might try reordering your statements like this, although I can't guarantee it'll fix your problem:

Code:
REG_TM3CNT = 0;
REG_TM3D = 0;
REG_TMCNT = TIME_FREQUENCY_1024 | TIME_ENABLE


You may also have to make sure that REG_TM3CNT is declared as volatile in the header file.

But you should be aware that this is a very bad way to have a delay if you plan on incorporating this into a game at all. You should keep your main loop cycling every VBlank, and just keep track of the number of VBlanks that pass. This lets you operate your main loop as a finite state machine.

Dan.

#22278 - sgeos - Wed Jun 16, 2004 8:13 pm

I agree with Dan. Counting vblanks is the way to go. This is still a bad way of doing things, but it might be a little simpler than the timer code:
Code:
void vblank(void)
{
   /* If we are in the vblank, wait for vdraw */
   while (*(volatile unsigned short *)0x4000006 > 159)
   {
      /* wait */
   }

   /* Wait for vblank to begin */
   while (*(volatile unsigned short *)0x4000006 < 160)
   {
      /* wait */
   }
}


void stall(int frames)
{
   int i;

   for (i = 0; i < frames; i++)
      vblank();
}


-Brendan

#22301 - Cearn - Thu Jun 17, 2004 8:25 am

The REG_TMxD registers don't quite behave as you might expect. When reading, it gives you the current timer value, when writing to it, it sets the number from which counting starts when you enable it, or when the counter overflows. To fix it, you could either set REG_TMxD to 0x10000-n, rather than just n and make use of the overflow, or disable/enable the timer after the wait-loop.

poslundc and sgeos are still right that using vblank is still better, of course, either via a vsync busy-wait loop or, preferably, with interrupts.

#22314 - expos1994 - Thu Jun 17, 2004 2:28 pm

Hey,

Thanks a lot for all of your help. My game is working again.

@poslundc, sgeos: You're right, I should have kept it in my main loop. I thought it would be easier to branch off the main loop, do this little task, then come back. It only brought on problems. I have it working now by keeping track of Vblanks. Someday I'm going to use interrupts...

@cearn: Thanks for the tip. I have since removed the timer from my code. I will probably reference this at some point in the future. Thanks also for the links. I didn't know those tutorials existed. That's a nice site, I'm sure it will come in handy.

Thanks again for the help.

--Chris

#49871 - diamondx - Wed Aug 03, 2005 3:38 am

sgeos wrote:
I agree with Dan. Counting vblanks is the way to go. This is still a bad way of doing things, but it might be a little simpler than the timer code:
Code:
void vblank(void)
{
   /* If we are in the vblank, wait for vdraw */
   while (*(volatile unsigned short *)0x4000006 > 159)
   {
      /* wait */
   }

   /* Wait for vblank to begin */
   while (*(volatile unsigned short *)0x4000006 < 160)
   {
      /* wait */
   }
}


void stall(int frames)
{
   int i;

   for (i = 0; i < frames; i++)
      vblank();
}


-Brendan


Hey, I used your code for a tetramino game using HAM, from the http://www.aaronrogers.com/ham/ tutorials, but it pauses the entire game, and all I want it to pause is that function. I need it to, when you press right, move 3 pixels right, and not beable to move right for about 200-500 miliseconds. Please help me! Thanks.

P.S. Im very new to GBA programming and kinda new to C++ programming.

#49872 - tepples - Wed Aug 03, 2005 4:01 am

Here's untested code that shows roughly how to do as you asked:
Code:
#define JOY (*(volatile unsigned short)0x04000130)
#define JOY_RIGHT 0x0010

{
  unsigned int last_joy = ~0;  /* buttons that were pressed in last frame */
  unsigned int countdown = 0;  /* time in vblanks until another press is allowed */

  while(1)
  {
    int pressed = ~JOY;  /* buttons that are pressed now */
    int just_pressed = pressed & ~last_joy;  /* buttons that just became pressed */

    if(just_pressed & JOY_RIGHT)
    {
      if(countdown == 0)
      {
        countdown = 20;  /* in units of 16.74 ms */
        move_cursor_by(3, 0);
      }
    }

    /* Do other processing here. */

    if(countdown > 0)
      countdown = 0;
    wait_for_vblank();
    last_joy = pressed;
  }
}


But you said you're trying to make a tetramino game. If you want to know the "right" way to handle auto-repeat with delay in a falling block puzzle game, then look for make_repeats() in the source code for TOD.

EDIT: correct TOD link
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.


Last edited by tepples on Wed Aug 03, 2005 4:17 am; edited 1 time in total

#49873 - diamondx - Wed Aug 03, 2005 4:16 am

Thanks. Very helpfull. I think I get it, but in HAM, I dont need to define JOY, do I? Because HAM has F_CTRLINPUT_RIGHT_PRESSED.