-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Got it talking, but still unrecognized? #17
Comments
Ah, my logic analyzer has the bit pattern reversed, so 0x80 0x42 is actually 0x01 0x42. Time to pull out the oscilloscope and look at this more carefully. I'll be back. P.S. The official spec for the LynxMotion controllers is here, so this is what I should be seeing: |
Ah, sorry. I tried doing a push up the crates.io last week but there’s an upstream deprecation warning that I was failing on (deny_warnings I’ve learned is an anti-pattern).
What bitrate are you using?
… On May 25, 2019, at 2:05 PM, Tim Boldt ***@***.***> wrote:
Ah, my logic analyzer has the bit pattern reversed, so 0x80 0x42 is actually 0x01 0x42. Time to pull out the oscilloscope and look at this more carefully. I'll be back.
P.S. The official spec for the LynxMotion controllers is here, so this is what I should be seeing:
http://www.lynxmotion.com/images/files/ps2cmd01.txt
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or mute the thread.
|
Just circling back here too, try lifting code chunks out of the Just an aside, Rust 1.35.0 should also allow for dynamically sized arrays on the stack now and I plan to make that huge amount of bytes transferred dynamic based on what comes from the response code from the controller. |
My SPI bus is running at 140.8kHz and there doesn't seem to be a way to change it, even though the The edges all look clean in an oscilloscope, and a real Playstation runs at 250kHz, so I don't think this is the issue. I also verified my results with and without a 1K pull-up, and it appears it is only necessary when the LynxMotion wireless adapter is not plugged in. With it plugged in, it actively pulls the DATA line high. The device identifies itself as either 0x83 0xFE (default config when I turn it on) or 0xE7 0xFE (if I press the mode button, which turns on a red led). This suggests that I have connectivity working end to end. The raw data (ControllerData.data) is all 0xFF, except for the last 3 bytes, which are 0x00. I guess the next thing to try is to get out my old Arduino Uno and try their sample code with that to confirm that I don't have a faulty device. |
Neither of those identifiers are right according to the doc you posted earlier:
41 --> Digital mode
73 --> analog mode
F3 --> DS2 native mode
Those do look right based on what I have in lib.rs
One thing, because the Pi doesn’t allow flipping bits in hardware I think I hard coded the bit flipping in software.
If there’s an bit flip option in the STMF103 crate, turn that off and see if it helps. If it fixes it, let’s figure out a better way than the naive option I chose.
If it doesn’t fix it, post your code here and I can try to run it on one of my blue pills.
… On May 26, 2019, at 1:10 AM, Tim Boldt ***@***.***> wrote:
My SPI bus is running at 140.8kHz and there doesn't seem to be a way to change it, even though the stm32f1xx-hal tries to set it correctly.
The edges all look clean in an oscilloscope, and a real Playstation runs at 250kHz, so I don't think this is the issue.
I also verified my results with and without a 1K pull-up, and it appears it is only necessary when the LynxMotion wireless adapter is not plugged in. With it plugged in, it actively pulls the DATA line high.
The device identifies itself as either 0x83 0xFE (default config when I turn it on) or 0xE7 0xFE (if I press the mode button, which turns on a red led). This suggests that I have connectivity working end to end.
The raw data (ControllerData.data) is all 0xFF, except for the last 3 bytes, which are 0x00.
I guess the next thing to try is to get out my old Arduino Uno and try their sample code with that to confirm that I don't have a faulty device.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.
|
I figured it out: it is a timing issue with the wireless controller. If I slow down the CPU from 72MHz to 8MHz, it results in enough of a gap (12.5usec in my case) between bytes that it works. I may do some experiments to see if adding a few delays in your code will let me run the CPU at full speed. (The Lynxmotion fork of the Arduino code also has a few extra delays to deal with the quirks of wireless controllers.) And by the way, it wasn't a question of SPI bus speed. I was easily able to run it at 250kHz, as long as there were gaps between bytes. With the CPU slowed down, here is what I see (which matches expectations, I think):
|
So, for posterity, the workaround I did was to lower the clock speed from 72MHz to 48MHz as follows.
This worked when compiled for debug with Given the nature of this workaround, there is no guarantee it will work in release mode, nor will it necessarily fail in debug mode with optimizations turned off. Most likely the correct fix is to have the user pass in a delay function that supports microsecond-level delays, and then add a 4us delay between bytes. Adding a delay is what most of the C/C++ libraries do. Specifically, a common Arduino PS2 library has these values: And the Lynxmotion fork of it changed the 3 to a 4: |
Great work! I had the same problem with a third party mouse device.
In reading some real hardware dumps the polling only happens once per frame, so 60Hz. I’m hesitant to force that as it might cause problems for users who would want to use hardware interrupts or other mechanisms that wouldn’t block the main thread.
Would have adding a delay to every example have helped you figure that out sooner?
… On May 26, 2019, at 4:36 PM, Tim Boldt ***@***.***> wrote:
So, for posterity, the workaround I did was lower the clock speed from 72MHz to 48MHz as follows.
let clocks = rcc
.cfgr
.use_hse(8.mhz())
.sysclk(48.mhz())
.pclk1(24.mhz())
.freeze(&mut flash.acr);
This worked when compiled for debug with opt-level = 2 (needed because flash is at a premium).
Given the nature of this workaround, there is no guarantee it will work in release mode, nor would it likely fail in debug mode if I didn't have optimizations turned on.
Most likely the correct fix is to have the user pass in a delay function that supports microsecond-level delays, and then add a 4us delay between bytes. This is what most of the C/C++ libraries do.
Specifically, a common Arduino PS2 library has these values:
https://github.com/madsci1016/Arduino-PS2X/blob/master/PS2X_lib/PS2X_lib.h#L95
And the Lynxmotion fork of it changed the 3 to a 4:
***@***.***
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.
|
Actually, the delay I was talking about was between individual bytes. The real PS2 uses hardware ACKs which result in short (<4usec) gaps between bytes. I believe the lack of a delay there was causing the issue. You can see the gap in the oscilloscope dumps of real hardware, at Curious Inventor. Most software implementations introduce an intentional delay between SPI transfer-byte calls, to compensate for the lack of a hardware ACK. The easiest solution would be a (optional) "delay between bytes" function that I could supply. P.S. It occurred to me that under Linux, the kernel transition might be slow enough that it introduces just enough delay to avoid the issue. Even on my Blue Pill microcontroller, changes in CPU speed were enough to introduce a small delay. The problem is that it is pretty much guaranteed to fail on faster MCUs like the F7, without introducing an intentional delay. |
Looking closer, I see you are using If my theory is right, this won't work if the SPI device is able to string bytes together fast enough without the multi-microsecond gap between bytes that the PS2 devices expect. For example, it is probably guaranteed to fail if the MCU uses DMA with its SPI device. On the plus side, this gives me an idea: I can create a virtual SPI device that does byte-by-byte transfers and injects delays between bytes (or even waits for a signal on the PS2 hardware ACK line). However, the best solution (from the perspective of a user of your general-purpose UI) would be to have the option of doing the SPI transfer byte by byte, with a user-supplied |
I also see why it works on a Raspberry Pi. The Pi kernel injects a one clock-cycle delay between bytes on the SPI bus (making each byte take 9 clock cycles). At 100kbit, that's 10usec. |
I like the single byte plan! I’m waffling over the details a bit here but the delay is likely the best bet until that doesn’t work for someone.
PR most welcomed!
… On May 27, 2019, at 12:41 PM, Tim Boldt ***@***.***> wrote:
I also see why it works on a Raspberry Pi. The Pi kernel injects a one clock-cycle delay between bytes on the SPI bus (making each byte take 9 clock cycles). At 100kbit, that's 10usec.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.
|
I got a chance to experiment with this again on my STM32F103.
I used this repo as of May 24 (not sure if that was a good choice, but I needed to include the commit that I submitted in April, which isn't on crates.io yet).
It still fails, but in a much more promising way.
Here are the first few hundred bytes I see being exchanged. The devices seem to be talking, but the library doesn't seem to recognize the device (the slave keeps responding with
E7 7F
). My device is a LynxMotion PS/2 V4.Either that, or I did something facepalm-worthy again. :-)
The text was updated successfully, but these errors were encountered: