I've been trying my hand at z80 assembly recently, so I'll be using this thread as needed for questions along the way. I'm using Spasm for an assembler, and a TI-84+ emulated with WabbitEmu for debugging.

To begin, I've run into a wall trying to get direct port input to work as I need it to. I'm making a program that requires detection of button press and release events, and though for the most part it functions properly, I seem to be getting some sporadic input that I cannot trace. Here's a simplified version of my code:

Code:

.nolist
#include "ti83plus.inc"
.list
.org $9D93
.db t2ByteTok, tAsmCmp

   bcall(_RunIndicOff)
   bcall(_ClrLCDFull)

KeyLoop:
    ld   a, %11111101       ; Check for [CLEAR] to exit (Port FD)
    call DirectInput
   
    bit   6, a
    jr   NZ, CheckArrows

    ld   a, $FF             ; Reset key port
    out   (1), a
    ret                  ; Exit program

CheckArrows:
    ld   a, %11111110      ; Check arrow pad (Port FE)
   call DirectInput
   push af
   
   cp   $FF               
   jr    Z, noKeysPressed   ; If an arrow key is pressed
   ld   a, (last_key)
   cp   $FF               ; If last_key was not arrow
   jr    NZ, StoreLastKey
   call InvertRectangle   ; Called on key press
   jr   StoreLastKey      
noKeysPressed:
   ld   a, (last_key)
   cp    $FF
   jr   Z, StoreLastKey
   call InvertRectangle   ; Called on key release
StoreLastKey:
   pop af
   ld    (last_key), a
   jr   KeyLoop
   
;##############   
;# Procedures #
;##############

;inputs: a = key group
;outputs: a = key code
;destroys: a, b
DirectInput:
   ld   b,a
   ld   a, $FF             ;Reset the keypad
   out   (1),a
   ld   a,b
   out   (1),a
   nop
   nop
   in   a,(1)
   ret

;inputs: none
;outputs: none
;destroys: hl, de
InvertRectangle:
   ld   hl, 0
   ld   de, $0A0A
   bcall(_InvertRect)
   ret   

; Data   
last_key:   .db   $FF         ; Keep track of last key pressed

This listens for any arrow keypress. When one is pressed, the rectangle is inverted on the screen, and inverted again when it is released. While an arrow is held, nothing is drawn.

My problem occurs when the key is held. Occasionally, the port reads in $FF even though an arrow is pressed, causing the program to detect a false key release and invert the rectangle. This produces an unwanted flickering effect. I attempted adding some nops for delay between writing to and reading from the port, but that didn't help. Also, I've tried debugging in WabbitEmu, but I can't seem to produce the issue when stepping through, only when the program is running at full speed.

What exactly am I messing up here?
The problem i believe is that the interrupts are occasionally interrupting you during the direct input. Try putting a "di" at the top of your DirectInput routine or after the _ClrLCDFull. I'm not sure if the _InvertRect bcall turns on the interrupts or not, but i think _ClrLCDFull does. To be safe you can just put it at the top of the DirectInput routine.

Interrupts have caused me a lot of headaches with reading keys...
Yep, that was the problem! Thanks for the quick response.

Also, it looks like the _InvertRect bcall doesn't turn on interrupts, because a di right after the _ClrLCDFull fixed it. However, I don't see any reference to this behavior on WikiTI or in TI's 83+ system routines list. Is there any documentation that would help anticipate how a bcall will affect interrupts?
Not that i know of, some people have started to make lists, for example deeph put together a small list of BCALLs that don't disable interrupts:
Quote:
_op1toop4
_op2toop1
_op4toop2
_setxxop1
_setxxop2
_setxxxxop2
_fpdiv
_fpmult
_fpadd
_int
_convop1
_dispop1a
_grbufclr
_ldhlind
_vputs
_vputmap
_lcdbusy
I haven't checked them, though. The easiest way would just be to run the BCALL through a debugger. If interrupts are enabled when the BCALL is over, then you know that it turns them on Wink You can keep a list of bcalls you use often if you need to, though i tend to stay away from them when i can.

Btw, if you disable interrupts, you don't need the _RunIndicOff BCALL. That's actually just an OS (im1) interrupt that runs in the background, so disabling interrupts will also disable the run indicator.

You also don't need to reset the key port before exiting. It's really not even necessary between writes, you will just have multiple rows open at the same time that may overlap, since you won't be able to tell if you're pressing [Enter] or [Down], for example. A lot of times that's fine since who would be pressing enter (or [+] or [-]). Try loading up some older games, you'll see that [Graph]->[Window] can sometimes be used like the arrow keys. That's because they never reset the key port so that group is still activated (and the top row is in the same group as [2nd], [Mode], and [Del], which are used in almost every game).
To the best of my understanding, the common wisdom is to assume that most bcalls may do unexpected things with interrupts. I usually try to avoid bcalls in sections of my code where I have disabled interrupts (or set up a custom interrupt of my own). Unfortunately, I don't believe we have any documentation on which routines mess with interrupts and which do not.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement