| |
Hurrican
Registered: Oct 2003 Posts: 10 |
Setting up a timer interrupt
Hello *.*,
I'm trying to set up a timer interrupt to make something happen at a regular basis (let's say: every 5 seconds). I already managed to do a raster interrupt, but setting up a timer interrupt beats me. After browsing the web I came up with this code:
----------------------8<----------------------8<---------
inittint lda #$7f
sta $dc0d ; disable cia1 int
lda $dc0e
and #$be
sta $dc0e ; stop timer a
lda $dc0f
and #$be
sta $dc0f ; stop timer b
lda #$00
sta $dc05 ; hibyte timer
lda #$ff
sta $dc04 ; lobyte timer
lda #<inthand
sta $0318
lda #>inthand
sta $0319 ; set t-int handler
lda $dc0e
and #$80
ora #$11
ldx #$81
stx $dc0d ; enable timer int
sta $dc0e ; start timer a
loop jmp loop
inthand lda $dc0d ; interrupt-source?
and #%00000001
beq timerint
rti
timerint jsr *fancy_stuff*
rti
----------------------8<----------------------8<---------
After running the program, the interrupt never seems to occur. Now, what's my mistake?
I assume I'm making a fool out of me for asking that question, but that's no problem for me... ;-) |
|
| |
Stryyker
Registered: Dec 2001 Posts: 468 |
read $dc0d after setting it and see if that helps. |
| |
Cybernator
Registered: Jun 2002 Posts: 154 |
CIA1 generates IRQ, while CIA2 generates NMI interrupt. Try using the $0314 vector, instead of $0318. Alternatively, use CIA2.
|
| |
yago
Registered: May 2002 Posts: 333 |
Make sure to sei before setting up interrupt, and to cli to get the interrupt.
This is too obvious, but i sometimes forget the cli, and wonder, why no irq...
|
| |
Hurrican
Registered: Oct 2003 Posts: 10 |
Thank you very much for the input. I added an SEI at the beginning and a CLI at the end (before the main loop), changed the interrupt vector to $0314 and acknowledged the interrupt after setting it. But now every time I start the Timer A (using STA $DC0E), the program is terminated (blue screen with ready.) and the memory is corrupted. Woaw... ;-)
Should I load a different value into the accu before doing so? Or am I doing another mistake? |
| |
Hoogo
Registered: Jun 2002 Posts: 105 |
$314/15 is not the hardware-irq-vector. When an irg occurs, the processor jumps to the adress stored in $FFFE/FF. Some of the usually necessary jobs like pushing registers to the stack are done by the kernel before it uses the software-vector $314/15. These values have tu be pulled from the stack again. When using $315/15 you better do not return with an RTI but jump to $ea31 (keyboard, timer and some kernal-stuff), $ea7e (lda $dc0d..) or $ea81 (only exit, best for you). And I think it should be ...bne timerint |
| |
Hurrican
Registered: Oct 2003 Posts: 10 |
Well... Now the program doesn't crash anymore, but no interrupt will occur. I guess I'll have to have a detailed look at the whole code.
Thanks to everyone! |
| |
MRT Account closed
Registered: Sep 2005 Posts: 149 |
try this:
;----------------------------------------------------
SetTimerInterrupt
;set NMI vector
lda #<TCF_SCR_DoNMI_1
sta $fffa ;nmi vector lsb
lda #>TCF_SCR_DoNMI_1
sta $fffb ;nmi vector msb
;set nr of wait cycles
lda #62
sta $dd04 ;low-cycle-count
lda #0
sta $dd05 ;high-cycle-count
;enable timerA interrupt
lda #%10000001
sta $dd0d
; ;fire the 1-shot timer at 50Hz
; lda #%10011001
; sta $dd0e
;fire the continuous timer at 50Hz
lda #%10010001
sta $dd0e
;done
rts
;----------------------------------------------------
UnsetTimerInterrupt
;disable timerA interrupt
lda #%00000001
sta $dd0d
;aknowledge nmi
lda $dd0d
;stop the continuous timer at 50Hz
lda #%10010000
sta $dd0e
;done
rts
;----------------------------------------------------
I used your code as a base, but changed all of the $dc0x addresses to $dd0x addresses... and now it works :-)
I don't know why, but this seems to do the trick. Maybe someone else can explain this...
If I use the $dc0x addresses, the vector is at $fffe
and if I use $dd0x addresses, the vector is at $fffa
I like the last one better, because then I can use NMI and IRQ at the same time.
|
| |
Wanderer Account closed
Registered: Apr 2003 Posts: 478 |
Quote: $314/15 is not the hardware-irq-vector. When an irg occurs, the processor jumps to the adress stored in $FFFE/FF. Some of the usually necessary jobs like pushing registers to the stack are done by the kernel before it uses the software-vector $314/15. These values have tu be pulled from the stack again. When using $315/15 you better do not return with an RTI but jump to $ea31 (keyboard, timer and some kernal-stuff), $ea7e (lda $dc0d..) or $ea81 (only exit, best for you). And I think it should be ...bne timerint
When using multiple interrupts (eg. setting the IRQ multiple times via $0314/0315) I use $ea81 and $ea31 for the final irq.
eg. IRQ1 INC $d019
lda #<irq2:sta $0314
lda #>irq2:sta $0315
lda #$a0;sta $d012
jmp $ea81
irq2 inc $d019
(stuff)
lda #<irq:sta $0314
lda #>irq:sta $0315
lda #$30:sta $d012
jmp $ea31
I've never really looked into it further as to how many cycles, if any, are saved this way but $EA81 works as long as you us $ea31 for the last interrupt :)
|
| |
Style Account closed
Registered: Jan 2002 Posts: 17 |
$0314/$0315 is for gheys
Use the hardware vectors.
|
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
@style: When you have graphics at $fffe/$ffff then the kernal vectors prove VERY potent. =) (such as in the case of an AGSP etc.)
So, it's not ONLY for ghays. |
| |
HCL
Registered: Feb 2003 Posts: 728 |
I'm not sure $0314-15 works at all, never used them a.f.a.i.can.remember. And.. why try now, after 15 years !? ;). |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
hahaha
I've started with 0314/15, but now Im also unsure wether it would work at all, fffe/ffff is my cosy territory, after all those years 314/15 is scarry :D |
| |
Krill
Registered: Apr 2002 Posts: 2980 |
i second jackasser... there are times when the kernal vectors just come in super-handy. :D and yes, of course they work. |
| |
Compyx
Registered: Jan 2005 Posts: 631 |
When writing programs like editors, you'll more or less have to use $0314/$0315 to be able to use kernal-routines like GETIN (scanning the keyboard queue).
When you look at $fffe/$ffff you'll see it points to $ff48 which in turn JMP's to ($0314) or ($0316) when bit 4 of P is set (BRK).
So you're basically rerouting the kernal interrupt handler when setting $0314/$0315. There's no need to use $ea31 unless you're using GETIN, $ea81 is sufficient as it pulls A,X and Y from the stack which were pushed on it by $ff48.
Just my 2 cents ;)
|
| |
Ninja
Registered: Jan 2002 Posts: 411 |
Dunno if your 5-second-interval is the true value, but if it is then one timer won't be enough, as it can just count 65536 cycles. So, either you combine two timers (Timer B counts underruns of Timer A) or you use the Time-of-day-Clock. |
| |
Graham Account closed
Registered: Dec 2002 Posts: 990 |
WHAAAAH no TOD clock please :D inaccurate as hell |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
compyx: you can call yourself SCNKEY, so u can use GETIN. no need for kernal interrupt. |
| |
Ninja
Registered: Jan 2002 Posts: 411 |
Well, okay, I assumed that a 5-second-interval could also live with some tolerance, hence mentioning the TOD. If it needs to be more exact, combinig timers is inevitable. |