USB low-speed host and HID keyboard/mouse "boot protocol" class driver v0.2 (alpha). It still has a long way to go, but it's time to give any interested folks a chance to bang on it a bit.
It enumerates all of the low-speed devices I currently have:
MS Wireless Comfort Keyboard 1.0A, model 1045
SIIG Mini Multimedia Keyboard v2.0, model 02-1230B
Kingston PocketMouse Pro Wireless, model 72117 (though it doesn't pay attention to "set idle" when in boot protocol)
Amazon Basics Mouse, model MSU0939
Logitech Extreme 3D Pro Joystick, model J-UF17
Gravis Gamepad Pro
The joystick and gamepad aren't "boot protocol" devices so no input data is retrieved, but their standard descriptors can be read.
Any and all comments/suggestions welcome.
USBHost.spin2:
--------------
FPGA board: Prop123-A9.
P2 image: v12.
Serial terminal: Parallax Serial Terminal (the Windows .exe) at 3MBd.
Default USB smart pins: DM = 32, DP = 33, but any even/odd pin pair should work.
For the host, both D- and D+ require a 15K pull-down resistor.
Cog zero is a minimal USB low-speed host/root hub implementation, capable of
basic device enumeration, address assignment and configuration. Cog one is an
HID class driver which should recognize and configure a keyboard/mouse if the
device supports "boot protocol". It is still far from complete, but I'd like to
get it in the hands of others that are interested to give it a go and see what
happens. Error recovery is still minimal. For missing/corrupt packets, up to
three retries will be attempted before giving up. If an endpoint issues a STALL
response, the system will stop.
Keyboard character output is US ASCII, and all "printable" characters
should be properly mapped. Non-printing keys other than tab/enter/backspace
will emit the ASCII equivalent of their USB keycode. The CapsLock, NumLock and
ScrollLock toggle keys are supported, and if your keyboard has LED indicators
for them, they should work, too. USB keyboards require key auto-repeat to be
implemented by the HID class driver. It works, but the current implementation
is not yet consistent with a "real" keyboard driver.
If a boot protocol mouse is detected, its button states and the X/Y position
and velocity data is output to the serial terminal. The default is to use PST
cursor control codes to inhibit line scrolling. To enable line scrolling as the
default, the OPT_MSCROLL constant can be assigned the value MSCROLLF.
On the Prop123-A9 board, pushbutton PB3 can be used to toggle on/off the option
to output detailed descriptor data to the terminal when the device is
connected. The startup default for this option is "off". To enable verbose
output at startup the OPT_VERBOSE constant can be assigned the value
PARSE_DESCSF.
Pushbutton PB2 can be used to toggle on/off the scrolling of mouse button
states and X/Y position/velocity values, as described above.
Note that these options can only be changed while the device is disconnected.
Is there a way to support both keyboard and mouse at same time?
Maybe with two instances?
I'm pretty sure the answer is yes, but this version would likely do something bad if it tried. It searches the entire configuration chain looking for both keyboard and mouse (both must support boot protocol), and each has its own interrupt timer, so in theory it should work. The Microsoft Wireless Optical Desktop 4000 package comes with both mouse and keyboard, but the mouse interface doesn't support boot protocol. That can be worked around, but I haven't been able to find the mouse, so I can't yet test this scenario :frown:
I also have a Microsoft Wireless Desktop 5000 keyboard and mouse, but its dongle is full-speed.
A second host cog could be used to support two physical ports, and the HID class driver cog should have plenty of time to talk to both, but right now the host and class driver cogs are joined at the hip through LUT sharing with write event triggers.
Ha! I found the mouse, so this can eventually be tested. The problem is that this keyboard/mouse combo is the only wireless product I've found that does low-speed. Right now there's no reason that four cogs and two physical ports shouldn't work. They just need to cooperate to provide a common interface for a client cog to get to the device data.
Nice milestone
Any indications on what SysCLK LS USB can operate down to ?
I haven't checked yet, as my assumption up to this point has been that all the p2 variants would be at least 80Mhz devices.
How does FS USB operation look ?
Or, if 80MHz is too low, what MHz does your code indicated is needed for FS USB ?
IMO full-speed is not too far away from 80MHz for getting data to/from the bus. The short experiments I did at full-speed suggest that the smart-pin implementation is likely sound, it was just that at 8x bandwidth I just couldn't get the bits in/out fast enough. But I think "boot protocol" keyboard/mouse and maybe other devices that use interrupt transfers and small packet size might be doable at 80MHz -- with a lot of non-USB-compliant short-cutting :-D
I couldn't find wired mice or keyboards among my treasures.
So, I got a pair from Walmart (ONN) Keyboard model ONA11H0089/ mouse model ONA11H0091. Compatible with Windows 2000. So should work.
I changed these options to:
OPT_VERBOSE = PARSE_DESCSF ' Set to PARSE_DESCSF for verbose output to the terminal, zero for off
OPT_MSCROLL = MSCROLLF
Splash screen at start still indicates they are off. PB2 and PB3 show correct status.
I get a blinking P123 LED at startup, which becomes solid when I plug in either the mouse or the keyboard.
When I plug in the mouse for a second time, the red led for the optical systems stays on. First time, it fails... which I assume means that first time, the P2 isn't seeing the mouse,
but the second time I plug it in, it does.
The keyboard has three green LED's, which flash once after plugging the keyboard in the first time after startup.
But then don't light up if I un-plug and then re-plug in the keyboard. So, first time it sees the keyboard... but second time it doesn't?
After that... I'm pretty much lost. Not seeing anything new after the P123's LED becomes solid. Not getting any other reports.
Hmm, off to a rocky start, we are. I'd think the P123-A9 would be as close to plug-n-play as we could get...
USB connector D- and D+ have 15K pull-downs, good ground (to both the USB connector and the P2123), and +5V to the USB connector VCC line?
I've tested with D-/D+ to I/O pins 0/1 and 32/33. With the P2v12 image, no code changes are needed except changing the DM/DP pin assignments.
Let's start with the OPT_VERBOSE and OPT_MSCROLL constants set to zero.
Load the code without a USB device connected. After the code loads, the cog0 and cog1 red LEDs should be lit, the splash screen goes out, and the GRN 12 LED should blink to indicate that it's waiting for a device to be connected. Both button option messages should show their "off" status.
When you press the PB3 and PB2 buttons, do their option state messages show the on/off state change? If so, that means that both host and driver cogs are running and in their "idle" states.
If we're good so far, make sure both pushbutton options show their "off" state, and connect the device. You should see one of two messages:
"<Low-Speed device connected.>" or "Full-speed not supported at this time.".
If you see no message that's definitely not good.
If you see the first message and it's not followed by a message that starts with either "Woo-hoo" or "Bummer", there's got to be an issue between the USB connector and the I/O pin hookup, or the quality of the signals. You said the GRN 12 LED goes from blinking to on solid? If so, it sounds like it's detecting a state change on the bus, but that's it. Even with the OPT_VERBOSE option set to zero, if there's an unexpected bus error, a message should get sent to the terminal. Since it sounds like that's not even happening, you just about need a 'scope or USB analyzer to see what's going on with the bus...
Load the code without a USB device connected. After the code loads, the cog0 and cog1 red LEDs should be lit, the splash screen goes out, and the GRN 12 LED should blink to indicate that it's waiting for a device to be connected. Both button option messages should show their "off" status.
When you press the PB3 and PB2 buttons, do their option state messages show the on/off state change? If so, that means that both host and driver cogs are running and in their "idle" states.
yes.. first push of each says "ON" second push shows "OFF"
If we're good so far, make sure both pushbutton options show their "off" state, and connect the device. You should see one of two messages:
"<Low-Speed device connected.>" or "Full-speed not supported at this time.".
If you see the first message and it's not followed by a message that starts with either "Woo-hoo" or "Bummer", there's got to be an issue between the USB connector and the I/O pin hookup, or the quality of the signals. You said the GRN 12 LED goes from blinking to on solid? If so, it sounds like it's detecting a state change on the bus, but that's it. Even with the OPT_VERBOSE option set to zero, if there's an unexpected bus error, a message should get sent to the terminal. Since it sounds like that's not even happening, you just about need a 'scope or USB analyzer to see what's going on with the bus...
I'm using 8" unshielded jumpers:) will tear it apart and reassemble today. Thanks
So it sounds like you're seeing all the descriptor output OK when you connect the mouse in verbose mode?
If that's working, I'm at a loss as to why the mouse data doesn't get scrolled. In the non-scroll mode, do the mouse X/Y data values change? The only difference between scroll/no-scroll is that a CR gets sent (source line #2984) instead of the outputting the PST GOTOX 0 cursor position chars (line #2998).
I have my PST "Prefs" set with (10) Line Feed unchecked, and (13) New Line checked.
I misunderstood... I was referring to the scroll wheel. The data scrolls just fine:)
Well, that's a relief :-D
Unfortunately, the "boot" protocol mouse interface offers no data for the scroll wheel. That's likely why I was thinking "scroll" was referring to a terminal output issue...
But it's pretty easy to get the scroll wheel data. During configuration (the dset_config routine) you just need to set the protocol type to REPORT_PROTOCOL rather than BOOT_PROTOCOL, and then modify the dget_mouse_in_report routine to output the longer packet you'll get. Edit: Address mouse_in_max_pkt always tells you how much report data is there. There is already a commented-out stub there that you can tweak to get the extra data. Then you just have to figure out which bits belong to the scroll wheel. Usually it follows the X/Y data and is also interpreted as signed direction/velocity.
In the future I was planning on expanding the "verbose" output option to also request the HID report descriptors. Initially it would be just the raw data, but even with that there are tools that will convert it into fully formatted report data.
For others (like me) with less than a partial understanding of all of this:
As a rule, if it doesn't work, reload the P2v image and then restart the software.
What I was doing wrong in the beginning: The P2v retains RAM contents and I suspect that something left resident in the hub was conflicting.
Recent example: I mindlessly set the cog assignments to 2 and 3... not remembering that Cog 0 is implicit. After that, I had to reload the P2v image to recover.
BTW: Think we can monitor 2 pairs of USB inputs with one cog?
I'm really not sure -- I've already pulled out a quite lot of hair trying to figure out how to manage one port :zombie:
When full-speed becomes a reality, it think trying to get a hub driver up and running might be something to think about.
Glad you figured out how to turn keyboard LEDs on.
I tried a little bit, but couldn't get it to work...
Whenever a toggle key-down event is received, a one-byte OUT report is sent to the keyboard's address and control endpoint that is a bit array of the current toggle key states. The keyboard doesn't keep track of the LED states -- it's up to the class driver to keep everything in sync.
- Expanded verbose output to include more USB transaction results to give a better idea of what's going on during device enumeration.
- HID report descriptors (up to two) are now retrieved and output as raw data when in verbose mode. The data can be copied from the terminal screen and pasted to the tool at the below website, which will attempt to parse the data into a human-readable format. Note that the data retrieved defines the report used when the device is configured in "report protocol" rather than "boot protocol".
Getting the full-speed 1ms start-of-frame token output implemented was fairly easy, as I already had the basics of it in place to handle the low-speed 1ms "keep-alive" EOP frame. In-lining the rx byte read code and skipping the in-line rx crc16 verification calcs (~6 instructions) saved enough cycles to get full-speed read to work. I've been able to enumerate a rather old USB SDCard reader, but not so much luck with other devices I've tried. This was done using the same code base I was using for low-speed. I can disconnect this FS device and connect my low-speed keyboard and start typing, so I'll call this progress!
I'm still mostly clueless as to why this FS device works and the others don't, but now that I have a device that can be read, I'll eventually find out why
I've also been reading up on what it will take to converse with a hub. The first interesting thing I ran into is section 11.8.4 of the USB spec, which says that when a hub is configured for full/low speed operation, low-speed data is sent or received through the hub’s upstream facing port at full-speed signaling even though the bit times are low-speed. In some docs I've seen it referred to as "low-speed over full-speed". Can the smart pins NCO be changed on the fly to switch between full/low-speed baud rates? I've got a couple of USB 1.1 hubs, so if I can get the current kinks worked out, we'll be able to eventually test this.
Wow! 178kB assembly code! That's massive, total kudos Garry!
Wow! I just went and looked at it. USB is no picnic.
In the next FPGA release, we'll have 2-clock RDPIN/WRPIN/WXPIN/WYPIN instructions. That should help with turn-around times. Maybe full-speed will be more viable.
In the v13 docs section regarding USB transmit, references to the use of AKPIN following WYPIN when sending a byte have been removed, which implies it supports the new WYPIN auto-ack feature. In the below code if the akpin is commented out, a corrupt tx packet is the result.
I'm assuming from this that the reason why is that the "buffer empty" flag is tied to upper pin of the smartpin pair and the wypin target is the lower pin -- is the wypin auto-ack supposed to support this particular USB usage scenario?
utx_byte
testin #DP wc ' Wait for tx buffer empty
if_nc jmp #utx_byte
akpin #DP
wypin utx, #DM
ret
BTW, the rdpin/rqpin updates in v13 have had a positive impact on getting full-speed AND crc verification of received packets working! Hopefully, in the very near future, I'll get a demo out that supports a wireless keyboard/mouse combo, as long as they are identified as "boot protocol" devices. For other full-speed capable devices, the verbose mode will dump as much descriptor data as it can. Oh, and low-speed devices should continue to work as they did in the previous demo.
Comments
It enumerates all of the low-speed devices I currently have:
MS Wireless Comfort Keyboard 1.0A, model 1045
SIIG Mini Multimedia Keyboard v2.0, model 02-1230B
Kingston PocketMouse Pro Wireless, model 72117 (though it doesn't pay attention to "set idle" when in boot protocol)
Amazon Basics Mouse, model MSU0939
Logitech Extreme 3D Pro Joystick, model J-UF17
Gravis Gamepad Pro
The joystick and gamepad aren't "boot protocol" devices so no input data is retrieved, but their standard descriptors can be read.
Any and all comments/suggestions welcome.
Any indications on what SysCLK LS USB can operate down to ?
How does FS USB operation look ?
Or, if 80MHz is too low, what MHz does your code indicated is needed for FS USB ?
Is there a way to support both keyboard and mouse at same time?
Maybe with two instances?
I also have a Microsoft Wireless Desktop 5000 keyboard and mouse, but its dongle is full-speed.
A second host cog could be used to support two physical ports, and the HID class driver cog should have plenty of time to talk to both, but right now the host and class driver cogs are joined at the hip through LUT sharing with write event triggers.
Using P123 A9
I couldn't find wired mice or keyboards among my treasures.
So, I got a pair from Walmart (ONN) Keyboard model ONA11H0089/ mouse model ONA11H0091. Compatible with Windows 2000. So should work.
I changed these options to:
OPT_VERBOSE = PARSE_DESCSF ' Set to PARSE_DESCSF for verbose output to the terminal, zero for off
OPT_MSCROLL = MSCROLLF
Splash screen at start still indicates they are off. PB2 and PB3 show correct status.
I get a blinking P123 LED at startup, which becomes solid when I plug in either the mouse or the keyboard.
When I plug in the mouse for a second time, the red led for the optical systems stays on. First time, it fails... which I assume means that first time, the P2 isn't seeing the mouse,
but the second time I plug it in, it does.
The keyboard has three green LED's, which flash once after plugging the keyboard in the first time after startup.
But then don't light up if I un-plug and then re-plug in the keyboard. So, first time it sees the keyboard... but second time it doesn't?
After that... I'm pretty much lost. Not seeing anything new after the P123's LED becomes solid. Not getting any other reports.
USB connector D- and D+ have 15K pull-downs, good ground (to both the USB connector and the P2123), and +5V to the USB connector VCC line?
I've tested with D-/D+ to I/O pins 0/1 and 32/33. With the P2v12 image, no code changes are needed except changing the DM/DP pin assignments.
Let's start with the OPT_VERBOSE and OPT_MSCROLL constants set to zero.
Load the code without a USB device connected. After the code loads, the cog0 and cog1 red LEDs should be lit, the splash screen goes out, and the GRN 12 LED should blink to indicate that it's waiting for a device to be connected. Both button option messages should show their "off" status.
When you press the PB3 and PB2 buttons, do their option state messages show the on/off state change? If so, that means that both host and driver cogs are running and in their "idle" states.
If we're good so far, make sure both pushbutton options show their "off" state, and connect the device. You should see one of two messages:
"<Low-Speed device connected.>" or "Full-speed not supported at this time.".
If you see no message that's definitely not good.
If you see the first message and it's not followed by a message that starts with either "Woo-hoo" or "Bummer", there's got to be an issue between the USB connector and the I/O pin hookup, or the quality of the signals. You said the GRN 12 LED goes from blinking to on solid? If so, it sounds like it's detecting a state change on the bus, but that's it. Even with the OPT_VERBOSE option set to zero, if there's an unexpected bus error, a message should get sent to the terminal. Since it sounds like that's not even happening, you just about need a 'scope or USB analyzer to see what's going on with the bus...
yes
ok
correct
yes.. first push of each says "ON" second push shows "OFF"
no message
I'm using 8" unshielded jumpers:) will tear it apart and reassemble today. Thanks
Rich
showing all three buttons and dx,dy in verbose mode
WUNDERBAR
If that's working, I'm at a loss as to why the mouse data doesn't get scrolled. In the non-scroll mode, do the mouse X/Y data values change? The only difference between scroll/no-scroll is that a CR gets sent (source line #2984) instead of the outputting the PST GOTOX 0 cursor position chars (line #2998).
I have my PST "Prefs" set with (10) Line Feed unchecked, and (13) New Line checked.
Unfortunately, the "boot" protocol mouse interface offers no data for the scroll wheel. That's likely why I was thinking "scroll" was referring to a terminal output issue...
But it's pretty easy to get the scroll wheel data. During configuration (the dset_config routine) you just need to set the protocol type to REPORT_PROTOCOL rather than BOOT_PROTOCOL, and then modify the dget_mouse_in_report routine to output the longer packet you'll get. Edit: Address mouse_in_max_pkt always tells you how much report data is there. There is already a commented-out stub there that you can tweak to get the extra data. Then you just have to figure out which bits belong to the scroll wheel. Usually it follows the X/Y data and is also interpreted as signed direction/velocity.
In the future I was planning on expanding the "verbose" output option to also request the HID report descriptors. Initially it would be just the raw data, but even with that there are tools that will convert it into fully formatted report data.
The fun is just beginning
The code reads like a novel. Incredibly beautiful stuff.
As a rule, if it doesn't work, reload the P2v image and then restart the software.
What I was doing wrong in the beginning: The P2v retains RAM contents and I suspect that something left resident in the hub was conflicting.
Recent example: I mindlessly set the cog assignments to 2 and 3... not remembering that Cog 0 is implicit. After that, I had to reload the P2v image to recover.
Had to upgrade firmware to V12. Finally had time to do that...
Is there a way to set your screen size somewhere and have the mouse driver instead report position on screen?
I'm surprised to hear boot mode works so well. Don't remember exactly, but thought it would be more difficult for some reason.
This keyboard driver will definitely save me some time.
Want to get a GUI going and mouse and keyboard drivers are just what I needed.
Glad you figured out how to turn keyboard LEDs on.
I tried a little bit, but couldn't get it to work...
When full-speed becomes a reality, it think trying to get a hub driver up and running might be something to think about.
Whenever a toggle key-down event is received, a one-byte OUT report is sent to the keyboard's address and control endpoint that is a bit array of the current toggle key states. The keyboard doesn't keep track of the LED states -- it's up to the class driver to keep everything in sync.
Requires FPGA image v12.
- Expanded verbose output to include more USB transaction results to give a better idea of what's going on during device enumeration.
- HID report descriptors (up to two) are now retrieved and output as raw data when in verbose mode. The data can be copied from the terminal screen and pasted to the tool at the below website, which will attempt to parse the data into a human-readable format. Note that the data retrieved defines the report used when the device is configured in "report protocol" rather than "boot protocol".
Frank Zhao's USB Descriptor and Request Parser
Please let me know of any issues you may encounter. Thanks!
Any updates?
Getting the full-speed 1ms start-of-frame token output implemented was fairly easy, as I already had the basics of it in place to handle the low-speed 1ms "keep-alive" EOP frame. In-lining the rx byte read code and skipping the in-line rx crc16 verification calcs (~6 instructions) saved enough cycles to get full-speed read to work. I've been able to enumerate a rather old USB SDCard reader, but not so much luck with other devices I've tried. This was done using the same code base I was using for low-speed. I can disconnect this FS device and connect my low-speed keyboard and start typing, so I'll call this progress!
I'm still mostly clueless as to why this FS device works and the others don't, but now that I have a device that can be read, I'll eventually find out why
I've also been reading up on what it will take to converse with a hub. The first interesting thing I ran into is section 11.8.4 of the USB spec, which says that when a hub is configured for full/low speed operation, low-speed data is sent or received through the hub’s upstream facing port at full-speed signaling even though the bit times are low-speed. In some docs I've seen it referred to as "low-speed over full-speed". Can the smart pins NCO be changed on the fly to switch between full/low-speed baud rates? I've got a couple of USB 1.1 hubs, so if I can get the current kinks worked out, we'll be able to eventually test this.
More fun ahead!
Wow! I just went and looked at it. USB is no picnic.
In the next FPGA release, we'll have 2-clock RDPIN/WRPIN/WXPIN/WYPIN instructions. That should help with turn-around times. Maybe full-speed will be more viable.
I'm assuming from this that the reason why is that the "buffer empty" flag is tied to upper pin of the smartpin pair and the wypin target is the lower pin -- is the wypin auto-ack supposed to support this particular USB usage scenario?
BTW, the rdpin/rqpin updates in v13 have had a positive impact on getting full-speed AND crc verification of received packets working! Hopefully, in the very near future, I'll get a demo out that supports a wireless keyboard/mouse combo, as long as they are identified as "boot protocol" devices. For other full-speed capable devices, the verbose mode will dump as much descriptor data as it can. Oh, and low-speed devices should continue to work as they did in the previous demo.