ECE 412 Lab 4 Introduction to Interrupt Systems Due on: 10/07/2008 Submitted on: 10/02/2008 Performed on: 9/29, 10/01 Chris McDowell
Patrick Riley
Title: Familiarization with Interrupt System using IRQ’
Program Objective: The purpose of this experiment is to familiarize ourselves with dealing with hardware-induced interrupts with our Assembly program. In this experiment, we were to first develop a background task that would allow for a debounced push button to activate the IRQ’ pin interrupt on the breadboard. In turn, our application would need to be constructed in a way that would perform a specific task during the interrupt and then return to normal operation. Explanation of Program: The background task of the application takes the input of the logic switches as two BCD numbers. Once the application recognizes the input, specific actions are to be taken in order to complete the run of the application. The first set of instructions to be done include verifying that the input number is valid BCD. In order to verify that validity of the input we needed to take the 8 bit used as the input and then proceed to mask both the upper and lower nibbles so that the values can be compared to the value 9 in order to ensure that the number is valid BCD. When masking the upper nibble, the resultant value cannot be greater than 9. When masking the lower nibble, the resultant value cannot be greater than 90. Once verified to be valid BCD, the entire 8 bits were to be compared to 90 again to ensure that the value does not exceed 90 as per the criteria for the experiment. Each nibble is stored separately for recall later in the application. An algorithm, albeit a short one, to transform the upper nibble into a form to be used later involved perform a Logic Shift Right 4 times in order to get the correct decimal place. Once completed, we were to output to the 7-segment display, starting at what the BCD number minus the value of the upper nibble would be and counting up to the value of the BCD number plus the lower nibble. An interrupt can occur during this portion. Once an interrupt is recognized, the background application would enter a subroutine specifically for the interrupt. Whatever number was currently being displayed on the display at the time of the interrupt would be stored to memory for recall later. Then the subroutine would count down from the value of the BCD number plus the lower nibble to the value of the BCD number minus the upper nibble. Once the countdown is complete, the application would restore the previous number displayed on the display before the interrupt request occurred and continue. The background task would perform the incrementation a total of four times before restarting the application and reading in the value from the logic switches. Pseudo Code: Start program Read input from logic switches Store in memory location
Mask upper nibble and compare value to 9, branch to subroutine if higher Store value in memory location Mask lower nibble and compare value to 90, branch to subroutine if higher Store value in memory location Compare input to value 90 and branch if higher Perform arithmetic on upper nibble to transform it to be in lower nibble position by using LSR Store value in memory location Subtract the value of the upper nibble from the input and store in memory to be used for lower bound Add the value of the lower nibble to the input and store in memory to be used for upper bound Enter loop to be run 4 times before going back to the start of the program Display lower bound on 7-segment display and increment by 1 until the upper bound is reached or an interrupt occurs. Interrupt Routine: Store current value on the 7 segment display to memory for recall Display the upper bound number on the display and decrement until the lower bound is reached Once the lower bound is reached, restore the value on the display of the number from before the interrupt routine was entered. Program resumes normal operation at this point Observations and Comments: One of the issues we originally ran into was when a number would cross a value of 10; i.e. when 42 is used. When our algorithms were performed to get the upper and lower bounds for counting, we would get invalid data that wasn’t valid BCD. This was because we were attempting to subtract the upper nibble from the real BCD number. The DAA command apparently doesn’t function after a SUBX procedure is performed. We had to modify our code at this point to instead subtract whatever the upper nibble was from the value 99 in order to decrement the original BCD correctly by adding said value to the BCD number. In order to decrement BCD by a single number, you simply add 99 to it. To subtract by two you would add 98 to the BCD number and so on. Once this was discovered our application appeared to run without a problem.
Conclusion: The application seemed fairly simple to implement and didn’t require a large amount of time to figure out. We did have a few subroutines and probably could have modularized it a little bit more especially with the comparing functions. This might not necessarily have made it more efficient but the flow of the actual code may have been easier to read and traverse. Implementation of the interrupt using the IRQ’ pin was fairly simple due to most of the lab work just requiring coding instead of a lot of wiring. The implementation of the interrupt was pretty straight forward and self explanatory. Program Listing: ********************************************************* *
LEDS: S1 -> PC7, S8 -> PC0
********************************************************* ********************************************************* *
Port addresses and assignments
********************************************************* DPB
EQU
$1000 ; Deboucned Push Button
LEDS EQU
$1004 ; 7-segment display(LED Port B)
INPUT EQU
$1003 ; logic switches(INPUT)
********************************************************* *
Variable declaration
********************************************************* BCDF EQU BCDN
$0000 ; BCD flag: 0 = !BCD, 1 = BCD
EQU
$0001 ; Place to store entire BCD from INPUT
BCDN1
EQU
$0002 ; Stores the upper nibble of N
BCDN2
EQU
$0003 ; Stores the lower nibble of N
N1
EQU
$0004 ; N1 = N - BCDN1
N2
EQU
$0005 ; N2 = N + BCDN2
IDSPVAL EQU
$0006 ; value on display before Interrupt
********************************************************* ********************************************************* *
Main Program
*********************************************************
ORG
$D000 ; start of program
********************************************************* *
Initialization
********************************************************* START LDS
#$01FF ; loads stack pointer
CLR
BCDF
; clear BCD flag
LDAA
INPUT ; load BCD number to ACCA
STAA
BCDN
TAB
; transfer ACCA to ACCB
ANDA
#$0F
STAA
; mask upper nibble of ACCA
BCDN2 ; and store the value in BCDN2
CMPA
#$09
BHI BCD0
; store the input in mem loc
; compare ACCA with 9
NOTBCD ; and branch to NOTBCD if higher
ANDB STAB
; otherwise, mask lower nibble of ACCB
BCDN1 ; and store ACCB in BCDN2
CMPB BHI
#$F0 #$90
; compare ACCB to 90
NOTBCD ; and branch to NOTBCD if higher ; at this point, the number is at least ; valid BCD but now need to check to ; see if 0 < N <= 90 is true
BCD1
INC
BCDF
; sets flag to verify that
; the input is valid BCD NLT90 LDAA CMPA BHI
BCDN #$90 NOTBCD
********************************************************* *
Conversion of BCD to Binary
*
Purpose if to get the upper nibble to transfer to
*
lower nibble form: xxxx0000 -> 0000xxxx
********************************************************* LSRB
; performs logic shift right on
LSRB
; upper nibble to transform it
LSRB
; to a valid lower nibble value
LSRB STAB
BCDN1
LDAB
#$99 ; loads ACCB with 99 then
SUBB
BCDN1 ; subtracts BCDN1 and adds 1 to
ADDB
#$01 ; ACCB then adds B to A
ABA
; stores result in BCDN1
; to get lower bound number
DAA STAA
N1
LDAA
BCDN
ADDA
BCDN2
DAA STAA
; stores result as N1 ; loads ACCA with the BCD number ; and adds the lower nibble to it
; to get upper bound number N2
; and stores result as N2
********************************************************* *
Count from N1 to N2 on Display 4 times
*
before pausing, then rereading the logic switches
*********************************************************
LOOP
LDAB
#$05 ; loads ACCB with 5 for looping
CLI
; enables interrupts
LDAA
N1
; loads ACCA with lower bound num
DECB
; decrements the loop counter
CMPB
#$00 ; and verifies that it hasnt
BEQ
NOTBCD
; looped 4 times and branches if
; it has
DISPLAY
STAA JSR
LEDS
; stores ACCA in the LEDS
DELAY; delay allowing number to be seen
ADDA
#$01 ; then increments by 1
DAA
; performs DAA to get valid bcd
CMPA
N2
; compares it to upper bound
BHI
LOOP ; and branches if it is higher
BRA
DISPLAY ; otherwise repeats counting
********************************************************* *
End of Main Program
********************************************************* ********************************************************* ********************************************************* *
Interrupt routine "VldBCD"
*
Purpose: Checks to see if input from PORTC(logic
*
switches) was valid BCD
********************************************************* VldBCD if not)
LDAB DPB
;load accumulator B with PORTA value (3 if pressed, 0
BITB #$01 BNE
;OR B with 0000 00001
VldBCD
;branch if not equal to zero
LDAA
LEDS
; stores value of LEDS before
STAA
IDSPVAL ; interrupt and stores in IDSPVAL
LDAA
BCDF
BEQ
NOTBCD ; and branches if previous was
; loads the BCD flag ; not valid BCD
********************************************************* *
Count down from N2 to N1 in BCD, display
********************************************************* LDAA DISPC
N2 STAA
JSR CMPA
DELAY N1
; loads upper bound number LEDS
; displays ACCA in LEDS
; jumps to delay sr ; compares ACCA to N1
BEQ
CDONE
ADDA
#$99
DAA
; and branches when they are eq
; otherwise, subtracts 1 from A
; performs DAA to get BCD
BRA
DISPC
; branches to repeat
********************************************************* *
Count is completed, restore value and return
********************************************************* CDONE LDAA
IDSPVAL ; loads ACCA with previous LED
STAA
LEDS
RTI
; displays ACCA in LEDs
; returns execution to main ; application
********************************************************* *
Subroutine for when input value is not valid BCD
********************************************************* NOTBCD LDAA
#$00
; loads ACCA with value 00
STAA
LEDS
; and displays it to the LEDS
JSR
DELAY
; performs delay routine so it
JSR
START
; can be seen then restarts app
********************************************************* *
Delay subroutine
********************************************************* DELAYLDY
#$0010
DELAY1
LDX
DELAY2
DEX
BNE
#$8000
DELAY2
DEY BNE RTS
DELAY1
ORG
$FFF2
; Interrupt vector
FDB
VldBCD
; IRQ Pin Interrupt
ORG
$FFFE
FDB
START
; Reset vector