Hi Nathan, I looked at that one as well and was tempted, because it had the additional channels and probably more advanced. I also considered:
securedwithssl.com/HobbyLab-us/product/15ce6b41-1ad9-41d8-85f2-26c8587ed712.aspx, but I have not seen any reviews of it to know how well it works.
Also looked at:pctestinstruments.com/ that has 34 channels for $389 and appeared to be liked by the guy at Nearfuture…
But in the end I chose the cheap KISS product. The good news is it should be delivered to my mailbox location today, so hopefully I will time to pick it up today (9 miles away) and play with it.
In the mean time I have been playing with the code and have it partially limping along. I am using the LEDS to help me know if I am getting timeouts. I also added a short delay between each packets going out to the controller and last night I was able to get it to configure it properly into the right mode without receiving any timeouts. For the fun of it I then put in a logitech controller in to see if it would work, it didn’t. I did receive timeout of the ACK on the third configuration packet in the packet header. Now I need to add the code that when it errors like this to retry so many times… But before I do that I need to clean up the code some as I am using/trashing too many of the registers which makes it hard to change and maintain the code. I should probably figure out a proper parameter passing scheme and use temporary stack variables internal to some of my internal functions. But in case anyone would like to see the current code that I am a not proud of:
[code];Project Lynxmotion PS2 Test program
;Hardware setup: ABB2 with ATOM 28 Pro, SSC32 V2, PS2 remote (See further for connections)
;
;NEW IN V1.3
; - Changed controls L1+ right stick
; - Balance calculations Thanks to KÃ¥re Halvorsen (aka Zenta)
;
;
;====================================================================
;[CONSTANDS]
TRUE con 1
FALSE con 0
BUTTON_DOWN con 0
BUTTON_UP con 1
;--------------------------------------------------------------------
;[SERIAL CONNECTIONS]
SSC_LM_SETUP con 1 ;Changes the SSC pins corresponding to the setup
;1 = Setup with connector to the front
;0 = Setup with connector to the back
SSC_OUT con P11 ;Output pin for (SSC32 RX) on BotBoard (Yellow)
SSC_IN con P10 ;Input pin for (SSC32 TX) on BotBoard (Blue)
SSC_BAUTE con i38400 ;SSC32 Baute rate
;--------------------------------------------------------------------
;[PS2 Controller]
PS2DAT con P12 ;PS2 Controller DAT (Brown)
PS2CMD con P13 ;PS2 controller CMD (Orange)
PS2SEL con P14 ;PS2 Controller SEL (Blue)
PS2CLK con P15 ;PS2 Controller CLK (White)
PadMode con $79
PS2ACK con P8 ;PS2 Controller try to work with ACK (Violet)
;--------------------------------------------------------------------
;--------------------------------------------------------------------
;--------------------------------------------------------------------
;[INPUTS]1
butA var bit
butB var bit
butC var bit
prev_butA var bit
prev_butB var bit
prev_butC var bit
;--------------------------------------------------------------------
;[OUTPUTS]
LedA var bit ;Red
LedB var bit ;Green
LedC var bit ;Orange
;--------------------------------------------------------------------
;[VARIABLES]
;--------------------------------------------------------------------
;[Ps2 Controller]
DualShock var Byte(70) ; Made much bigger to debug with return of init stuff…
PS2InitSent var byte
Ps2Save var Byte(9)
i var byte
j var byte
fChanged var byte
LastButton var Byte(2)
PS2Index var byte
BodyYShift var sbyte
_PS2InCnt var byte ; internal to PS2 function
_PS2OutCnt var byte ; internal to PS2 function
_PS2PDR var WORD ;PS2 Contoller (DAT/CMD/SEL/CLK) pins should all be on same PDR
_PS2DATPIN var byte ;PS2 Controller DAT (Brown)
_PS2CMDPIN var byte ;PS2 controller CMD (Orange)
_PS2SELPIN var byte ;PS2 Controller SEL (Blue)
_PS2CLKPIN var byte ;PS2 Controller CLK (White)
_PS2ACKPDR var word ;PS2 controller ACK pin may be on different PDR
_PS2ACKPIN var byte ;PS2 controller ACK (violet)
;--------------------------------------------------------------------
;[GLOABAL]
;====================================================================
;[INIT]
;Turning off all the leds
sound 9,[50\3960]
LedA = 0
LedB = 0
LedC = 0
;PS2 controller
gosub PS2Init
high p4
high p5
high p6
;SSC
;====================================================================
;[MAIN]
main:
;Read input
GOSUB Ps2Input
fChanged = 0
for i = 0 to 6
if DualShock(i) <> ps2Save(i) then
fChanged = 1
Ps2Save(i) = DualShock(i)
endif
next
; if fChanged <> 0 then
serout S_OUT, i9600, [dec _PS2INCnt,":",hex DualShock(0)\2, hex DualShock(1)\2, hex DualShock(2)\2, hex DualShock(3)\2, |
hex DualShock(4)\2, hex DualShock(5)\2, hex DualSHock(6)\2, 13]
if ps2InitSent <> 0 then
serout S_OUT, i9600, “(”,dec ps2InitSent, “:”, dec _PS2Incnt,")", 13]
j = 7
for i = 0 to 4
serout S_OUT, i9600, [hex DualShock(j)\2, hex DualShock(j+1)\2, |
hex DualShock(j+2)\2, hex DualShock(j+3)\2, hex DualShock(j+4)\2, |
hex DualShock(j+5)\2,hex DualShock(j+6)\2, 13]
j = j + 7
next
serout S_OUT, i9600, [13]
endif
high p4
high p5
high p6
; endif
pause 500
goto main
;====================================================================
;--------------------------------------------------------------------------------------------------
PS2Init:
; First let the basic system know what we are using each of the pins for
input PS2DAT ; P12 (P84)
output PS2CMD ; P13 P85
output PS2SEL ; P14 P86
output PS2CLK ; P15 P87
input PS2ACK ; p8 P80 also P15
high PS2CLK
jsr _PS2INIT ; call the main ps2 init function
return
;---------------------------------------------------------------------------------------------------
; PS2Input - is a simple basic wrapper to assembly language for the assembly code
;
PS2Input:
Ps2InitSent = 0; ; did we have to send the init?
jsr _PS2INPUT:8
return
asm{
;======================================================================================================
;Macros from AcidTech
;======================================================================================================
.macro _ints_enable
bset #0,@SYSF:8
andc #0x7F,ccr
.endm
.macro _ints_disable
bclr #0,@SYSF:8
orc #0x80,ccr
.endm
.macro _ints_save_enable
andc #0x7F,ccr ;2
.endm
.macro _ints_save_disable
orc #0x80,ccr ;2
.endm
.macro _ints_restore
orc #0x80,ccr ;2 Disable ints
btst #0,@SYSF:8 ;6
beq .+4:8 ;4 If clear then dont enable ints
andc #0x7F,ccr ;2(14) Enable ints
.endm
.macro _ratedelay rate,offset
.ifdef _DEF20MHZ
delay = (20000000/\rate)
temp1 = 20000000/delay
temp2 = 20000000/(delay+1)
.else
delay = (16000000/\rate)
temp1 = 16000000/delay
temp2 = 16000000/(delay+1)
.endif
temp3 = \rate - temp1
temp4 = \rate - temp2
.if temp3 < 0
temp3 = temp3 * -1
.endif
.if temp4 < 0
temp4 = temp4 * -1
.endif
.if temp4 < temp3
delay = delay + 1
.endif
delay = delay - \offset
.if delay >= 4
delay = delay - 6
count = delay / 8
mov.l #count,er4 ;6
.if count > 0
nop ;2
dec.l #1,er4 ;2
bne .-4:8 ;4(8 clks)
.endif
.endif
rem = delay % 8
.if rem == 1
nop ;2
.endif
.if rem == 2
nop ;2
.endif
.if rem == 3
mov.b #TCRV0,r4l ;3
.endif
.if rem == 4
nop ;2
nop ;2(4)
.endif
.if rem == 5
mov.b #TCRV0,r4l ;3
nop ;2(5)
.endif
.if rem == 6
nop ;2
nop ;2
nop ;2(6)
.endif
.if rem == 7
mov.b #TCRV0,r4l ;3
nop ;2
nop ;2(7)
.endif
.endm
.macro _cycledelay delay
tdelay = \delay
.if tdelay >= 6
tdelay = tdelay - 6
count = tdelay / 8
mov.l #count,er4 ;6
.if count > 0
nop ;2
dec.l #1,er4 ;2
bne .-4:8 ;4(8 clks)
.endif
.endif
rem = tdelay % 8
.if rem == 1
nop ;2
.endif
.if rem == 2
nop ;2
.endif
.if rem == 3
mov.b #TCRV0,r4l ;3
.endif
.if rem == 4
nop ;2
nop ;2(4)
.endif
.if rem == 5
mov.b #TCRV0,r4l ;3
nop ;2(5)
.endif
.if rem == 6
nop ;2
nop ;2
nop ;2(6)
.endif
.if rem == 7
mov.b #TCRV0,r4l ;3
nop ;2
nop ;2(7)
.endif
.endm
.macro _usdelay delay,offset
.ifdef _DEF20MHZ
tdelay = (\delay * 20)-\offset
.else
tdelay = (\delay * 16)-\offset
.endif
.if tdelay >= 6
tdelay = tdelay - 6
count = tdelay / 8
mov.l #count,er4 ;6
.if count > 0
nop ;2
dec.l #1,er4 ;2
bne .-4:8 ;4(8 clks)
.endif
.endif
rem = tdelay % 8
.if rem == 1
nop ;2
.endif
.if rem == 2
nop ;2
.endif
.if rem == 3
mov.b #TCRV0,r4l ;3
.endif
.if rem == 4
nop ;2
nop ;2(4)
.endif
.if rem == 5
mov.b #TCRV0,r4l ;3
nop ;2(5)
.endif
.if rem == 6
nop ;2
nop ;2
nop ;2(6)
.endif
.if rem == 7
mov.b #TCRV0,r4l ;3
nop ;2
nop ;2(7)
.endif
.endm
.macro _msdelay delay,offset
.ifdef _DEF20MHZ
tdelay = (\delay * 20000)-\offset
.else
tdelay = (\delay * 16000)-\offset
.endif
.if tdelay >= 6
tdelay = tdelay - 6
count = tdelay / 8
mov.l #count,er4 ;6
.if tdelay >= 8
nop ;2
dec.l #1,er4 ;2
bne .-4:8 ;4(8 clks)
.endif
.endif
rem = tdelay % 8
.if rem == 1
nop ;2
.endif
.if rem == 2
nop ;2
.endif
.if rem == 3
mov.b #TCRV0,r4l ;3
.endif
.if rem == 4
nop ;2
nop ;2(4)
.endif
.if rem == 5
mov.b #TCRV0,r4l ;3
nop ;2(5)
.endif
.if rem == 6
nop ;2
nop ;2
nop ;2(6)
.endif
.if rem == 7
mov.b #TCRV0,r4l ;3
nop ;2
nop ;2(7)
.endif
.endm
;********************************
; Getpin
;********************************
;R0L = Pin number
;********************************
;ER1 = WORK
;R2 = PORT
;R3L = BIT
;********************************
.macro _GETPINMAC
;.equ _DEFGETPIN,0
;One table GETPIN macro ;(18)
and.w #0x3F,r0 ;4
shll.l er0 ;2
mov.w @(_PORTTABLE:16,er0),r2 ;6
shlr.l er0 ;2 Restore pin number
mov.b r2h,r3l ;2
mov.b #0xFF,r2h ;2
.endm
;********************************
; GetDirMac
;********************************
;R0L = Pin number
;********************************
.macro _GETDIRMAC ;(14)
xor.b r1h,r1h ;2 Clear Mask
bset r3l,r1h ;2 Set Mask
mov.b @(0x70-0xD0,er2),r1l ;6 Get PCRS value
and.b r1h,r1l ;2 Isolate BIT
add.b #0xFF,r1l ;2 Move to CARRY
.endm
;********************************
; SetDirMac
;********************************
;R0L = Pin number
;********************************
.macro _SETDIRMAC ;(30)
mov.b @(0x70-0xD0,er2),r1l ;6 Get PCRS value
bcs .+4:8 ;4
bclr r3l,r1l ;2 Clear PCR bit
bcc .+4:8 ;4
bset r3l,r1l ;2 Set PCR bit
mov.b r1l,@(0x70-0xD0,er2) ;6 Save PCRS
mov.b r1l,@(0x10,er2) ;6 Set PCR
.endm
;********************************
; GetStateMac
;********************************
;R0L = Pin number
;********************************
.macro _GETSTATEMAC ;(12)
xor.b r1h,r1h ;2 Clear Mask
bset r3l,r1h ;2 Set Mask
mov.b @er2,r1l ;4 Get PORT
and.b r1h,r1l ;2 Isolate BIT
add.b #0xFF,r1l ;2 Move to CARRY
.endm
;********************************
; SetStateMac
;********************************
;R0L = Pin number
;********************************
.macro _SETSTATEMAC ;(24 ?? 16)
bcc .+6:8 ;4
bset r3l,@er2 ;8
bcs .+6:8 ;4
bclr r3l,@er2 ;8
.endm
;********************************
; HighFuncMac
;********************************
;R0L = Pin number
;********************************
.macro _HIGHFUNCMAC ;(46)
_GETPINMAC ;18
bset r3l,@er2 ;8 Set PDR bit
mov.b @(0x70-0xD0,er2),r1l ;6 Get PCRS value
bset r3l,r1l ;2 Set PCR bit
mov.b r1l,@(0x70-0xD0,er2) ;6 Save PCRS
mov.b r1l,@(0x10,er2) ;6 Set PCR
.endm
;********************************
; HighFastFuncMac
;********************************
;R0L = Pin number
;********************************
.macro _HIGHFASTFUNCMAC ;(26)
_GETPINMAC ;18
bset r3l,@er2 ;8
.endm
;********************************
; LowFuncMac
;********************************
;R0L = Pin number
;********************************
.macro _LOWFUNCMAC ;(46)
_GETPINMAC ;18
bclr r3l,@er2 ;8 Set PDR bit
mov.b @(0x70-0xD0,er2),r1l ;6 Get PCRS value
bset r3l,r1l ;2 Set PCR bit
mov.b r1l,@(0x70-0xD0,er2) ;6 Save PCRS
mov.b r1l,@(0x10,er2) ;6 Set PCR
.endm
;********************************
; LowFastFuncMac
;********************************
;R0L = Pin number
;********************************
.macro _LOWFASTFUNCMAC ;(26)
_GETPINMAC ;18
bclr r3l,@er2 ;8
.endm
;********************************
; ToggleFuncMac
;********************************
;R0L = Pin number
;********************************
.macro _TOGGLEFUNCMAC ;(46)
_GETPINMAC ;18
bnot r3l,@er2 ;8
mov.b @(0x70-0xD0,er2),r1l ;6 Get PCRS value
bset r3l,r1l ;2 Set PCR bit
mov.b r1l,@(0x70-0xD0,er2) ;6 Save PCRS
mov.b r1l,@(0x10,er2) ;6 Set PCR
.endm
;********************************
; ToggleFastFuncMac
;********************************
;R0L = Pin number
;********************************
.macro _TOGGLEFASTFUNCMAC ;(26)
_GETPINMAC ;18
bnot r3l,@er2 ;8
.endm
;********************************
; InputFuncMac
;********************************
;R0L = Pin number
;********************************
.macro _INPUTFUNCMAC ;(38)
_GETPINMAC ;18
mov.b @(0x70-0xD0,er2),r1l ;6 Get PCRS value
bclr r3l,r1l ;2 Clear PCR bit
mov.b r1l,@(0x70-0xD0,er2) ;6 Save PCRS
mov.b r1l,@(0x10,er2) ;6 Set PCR
.endm
;********************************
; OutputFuncMac
;********************************
;R0L = Pin number
;********************************
.macro _OUTPUTFUNCMAC ;(38)
_GETPINMAC ;18
mov.b @(0x70-0xD0,er2),r1l ;6 Get PCRS value
bset r3l,r1l ;2 Set PCR bit
mov.b r1l,@(0x70-0xD0,er2) ;6 Save PCRS
mov.b r1l,@(0x10,er2) ;6 Set PCR
.endm
;********************************
; ReverseFuncMac
;********************************
;R0L = Pin number
;********************************
.macro _REVERSEFUNCMAC ;(38)
_GETPINMAC ;18
mov.b @(0x70-0xD0,er2),r1l ;6 Get PCRS value
bnot r3l,r1l ;2 Toggle PCR bit
mov.b r1l,@(0x70-0xD0,er2) ;6 Save PCRS
mov.b r1l,@(0x10,er2) ;6 Set PCR
.endm
;********************************
; InputStaicMac
;********************************
;R0L = Pin number
;********************************
.macro _INPUTSTATICMAC pin ;(20)
mov.b @0x70-0xD0+(\pin&0xFF):8,r1l ;6 Get PCRS value
bclr #(\pin>>8),r1l ;2 Clear PCR bit
mov.b r1l,@0x70-0xD0+(\pin&0xFF):8 ;6 Save PCRS
mov.b r1l,@0x10+(\pin&0xFF):8 ;6 Set PCR
.endm
;********************************
; OutputStaticMac
;********************************
;R0L = Pin number
;********************************
.macro _OUTPUTSTATICMAC pin ;(20)
mov.b @0x70-0xD0+(\pin&0xFF):8,r1l ;6 Get PCRS value
bset #(\pin>>8),r1l ;2 Set PCR bit
mov.b r1l,@0x70-0xD0+(\pin&0xFF):8 ;6 Save PCRS
mov.b r1l,@0x10+(\pin&0xFF):8 ;6 Set PCR
.endm
;********************************
; ReverseStaticMac
;********************************
;R0L = Pin number
;********************************
.macro _REVERSESTATICMAC pin ;(20)
mov.b @0x70-0xD0+(\pin&0xFF):8,r1l ;6 Get PCRS value
bnot #(\pin>>8),r1l ;2 Reverse PCR bit
mov.b r1l,@0x70-0xD0+(\pin&0xFF):8 ;6 Save PCRS
mov.b r1l,@0x10+(\pin&0xFF):8 ;6 Set PCR
.endm
;=======================================================================================
; End of macros
;=======================================================================================
;=======================================================================================
; PS2 Init Assembly Function
; We will initialize the port pins here once as well as we will map the BAP pins to
; the H8 port and pin number to use in the main PS2 input function.
;=======================================================================================
_PS2INIT:
; Ok first let map all of our pins to the state we want…
mov.l #PCRS8, er2 ; try to init the ER2 register to use the shadow register locations
mov.b #PS2DAT, r0l
_INPUTFUNCMAC
mov.w r2, @_PS2PDR ; save away the PDR for later
mov.b r3l,@_PS2DATPIN
mov.b #PS2CMD, r0l
_OUTPUTFUNCMAC
mov.b r3l,@_PS2CMDPIN
mov.b #PS2CLK, r0l
_OUTPUTFUNCMAC
mov.b r3l,@_PS2CLKPIN
mov.b #PS2SEL, r0l
_OUTPUTFUNCMAC
mov.b r3l,@_PS2SELPIN
mov.b #PS2ACK, r0l
_INPUTFUNCMAC
mov.w r2,@_PS2ACKPDR ; ack may easily be on different Data register...
mov.b r3l,@_PS2ACKPIN
; BUGBUG - Hack to know that our ACK pin as also on P15 which has pull-up...
bclr.b #5,@PMR1:8;
bclr.b #5,@PCR1:8 ; note BAP P8 has two 3694 pins connected P80 and P15. P15 has pull-up
bset.b #5,@PUCR1:8 ; So try to use it pull up the ACK line without having to add external pull-up
rts
;=======================================================================================
; Main PS2 Input assembly function
;=======================================================================================
_PS2INPUT:
; now lets try a simple query
mov.b #6, r1l ; length of return buffer.
mov.l #_PS2QCMD,er4 ; point to the standard output command table
mov.l #DUALSHOCK, er5 ; point to where we want the output to go
; Now lets do the input and output of the command
jsr PS2_INPUT_OUTPUT_CMD
mov.b #0, r1h
mov.b @_PS2INCNT, r1l
bne _PS2_TIMEOUT:16
mov.b @DUALSHOCK,r1l
cmp.b #0x79,r1l ; see if we are in the correct mode.
beq _PS2_END:16 ; yes so go to the end
; Let our caller know that we had to output some init strings...
mov.b #1, r1l
mov.b r1l,@PS2INITSENT
; not in the right mode, so now lets output our init strings.
; hopefully the ACK processing will pace it correctly
_usdelay 100, 0
mov.l #_PS2I1, er4
mov.l #DUALSHOCK+7, er5 ; point to where we want the output to go
mov.b #6, r1l ; length of return buffer.
jsr PS2_INPUT_OUTPUT_CMD
mov.b #1, r1h
mov.b @_PS2INCNT, r1l
bne _PS2_TIMEOUT:16
_usdelay 100, 0
mov.l #_PS2I2, er4
mov.l #DUALSHOCK+14, er5 ; point to where we want the output to go
mov.b #6, r1l ; length of return buffer.
jsr PS2_INPUT_OUTPUT_CMD
mov.b #2, r1h
mov.b @_PS2INCNT, r1l
bne _PS2_TIMEOUT:16
_usdelay 100, 0
mov.l #_PS2I3, er4
mov.l #DUALSHOCK+21, er5 ; point to where we want the output to go
mov.b #6, r1l ; length of return buffer.
jsr PS2_INPUT_OUTPUT_CMD
mov.b #3, r1h
mov.b @_PS2INCNT, r1l
bne _PS2_TIMEOUT:8
_usdelay 100, 0
mov.l #_PS2I4, er4
mov.l #DUALSHOCK+28, er5 ; point to where we want the output to go
mov.b #6, r1l ; length of return buffer.
jsr PS2_INPUT_OUTPUT_CMD
mov.b #4, r1h
mov.b @_PS2INCNT, r1l
bne _PS2_TIMEOUT:8
_usdelay 100, 0
mov.l #_PS2I5, er4
mov.l #DUALSHOCK+35, er5 ; point to where we want the output to go
mov.b #6, r1l ; length of return buffer.
jsr PS2_INPUT_OUTPUT_CMD
mov.b #5, r1h
mov.b @_PS2INCNT, r1l
bne _PS2_TIMEOUT:8
_PS2_END:
rts
_PS2_TIMEOUT:
mov.b r1h,@PS2INITSENT
rts
;=============================================================================================
; PS2_INPUT_OUTPUT_CMD: This function will do the standard input/output processing for a single
; command string. It will try to properly use the ACK line of the PS2 to
; to the proper pacing of the command. It will also look at the PS2 mode
; valuethat is returned as the second byte to update how many bytes that
; is returned.
; Input/Output Registers: (note all of these may be trashed…)
; r1l - Input - The number of bytes including Mode we wish to have returned -
; ER4 - (Input) The Command string with input/output size as first bytes
; ER5 - (Input) The location of where to save away the returned bytes.
; may be zero if we don’t wish to save…
; First byte returned will be mode, followed by the number of
; bytes the user asked for or less if the mode does not have that
; many bytes.
; Registers changed:
; r1 - scratch
; er2 - used to point to PDR register
; r3h - Used to hold the clock pin
; r3l - used to hold which PIN on the IO block some IO function (CMD/DAT…)
; e3 - bit counter.
; R6L - Byte to shift out using TXRX Byte
; R6H - The byte that TXRX returned
PS2_INPUT_OUTPUT_CMD:
mov.b r1l, @_PS2INCNT ; save away the requested number of bytes.
mov.b @er4+, r1l ; OK lets get the length of the cmd from the second byte
mov.b r1l, @_PS2OUTCNT ; how many bytes we want to output
; Now lets set the select to low
mov.b #PS2SEL, r0l ; set the pin we want to use
_LOWFASTFUNCMAC
; OK we wish to input and output the first 3 bytes which are considered
; the packet header.
mov.b @er4+, r6l ; get first byte of header
mov.b #1, r1l ; Yes wait for ACK
jsr PS2_TXRX_BYTE:16 ; Ok lets process the input and output of the byte...
; Don't care about return value should be 0xff
bcs _PS2_NO_ACK_ON_HEADER:16 ; we did not get an ack on the first byte...
mov.b @er4+, r6l ; Get Second byte of header
mov.b #1, r1l ; Yes wait for ACK
jsr PS2_TXRX_BYTE:16 ; Ok lets process the input and output of the byte...
;
bcs _PS2_NO_ACK_ON_HEADER:8 ; we did not get an ack...
cmp.l #0,er5 ; ok see if we wish to return info
beq _PS2_IOC_NORET_MODE:8
mov.b r6h,@er5 ; save the mode byte away
inc.l #1, er5 ; increment to point to next byte
_PS2_IOC_NORET_MODE:
and.b #0xf,r6h ; only use the low nibble of mode which is number of words of data past header
shal.b r6h ; convert to bytes
mov.b @_PS2INCNT, r6l ; get how many bytes we think we wish to process
cmp.b r6l,r6h ; compare (num bytes avail - num bytes wanted)
bcc _PS2_IOC_CNT_OK:8 ; ok looks good
mov.b r6h,@_PS2INCNT ; nope update to only return the valid number of bytes…
_PS2_IOC_CNT_OK:
mov.b @er4+, r6l ; get first byte of header
mov.b #1, r1l ; Yes wait for ACK
jsr PS2_TXRX_BYTE:16 ; Ok lets process the input and output of the byte…
; Don’t care about return value should be 0xff
bcs _PS2_NO_ACK_ON_HEADER:8 ; we did not get an ack…
; Ok we are done with the 3 byte header, lets setup to input/output the rest of the bytes...
_PS2_SETUP_NEXT_BYTE:
mov.b @_PS2OUTCNT, r1l
bne #_PS2_YES_MORE:8
xor r6l, r6l ; no more
bra #_PS2_C1:8
_PS2_YES_MORE:
mov.b @er4+, r6l ; get the next byte from the input string.
dec.b r1l ; decrement our count
mov.b r6l,@_PS2OUTCNT
_PS2_C1:
mov.b @_PS2INCNT, r1l ; We don’t expect an ack on the last byte
beq .+2:8 ; don’t decrement if we are zero already
dec.b r1l ; sets r1l to zero on last byte to say don’t look for ack
jsr PS2_TXRX_BYTE:16 ; Ok lets process the input and output of the byte...
bcs _PS2_NO_ACK_ON_DATA:8 ; we did not get an ack on the first byte...
cmp.l #0,er5 ; ok see if we wish to return info
beq _PS2_IOC_NORET_DATA:8
mov.b r6h,@er5 ; save the mode byte away
inc.l #1, er5 ; increment to point to next byte
; We do not look for ack if this is our last byte...
_PS2_IOC_NORET_DATA:
mov.b @_PS2INCNT, r1l ; lets get our input counter
beq _PS2_CHECK_OUT_COUNT:8
dec.b r1l ; decrement how many bytes we are going to input and if not zero go to process next byte
mov.b r1l, @_PS2INCNT ; save away the updated counter
bne _PS2_SETUP_NEXT_BYTE:16 ; and process the next byte
_PS2_CHECK_OUT_COUNT:
mov.b @_PS2OUTCNT, r1l ; make sure our output count is zero as well
bne _PS2_SETUP_NEXT_BYTE:16 ; and process the next byte
bra _PS2_IN_DONE:8
_PS2_NO_ACK_ON_HEADER:
bset.b #6, @PCR5:8 ; BUGBUG : debug
bclr.b #6,@PDR5:8 ; BUGBUG : debug
_PS2_NO_ACK_ON_DATA:
_PS2_IN_DONE:
mov.b #PS2SEL, r0l
_HIGHFASTFUNCMAC ; set it high
rts
; and return
;=============================================================================================
; PS2_TXRX_BYTE: This function will handle the internal processing for the PS2 code to
; transmit a byte on CMD and at the same type Receive it on DAT. The bytes are
; shifted in and out using a clock signal (CLK) This code works like a SPI except
; PS2 has another IO line ACK that the controller will ACK the receipt of most
; bytes. The code keeps the clock cycle consistent for both High and low…
; Input/Output Registers:
; r1l - (Input) should we wait for ack or not, will be trashed…
; R6L - (Input) The byte to shift out
; R6H - (Output) The byte that was shifted in
; Registers changed:
; r1 - scratch
; r2 - R2 is pointing to the PDR register that DAT/CMD/CLK/SEL is on
; r3h - Used to hold the clock pin
; r3l - used to hold which PIN on the IO block some IO function (CMD/DAT…)
; e3 - bit counter.
; return
; Carry false if OK
; Carry true if Timeout
PS2_TXRX_BYTE:
push.w r1 ; save away R1 so we can test if we should wait for timeouts R1l
xor.b r6h, r6h ; setup for the next byte
mov.w #8, e3 ; We need to do 8 bits.
; we assume that R2 is pointing to the PDR - IO data register for CLK/CMD/DAT/SEL when we get here...
mov.w @_PS2PDR, r2 ; Make sure the are pointing to the right IO Data register...
mov @_PS2CLKPIN:16, r3h ; (6)Setup the CLK pin to use use r3h as to only set once for the loop
_PS2_BIT_LOOP:
; +++++ CLOCK IS HIGH ++++++(32+14=46)
; map the CMD pin to the right port/pin and then store the next bit into it.
mov @_PS2CMDPIN:16, r3l ; (6)Setup the CMD pin to use
shlr.b r6l ; (2)ok shift our CMD bit into the carry
_SETSTATEMAC ; (16) use the carry to set the pin state
bclr r3h,@er2 ;8
; ----- CLOCK IS LOW ------(48)
mov.b #3,r1h ;2
nop ;2 (LOOP)
dec.b r1h ;2 (LOOP)
bne .-4:8 ;4(8 clks)
nop ;2
; we broke apart the get state macro such that we can part of it while clock is low
; and we have spare cylcles..
mov @_PS2DATPIN:16, r3l ; (6)Setup the CLK pin to use
xor.b r1h,r1h ;2 Clear Mask
bset r3l,r1h ;2 Set Mask
bset r3h,@er2 ;8 ; set the clock high again
; +++++ CLOCK IS HIGH ++++++
mov.b @er2,r1l ;4 Get PORT
and.b r1h,r1l ;2 Isolate BIT
add.b #0xFF,r1l ;2 Move to CARRY
rotxr.b r6h ; (2)
dec.w #1,e3 ; (2) decrement our bit loop counter
bne #_PS2_BIT_LOOP:8 ; (4) and go to the next bit if we have not done all of them
pop r1 ; restore r1 which has our flag to say if we whould wait for ack
add.b #0xff,r1l ; if it is non zero will set carry
bcc _PS2_TXRX_RET:8 ; Nope don't wait...
; yes we need to wait for an ack.
mov.b #PS2ACK, r0l ; setup to look for an ACK
_GETPINMAC
mov.w #0xffff,e3 ; lets have some form of counter so we can time out of waiting for ACK to happen...
_PS2_WAIT_FOR_ACK:
_GETSTATEMAC ; ok lets the the IO pin state
bcc #_PS2_HAVE_ACK:8
sub.w #1,e3 ; dont have ack, but lets try up to 65536 use sub not dec as sets carry…
bcc #_PS2_WAIT_FOR_ACK:8 ;
bset.b #5,@PCR5:8 ; BUGBUG: debug leaves carry…
bclr.b #5,@PDR5:8 ; BUGBUG: debug leaves carry
bra _PS2_TXRX_RET:8 ; we timed out without an ack
_PS2_HAVE_ACK:
bset.b #4, @PCR5:8 ; DEBUG - Carry left OK
bclr.b #4, @PDR5:8 ; DEBUG set an LED to show we received an ACK
_PS2_TXRX_RET:
rts ; and return
;=============================================================================================
; PS2 Command strings:
; first byte is length of the command - after the 3 byte header
_PS2QCMD:
.byte 0x0, 0x1, 0x42,0x0 ; 2 bytes in the command string… (changed to 3 to make code easier…
_PS2I1:
.byte 0x2, 0x1,0x43,0x0,0x1,0x0 ;CONFIG_MODE_ENTER
_PS2I2:
.byte 0x6, 0x01,0x44,0x00,0x01,0x03,0x00,0x00,0x00,0x00 ;SET_MODE_AND_LOCK
_PS2I3:
.byte 0x6, 0x01,0x4F,0x00,0xFF,0xFF,0x03,0x00,0x00,0x00 ;SET_PS2_NATIVE_MODE
_PS2I4:
.byte 0x6, 0x01,0x43,0x00,0x00,0x5A,0x5A,0x5A,0x5A,0x5A ;CONFIG_MODE_EXIT_PS2_NATIVE
_PS2I5:
.byte 0x6, 0x01,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ;CONFIG_MODE_EXIT
}
[/code]