Reading Touch Pad

Basic and Machine Language

Moderator: Moderators

Post Reply
User avatar
Jeff-20
Denial Founder
Posts: 5761
Joined: Wed Dec 31, 1969 6:00 pm

Reading Touch Pad

Post by Jeff-20 »

I've resurrected a project that would use the Atari 2600's keypad controller. I found great pin out info at this site.

As compared to the Joystick pinout:

Pin Description
1 Up
2 Down
3 Left
4 Right
5 NC
6 Fire
7 NC
8 Ground
9 NC

Here's the Kids Controller (Touch Pad)


Pin #
# 5 9 6
1
1 2 3
2 4 5 6
3 7 8 9
4 * 0 #
7 +5v pulls pins 5 & 9 through 4.7k resistors

My table isn't aligned, but the idea is: pressing 3 on the keypad would be the same as holding the fire button and UP on a joystick simultaneously.

It uses the Paddle control pins too. When I do a straight read of locations 37151, 37152, 36872, 36873, I get a lot of "flickering" results (similar to paddle reads). Should I change the value of 37154 as if I am reading the joystick? I wanted to see if anyone has ideas. I'm still testing.
High Scores, Links, and Jeff's Basic Games page.
User avatar
GreyGhost
Vic 20 Nerd
Posts: 526
Joined: Wed Oct 05, 2005 11:10 pm

Post by GreyGhost »

Here's this if it helps. I can't remember where I found it. It was a magazine article in RUN or something.

Code: Select all

200 print"S...  loading interface"
210 tm%=peek(51)+256*peek(52)-160:nh%=tm%/256:nl%=tm%-nh%*
256
220 poke51,nl%:poke55,nl%:poke52,nh%:poke56,nh%:clr
230 tm%=peek(51)+256*peek(52)
240 fori=0to159
250 readn%
260 ifn%=-1thenn%=peek(51)
270 ifn%=-2thenn%=peek(52)
280 poketm%+i,n%
290 next
300 systm%+143
320 end
330 data 240,12
350 rem place values for cntroller keys here...
390 data 55:rem s1=7
400 data 56:rem s2=8
410 data 57:rem s3=9
420 data 52:rem s4=4
430 data 53:rem s5=5
440 data 54:rem s6=6
450 data 49:rem s7=1
460 data 50:rem s8=2
470 data 51:rem s9=3
480 data 46:rem s10=,
490 data 48:rem s11=0
500 data 13:rem s12=cr
520 data160,1,169,195,45,17,145,141,17,145,169,127,141,32,145,141,34
,145
530 data173,19,145,41,195,133,254,162,3,169,2,133,203,6,203,165
540 data203,5,254,141,19,145,152,160,0,136,208,253,168,169,128,205
550 data9,144,144,32,200,205,8,144,144,26,200,173,17,145,41,32
560 data240,18,200,202,48,51,208,213,165,254,141,19,145,169,128,141
570 data34,145,208,210,196,251,240,20,132,251,200,173,20,3,133,245
580 data173,21,3,133,246,177,245,240,3,32,201,235,169,247,141,32
590 data145,169,255,141,34,145,76,191,234,169,255,133,251,208,237
,120
600 data169,-1,141,20,3,169,-2,141,21,3,169,255,133,251,88,96
I think the key pad needs to be scanned like the keyboard.
Rob
User avatar
Jeff-20
Denial Founder
Posts: 5761
Joined: Wed Dec 31, 1969 6:00 pm

Post by Jeff-20 »

Thanks! I am excited to try this!

Grrr. Why couldn't they do this in BASIC? Can anyone deconstruct this for me?
High Scores, Links, and Jeff's Basic Games page.
Leeeeee
soldering master
Posts: 396
Joined: Fri Apr 23, 2004 8:14 am

Post by Leeeeee »

Try this ..

Code: Select all

; touch pad controller code for VIC 20
;
; the controller is a matrix of switches and is connected to the VIC 20 as follows ..
;
;     joy 0 --> 1 2 3
;     joy 1 --> 4 5 6
;     joy 2 --> 7 8 9
;     joy 3 --> * 0 #
;               | | |
;     pot y <---+ | |
;     pot x <-----+ |
;     fire  <-------+
;
; The code works by sequentially making joy 0 to 3 output zero and reading pot y, pot x
; and fire


LAB_CB      = $CB             ; current row drive

LAB_F5      = $F5             ; keyboard matrix lookup table pointer low byte
LAB_F6      = $F6             ; keyboard matrix lookup table pointer high byte

LAB_FB      = $FB             ; last key number, $FF if no key pressed
LAB_FE      = $FE             ; temporary port direction mask

LAB_0314    = $0314           ; IRQ vector low byte
LAB_0315    = $0315           ; IRQ vector high byte

LAB_9008    = $9008           ; pot x
LAB_9009    = $9009           ; pot y

LAB_9111    = $9111           ; VIA 1 DRA
                              ; bit function
                              ; --- --------
                              ;  7  serial ATN out
                              ;  6  cassette switch
                              ;  5  LP     FIRE
                              ;  4  joy 2  LEFT
                              ;  3  joy 1  DOWN
                              ;  2  joy 0  UP
                              ;  1  serial DATA in
                              ;  0  serial CLK in
LAB_9113    = $9113           ; VIA 1 DDRA

LAB_9120    = $9120           ; VIA 2 DRB, keyboard column drive
                              ; bit function
                              ; --- --------
                              ;  7  joy 3  RIGHT
                              ; 6-0 keyboard column drive
LAB_9122    = $9122           ; VIA 2 DDRB

LAB_EABF    = $EABF           ; VIC IRQ handler
LAB_EBC9    = $EBC9           ; save the key in A to the keyboard buffer

; this code is loaded by the BASIC program to the 160 bytes at the top of memory. In this
; case the code has been assembled for an unexpanded VIC but it will work, with only two
; bytes changed in the setup routine, at other addresses.


      .ORG  $1D60

; our IRQ routine for the touchpad

LAB_1D60
      BEQ   LAB_1D6E          ; go do the code, branch always

; controller key definitions

;LAB_1D62
      .byte '7'               ;  S1 = 7
      .byte '8'               ;  S2 = 8
      .byte '9'               ;  S3 = 9
      .byte '4'               ;  S4 = 4
      .byte '5'               ;  S5 = 5
      .byte '6'               ;  S6 = 6
      .byte '1'               ;  S7 = 1
      .byte '2'               ;  S8 = 2
      .byte '3'               ;  S9 = 3
      .byte ','               ; S10 = ,
      .byte '0'               ; S11 = 0
      .byte $0D               ; S12 = [CR]

; touchpad IRQ code continues

LAB_1D6E
      LDY   #$01              ; set key 1

      LDA   #$C3              ; set mask xx00 00xx, fire button and joy pins
      AND   LAB_9111          ; mask VIA 1 DRA, clear the fire button and joy pins
      STA   LAB_9111          ; save VIA 1 DRA

      LDA   #$7F              ; set joy3 bit to input, others to output
      STA   LAB_9120          ; save VIA 2 DRB, joy 3 to zero
      STA   LAB_9122          ; set VIA 2 DDRB, joy 3 to input

      LDA   LAB_9113          ; read VIA 1 DDRA
      AND   #$C3              ; AND with mask xx00 00xx, fire button and joy pins to
                              ; inputs
      STA   LAB_FE            ; save the port direction mask

      LDX   #$03              ; set the row count
      LDA   #$02              ; set the row drive to the first row - 1
      STA   LAB_CB            ; save the row drive
LAB_1D8D
      ASL   LAB_CB            ; shift the row drive left
      LDA   LAB_CB            ; get the row drive
      ORA   LAB_FE            ; OR in the port direction mask
      STA   LAB_9113          ; save VIA 1 DDRA, set just one of the joy pins to output
LAB_1D96
      TYA                     ; save Y

; wait for a bit

      LDY   #$00              ; set for 256 loop delay
LAB_1D99
      DEY                     ; decrement delay count
      BNE   LAB_1D99          ; loop if more to do

      TAY                     ; restore Y

      LDA   #$80              ; set a half way value
      CMP   LAB_9009          ; compare the half way value with the pot y value
      BCC   LAB_1DC4          ; if the input is low go process it

      INY                     ; increment the key number

      CMP   LAB_9008          ; compare the half way value with the pot x value
      BCC   LAB_1DC4          ; if the input is low go process it

      INY                     ; increment the key number

      LDA   LAB_9111          ; read VIA 1 DRA
      AND   #$20              ; mask 00x0 0000, the fire button
      BEQ   LAB_1DC4          ; if the input is low go process it

      INY                     ; increment the key number

      DEX                     ; decrement the row count
      BMI   LAB_1DE9          ; if the count is negative no keys have been pressed so
                              ; clear the last key pressed, tidy up and exit

      BNE   LAB_1D8D          ; loop if not all of joy 0 to 2 done ..

; joy 0 to 2 done, now do joy 3

      LDA   LAB_FE            ; get the port direction mask
      STA   LAB_9113          ; save VIA 1 DDRA, joy 0 to 2 and fire to inputs
      LDA   #$80              ; set joy 3 to output, data bit already set to 0
      STA   LAB_9122          ; save VIA 2 DDRB
      BNE   LAB_1D96          ; go scan the last row, branch always

; a column is low

LAB_1DC4
      CPY   LAB_FB            ; compare the key number with the previous key number
      BEQ   LAB_1DDC          ; if the same just restore the keyboard ports and exit

      STY   LAB_FB            ; else save this key number as the last key number
      INY                     ; increment the key number for the table index
      LDA   LAB_0314          ; get the start of out code pointer low byte
      STA   LAB_F5            ; save the keyboard pointer low byte
      LDA   LAB_0315          ; get the start of out code pointer high byte
      STA   LAB_F6            ; save the keyboard pointer high byte
      LDA   (LAB_F5),Y        ; get the ASCII key code
      BEQ   LAB_1DDC          ; if null skip the key save

      JSR   LAB_EBC9          ; save the key in A to the keyboard buffer
LAB_1DDC
      LDA   #$F7              ; set keyboard column c3 for [RUN/STOP]
      STA   LAB_9120          ; save VIA 2 DRB, keyboard column drive
      LDA   #$FF              ; set all outputs
      STA   LAB_9122          ; save VIA 2 DDRB

      JMP   LAB_EABF          ; go do the normal VIC IRQ handler

LAB_1DE9
      LDA   #$FF              ; set A
      STA   LAB_FB            ; clear the last key number
      BNE   LAB_1DDC          ; restore the keyboard ports and go do the normal IRQ
                              ; routine, branch always

; setup the interrupt, called using SYS tm% + 143

LAB_1DEF
      SEI                     ; disable interrupts
      LDA   #>LAB_1D60        ; set our code start low byte
      STA   LAB_0314          ; save the IRQ vector low byte
      LDA   #<LAB_1D60        ; set our code start high byte
      STA   LAB_0315          ; save the IRQ vector high byte
      LDA   #$FF              ; set A
      STA   LAB_FB            ; clear the last key number
      CLI                     ; enable interrupts
      RTS

;; changing the above code as follows would make it able to be run from any address
;; without needing changes as the end of memory pointer contains the address needed
;
;; setup the interrupt, called using SYS tm% + 143
;
;LAB_37     = $37             ; end of memory low byte
;LAB_38     = $38             ; end of memory high byte
;
;LAB_1DEF
;      SEI                    ; disable interrupts
;      LDA   LAB_37           ; get the end of memory low byte
;      STA   LAB_0314         ; save the IRQ vector low byte
;      LDA   LAB_38           ; get the end of memory high byte
;      STA   LAB_0315         ; save the IRQ vector high byte
;      LDA   #$FF             ; set A
;      STA   LAB_FB           ; clear the last key number
;      CLI                    ; enable interrupts
;      RTS

      .END
Lee.
User avatar
Jeff-20
Denial Founder
Posts: 5761
Joined: Wed Dec 31, 1969 6:00 pm

Post by Jeff-20 »

Thanks for the explication! This is all so confusing. Especially without good knowledge of machine language. I set 37154 to 127. But after that it seems like timing is everything! Am I misunderstanding?
High Scores, Links, and Jeff's Basic Games page.
User avatar
buzbard
Vic 20 Devotee
Posts: 213
Joined: Sun Jul 03, 2005 9:10 am

Post by buzbard »

@Leeeeee
Nice program!
Slight change though, this:

Code: Select all

LAB_1DEF
      SEI                     ; disable interrupts
      LDA   #>LAB_1D60        ; set our code start low byte
      STA   LAB_0314          ; save the IRQ vector low byte
      LDA   #<LAB_1D60        ; set our code start high byte
      STA   LAB_0315          ; save the IRQ vector high byte
      LDA   #$FF              ; set A
      STA   LAB_FB            ; clear the last key number
      CLI                     ; enable interrupts
      RTS 
should be:

Code: Select all

LAB_1DEF
      SEI                     ; disable interrupts
      LDA   #<LAB_1D60        ; set our code start low byte
      STA   LAB_0314          ; save the IRQ vector low byte
      LDA   #>LAB_1D60        ; set our code start high byte
      STA   LAB_0315          ; save the IRQ vector high byte
      LDA   #$FF              ; set A
      STA   LAB_FB            ; clear the last key number
      CLI                     ; enable interrupts
      RTS 
< = low byte
> = hi byte
Leeeeee
soldering master
Posts: 396
Joined: Fri Apr 23, 2004 8:14 am

Post by Leeeeee »

< = low byte
> = hi byte
That depends entirely on the assembler.

Lee.
User avatar
Jeff-20
Denial Founder
Posts: 5761
Joined: Wed Dec 31, 1969 6:00 pm

Post by Jeff-20 »

Help! Can someone turn this Machine Code into BASIC, so that I can understand it?????
High Scores, Links, and Jeff's Basic Games page.
ravenxau
Vic 20 Devotee
Posts: 296
Joined: Fri May 28, 2004 10:03 pm

Post by ravenxau »

Jeff-20 wrote:Help! Can someone turn this Machine Code into BASIC, so that I can understand it?????
Jeff, Your Basic programming skills are awesome - mabey it is time to 'Dip your toe' in the waters of ML. It's not that scary, just take your time and absorb everything before moving on. Usborne's Machine Code for Beginners (pdf is available at worldofspectrum) is a great place to start. It has simple examples that are designed so a programmer aged 12 can understand. Even if you don't end up writing any ML code, it's good to be able to de-cypher other programmers work to learn new tricks and techniques :)
Android Tablet running Frodo 64 emulator running VIC 20 emulator....
User avatar
Jeff-20
Denial Founder
Posts: 5761
Joined: Wed Dec 31, 1969 6:00 pm

Post by Jeff-20 »

I know. I have plenty of ML resources from which to learn. I just haven't had the time. This program even has a sideline explication, but I can't get it to work in BASIC. I was hoping for a hint or something.
High Scores, Links, and Jeff's Basic Games page.
User avatar
Mike
Herr VC
Posts: 4901
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

The ML routine runs in the interrupt, and accesses the same VIA ports which are also used to scan the normal keyboard.

Even if you do a 1:1 translation of the machine code to BASIC, it can't be run as an interrupt routine, only in the "foreground" (i.e. within the main program). Furthermore, exactly the keyscan routine in the IRQ will disturb a BASIC translation of the touch pad decode routine, as both access the same VIA registers, unless you disable interrupts - and then neither jiffy clock nor keyboard will work anymore.

Isn't it acceptable for you to use a working solution, just because it isn't written in BASIC?

Finally, as for an explanation of how it works, Lee did it in the last line of the introductory comments of the ML source code:

Code: Select all

; touch pad controller code for VIC 20 
; 
; the controller is a matrix of switches and is connected to the VIC 20 as follows .. 
; 
;     joy 0 --> 1 2 3 
;     joy 1 --> 4 5 6 
;     joy 2 --> 7 8 9 
;     joy 3 --> * 0 # 
;               | | | 
;     pot y <---+ | | 
;     pot x <-----+ | 
;     fire  <-------+ 
Leeeeee wrote:The code works by sequentially making joy 0 to 3 output zero and reading pot y, pot x and fire
User avatar
Jeff-20
Denial Founder
Posts: 5761
Joined: Wed Dec 31, 1969 6:00 pm

Post by Jeff-20 »

Now I see! This can't really be done in BASIC alone. Thanks for explaining. I would have to SYS a routine. I was running the BASIC code above, and nothing was happening. How would I get the input information from this routine to use in a BASIC program? To put it simple, I'm not sure how to interface.
High Scores, Links, and Jeff's Basic Games page.
Post Reply