REF: TrackBall Programming Guide

From: Craig Lisowski (aa853@cleveland.Freenet.Edu)
Date: 04/21/94-11:21:57 PM Z


From: aa853@cleveland.Freenet.Edu (Craig Lisowski)
Subject: REF: TrackBall Programming Guide
Date: Thu Apr 21 23:21:57 1994



                   PROGRAMMING THE CX-22 TRACK BALL

                           William Bartlett
                           October 26, 1983

           This document will attempt to provide programmers with an
      understanding of what the Atari Trak-Ball is capable of doing,
      how it does it, and how to tap it's potential from an appli-
      cation program.  The scope of this document is limited to 
      using the Trak-Ball in true trak-ball (TB) mode.  Programming
      the Trak-Ball in joystick (JS) mode is exactly the same as
      programming a joystick.

           Let me briefly review how the PIA chip handles the Atari
      joystick.  A joystick plugged into port 1 will toggle the lower
      four bits of PORTA located at $D300 and shadowed at $278.  One
      bit is cleared (zero) to indicate the joystick is being pushed
      in any of four directions; right, left, forward or back.  If
      the joystick is stationary, the four bits are set (one).  Atari
      BASIC provides the STICK function to provide the value of these
      four bits to a BASIC programmer.


      HOW DOES A TRAK-BALL DIFFER FROM A JOYSTICK?

           A joystick is only capable of indicating direction whereas
      a trak-ball is capable of indicating direction and speed.  The
      best implementation of trak-ball application programs will re-
      flect the varying speeds of ball movement.


      HOW IS DIRECTION AND SPEED IMPLEMENTED IN THE HARDWARE?

           A trak-ball plugged into port 1 will toggle the lower four
      bits of PORTA located at $D300 and shadowed at $278.  There are
      two direction bits and two rate bits; one each for the hori-
      zontal and vertical axis.  The direction bits indicate which
      direction along the axis the ball is rolling.  The rate bits
      change from 0 to 1 and back to 0 as the ball is rolled.  The 
      faster the ball rolls, the faster the rate bits change.


      HOW CAN AN APPLICATION PROGRAM UTILIZE THE TRAK-BALL?

           Unfortunately, Atari BASIC is very inefficient for using
      the Trak-Ball.  To quickly implement direction and speed it is
      necessary to test the individual bits of PORTA.  The AND func-
      tion in Atari BASIC is byte-to-byte instead of a true bit-to-bit
      test.  Therefore, machine language is going to be required to
      tap the potential of the Trak-Ball.

           To determine the direction of ball movement, the direction
      bits need to be tested only once.  To determine the speed of
      ball movement, the rate bits will have to be sampled many times
      and a count made of the changes from 0 to 1 and back.  The
      lower four bits of PORTA are assigned as follows:

                +---------------+---+---+---+---+
      PORTA >>  |               | 4 | 3 | 2 | 1 |
                +---------------+---+---+---+---+
         
                * bit 4 = vertical rate,
                * bit 3 = vertical direction (0=up, 1=down),
                * bit 2 = horizontal rate,
                * bit 1 = horizontal direction (0=left, 1=right).
                  
           Let's assume we wish to control an object on the screen
      with a trak-ball.  There are two logical approaches to this
      programming problem.  I shall refer to these as the vector
      approach and the incremental approach.

      VECTOR : The vector approach is to maintain a value for the
      horizontal and vertical locations, sample the trak-ball N
      times, calculate the new horizontal and vertical locations,
      and then reposition the object.  A complication is that if
      the object is a player or missile, we could vector to a new
      location without recognizing a collision.  Another complication
      is that of boundaries.  What if the new location is outside of
      a boundary?  Should we ignore the boundary, ignore the sample,
      or calculate where the vector crosses the boundary?  Using the 
      vector method we will either have complicated coding or flaky
      response.

      INCREMENTAL : The incremental approach is to move the object
      when the rate bit changes as you sample the trak-ball N times.
      Boundary and collision checking is much simpler than that of
      the vector approach.


      SAMPLE PROGRAMS

      I have provided three tutorial programs to be used in
      conjunction with the trak-ball:

      1) TBALLTST.BAS allows you to observe the lower four bits of
         PORTA changing so that you can familiarize yourself with
         their action.

      2) TBALL.BAS will demonstrate how the trak-ball can be sampled
         from Atari BASIC to provide a signed value of direction and
         speed for each axis.  The three numbers displayed are the
         horizontal axis, the vertical axis, and the joystick value.
      
      3) VBITBALL.BAS demonstrates a vertical blank routine to sample
         the trak-ball and move a player using the incremental method
         discussed above.   Because the movement is done using a
         vertical blank interrupt (background), other activity may
         proceed in BASIC (foreground).
      
      (Listing follows:)
      
      10 REM :TBALLTST.BAS
      100 DATA 169,0,133,212,133,213,104,104,104,133,203,104,104
      101 DATA 37,203,240,2,230,212,96
      110 FOR I=1536 TO 1555:READ J:K=K+J:POKE I,J:NEXT I
      111 IF K-2736 THEN ? "BAD DATA!":END
      120 GRAPHICS 0:POKE 710,0:TRAP 21:? "BIT OPTIONS (0-15)...";:INPUT OP
      125 GRAPHICS 18
      130 I=PEEK(632):POSITION 0,0
      135 IF USR(1536,OP,8) THEN ? #6;USR(1536,I,8),"Y RATE"
      136 IF USR(1536,OP,4) THEN ? #6;USR(1536,I,4),"Y DIR"
      137 IF USR(1536,OP,2) THEN ? #6;USR(1536,I,2),"X RATE"
      138 IF USR(1536,OP,1) THEN ? #6;USR(1536,I,1),"X DIR"
      140 IF PEEK(53279)=6 THEN 120
      141 GOTO 130
      
            10 ;#D1:TBALLTST.SRC
            20 ;TEST A BIT
00D4        30 BASIC    =    $D4
00CB        40 MASK     =    $CB
0000        50          *=   $0600
0600 A900   60          LDA  #0
0602 85D4   70          STA  BASIC
0604 85D5   80          STA  BASIC+1
0606 68     90          PLA             ;BASIC
0607 68     0100        PLA             ;MSB MASK
0608 68     0110        PLA             ;LSB MASK
0609 85CB   0120        STA  MASK
060B 68     0130        PLA             ;MSB VALUE
060C 68     0140        PLA             ;LSB VALUE
060D 25CB   0150        AND  MASK
060F F002   0160        BEQ  DONE
0611 E6D4   0170        INC  BASIC
0613 60     0180 DONE   RTS


10 REM :TBALL.BAS
100 REM 1536-1619
101 DATA 104,169,0,133,212,133,213,173,0,211,41,2,133,205,160,255,173,0,211
102 DATA 41,2,197,205,240,2,230,212,133,205,136,208,240,173,0,211,41,1,208
103 DATA 6,165,212,9,128,133,212,173,0,211,41,8,133,205,160,255,173,0,211
104 DATA 41,8,197,205,240,2,230,213,133,205,136,208,240,173,0,211,41,4,208
105 DATA 6,165,213,9,128,133,213,96,-1
110 FOR I=1536 TO 1619:READ J:K=K+J:POKE I,J:NEXT I
111 IF K-11306 THEN ? "BAD DATA!":END
200 U=USR(1536):Y=INT(U/256):X=U-Y*256
210 IF X>127 THEN X=X-128:IF X THEN X=-X
211 IF Y>127 THEN Y=Y-128:IF Y THEN Y=-Y
220 ? X,Y,PEEK(632):GOTO 200

            10 ;#D1:TBALL.SRC
            20 ;SAMPLE TBALL X,Y DIR, RATE
            30 ;CALLED FROM BASIC U=USR(ORG) ;HIBYTE=Y AXIS ;LOBYTE=X AXIS
D300        40 PORTA    =    $D300
00D4        50 XCOUNT   =    $D4
00D5        60 YCOUNT   =    $D5
00CD        70 LAST     =    $CD
0000        80          *=   $600
0600 68     90          PLA
0601 A900   0100        LDA  #0
0603 85D4   0110        STA  XCOUNT
0605 85D5   0120        STA  YCOUNT
0607 AD00D3 0130 XINIT  LDA  PORTA
060A 2902   0140        AND  #2
060C 85CD   0150        STA  LAST
060E AOFF   0160        LDY  #$FF
0610 AD00D3 0170 XSAMP  LDA  PORTA
0613 2902   0180        AND  #2
0615 C5CD   0190        CMP  LAST
0617 F002   0200        BEQ  XDEC
0619 E6D4   0210        INC  XCOUNT
061B 85CD   0220 XDEC   STA  LAST
061D 88     0230        DEY
061E D0F0   0240        BNE  XSAMP
0620 AD00D3 0250        LDA  PORTA
0623 2901   0260        AND  #1
0625 D006   0270        BNE  YINIT
0627 A5D4   0280        LDA  XCOUNT
0629 0980   0290        ORA  #128
062B 85D4   0300        STA  XCOUNT
062D AD00D3 0310 YINIT  LDA  PORTA
0630 2908   0320        AND  #8
0632 85CD   0330        STA  LAST
0634 A0FF   0340        LDY  #$FF
0636 AD00D3 0350 YSAMP  LDA  PORTA
0639 2908   0360        AND  #8
063B C5CD   0370        CMP  LAST
063D F002   0380        BEQ  YDEC
063F E6D5   0390        INC  YCOUNT
0641 85CD   0400 YDEC   STA  LAST
0643 88     0410        DEY
0644 D0F0   0420        BNE  YSAMP
0646 AD00D3 0430        LDA  PORTA
0649 2904   0440        AND  #4
064B D006   0450        BNE  RETURN
064D A5D5   0460        LDA  YCOUNT
064F 0980   0470        ORA  #128
0651 85D5   0480        STA  YCOUNT
0653 60     0490 RETURN RTS


10 REM :VBITBALL.BAS
100 REM 1536-1762
101 DATA 160,255,173,0,211,41,2,133,203,173,0,211,41,2,197,203,240,39,133,203
102 DATA 173,0,211,41,1,240,16,174,149,6,232,224,196,240,22,142,149,6,142,0
103 DATA 208,208,14,174,149,6,202,224,48,240,6,142,149,6,142,0,208,136,208,205
104 DATA 160,255,173,0,211,41,8,133,203,173,0,211,41,8,197,203,240,65,133,203
105 DATA 173,0,211,41,4,208,29,174,150,6,224,32,240,49,202,142,150,6,152,72
106 DATA 160,8,189,1,44,157,0,44,232,136,16,246,104,168,208,27,174,150,6,224
107 DATA 218,240,20,232,142,150,6,152,72,160,8,189,6,44,157,7,44,202,136,16
108 DATA 246,104,168,136,208,179,76,98,228,0,0,104,160,255,169,0,153,0,44,136
109 DATA 208,250,185,219,6,153,120,44,200,192,8,208,245,169,120,141,149,6,141,150
110 DATA 6,141,0,208,169,34,141,192,2,169,1,141,8,208,169,40,141,7,212,169
111 DATA 62,141,47,2,169,3,141,29,208,169,7,162,6,160,0,32,92,228,96,24
112 DATA 24,24,231,231,24,24,24
113 REM * 227 BYTES
120 FOR I=1536 TO 1762:READ J
130 K=K+J:POKE I,J:NEXT I
140 IF K-26973 THEN ? "BAD DATA!":END
150 I=USR(1687)


                10 ;          :VBITBALL.SRC 
                20 ; VBLANK TO MOVE PLYR 0 WITH T-BALL
                30 ; EQUATES    
    =D300       40 PORTA     =    $D300
    =00CB       50 LASTA     =    $CB
0000            60          *=   $0600
                70 ;X-AXIS:BIT1=X DIR, BIT2=X RATE
0600 A0FF       80 VBI      LDY #$FF
0602 AD00D3     90          LDA PORTA
0605 2902       0100        AND #2
0607 85CB       0110        STA LASTA
0609 AD00D3     0120 XSAMP  LDA PORTA
060C 2902       0130        AND #2
060E C5CB       0140        CMP LASTA
0610 F027       0150        BEQ XNEXT
0612 85CB       0160        STA LASTA
0614 AD00D3     0170        LDA PORTA
0617 2901       0180        AND #1
0619 F010       0190        BEQ XLEFT
061B AE9506     0200 XRGHT  LDX XPOS
061E E8         0210        INX
061F E0C4       0220        CPX #196
0621 F016       0230        BEQ XNEXT
0623 8E9506     0240        STX XPOS
0626 8E00D0     0250        STX P0HPOS
0629 D00E       0260        BNE XNEXT
062B AE9506     0270 XLEFT  LDX XPOS
062E CA         0280        DEX
062F E030       0290        CPX #48
0631 F006       0300        BEQ XNEXT
0633 8E9506     0310        STX XPOS
0636 8E00D0     0320        STX P0HPOS
0639 88         0330 XNEXT  DEY
063A D0CD       0350 ;Y AXIS:  BIT3=Y DIR, BIT4=Y RATE
063C A0FF       0360        LDY #$FF
063E AD00D3     0370        LDA PORTA
0641 2908       0380        AND #8
0643 85CB       0390        STA LASTA
0645 AD00D3     0400 YSAMP  LDA PORTA
0648 2908       0410        AND #8
064A C5CB       0420        CMP LASTA
064C F041       0430        BEQ YNEXT
064E 85CB       0440        STA LASTA
0650 AD00D3     0450        LDA PORTA
0653 2904       0460        AND #4
0655 D01D       0470        BNE YDOWN
0657 AE9606     0480 YUP    LDX YPOS
065A E020       0490        CPX #32
065C F031       0500        BEQ YNEXT
065E CA         0510        DEX
065F 8E9606     0520        STX YPOS
0662 98         0530        TYA
0663 48         0540        PHA
0664 A008       0550        LDA #8
0666 BD012C     0560 YUP1   LDA P0BASE+1,X
0669 9D002C     0570        STA P0BASE,X
066C E8         0580        INX
066D 88         0590        DEY
066E 10F6       0600        BPL YUP1
0670 68         0610        PLA
0671 A8         0620        TAY
0672 D01B       0630        BNE YNEXT
0674 AE9606     0640 YDOWN  LDX YPOS
0677 E0DA       0650        CPX #218
0679 F014       0660        BEQ YNEXT
067B E8         0670        INX
067C 8E9606     0680        STX XPOS
067F 98         0690        TYA
0680 48         0700        PHA
0681 A008       0710        LDY #8
0683 BD062C     0720 YDOWN1 LDA P0BASE+6,X
0686 9D072C     0730        STA P0BASE+7,X
0689 CA         0740        DEX
068A 88         0750        DEY
068B 10F6       0760        BPL YDOWN1
068D 68         0770        PLA
068E A8         0780        TAY
068F 88         0790 YNEXT  DEY
0690 D0B3       0800        BNE YSAMP
0692 4C62E4     0810        JMP XITVBV
0695 00         0820 XPOS   .BYTE 0
0696 00         0830 YPOS   .BYTE 0
                0840 ;INIT. PM/VBI
                0850 ;EQUATES
    =D407       0860 PMBASE = $D407
    =2800       0870 PMRAM  = $2800
    =2C00       0880 P0BASE = PMRAM+$0400
    =D000       0890 P0HPOS = $D000
    =02C0       0900 P0COLR = $02C0
    =D008       0910 P0SIZE = $D008
    =022F       0920 SDMCTL = $022F
    =D01D       0930 GRACTL = $D01D
    =0224       0940 VVBLKD = $0224
    =E45C       0950 SETVBV = $E45C
    =E462       0960 XITVBV = $E462
                0970 ;CLEAR PLAYER 0
0697 68         0980        PLA
0698 A0FF       0990        LDY #$FF
069A A900       1000        LDA #0
069C 99002C     1010 INIT1  STA P0BASE,Y
069F 88         1020        DEY
06A0 D0FA       1030        BNE INIT1
                1040 ;DEFINE PLAYER 0
06A2 B9DB06     1050 INIT2 LDA P0SHAP,Y
06A5 99782C     1060        STA P0BASE+120,Y
06A8 C8         1070        INY
06A9 C008       1080        CPY #8
06AB D0F5       1090        BNE INIT2
06AD A978       1100        LDA #120
06AF 8D9506     1110        STA XPOS
06B2 8D9606     1120        STA YPOS
06B5 8D00D0     1130        STA P0HPOS
06B8 A922       1140        LDA #34
06BA 8DC002     1150        STA P0COLR
06BD A901       1160        LDA #1      ;DOUBLE WIDTH
06BF 8D08D0     1170        STA P0SIZE
06C2 A928       1180        LDA #PMRAM/256
06C4 8D07D4     1190        STA PMBASE
06C7 A93E       1200        LDA #$3E    ;SINGLE LINE P/M
06C9 8D2F02     1210        STA SDMCTL
06CC A903       1220        LDA #$03    ;TURN ON P/M
06CE 8D1DD0     1230        STA GRACTL
                1240 ;INIT. VBI
06D1 A907       1250        LDA #7
06D3 A206       1260        LDX #VBI/256
06D5 A000       1270        LDY #VBI&255
06D7 205CE4     1280        JSR SETVBV
06DA 60         1290        RTS
06DB 181818E7   1300 P0SHAP .BYTE $18,$18,$18,$E7,$E7,$18,$18,$18
06DF E7181818

[END]


-----------------------------------------
Return to message index