user3050884
user3050884

Reputation: 31

Basic Programming of a 6502 Microcontroller using Interrupts

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

Answers (1)

LawrenceC
LawrenceC

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

Related Questions