Skip to main content
Home▸ Forums▸ 68kMLA▸ Skunkworks PS-2 <-> ADB Project — #21
Post #21 by techknight
Source Forum68kMLA
CategoryPeripherals
Post DateThu, 29 Mar 2012 - 03:41
Original URLhttps://68kmla.org/bb/threads/skunkworks-ps-2-lt-gt-adb-project.25038/
Post
eh, have a looksee anyway.

Might be useful, then again, it might not be. but its published now for your eyes to see.

Alot of this could be optimized and cleaned up, such as the 2 dedicated I/O pins for active pulldowns really arnt necessary, but it was my first attempt at working a protocol, and it works. lol.

Remember now, the original intent which was never finished, was using a PS/2 based mouse on a Mac 128/512/Plus so it was provisioned to emulate the square wave encoder signals but i never got that far, so debugging routines are in there, for example LEDs are used to indicate the mouse movement, and positioning information.

Code:
' *
' * Title         : PS2.bas
' * Version       : 1.0
' * Target        : ATTiny2313
' * Author        : techknight
' * Program code  : BASCOM AVR
' * Hardware req. :
' * Description   : IBM PS/2 Mouse to Macintosh Bus Mouse translator
' * TODO          : Timeouts need added into PS/2 routines to prevent hangs
' *
' ***************************************************************************
'$regfile = "attiny2313.dat"                                 ' use the Tiny2313
$regfile = "2313def.dat"
$crystal = 18432000                                         ' at 18.432mhz


'Configure the data direction registers for port D
'PD0 PS2 Data
'PD1 PS2 Clock
'PD2 PS2 Data PullDown NPN Transistor
'PD3 PS2 Clock Pulldown NPN Transistor

'PB0 Y interrupt
'PB1 Y direction
'PB2 X interrupt
'PB3 X direction
'PB4 Mouse Button 1

Disable Interrupts

Config Portd = Output
Config Portd.0 = Input
Config Portd.1 = Input
Config Portb = Output

Portd = 0                                                   'turn all internal pullups OFF and outputs to 0
Portb = 0
Portd.3 = 1                                                 'inhibit communication between any PS/2 device

Dim Temp As Byte
Dim Temp2 As Byte
Dim Count As Byte
Dim Index As Byte
Dim I As Byte
Dim Ps2 As Byte
Dim Parity As Byte
Dim Status As Byte
Dim Movex As Byte
Dim Movey As Byte
Dim Button As Byte

'PS2 data send/receive routines

Declare Sub Sendps2(byval A As Byte)
Declare Sub Recps2
Declare Sub Initmouse



'Main Loop
Call Initmouse

Do
Call Recps2
Status = Ps2
Call Recps2
Movex = Ps2
Call Recps2
Movey = Ps2

'Set mouse button
Portb.4 = Status.0
                                                            'Mouse has moved down
If Status.5 = 1 Then
  Portb.1 = 1
End If
If Status.4 = 1 Then                                        'mouse has moved left
  Portb.3 = 1
End If
If Movex > 0 And Movex < &H7F Then                          'mouse has moved right
  Portb.2 = 1
End If
If Movey > 0 And Movey < &H7F Then                          'mouse has moved up
  Portb.0 = 1
End If
If Status.7 = 1 Then
  Portb.0 = 1
End If
If Status.6 = 1 Then
  Portb.2 = 1
End If
Waitms 5
Portb = 0

'DEBUGGING ROUTINE... Flash out byte PS2 and HALT
'I = 0
'For I = 7 To 0 Step - 1
'Portb.1 = 1
'Portb.0 = Status.i
'Wait 1
'Portb.1 = 0
'Wait 1
'Next




Loop









'This subroutine prepares the PS/2 Slave device for a data transmission from the AVR Host...
'data byte in A is written to the slave device
Sub Sendps2(byval A As Byte)
Parity = 0
I = 0
Ps2 = 0
Count = 0
Temp2 = A

Portd.3 = 1                                                 'pull clock low, inhibit communication
Waitus 100                                                  'wait 100 microseconds
Portd.2 = 1                                                 'pull the data line low
                                                           'Request to Send

Portd.3 = 0                                                 'Release the clock line

Do
Loop Until Pind.1 = 1                                       'wait high/low transistion. data valid only on low transition
Do
Loop Until Pind.1 = 0


Do
  Shift Temp2 , Right
  Temp = Sreg And 1
  If Temp = 1 Then
     Portd.2 = 0                                           'Release data line, pulls high
     Parity = Parity + 1
  Else
     Portd.2 = 1                                           'pull data low
  End If

  Do
  Loop Until Pind.1 = 1                                    'wait high/low transistion. data valid only on low transition
  Do
  Loop Until Pind.1 = 0

  I = I + 1
Loop Until I = 8


  If Parity.0 = 0 Then
     Portd.2 = 0                                           'if even parity, set data line high by turning off pulldown
  Else
     Portd.2 = 1                                           'otherwise its odd parity so set data line low turning on pulldown
  End If

  Do
  Loop Until Pind.1 = 1                                    'wait high/low transistion. data valid only on low transition
  Do
  Loop Until Pind.1 = 0

  Portd.2 = 0                                              'release the data line

  Do
  Loop Until Pind.1 = 1                                    'wait high/low transistion. data valid only on low transition
  Do
  Loop Until Pind.1 = 0


  If Pind.0 = 1 Then                                       'If no ACK received, then we try it again 3 times
     Portd.3 = 1                                           'inhibit communication and try resending again.
     Goto Sendps2
     Count = Count + 1
     If Count = 3 Then
        Ps2 = &HFF
        Exit Sub
     End If
  End If

  Do
  Loop Until Pind.1 = 1                                    'wait for clock to go idle high

  Waitus 50
  Portd.3 = 1                                              'Inhibit communications after transmission

End Sub




'This subroutine recieves back any data that the PS/2 slave device may have in its buffer.
'Data and Clock lines get set to idle state and listen for any responses from the device
'Received data byte stored into variable PS2
Sub Recps2
Parity = 0
I = 0
Ps2 = 0

Portd.3 = 0                                                 'release the clock and data line to idle = high
Portd.2 = 0                                                 'Ready to Receive

Do
Loop Until Pind.1 = 0                                       'wait until clock transistion low

If Pind.2 = 1 Then Goto Recps2                              'if data high, false start bit received, re-call routine


'Read in 8 data bits
Do

  Rotate Ps2 , Right , 1                                   'Rotate the data bits by 1

  Do
  Loop Until Pind.1 = 1                                    'wait high/low transistion. data valid only on low transition
  Do
  Loop Until Pind.1 = 0

  If Pind.0 = 1 Then
     Set Ps2.7
     Parity = Parity + 1
  Else
     Reset Ps2.7
  End If

  I = I + 1

Loop Until I = 9                                            '0 is a state in this sense.

Do
Loop Until Pind.1 = 1                                       'wait high/low transistion. data valid only on low transition
Do
Loop Until Pind.1 = 0

'parity bit is 0 on an odd number of 1's
'parity bit is 1 on an even number of 1's
'So, we test on the condition of bad parity.
'so if we had 3 1's, and parity bit is 1, packet is BAD.
'or vice-versa, even number of 1's and 0 parity bit.
'otherwise, packet recieved properly
If Parity.0 = 1 And Pind.0 = 1 Then
  Portd.3 = 1                                              'inhibit communication forcing clock low
  Call Sendps2(&Hfe)                                       'Call for Resend on bad parity and try again
  Goto Recps2
Elseif Parity.0 = 0 And Pind.0 = 0 Then
  Portd.3 = 1
  Call Sendps2(&Hfe)
  Goto Recps2
End If

Do
Loop Until Pind.1 = 1                                       'wait high/low transistion. data valid only on low transition
Do
Loop Until Pind.1 = 0

If Pind.0 = 0 Then                                          'stop bit is logical 1, if 0 then bad transmission try again..
  Portd.3 = 1
  Call Sendps2(&Hfe)
  Goto Recps2
End If

'otherwise, if we pass all this crap above, then yay the PS/2 packet was received properly.

Portd.3 = 1                                                 'Transmission recieved, inhibit communication to allow time for processing

End Sub





'This subroutine initializes a PS/2 mouse and puts it into data reporting mode.
'When in data reporting mode, any movment or action from the mouse, it will transmitt bytes
'back to host when lines are idle (logic high), otherwise it buffers until overflow, or lines release
Sub Initmouse
Index = 0
Ps2 = 0

Do
  Call Sendps2(&Hff)                                       'Reset the mouse
  Call Recps2                                              'Receive the ACK
  If Ps2 = &HFA Then                                       'is ACK ok?
     Call Recps2
     If Ps2 = &HAA Then                                    'Self test passed?
        Call Recps2
        If Ps2 = &H00 Then                                 'is PS/2 device a valid mouse?
           Call Sendps2(&Hf4)                              'Enable data reporting streaming (sends data on mouse movement or action)
           Call Recps2
           If Ps2 = &HFA Then                              'did mouse ACK the sent command?
              Ps2 = 0
              Exit Sub                                     'mouse initiliazation passed
           End If
        End If
     End If
  End If

  Index = Index + 1
Loop Until Index = 3

Ps2 = &HFF                                                  'mouse initialization failed

End Sub