#51563 - jarobi - Sun Aug 21, 2005 9:22 pm
I have just started getting into interrupts and for some reason, they are not working for me. I have looked at numerous threads regarding the issue, but I can't seem to find any info that helps me out. Since I do not have the time to learn ARM assembly, I have used the IrqHandler routine from The PERN Project website (day 4 in tutorials). I have also modified the interrupt.h from that same tutorial. I have checked the assembler instructions at 0x3007ffc and the IrqHandler routine is there. However, when I load my ISR into the IntrTable and enable interrupts, absolutely nothing happens. Everything seems to be in the right place, which makes things very confusing for me now. The code (partial) below should move a 32x32 px window one pixel down and one pixel right during vblank:
_________________
Nihongo o hanasemasen!
Code: |
//
// interrupt.h // #define INT_VBLANK 0x0001 #define INT_HBLANK 0x0002 #define INT_VCOUNT 0x0004 #define INT_TIMER0 0x0008 #define INT_TIMER1 0x0010 #define INT_TIMER2 0x0020 #define INT_TIMER3 0x0040 #define INT_SERIALCOM 0x0080 //serial communication interupt #define INT_DMA0 0x0100 #define INT_DMA1 0x0200 #define INT_DMA2 0x0400 #define INT_DMA3 0x0800 #define INT_KEYPAD 0x1000 #define INT_CART 0x2000 void interruptEnable(); //sets REG_IME to 1 void interruptDisable(); //sets REG_IME to 0 void irqEnable(int, fp); //enables an interrupt request for a given interrupt void irqDisable(int); //disables an interrupt request // // interrupt.c // extern void IrqHandler(); fp IntrTable[14]; void interruptEnable() { REG_IME = 1; } void interruptDisable() { REG_IME = 0; } void irqEnable(int irqId, fp irq_funct) { int i, j, prevIMEval; for (i = 0, j = 1; i < 14; i++, j<<=1) { if ((j & irqId) != 0) { IntrTable[i] = irq_funct; } } REG_IRQHAND = IrqHandler; prevIMEval = REG_IME; REG_IME = 0; REG_IE |= irqId; REG_IME = prevIMEval; } void irqDisable(int irqId) { int prevIMEval; prevIMEval = REG_IME; REG_IME = 0; REG_IE ^= irqId; REG_IME = prevIMEval; } // // irqh.s // @ Interrupt Request Handler taken from "The Pern Project" @ http://www.thepernproject.com/tutorials/GBA/day_4.html .SECTION .iwram,"ax",%progbits .EXTERN IntrTable .GLOBAL IrqHandler .ALIGN .ARM IrqHandler: @ Multiple interrupts support mov r2, #0x4000000 @ REG_BASE ldr r3, [r2,#0x200]! @ r2 = IE : r3 = IF|IE ldrh r1, [r2, #0x8] @ r1 = IME mrs r0, spsr stmfd sp!, {r0-r2,lr} @ {spsr, IME, REG_IE, lr} mov r0, #1 @ IME = 1 strh r0, [r2, #0x8] and r1, r3, r3, lsr #16 @ r1 = IE & IF @BIOS uses 0x300:7FF8 to hold IRQ flags for certain functions @such as IntrWait ldrh r3, [r2, #-8] @ r3 = [0x300:7FF8] orr r3, r3, r1 @ r3 |= IF & IE strh r3, [r2, #-8] @ [0x300:7FF8] = r3 @Set r12 to point to our IRQ table ldr r12, =IntrTable @cycle through IF checking to see if the bits are set. @if set we jump to the interrupt table ands r0, r1, #1 @ V-blank interrupt bne jump_intr add r12,r12, #4 ands r0, r1, #2 @ H-blank interrupt bne jump_intr add r12,r12, #4 ands r0, r1, #4 @ V-counter interrupt bne jump_intr add r12,r12, #4 ands r0, r1, #8 @ Timer 0 interrupt bne jump_intr add r12,r12, #4 ands r0, r1, #0x10 @ Timer 1 interrupt bne jump_intr add r12,r12, #4 ands r0, r1, #0x20 @ Timer 2 interrupt bne jump_intr add r12,r12, #4 ands r0, r1, #0x40 @ Timer 3 interrupt bne jump_intr add r12,r12, #4 ands r0, r1, #0x80 @ Serial Comm Interrupt bne jump_intr add r12,r12, #4 ands r0, r1, #0x100 @ DMA 0 interrupt bne jump_intr add r12,r12, #4 ands r0, r1, #0x200 @ DMA 1 interrupt bne jump_intr add r12,r12, #4 ands r0, r1, #0x400 @ DMA 2 interrupt bne jump_intr add r12,r12, #4 ands r0, r1, #0x800 @ DMA 3 interrupt bne jump_intr add r12,r12, #4 ands r0, r1, #0x1000 @ Key interrupt bne jump_intr add r12,r12, #4 ands r0, r1, #0x2000 @ Cart interrupt strneb r0, [r3, #0x84 - 0x200] @ Stop sound if cart removed (REG_SOUNDCNT_X) jump_intr: strh r0, [r2, #2] @ Clear IF mrs r3, cpsr bic r3, r3, #0xdf @ Stack stuff orr r3, r3, #0x1f @ msr cpsr, r3 ldr r0, [r12] stmfd sp!, {lr} adr lr, IntrRet bx r0 IntrRet: ldmfd sp!, {lr} mrs r3, cpsr bic r3, r3, #0xdf @ orr r3, r3, #0x92 @ msr cpsr, r3 ldmfd sp!, {r0-r2,lr} @ {spsr, IME, REG_IE, lr} strh r1, [r2, #0x8] @ restore REG_IME msr spsr, r0 @ restore spsr bx lr .ALIGN .POOL // // main.c // #define WIN_SIZE 32 int i = 0, j = 0; void doSomething() { setWin0Bounds(i++, i+32, j++, j+32); } int main() { Background demon_bk; irqEnable(INT_VBLANK, doSomething); interruptEnable(); demon_bk.bgNumber = 2; demon_bk.attributes = BG_COLOR_256 |ROTBG_SIZE_1 |BG_PRIORITY(3) |CHAR_BASE_BLOCK(0) |SCREEN_BASE_BLOCK(24) |WRAP_AROUND; loadBGPalette(demonPal); loadBGTiles((u16*)demonData, 0, 256, 0); loadBGMap(demon_map, 24, 16, 16); REG_BG2CNT = demon_bk.attributes; setWin0Content(W0_BG2); setMode(MODE_2|BG2_ENABLE|WIN0_ENABLE); while (1) { waitForVBlank(); } return 0; } // // window.h // //Window 0 content flags (inside window) #define W0_BG0 0x1 #define W0_BG1 0x2 #define W0_BG2 0x4 #define W0_BG3 0x8 #define W0_SPRITE 0x10 #define W0_BLEND 0x20 //Window 1 content flags (inside window) #define W1_BG0 0x100 #define W1_BG1 0x200 #define W1_BG2 0x400 #define W1_BG3 0x800 #define W1_SPRITE 0x1000 #define W1_BLEND 0x2000 //Window Out content flags (outside window) #define WOUT_BG0 0x1 #define WOUT_BG1 0x2 #define WOUT_BG2 0x4 #define WOUT_BG3 0x8 #define WOUT_SPRITE 0x10 #define WOUT_BLEND 0x20 //Object Window content flags (in object window) #define WOBJ_BG0 0x100 #define WOBJ_BG1 0x200 #define WOBJ_BG2 0x400 #define WOBJ_BG3 0x800 #define WOBJ_SPRITE 0x1000 #define WOBJ_BLEND 0x2000 #define setWin0Content(n) (REG_WININ=(REG_WININ&=0x3f00)|(n&0x3f)) #define setWin1Content(n) (REG_WININ=(REG_WININ&=0x3f)|(n&0x3f00)) #define setWinOutContent(n) (REG_WINOUT=(REG_WINOUT&=0x3f00)|(n&0x3f)) #define setWinObjContent(n) (REG_WINOUT=(REG_WINOUT&=0x3f)|(n&0x3f00)) #define setWin0Bounds(x1, x2, y1, y2) REG_WIN0H=((x1)<<8)|(x2);REG_WIN0V=((y1)<<8)|(y2); #define setWin1Bounds(x1, x2, y1, y2) REG_WIN1H=((x1)<<8)|(x2);REG_WIN1V=((y1)<<8)|(y2); |
_________________
Nihongo o hanasemasen!