I am asked to rewrite my code below with interrupts (full instructions). We haven’t really covered interupts in class and I’m not exactly sure how they are used or how to implement them. Here is my code that I wrote without using interrupts that basically makes the keyboard into a piano or can play a song(lamb,chromsc,hall) which was written for a motorola 68hc11:
PORTA EQU $1000 ;The speaker port
SPEAKER EQU PORTA
SPEAKERBIT EQU %00100000
SCSR EQU $6400 ; Serial communications status register
SCDR EQU $6401 ; Serial communcations data register
TDRE EQU %00000010 ; mask for TDRE flag in SCSR
RDRF EQU %00000001 ; mask for RDRF flag in SCSR
ORG $8000; Place data at 8000
LAMB FCB 'trerttttrrrrtuuutrerttttrrtre',$00
CHROMSC FCB 'q2we4r5ty7u8i9op-[=]',$00
HALL FCB 'qwertet5w5r2rqwertetiutetu',$00
KEYMAP FDB 'q', 220, 758 ; A ;key, frequency, and 1/4 second "period"
FDB '2', 233, 715 ; A#
FDB 'w', 247, 675 ; B
FDB 'e', 262, 636 ; C
FDB '4', 277, 602 ; C#
FDB 'r', 294, 567 ; D
FDB '5', 311, 536 ; D#
FDB 't', 330, 505 ; E
FDB 'y', 349, 478 ; F
FDB '7', 370, 450 ; F#
FDB 'u', 392, 425 ; G
FDB '8', 415, 402 ; G#
FDB 'i', 440, 379 ; A
FDB '9', 466, 358 ; A#
FDB 'o', 494, 337 ; B
FDB 'p', 523, 319 ; C
FDB '-', 554, 301 ; C#
FDB '[', 587, 284 ; D
FDB '=', 622, 268 ; D#
FDB ']', 659, 253 ; E
FDB $00 ; Null termination character
PROMPT FCB $0D, 'Piano program - use QWERTY row to play notes', $0D, $00 ;Prompt String
ORG $8800
LDS #$DFFF
;;;;;;;;;; Main Start ;;;;;;;;;;
LDX #PROMPT
PSHX ;Push the argument to the stack
JSR printString ;Print the promp string
PULX
ALWAYS DES
JSR getChar ;Get a character from the keyboard
JSR putChar
PULA ;put the character in A
PSHA ;Push character to the stack
JSR playTone ;Play the tone
PULA
CMPA #'a'
BNE SKIPLAMB
LDX #HALL
PSHX
JSR playSong
PULX
SKIPLAMB CMPA #'s'
BNE BRAALW
LDX #LAMB
PSHX
JSR playSong
PULX
BRAALW BRA ALWAYS ;Loop to the top and continue playing
;;;;;;;;;; Main End ;;;;;;;;;;
;;;;;;;;;; playTone Start ;;;;;;;;;; Passed an ascii character and a length on the stack
playTone PSHB ;for transparency
PSHA
PSHX
PSHY
TSY ;make Y point to the top of the stack
LDAA 8,Y ;load A with the passed argument
LDX #KEYMAP ;make Y point to the KEYMAP
CBAALWAYS LDAB 1,X ;load B with the ascii value
BEQ EXITPT ;If current value is $00, end of table, no key match, exit routine
CBA ;Compare B to A
BEQ SKIPTESTS ;If value are equal, skip rest of test to play tone
XGDX
ADDD #6 ;Make X point to the next character to compare
XGDX
BRA CBAALWAYS ;Branch until the end of table is reached
SKIPTESTS LDD 2,X ;Load D with the frequency
LSRD ;Number of times to toggle the speaker in a 1/4 second
LSRD ;this shortens the tone to an 1/8 note
;LSRD ;this plays a 1/16 note
;LSRD ;this plays a 1/32 note
PERIODLOOP LDY 4,X ;Load Y with the delay between toggles
FREQLOOP DEY ;Decrement Y until it's 0
BNE FREQLOOP ;Branch until X is 0
PSHB ;preserve D
PSHA
LDAA PORTA ;Load A with the speaker
EORA #SPEAKERBIT ;Toggle the speaker bit
STAA PORTA ;Store back into the speaker
PULA ;restore D
PULB
SUBD #1 ;Decrement D
CPD #0 ;Compare D to 0
BNE PERIODLOOP ;Branch until D is 0
EXITPT PULY
PULX
PULA
PULB ;return the stack to normal
RTS ;return to the main program
;;;;;;;;;; playTone End ;;;;;;;;;;
;;;;;;;;;; playSong Start;;;;;;;;;;
playSong PSHB ;Reference is passed on the stack
PSHA ;Pushes for transparency
PSHX
PSHY
TSX
LDX 8,x ;Load X with the passed value
LOOPSTRING LDAA 0,X ;Load A with the ith character of the string
BEQ ENDPSTRING ;Skips to end of subroutine if current character is null character
PSHA ;Pass the argument in A to putChar
JSR playTone
INS ;Return the stack to normal
INX ;increments X to point to the next character
BRA LOOPSTRING
ENDPSTRING PULY
PULX
PULA
PULB
RTS
;;;;;;;;;; playSong End ;;;;;;;;;;
;;;;;;;;;; putChar start ;;;;;;;;;; Passed argument should be an ascii value
putChar PSHB ;is passed an argument on the stack
PSHA ;for transparency
PSHX
PSHY
TSY ;stack frame
LDX #SCSR ;Load in address of SCSR (Serial Communication Status Register)
GCWAIT BRCLR 0,X TDRE GCWAIT ;Loop
LDAA 8,Y ;Load A with the passed value
STAA SCDR ;Write A to the SCDR
PULY
PULX
PULA
PULB
RTS
;;;;;;;;;; putChar end ;;;;;;;;;;
;;;;;;;;;; getChar start ;;;;;;;;;; ascii value is returned
getChar PSHB ;No argument. Passes result back on the stack.
PSHA ;For transparency
PSHX
PSHY
TSY
LDX #SCSR ;Load in address of SCSR (Serial Communication Status Register)
PCWAIT BRCLR 0,X RDRF PCWAIT ;Loop when the
LDAA SCDR ;Load A with what's in the SCDR (should be the pressed key)
STAA 8,Y ;Store it to the stack to be passed back
PULY
PULX
PULA
PULB
RTS
;;;;;;;;;; getChar end ;;;;;;;;;;
;;;;;;;;;; printString start ;;;;;;;;;; argument passed on the stack in ascii
printString PSHB ;Reference is passed on the stack
PSHA ;Pushes for transparency
PSHX
PSHY
TSX
LDX 8,x ;Load X with the passed value
LOOPSTRING1 LDAA 0,X ;Load A with the ith character of the string
BEQ ENDPSTRING1 ;Skips to end of subroutine if current character is null character
PSHA ;Pass the argument in A to putChar
JSR putChar
INS ;Return the stack to normal
INX ;increments X to point to the next character
BRA LOOPSTRING1
ENDPSTRING1 PULY
PULX
PULA
PULB
RTS
;;;;;;;;;; printString end ;;;;;;;;;;
Can someone please give me an example how to effectively implement or just a hint how to start coding interrupts so I can rewrite my code with them.
To use interrupts on the hc11 there is four things you’ll have to do:
For the next steps I’ll assume you are using the IRQ interrupt. It’s just a simple interrupt pin on the hc11 that interrupts the system when it’s voltage drops to low. However the steps would be very similar for any other interrupt.
You need to initialize the start location of the interrupt service routine. When the interrupt is triggered the processor will check a vector table to figure out where it needs to go. So for example when IRQ is triggered it will go to the table entry corresponding to IRQ ($FFF2) and then jump to the address stored there. We’ll label the interrupt service routine
IRQ_INTand store it in the table entry corresponding to IRQ so that when IRQ is triggered it will start executing the code at the labelIRQ_INT.Next you need to enable the interrupt so that the processor will recognize it when it is triggered. Once again you will have to check the manual on what value and which register you have to store the value in to enable it. To enable IRQ the IRQ enable bit (IRQEN) must be set to 1 in the interrupt control register (INTCR). Then it can be enabled with the
CLIcommand.Lastly you need to write your interrupt service routine. This is the code that will be executed every time the interrupt is triggered. It will start at the label we set earlier in the vector table and end when it hits the instruction
RTI. The return from interrupt instruction tells the processor that the service routine is finished and it should return to the the whatever it was executing before the interrupt was triggered.My guess is that you will want some sort of interrupt on the keyboard port that triggers when a key is hit. Once a key is hit the interrupt will trigger the processor to go to the interrupt service routine. There you will have to write code that determines which key was hit and plays the proper note.