Is there a way with programing a PS2 controler to use one of the buttons as a “Shift” key. Meaning for example if you hold down the R2 button and hit another button can you assign diffrent moves to the rest of the buttons. Ideally doubling the number of controls the PS2 controller can do? Another example: If I hit the forword button I want the robot to take steps forword, but if I hold the R2 button and hit the forword button it will move say the arm forword?
um, doesn’t the ps2 return individual bits for each button? it seems like this would be just a software function to interpret the status of the remaining bits based on the status of the one you designate as “shift”.
Yes you can certainly do it that way. You can read the status of the “shift” button first, and then route to a different subroutine when the next button is pressed.
Interesting thing about the PS2 controller. Did you know all of the buttons are pressure sensitive! The true blue Sony PS2 controller and our Lynxmotion brand have pressure sensitive buttons. They work by returning an 8 bit value proportional to how hard you press on the buttons. 8)
Hi Jim,
They are? I’m not seeing that in the return values (mode 73h analog).
This is what I currently get back:
[0x73, 0x5A, 0xFF, 0xFF, 0x80, 0x80, 0x80, 0x80]
No room in the “bits” for any more info that I can see. Is there a different mode, or a command that I’m unaware of? The buttons DO feel a little different, no simple “contact closure” feeling. Not sure what I’d do with the information at this point, but nice to know.
By the way, 73h is a “DualShock 1” mode. I recall seeing PadMode con $79 in H3R program #1 and AH3R program #1. Not the 73h I’m using with the Lynxmotion PS2 controller I’m using.
Do you have any more information on this?
Alan KM6VV
Here is the Atom Pro code I am using. It displays the pressure values in the debug window. I’m not a programming guru, so don’t ask me any questions about it.
[code]DAT con P12
CMD con P13
SEL con P14
CLK con P15
index var byte
temp var byte(19)
mode var byte
Small_Motor var byte
Large_Motor var byte
;PS2Init
high CLK
again
low SEL
shiftout CMD,CLK,FASTLSBPRE,$1\8,$43\8,$0\8,$1\8,$0\8] ;CONFIG_MODE_ENTER
high SEL
pause 1
low SEL
shiftout CMD,CLK,FASTLSBPRE,$01\8,$44\8,$00\8,$01\8,$03\8,$00\8,$00\8,$00\8,$00\8] ;SET_MODE_AND_LOCK
high SEL
pause 100
low SEL
shiftout CMD,CLK,FASTLSBPRE,$01\8,$4F\8,$00\8,$FF\8,$FF\8,$03\8,$00\8,$00\8,$00\8] ;SET_DS2_NATIVE_MODE
high SEL
pause 1
low SEL
shiftout CMD,CLK,FASTLSBPRE,$01\8,$4D\8,$00\8,$00\8,$01\8,$FF\8,$FF\8,$FF\8,$FF\8] ;VIBRATION_ENABLE
high SEL
pause 1
low SEL
shiftout CMD,CLK,FASTLSBPRE,$01\8,$43\8,$00\8,$00\8,$5A\8,$5A\8,$5A\8,$5A\8,$5A\8] ;CONFIG_MODE_EXIT_DS2_NATIVE
high SEL
pause 1
low SEL
shiftout CMD,CLK,FASTLSBPRE,$01\8,$43\8,$00\8,$00\8,$00\8,$00\8,$00\8,$00\8,$00\8] ;CONFIG_MODE_EXIT
high SEL
pause 1
main
;-----------PS2 Mode----------
low SEL
; asking “mode” to PS2 controller
shiftout CMD,CLK,FASTLSBPRE,$1\8]
; reading “mode” from PS2 controller
; 73(hex) is dualshock1 (digital buttons)
; 79(hex) is dualshock2 (analog buttons)
shiftin DAT,CLK,FASTLSBPOST,[mode\8]
high SEL
if (mode <> $73) and (mode <> $79) then again
;-----------------------------
pause 1
;-----------PS2 Data----------
low SEL
; asking data to PS2 controller
shiftout CMD,CLK,FASTLSBPRE,$1\8,$42\8]
; reading data from controller
; (don’t use a “for-next” loop, it’s too slow to read PS2 data)
shiftin DAT,CLK,FASTLSBPOST,[temp(0)\8,temp(1)\8,temp(2)\8,temp(3)\8,temp(4)\8,temp(5)\8,temp(6)\8,temp(7)\8,temp(8)\8, |
temp(9)\8,temp(10)\8,temp(11)\8,temp(12)\8,temp(13)\8,temp(14)\8,temp(15)\8,temp(16)\8,temp(17)\8,temp(18)\8]
high SEL
;-----------------------------
pause 1
;-----------PS2 Vibration motors----------
Small_Motor = 1 - Temp(1).bit5 ; Numeric right arrow button (Small Motor on/off)
Large_Motor = Temp(8) ; Analog left arrow button (Large Motor speed)
low SEL
; asking data to PS2 controller (again)
; sending at the same time the vibration motors speed to perform
; (using the previously read analog buttons position ( <- : large motor, -> : small motor )
; the more you press on these buttons, the more the corresponding motor vibrates fast
; some wireless PS2 controllers react only to the large motor command and some have no motor at all.
shiftout CMD,CLK,FASTLSBPRE,$1\8,$42\8,$0\8,Small_Motor\8,Large_Motor\8]
; we don’t care about reading the data from the controller here.
; so, why not use this to read PS2 data the first time? because it’s not working:
; as the PS2 controller is starting to send data just after receiving the
; “shiftout CMD,CLK,FASTLSBPRE,$1\8,$42\8…”<------here
; and as we are sending after that some data for motors “… ,$0\8,temp(7)\8,temp(8)\8]”
; it’s now too late to read all the data from the PS2 controller
; because there’s already some bytes sent by it and lost (no buffer here).
high SEL
;-----------------------------
;-----------Basic Micro IDE terminal----------
; sending carriage return (CR = 13) and the PS2 mode(hex) to the PC
serout S_OUT,i57600,[13, hex2 mode\2] ; Basic Micro Pro IDE
for index = 1 to 18 ; temp(0) contains a dummy variable so we don’t send it to the PC
; sending all the data to the PC
serout S_OUT,i57600," ", dec3 temp(index)\3] ; Basic Micro Pro IDE
next
;-----------------------------
goto main[/code]
Thanks Jim,
I see that! I’ll try it out.
And P.S., I CAN write/read to PS2 controller at the same time with the C code I posted earlier on this thread. Probably still no way to do it in Atom BASIC Pro 'tho.
I did see something that surprised me. The “tokenized” BASIC code used in the Atom is quite compact! I would have thought a compiled program would tend to be smaller then it’s BASIC counterpart and the interpreter. But I do currently have a lot of debug and text strings…
I might have get a 'bot board and an Atom Pro for some more experiments!
Alan KM6VV
What exactly is “DS2 Native Mode”?
I tried those commands and this is what I observed with my OEM DS2:
-pressure readings only work in digital mode
-the large motor works ONLY in DS2 Native Mode, but the small one works in/out of DS2 Native Mode
-DS2 Native Mode locks it into analog mode (possibly among other things)
Also, I noticed from Google searching that there are two command sets to “set DS2 native mode”, {01,44,00,01,03} and {01,4F,0,FF,03}, but I only found the first set to work in my case. I’m not sure why other programs have the second set.
think I’ve got the commands working yet. I have no idea what “Native” mode is either. I did run down some more code snips using your quote as a search phrase.
I’ll try some more commands, but presently I’m more inclined to get back to the IK in the Atom code sample!
Thanks for the info.
Alan KM6VV
DS2 Native mode(the true version) is the mode you can read all digital buttons and all analog buttons(eg sticks and pressure sensors) and enable the vibration motors. That is what the sample code Jim posts shows how to do.
You are also correct that the AtomPro(using the shiftin and shiftout commands) can’t read and write to the PS2 at the same time. it’s not necessary to get full functionality but it would be faster(a little bit).
IIRC the digital bits for each button are in bytes 3 and 4(I’m using base 0 for the first button). All the bytes after that are the analog values(sticks then pressure sensors). Not all PS2 controllers support all the pressure sensors. The Lynxmotion PS2 controller supports all the buttons. Some PS2 controllers are two slow to be usable with all the pressure sensors being read though they can read them all(a Logitech one I testes was like this) so you may not be able to read all the pressure sensors in a usable loop.
AtomPro code is smaller than your C compiled code because most of the generated code is hand written assembly. The rest is tokens which reference those hand coded assembly routines. It’s very difficult to make a compiler that is good enough to beat hand coded assembly. You’ll notice the larger your program is the more efficient(size wise) our basic is compared to compiled C. I’m not saying you can’t do better in C, because you probably ccould, but it will take a lot more work to do it.
Below is the original program with more descriptions of the commands. I worked this out about 5 years ago by searching through a bunch of japanese posts.
[code]_PS2_SIZE con 18
DAT con P4
CMD con P5
SEL con P6
CLK con P7
ps2index var byte
ps2data var byte(21)
ps2mode var byte
ps2small var byte
ps2large var byte
ps2cntr var byte
high CLK
initPS2:
;****************************************************
;****************************************************
;<<CONFIG_MODE_ENTER>>
;CMD=01,43,00,01,00 (,00,00,00,00)
;DAT=–,ID,SS,XX,XX (,XX,XX,XX,XX)
;
;ID=mode number
;
;SS=5A --> mode not changed
;SS=00 --> mode changed
;
;XX= button/stick data
low SEL
shiftout CMD,CLK,FASTLSBPRE,$1\8,$43\8,$0\8,$1\8,$0\8]
high SEL
pause 1
;****************************************************
;****************************************************
;<<SET_MODE_AND_LOCK>>
;CMD=01,44,00,XX,YY (00,00,00,00)
;DAT=–,ID,SS,00,00 (00,00,00,00)
;
;XX=01 --> analog mode
;XX=00 --> digital mode
;
;YY=03 --> lock mode. Mode button on controller is locked
;
;ID=mode number
;
;SS=5A --> mode not changed
;SS=00 --> mode changed
low SEL
shiftout CMD,CLK,FASTLSBPRE,$01\8,$44\8,$00\8, $01\8, $03\8,$00\8,$00\8,$00\8,$00\8]
high SEL
pause 1
;****************************************************
;****************************************************
;<<VIBRATION_ENABLE>>
;CMD=01,4D,00,00,01 (FF,FF,FF,FF)
;DAT=–,ID,SS,XX,YY (FF,FF,FF,FF)
;
;ID=mode number
;
;SS=5A --> mode not changed
;SS=00 --> mode changed
;
;XX,YY=00,01: pad vibration enabled
;XX,YY=FF,FF: pad vibration disabled
; low SEL
; shiftout CMD,CLK,FASTLSBPRE,$1\8,$4D\8,$0\8,$0\8,$1\8,$ff\8,$ff\8,$ff\8,$ff\8]
; high SEL
; pause 1
;****************************************************
;****************************************************
;<<SET_DS2_NATIVE_MODE>>
;CMD=01,4F,00,FF,FF (03,00,00,00)
;CMD=–,ID,SS,00,00 (00,00,00,XX)
;
;ID=mode number
;
;SS=5A --> mode not changed
;SS=00 --> mode changed
;
;XX=5A --> OK
;XX=00 --> NG
low SEL
shiftout CMD,CLK,FASTLSBPRE,$01\8,$4F\8,$00\8,$FF\8,$FF\8,$03\8,$00\8,$00\8,$00\8]
high SEL
pause 1
;****************************************************
;****************************************************
;<<CONFIG_MODE_EXIT_DS2_NATIVE>>
;CMD=01,43,00,00,5A (5A,5A,5A,5A)
;DAT=–,ID,SS,00,00 (00,00,00,00)
;
;ID=mode number
;
;SS=5A --> mode not changed
;SS=00 --> mode changed
low SEL
shiftout CMD,CLK,FASTLSBPRE,$01\8,$43\8,$00\8,$00\8,$5A\8,$5A\8,$5A\8,$5A\8,$5A\8]
high SEL
pause 1
;****************************************************
;****************************************************
;<<CONFIG_MODE_EXIT>>
;CMD=01,43,00,00,00 (00,00,00,00)
;DAT=–,ID,SS,00,00 (00,00,00,00)
;
;ID=mode number
;
;SS=5A --> mode not changed
;SS=00 --> mode changed
; low SEL
; shiftout CMD,CLK,FASTLSBPRE,$01\8,$43\8,$00\8,$00\8,$00\8,$00\8,$00\8,$00\8,$00\8] ;Config Exit
; high SEL
; pause 1
;Check for correct mode
low SEL
shiftout CMD,CLK,FASTLSBPRE,$1\8]
shiftin DAT,CLK,FASTLSBPOST,[ps2mode\8]
high SEL
if ps2mode <> $79 then
serout S_OUT,i57600,"Error setting/locking mode",13]
pause 2000
endif
main
gosub getps2
serout S_OUT,i57600,[13,hex2 ps2mode(ps2index)\2]
for ps2index = 0 to 18
serout S_OUT,i57600," ",dec3 ps2data(ps2index)\3]
next
goto main
getps2
low SEL
shiftout CMD,CLK,FASTLSBPRE,$1\8,$42\8]
for ps2index = 0 to _PS2_SIZE ;Only reading first 4 analog buttons. Logitech wireless slows down too much when reading more than 6 analog buttons
shiftin DAT,CLK,FASTLSBPOST,[ps2data(ps2index)\8]
next
high SEL
return[/code]
The basic steps to init the PS2 controller are:
Enter Config mode
Set mode to digital or analog and optionally lock it
Enable virbation if desired
Optionally:
Set DS2 Native mode
Exit DS2 Native Config if set DS2 Native above
or
Exit Normal Config
Check mode.(Should be 0x79 if DS2 native was enabled properly)
Now you can just read all the buttons/sticks unless you want to change the mode.
You can also set the Vibration motors instead of reading the digital buttons(bytes 3 and 4) write a 0x00 or 0x01 for the small motor(it can only be turned on or off) and a value for large motor speed(0x00 to 0xFF).
So either:
write 0x1,0x42 and read 19 bytes
or
write 0x1,0x42,0x0,Small Motor,Large Motor and read 16 bytes
Thats it. Simple really.
Hi Nathan,
So you’re involved in writing/maintaining Atom’s BASIC interpreter? Interesting product! I have to admit, 'tho, that I’m more inclined to write ‘C’ code.
I’ve played with Jim’s code a little. Got the PS2 working for buttons and joysticks, which is what I need the most at this time. I would like to finish up a complete ‘C’ driver (routines) for the PS2.
Yes, not necessary for the most part. Could be transparent to the user (only use return data when wanted).
I’m using the all the buttons and two joysticks. I would like to read the PS2 via interrupts, and using the SPI hardware to cut down on the overhead, and all those delays! The pressure switches are actually more then I need! I WOULD like to see what they use for a pressure switch in the PS2, 'tho!
That makes sense! It was, however, a surprise to me, until I thought about it for a while. Certainly an advantage for small projects.
It’s more like making up a LARGE set of standardized routines, and using them all the time. Interesting work. I’ve only written parsers and simple interpreters, never a full-blown, token-generating interpreter or a full compiler.
Thanks! I’ll see about integrating it into my code. That Japanese must have been fun!
Alan KM6VV
P.S. (EDITED)
Can you clarify the use of ‘/’ and ‘|’ in BASIC Atom code?
LittleGripOCPulse = ((LittleGripOCPulse + (DualShock(2).bit3 * 50) - (DualShock(2).bit2 * 50)) |
min LGripOC_PulseMin) max LGripOC_PulseMax
Looks like the ‘|’ MIGHT be OR, but why there? Also, multiplying a constant times a bit position? Does “DualShock(2).bit3” resolve to a 0 or 1 instead of a value of 0x08?
HipH_Pulse(Index) = (((HipH_PulseMax - HipH_PulseMin) * (HipH_Angle - HipH_AngleMin) |
/ (HipH_AngleMax - HipH_AngleMin) + HipH_PulseMin) max HipH_PulseMax) min HipH_PulseMin
This snip uses both. The intent is to scale and limit HipH_Pulse(Index) given HipH_Angle, at least that’s what I wrote my ‘C’ routine to do. Or is there something else? Could ‘|’ be a “line continue”?
The ‘|’ in this case means continue this line of code using the next line. The ‘/’ is just a divide. Note the ‘|’ is also used as a bitwise or in expressions. Only when it’s then end of a line of code does it mean continue this line on the next line. Unlike C basic has no endofline character(eg ‘;’).