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++ > Help Setting up Interrupts for DevKitAdv...

#10447 - Mr. GBA - Fri Sep 05, 2003 11:22 am

I've seen much documentation on this topic, all with conflicting methodologies.

I'm hoping that one of you intellectuals will be able to help me: set up interrupts for devkitadv (unsing the LinkScript? etc).

Thanks for your concern!
_________________
my dev/business site:

http://codebytesdev.afraid.org

#10452 - Lupin - Fri Sep 05, 2003 2:35 pm

what exactly is your problem about interrupts?

you could use interrupts by using the crt0.s file and creating an array of function pointers or specify the interrupt handler yourself using the interrrupt vector (that's how I do it).


that's my code:

//Interrupts
#define INT_VBLANK 0x0001
#define INT_HBLANK 0x0002
#define INT_VCOUNT 0x0004
#define INT_TIMMER0 0x0008
#define INT_TIMMER1 0x0010
#define INT_TIMMER2 0x0020
#define INT_TIMMER3 0x0040
#define INT_COMUNICATION 0x0080 //serial communication interupt
#define INT_DMA0 0x0100
#define INT_DMA1 0x0200
#define INT_DMA2 0x0400
#define INT_DMA3 0x0800
#define INT_KEYBOARD 0x1000
#define INT_CART 0x2000 //the cart can actually generate an interupt
#define INT_ALL 0x4000 //this is just a flag we can set to allow the function to enable or disable all interrupts. Doesn't actually correspond to a bit in REG_IE

typedef void (*interrupt_handler_t)();
typedef interrupt_handler_t *interrupt_handler_ptr_t;

#define REG_IME (*(vu16*)0x4000208) //Interrupt Master Enable
#define REG_IE (*(vu16*)0x4000200) //Interrupt Enable (Welche Interrupts sollen verarbeitet werden?)
#define REG_IF (*(vu16*)0x4000202) //Interrupt Flags (welcher Interrupt ausgel??t wurde, wichtig zur Auswertung)
#define REG_INTERUPT (*((interrupt_handler_ptr_t)0x03007FFC))


//Interruptfunktionen
void VBLANK(void);
void KEYBOARD(void);

//Das ist der Interrupt-Handler, vielleicht ist es besser ihn
//im Rom zu haben, da spart man sich immerhin einen long call
void HandleInterrupt() {
if (REG_IF & INT_VBLANK) {
VBLANK();
}
if (REG_IF & INT_KEYBOARD) {
KEYBOARD();
}
}


/*-------enable/disable interupt rutien---------------*/
void EnableInterrupt(u16 interrupt) {
REG_IME = 0; //probably not necessary but not a good idea to change interupt registers when an interupt is ocuring

if(interrupt == INT_VBLANK)
REG_DISP_STAT |= 0x8;
else if(interrupt == INT_HBLANK)
REG_DISP_STAT |= 0x10;
else if(interrupt == INT_KEYBOARD) //Alle Tasten aktivieren
REG_P1CNT |= BIT14 | BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7 | BIT8 | BIT9;

REG_IE |= interrupt;
REG_IME = 1;
}

void DissableInterrupts(u16 interrupts) {
REG_IE &= ~interrupts;

if(interrupts == INT_ALL) //this is were that ALL comes in
REG_IME = 0; //disable all interupts;
}



......in main()

REG_INTERUPT = HandleInterrupt;
EnableInterrupt(INT_VBLANK);
EnableInterrupt(INT_KEYBOARD);

#10453 - tepples - Fri Sep 05, 2003 2:43 pm

The interrupt strategy I use doesn't involve any mucking about with link scripts or crt0 startup files. Here's what I do for interrupts:

1. Write an ISR meeting the GBA's requirements. (Read IF into a variable, act on interrupts, write variable back to IF, 'or' variable into BIOS's mirror of IF, and return.)
2. Compile it as ARM code and put it in IWRAM. (In DevKitAdv R5b3, use -marm instead of -mthumb, and name the object file containing ".iwram.")
3. Set it as the master ISR by writing the address of the function to 0x03fffffc.
4. Enable interrupt sources, the corresponding bits in the mask, and the master enable.

Lupin's code has pretty much the same idea but a few bugs (namely writing back to IE instead of IF and ignoring the BIOS mirror of IF entirely). Here's some boilerplate code that has actually been tested on hardware, taken from Tetanus On Drugs:
Code:

/* in isr.iwram.c */

#define BIOS_IF (*(u32 *)0x03fffff8)
/* BIOS_IF is needed by IntrWait() and VblankIntrWait() */

void isr(void)
{
  unsigned int interrupts = REG_IF;

  /* for each interrupt: */
  if(interrupts & INTMASK_VBL)
  {
    /* do something */
  }

  REG_IF = interrupts;  /* important that this is = not |= */
  BIOS_IF |= interrupts;  /* important that this is |= not = */

  REG_IME = 1;
}

/* in main.c */

#define SET_MASTER_ISR(isr) (*(u32 *)0x03fffffc = (u32)isr)
/* yeah, nasty casts, but I was up at 1 AM and couldn't think
   straight enough for type safety */

int main(void)
{
  /* ... */
  SET_MASTER_ISR(isr);
  REG_IE = INTMASK_FOO | INTMASK_BAR;
  REG_IME = 1;
  /* ... */
}

Please refer to the CowBite spec for more information.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.