[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Reading Joystick Position



Simon Williams replied:



>On Mon, 18 Nov 2002 20:51:36 -0600 "Joel" <joelbuckley54.nospam.@hotmail.com>
>wrote:
> 
>> You have the right addresses, but the wrong technique.
>> Accessing $C070 (49266) starts a quad timer (all four Paddle inputs).
>> The paddles provide the R in an RC time constant.
>> The timer outputs show up as the hi bit of those 4 addresses.
>> After the timers time out, the hi bit goes from high to low.
>> A software timing loop determines the PDL value.
>> It's fast (12 microseconds per tic), so you can't duplicate this with Peeks
>> from Applesoft.
>> Here's the routine.
>> $FB1E
>> PREAD LDA $C070 start timers, enter with paddle # in X
>>  LDY #0
>>  NOP
>>  NOP
>> PREAD2 LDA $C064,X
>>  BPL RTS2D
>>  INY
>>  BNE PREAD2
>>  DEY ; 255 max
>> RTS2D RTS
>
>Hmmm. think I've got it: to get the X-Y coords of the Joystick, I would
>need to call this routine twice with LDX #0 and LDX #1 respectively. 

That is correct.  You also need to be careful about calling the second
time before the axis you _didn't_ request has timed out, since that
would result in a too-low reading for the second axis.

>Each time thru I would need to return to sender and store $C064,X.

No, $C064,X has nothing to do with the joystick value--it is simply
a flag which indicates whether the triggered timer for the selected
axis has timed out yet.

>If this works the way I think it does, then it is possible to read 
>either coordinate seperately.

No.  It is impossible to start the timer for only one axis, but it
is, in fact, difficult to determine the time constant of more than
one timer at a time.  (The above routine determines the time
constant of axis "X" only.)

The joystick or paddle capability of the Apple II is a set of four
not-quite-independent timing circuits.  Their time constants are
set independently by the joystick variable resistances.  They
are all triggered simultaneously by the reference to $C070,
and, after a few microseconds, all timers are reset and begin
to "run down" at a rate determined by their respective time
constants (joystick resistance settings).

Whether or not a particular timer has "run down" can be sensed
by reading the high bit of $C064,X--when it goes low (byte
read is positive), the timer has run down and ended its timing
cycle.  The time required to run down is measured by looping
on this bit and counting to measure the time elapsed.  The
number of iterations taken for the timer to run down is the
"joystick axis reading".  This reading is purely a creation of
the looping routine, and does not exist anywhere else as a
number.

The fact that all timers are triggered by the reference to $C070
creates the problem alluded to above:  that a second call to
this routine in quick succession can produce an erroneous
reading for the second call.

The reason is that all timers have been triggered, and the
time constant for the first call may be short, while the second
may be long.  Since the "standard" routine does not wait for
the requested timer to be "timed out" prior to resetting it and
starting to time it, and since the timer hardware does not
reset a still-running timer, a second call in quick succession
may result in measuring only the _remaining_ time for the
second timer to run down, not the _total_ time from a fresh
start.

As hinted, this "bug" can be fixed by polling the state of
the timer about to be read and stalling until it times out
before calling the PREAD routine.

>Is this routine part of ProDOS or BASIC.SYSTEM or would I need to make
>it part of my program?

It's part of the monitor ROM, at location $FB1E.

-michael

Check out 8-bit Apple sound that will amaze you on my
Home page:  http://members.aol.com/MJMahon/