Reputation: 31
I am trying to get the hang of using interrupts as a way of timing actions on a 6502 Teensy micro-controller. I have managed to create a counter that adds bits faster by triggering the interrupt:
%uasm65
; v.002
; Increment port 0A200h at a rate of once increment
; per second. Use the timer based interrupt handler
; to control the time delay.
T1LL: equ B006h
T1LH: equ B007h
IER: equ B00Eh
ACR: equ B00Bh
COUNTDOWN: equ 500d
IRQVect: equ 0002d
OutChar: equ 0e003h
PrntMess: equ 0e00ch
org 0200h
lda #0d
sta IER ; Disable all interrupts.
lda #11000000b
sta ACR ; Set to T1 free running mode;
lda #COUNTDOWN<
sta T1LL ; Low byte of latch.
lda #COUNTDOWN>
sta T1LH ; High byte of latch.
; Initialize the interrupt vector.
lda #InterruptHandler<
sta IRQVect
lda #InterruptHandler>
sta IRQVect+1d
lda #01000000b
sta IER ; Enable all interrupts
cli ; Enable interrupts
MainLoop:
nop
jmp MainLoop
InterruptHandler:
;Save registers on the stack.
php
pha
txa
pha
tya
pha
inc 0a200h
;Restore registers from the stack.
pla
tay
pla
tax
pla
plp
cli ; Enable interrupts.
rti ; Return from interrupt.
end
%/uasm65
What I am trying to do is to print out "hello" to the console once a second and "there" when the IRQ is pressed, triggering the interrupt. Would I use a delay loop like:
Delay:
;Save registers on the stack.
pha
txa
pha
tya
pha
;Change the number that is being loaded into the
; 'A' register in order to change the delay time.
lda 0a600h
OutLoop:
ldx #0dfh
InLoop1:
ldy #0ffh
InLoop2:
dey
bne InLoop2
dex
bne InLoop1
sec
sbc #1d
bne OutLoop
;Restore registers from the stack.
pla
tay
pla
tax
pla
rts
end
Or do I need something that is timed by interrupts? Any guidance would be helpful.
Upvotes: 0
Views: 952
Reputation: 453
If your 6502 is running at 1MHz, that means it's executing 1,000,000 cycles in 1 second. The minimum number of cycles an instruction can take is 2 and the maximum is 8 (the real maximum is 7 but some instructions have a penalty cycle if the address spans a page e.g. 22FF-2300).
So if you do not want to rely on waiting on a timer, you can come up with any creative way to burn 1 million cycles. Obviously you will rely on loops. Any good 6502 instruction reference will give you the cycle timings for each individual instruction.
If you were controlling factory equipment, delay loops without controlling any interrupt source, including NMI and RESET, is a no-no. But you are fine here.
So, you're doing it the right way - but not in the right spot.
I'm assuming your main loop would print "Hello" once a second, and the ISR would print "There." So you do not want to put your delay loops in the ISR. The words "delay" and "interrupt service routine" as a rule do not ever, ever go together.
You probably don't want the thing to do something like print Hello Hello HeTherello Hello
either.
So you need to construct your ISR to do nothing but set a flag which your main loop will then checks. Your main loop can check for this flag each loop and print "There", after printing "Hello", if it's set. It should then clear the flag, obviously.
If you would like this to respond the moment you trigger the IRQ, you may need to check for the flag in your delay loop, and terminate the loop if the flag is set. If you do this, you will have to implement debouncing as well - you will either need a period of time where the flag is ignored or some programming to only set the flag if a button press and then release is detected - unless you don't mind the unit spamming "Hello There" constantly while the button is pressed.
Upvotes: 0