USB Composite (HID / MIDI / Mass Storage) library

arpruss
Sun Dec 03, 2017 8:32 pm
I’ve worked hard to bring the addMidiHID branch of the libmaple-based core up to date, and even made a pull request to merge that into the main branch, but then today I realized that it would be simpler for maintenance and customization to put all the stuff into a separate library, making use of the fact that the core’s USB serial support has __weak references where it matters.

So, here is a USB library compatible with the main libmaple-based core:

(The library is also bundled with Roger’s core.)

As of February 2018, the library supports:

  • USB HID
  • Serial (use CompositeSerial, not Serial)
  • USB MIDI
  • XBox 360 controller
  • Mass storage

You can do various composite combinations, e.g., HID+Serial, Mass storage+HID, etc.

Here’s some example code: an adapter from the IBM PC game port to USB joystick:

#include <GameControllers.h> // https://github.com/arpruss/GameControllersSTM32
#include <USBComposite.h>

USBHID HID; // declare HID plugin instance
HIDJoystick Joystick(HID); // declare Joystick profile instance

GamePortController controller(PA0,PA1,PA2,PA3,PA4,PA5,PA6,PA7);

void setup()
{
// to composite serial, use USBHID_begin_with_serial() instead
USBHID.begin(HID_JOYSTICK); // other options: HID_KEYBOARD, HID_MOUSE, HID_KEYBOARD_JOYSTICK, HID_KEYBOARD_MOUSE, HID_KEYBOARD_MOUSE_JOYSTICK

pinMode(LED_BUILTIN, OUTPUT);

digitalWrite(LED_BUILTIN, 1);
controller.begin();
Joystick.setManualReportMode(true); // aggregate data before sending
}

void loop()
{
GameControllerData_t data;
if (controller.read(&data)) {
Joystick.X(data.joystickX);
Joystick.Y(data.joystickY);
Joystick.Xrotate(data.cX);
Joystick.sliderRight(data.shoulderRight);
uint8_t mask = 1;
for (int i=1; i<=8; i++, mask <<= 1)
Joystick.button(i, (data.buttons & mask) != 0);
Joystick.send();
}

delay(10);
}


RogerClark
Sun Dec 03, 2017 9:16 pm
Any idea how we could stop the code hanging if calls are made to Serial ?

arpruss
Sun Dec 03, 2017 10:51 pm
[RogerClark – Sun Dec 03, 2017 9:16 pm] –
Any idea how we could stop the code hanging if calls are made to Serial ?

Actually, my note about hanging was unduly alarmist: when I actually tried it, there was no hang.

Nonetheless, to be safe, I just added a USBSerialNOP class that extends USBSerial and does nothing, and made the init code for HID and MIDI overwrite Serial with an instance of USBSerialNOP. We still waste flash space by having the Serial code, but at least we won’t have any issues with interference.


RogerClark
Sun Dec 03, 2017 11:59 pm
OK

Thanks

I’ll give the libs a try when I get chance (possibly this evening)


arpruss
Mon Dec 04, 2017 3:57 pm
By the way, does the Serial.begin() call have to be there in variants/*/wirish/boards_setup.cpp : board_setup_usb()? All the sketches I’ve looked at or written that use serial call Serial.begin() in setup() anyway.

If the Serial.begin() call were removed from the global setup code in the core, and if one left the issues about using Serial by mistake for the user to worry about out, then the linker wouldn’t link in the USBSerial and usbcdcacm code, and library users would save flash. It’s that one call to Serial.begin() in the default board_setup_usb() that gets the linker to pull in the usb serial code.

What’s weird is that board_setup_usb() is declared __weak and I override it in the library. The override works, but the stupid(?) linker still pulls in the dependencies for the original __weak board_setup_usb(). This happens even in LTO mode, which make no sense to me. But if one comments out the Serial.begin() line in the core, all that unnecessary code disappears.


arpruss
Mon Dec 04, 2017 5:21 pm
Nevermind the suggestion to remove Serial.begin(). It’s needed for the serial-reset functionality. :-(

It would still be nice to find some way to override it without bringing in the unnecessary dependencies.


RogerClark
Mon Dec 04, 2017 7:56 pm
Yes…
Unfortunately, the Serial.begin is essential so that the core can be triggered to reboot via the IDE

I did look to see if commands can be sent via HID which could be uses to reboot, but i could not find much useful information about how this could be done using the generic Windows HID driver


arpruss
Tue Dec 05, 2017 1:18 pm
Maybe the best solution would be to add a menu option that turns off USB Serial in the core. This would be like the addMidiHID branch, but easier to maintain, since all the actual Midi and HID support would be pushed out into libraries, and with two usb menu options instead of four or five. And once ready someone puts in the effort, they can write a HID+serial composite library.

RogerClark
Tue Dec 05, 2017 7:59 pm
It would be good if we could add the menu, but its not that simple, because several of the upload methods already dont have USB Serial turned on.

So it would break things for anyone currently using Serial or BMP upload, if it was defaulted to being turned on.

Unfortunately, the menu system in the IDE is not cascading, so there is no way to just have this as an option for the upload methods which currently have USB Serial turned included in the build.

From what I understand, having USB Serial initially turned on, means the code is bigger, but your code turns it off.

i dont see this as a big problem, because conversely, someone may want to use USB HID to start with, but then switch back to USB Serial later in their code. In which case USB Serial would need to be compiled in.

Most BluePills have 128k so I dont think an additional 5k all the time is a big problem

if the problem is that USB Serial starts and then stops again ( because the HID library disables Serial), perhaps there is a way to add a global flag which is set as part if the HID library, which prevents the code calling Serial.begin() in the core.


arpruss
Thu Dec 07, 2017 3:51 am
I’ve replaced the three Keyboard-Mouse / Joystick / Keyboard-Mouse-Joystick libraries with a single USB HID library. This requires a single initialization line to select between options:
HID.begin(device); // where HID is your instance of USBHID

RogerClark
Thu Dec 07, 2017 4:05 am
Wow

Looks good

I will try to test, when I get time, probably at the weekend


RogerClark
Thu Dec 07, 2017 4:06 am
Umm

You link does not work :-(

Is it this one

https://github.com/arpruss/USBHID_stm32f1


arpruss
Thu Dec 07, 2017 5:12 am
Yeah, it’s this one.

One problem I haven’t figured out is how to reset the USB connection. HID.begin(USB_HID_JOYSTICK); HID.end(); HID.begin(USB_HID_KEYBOARD); doesn’t work, at least not with Windows. Windows still sees the joystick device, not the keyboard, even though HID.begin() includes the PA12 reset code.


arpruss
Thu Dec 07, 2017 4:55 pm
Looking at the bootloader code, I figured out the issue of how to reset the connection to switch HID identities: I now turn off the USB peripheral in usb_hid_disable() and usb_midi_disable(). Probably something similar should be done in the core with regard to serial.

A minor issue I noticed is that if you send data to the keyboard (and probably other devices) too soon after HID.begin(), it will disappear. A 500ms pause is good enough.


RogerClark
Thu Dec 07, 2017 7:56 pm
Serial seems to have the same problem.

Sending too soon after the USB starts, causes the data to be lost.


arpruss
Fri Dec 08, 2017 1:55 am
I posted a pull request for powering down USB with Serial.end().

RogerClark
Fri Dec 08, 2017 3:21 am
OK

I’m a bit snowed under with PR’s at the moment.

There are 2 urgent ones, because Wire is not working correctly and nor is tone()

And there seem to be other assorted PR’s some of which I will decline

I’m also in the middle of bringing the ZumSpot branch up to date, as it was nearly 300 commits out of date…
So I need to confirm the merge with Head Master (plus some manual changes) are OK.

If your PR is just the addition of lib’s I should be able to take a look at the weekend.


arpruss
Fri Dec 08, 2017 4:06 am
No, my PR is just to power down USB when the serial disable function is called. This is needed to allow one to disconnect and start a different USB mode, e.g., switching from Serial to HID or from Serial to MIDI. It’s about five lines of code, ported from the bootloader’s USB powerdown code.

I am not merging in the libraries yet, as I would like to be able to make improvements to them over the next couple of weeks, as I have a project that will use them, so I may have more ideas for them.

I closed my PR to merge in the addMidiHID branch. If you want, I can give you a PR to bring the addMidiHID branch up to date with Master, but I am thinking that that branch is obsolete given the libraries.


RogerClark
Fri Dec 08, 2017 6:24 am
If the libraries are as good as, or better than the branch, then we may as well only use the libraries

arpruss
Sat Dec 09, 2017 4:03 pm
At this point, the libraries are better than the branch.

One thing I haven’t been able to get working — it also wasn’t working in the branch — is two-way HID RAW. I have one-way (device to host) transmission working, but the receive interrupt function isn’t being called.


arpruss
Sat Dec 09, 2017 6:39 pm
The HID RAW stuff is frustrating. USB MIDI works in both directions just fine, and I don’t see any significant difference in the code. I tried sending HID RAW data both from PyWinUSB and Android HID Terminal. The oscilloscope shows that there is data on the line, but I don’t know how to interpret the data.

If anybody has ideas on how to get HID RAW host-to-device working, I would welcome input. Not that I really need it for anything — just would be a nice completion to the library.


RogerClark
Sat Dec 09, 2017 7:56 pm
BTW.

Re: USB power enable and disable

If Serial.end disables power in your PR, Serial.begin should enable power, as it should be possible to all end() and then call begin()

I agree that moving the USB reset to Serial.begin() should be investigated, but I have not had time to look at the existing code to see if there are any pitfalls with this.


arpruss
Sat Dec 09, 2017 9:30 pm
Serial.begin() calls usb_cdcacm_enable() which calls usb_init_usblib() which calls (via a callback) usbInit() which powers up the USB peripheral.

Serial.end() currently calls usb_cdcacm_disable() which I think should power down the USB peripheral (it does that in my PR).

I am inclined to think the best place for the GENERIC_BOOTLOADER usb reset code for serial is usb_cdcacm_enable(), because that’s where the disconnect code is for devices that have disconnect hardware. The only issue I foresee with that is that if a user has an explicit Serial.begin(), then there will be two calls to the usb reset code. I don’t know if that’s a problem or not.


RogerClark
Sat Dec 09, 2017 11:32 pm
Serial.begin() has some code to prevent it doing anything if its already been called

if (_hasBegun)
return;


arpruss
Sun Dec 10, 2017 1:12 am
Oh, good. So putting the reset code into usb_cdcacm_enable() should work fine.

RogerClark
Sun Dec 10, 2017 5:32 am
I’m not comfortable with a function to power down the USB with no obvious way to power it back up again

I understand its done elsewhere, its just not obvious to anyone looking in the code.

Perhaps we could have a function that can do both enable and disable the USB power, or have separate functions.


arpruss
Sun Dec 10, 2017 6:46 am
Maybe some comments should just be added. The power up only happens in a call back to the serial device code, after a bunch of configuration things are done by the USBLIB. I wouldn’t want to risk moving that elsewhere.

OK.
I didnt mean to move the function. So perhaps some comments would be useful, for anyone else who investigates the USB


arpruss
Mon Dec 11, 2017 3:44 am
I’ve added comments about the powerdown and powerup to the PR.

By the way, I still can’t get RAWHID host-to-device to work, but host-to-device feature settings now work in the featuresetting branch of the library.

(In theory, one could use host-to-device feature setting to implement a software-forced reset.)


RogerClark
Mon Dec 11, 2017 6:36 am
Re: Host To Host

A few weeks ago, I did try to find if it was possible to send a command via HID, as its supposed to be bi-directional, but did not find anything useful

There was a post on AVRFreaks where someone was using VUSB for HID and wanted to send commands to the AVR but he seemed to have a roadblock with the default HID drivers on Windows, and custom drivers may be required for that functionality


arpruss
Mon Dec 11, 2017 2:32 pm
No custom drivers seem to be needed. I am using a simple python script and pywinusb to send a feature report from Windows.

arpruss
Mon Dec 11, 2017 5:39 pm
If you want to try out host-to-device USB communication, the featuresetting branch of USBHID includes examples/softjoystick which is a project that mirrors to the PC whatever report it got from the PC via USB HID feature set. (It’s not completely silly. It provides something like vJoy functionality without the need for installing vJoy drivers, so you can implement a joystick in software on the PC. That said, I don’t see a very good use case other than for testing communications.)

To test it on Windows, install it to an stm32f1, run send.py (which needs pywinusb) on the PC, and then look in the Game Controllers config tool in Windows to see if the joystick is moving. (Win-R, joy.cpl, enter, click on “Maple”, click on “Properties”) Another test is whether the fetch line matches the previous send line in the output.
$ c:/python36/python send.py
HID device (vID=0x1eaf, pID=0x0024, v=0x0200); LeafLabs; Maple, Path: \\?\hid#vid_1eaf&pid_0024#6&149a03ce&2&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
send: [3, 7, 0, 0, 0, 15, 0, 0, 0, 2, 8, 32, 128] fetch: [3, 7, 0, 0, 0, 15, 0, 0, 0, 2, 8, 32, 128]


RogerClark
Mon Dec 11, 2017 7:15 pm
Cool..

So could you send a command via HID to reboot ??


arpruss
Mon Dec 11, 2017 7:47 pm
Yeah. Just add a feature output to a HID description, and then decide on a magic string of bytes that forces a reset when it’s sent to the device.

But one would have to decide which HID description(s) to add it to, and there would be some SRAM wasted (40-300 bytes or so) depending on how one implemented it.


RogerClark
Mon Dec 11, 2017 7:54 pm
OK. it’s not so good that it needs more RAM

Also there would need to be binary tools for all platforms to send this command, as people would not necessarily have python installed


arpruss
Mon Dec 11, 2017 9:28 pm
[RogerClark – Mon Dec 11, 2017 7:54 pm] –
OK. it’s not so good that it needs more RAM

Also there would need to be binary tools for all platforms to send this command, as people would not necessarily have python installed

Personally, I think this is more trouble than it’s worth. :-) I’d rather just pull the plug or press the reset button instead of testing things on three platforms.


RogerClark
Mon Dec 11, 2017 9:53 pm
[arpruss – Mon Dec 11, 2017 9:28 pm] –

[RogerClark – Mon Dec 11, 2017 7:54 pm] –
OK. it’s not so good that it needs more RAM

Also there would need to be binary tools for all platforms to send this command, as people would not necessarily have python installed

Personally, I think this is more trouble than it’s worth. :-) I’d rather just pull the plug or press the reset button instead of testing things on three platforms.

Agreed


anv
Tue Dec 12, 2017 9:12 am
There is an usb keyboard library for arduino leonardo that support receiving keyboard leds status from the host. May be you could check how it works. I don’t remember now but if I find it I will tell you.

arpruss
Tue Dec 12, 2017 5:54 pm
I took a lot of code from libarra111’s branch and now the library implements a composite serial / HID device, with reset functionality using the standard upload tools. There is rather more flash/SRAM used because of the serial support, but the serial support should be worth it.

The only thing I couldn’t figure out to do is how to override the core’s Serial, so currently if you want to do serial i/o, you need to use CompositeSerial.

Maybe one could make a virtual USBSerial class and make the Serial instance be __weak in the core or something like that. I don’t know enough about C++ inheritance to figure this out right now.


anv
Tue Dec 12, 2017 7:43 pm
Just downloaded master branch. The example for twojoysticks does not compile.
Tried usb keyboard. USB HID is detected but can’t be configured.
Serial interface is detected and module loaded.

This is my dmesg output when I plug the device.

74281.945860] usb 1-4: new full-speed USB device number 107 using xhci_hcd
[74282.115902] usb 1-4: New USB device found, idVendor=1eaf, idProduct=0024
[74282.115904] usb 1-4: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[74282.115905] usb 1-4: Product: Maple
[74282.115905] usb 1-4: Manufacturer: LeafLabs
[74292.251940] cdc_acm 1-4:1.0: ttyACM0: USB ACM device
[74292.253017] usbhid 1-4:1.2: can’t add hid device: -71
[74292.253026] usbhid: probe of 1-4:1.2 failed with error -71
[74293.769062] cdc_acm 1-4:1.0: failed to set dtr/rts
[74306.967792] cdc_acm 1-4:1.0: failed to set dtr/rts
[74306.969538] cdc_acm 1-4:1.0: failed to set dtr/rts
[74316.062451] cdc_acm 1-4:1.0: failed to set dtr/rts
[74316.063964] cdc_acm 1-4:1.0: failed to set dtr/rts
[74322.061371] cdc_acm 1-4:1.0: failed to set dtr/rts

Source code for the program:

#include <USBHID.h>

const uint8_t reportDescription[] = {
USB_HID_ABS_MOUSE_REPORT_DESCRIPTOR(USB_HID_MOUSE_REPORT_ID)
,USB_HID_KEYBOARD_REPORT_DESCRIPTOR(USB_HID_KEYBOARD_REPORT_ID)
};

HIDAbsMouse mouse;

void setup(){
HID.begin(reportDescription, sizeof(reportDescription));
delay(1000);
mouse.move(0,0);
delay(1000);
mouse.press(MOUSE_LEFT);
mouse.move(500,500);
mouse.release(MOUSE_ALL);
mouse.click(MOUSE_RIGHT);

}

void loop(){
delay(100);
mouse.move(16384,16384);

Keyboard.write('h');
Keyboard.write('o');
Keyboard.write('l');
Keyboard.write('a');
delay(100);
}


arpruss
Tue Dec 12, 2017 8:27 pm
[anv – Tue Dec 12, 2017 7:43 pm] –
Just downloaded master branch. The example for twojoysticks does not compile.

Sorry: I changed the API without changing the example. It’s fixed now.

Tried usb keyboard. USB HID is detected but can’t be configured.

That’s not good. I’ve only tested on Windows.

1. Do you know if the libarra111 USB core works for you?

2. Can you try something super-basic like:

#include <USBHID.h>

void setup() {
USB.begin(USB_HID_JOYSTICK);
}

void loop() {
Joystick.X(0);
delay(500);
Joystick.X(1023);
delay(500);
}


arpruss
Tue Dec 12, 2017 8:44 pm
You might also try the solution here:
https://aweirdimagination.net/2015/04/0 … id-errors/

Also, you can send or post the lsusb output, like in this post: https://bbs.archlinux.org/viewtopic.php … 2#p1578802


arpruss
Tue Dec 12, 2017 10:57 pm
I’ve been trying this with an Ubuntu VM on Windows. It works when I turn off the serial in the code (#undef SERIAL_COMPOSITE in composite_usb.h in the current code version), but with serial AND keyboard, it fails.

arpruss
Wed Dec 13, 2017 1:04 am
Now it works under Android and in the Ubuntu VM. The problem was in a descriptor I grabbed from the libarra111 fork.

mrburnette
Wed Dec 13, 2017 3:41 pm
[arpruss – Wed Dec 13, 2017 1:04 am] –
Now it works under Android and in the Ubuntu VM. The problem was in a descriptor I grabbed from the libarra111 fork.

This is indeed interesting.

I played much a long time ago with the AVR-specific V-USB implementation. I also played with the ATmega32U4 “micro.”

Ray


arpruss
Wed Dec 13, 2017 4:38 pm
What I do need help with is figuring out how to make HID output (host-to-device) reports work. HID feature reports work fine in both directions.

Of course, it’s not really needed, except maybe for speed and efficiency. Everything you can do with an output report you can do with a feature report, I think.


anv
Wed Dec 13, 2017 6:39 pm
[arpruss – Wed Dec 13, 2017 1:04 am] –
Now it works under Android and in the Ubuntu VM. The problem was in a descriptor I grabbed from the libarra111 fork.

Yes!! Keyboard now works under linux. If you need tests or USB info from real joysticks, keyboard, mous or midi devices just ask me. I can copy it for you.
I.E. here is the info from a real usb keyboard:

Kernel information (dmesg) when plugging the device:
[ 579.488436] usb 1-4: new low-speed USB device number 7 using xhci_hcd
[ 579.663196] usb 1-4: New USB device found, idVendor=0461, idProduct=4e29
[ 579.663197] usb 1-4: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 579.663198] usb 1-4: Product: Wired USB Keyboard
[ 579.663199] usb 1-4: Manufacturer: PRIMAX
[ 579.666268] input: PRIMAX Wired USB Keyboard as /devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.0/0003:0461:4E29.0005/input/input19
[ 579.717495] hid-generic 0003:0461:4E29.0005: input,hidraw4: USB HID v1.10 Keyboard [PRIMAX Wired USB Keyboard] on usb-0000:00:14.0-4/input0
[ 579.723297] input: PRIMAX Wired USB Keyboard as /devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.1/0003:0461:4E29.0006/input/input20
[ 579.775720] hid-generic 0003:0461:4E29.0006: input,hiddev0,hidraw5: USB HID v1.10 Device [PRIMAX Wired USB Keyboard] on usb-0000:00:14.0-4/input1


anv
Wed Dec 13, 2017 6:59 pm
[arpruss – Wed Dec 13, 2017 4:38 pm] –
What I do need help with is figuring out how to make HID output (host-to-device) reports work. HID feature reports work fine in both directions.

Of course, it’s not really needed, except maybe for speed and efficiency. Everything you can do with an output report you can do with a feature report, I think.

May be you could check the HID-project library https://github.com/NicoHood/HID
It works OK reciving data from the host like keyboard leds. See this example (I tested it with an Arduino Leonardo and works ok):

/*
Copyright (c) 2014-2015 NicoHood
See the readme for credit to other people.

KeyboardLed example

Press a button to toogle caps lock.
Caps lock state is represented by the onboard led.
Leds are only supported on single report HID devices.

See HID Project documentation for more information.
https://github.com/NicoHood/HID/wiki/Keyboard-API
*/

#include "HID-Project.h"

const int pinLed = LED_BUILTIN;
const int pinButton = 2;

void setup() {
pinMode(pinLed, OUTPUT);
pinMode(pinButton, INPUT_PULLUP);

// Sends a clean report to the host. This is important on any Arduino type.
BootKeyboard.begin();
}

void loop() {
// Update Led equal to the caps lock state.
// Keep in mind that on a 16u2 and Arduino Micro HIGH and LOW for TX/RX Leds are inverted.
if (BootKeyboard.getLeds() & LED_CAPS_LOCK)
digitalWrite(pinLed, HIGH);
else
digitalWrite(pinLed, LOW);

// Trigger caps lock manually via button
if (!digitalRead(pinButton)) {
BootKeyboard.write(KEY_CAPS_LOCK);

// Simple debounce
delay(300);
}
}


arpruss
Wed Dec 13, 2017 7:32 pm
[anv – Wed Dec 13, 2017 6:39 pm] –

[arpruss – Wed Dec 13, 2017 1:04 am] –
Now it works under Android and in the Ubuntu VM. The problem was in a descriptor I grabbed from the libarra111 fork.

Yes!! Keyboard now works under linux.

But my changes broke feature reports on Windows. I made some more changes and it now seems to work under both Windows and Android. Can you check Linux? (I know Android is Linux, but it might use other USB drivers.)


arpruss
Wed Dec 13, 2017 9:28 pm
Output reports now work. I didn’t really have to do anything special once I fixed the descriptors: under the hood, they work just like feature reports. I am learning a bit about USB as I go along.

RogerClark
Wed Dec 13, 2017 10:45 pm
Just a thought, but I noticed someone asking about USB Mass storage…

I recall there was some old code from the leaflabs forum, which I tried a long time ago.

I presume that in theory we could add USB mass storage as a library ???


arpruss
Thu Dec 14, 2017 1:12 am
One certainly could add it. I don’t want to do it myself, as I don’t have a use case myself.

RogerClark
Thu Dec 14, 2017 3:38 am
No worries

If someone else wants it, they can add it


arpruss
Sun Dec 17, 2017 3:49 pm
I’ve made a lot of changes to the library over the last couple of days.

1. The publicly useful USB_HID_xxx macros have been renamed to just HID_xxx.
2. The main USBDevice instance should now be referred to as USB instead of HID.
3. Added a consumer control device (volume, pause/play, brightness, etc.). See the consumer example.
4. Improved flow control for host-to-device.


arpruss
Mon Dec 18, 2017 3:40 pm
Added serial number support to the library. Default serial number is 00000000000000000001. It can be specified in the USB.begin() call. You can even make it be the device ID, but then you lose any potential usefulness it might have for cryptographic purposes.

RogerClark
Mon Dec 18, 2017 8:19 pm
BTW.

i pulled your change for USB power, to my local machine, and then manually checked out the tools files ( from my local master) which had been also changed by your PR, but I think if I merge this back into my local Master (HEAD), it tracks the changes to the tool files as if they were changed twice.

So I think I will need to start again, and manually update the individual USB files, otherwise the git history is confusing as it has those changes to the tools, which are unnecessary


anv
Tue Dec 19, 2017 9:41 am
[arpruss – Mon Dec 18, 2017 3:40 pm] –
Added serial number support to the library. Default serial number is 00000000000000000001. It can be specified in the USB.begin() call. You can even make it be the device ID, but then you lose any potential usefulness it might have for cryptographic purposes.

Great job. Is it possible also to assign a text string of the device?


arpruss
Tue Dec 19, 2017 2:50 pm
What do you mean?

anv
Tue Dec 19, 2017 4:38 pm
[arpruss – Tue Dec 19, 2017 2:50 pm] –
What do you mean?

I’m talking about the ascii strings that describes the devices:

Bus 001 Device 004: ID 0bda:57f3 Realtek Semiconductor Corp. <---webcam
Bus 001 Device 003: ID 8087:0a2a Intel Corp. <-- bluetooth
Bus 001 Device 007: ID 054c:0268 Sony Corp. Batoh Device / PlayStation 3 Controller <-- PS3 joystick
Bus 001 Device 005: ID 0079:0006 DragonRise Inc. PC TWIN SHOCK Gamepad <-- arkade joystick
Bus 001 Device 006: ID 1eaf:0024 <-- STM32


arpruss
Wed Dec 20, 2017 2:17 am
Sure. When you call usb.begin(), you can do something like usb.begin(HID_JOYSTICK, 0, 0, “I made it”, “My funny joystick”). See USBHID.h for all parameters. If you want, you can replace the 0,0 with your favorite VID and PID numbers, e.g., to fool the OS into thinking you’ve got a different device than you do.

arpruss
Thu Dec 21, 2017 4:47 pm
I just switched the default PID from 0x24 to 0x04, to match the standard core PID.

arpruss
Wed Jan 03, 2018 6:06 pm
I added a no-wait option for output/feature host-to-device, so that the USB HID handler silently updates the output/feature buffers in the background without polling being needed to ensure that the sketch doesn’t miss data.

And added a keyboardwithleds example that echoes keyboard LED status to serial.


anv
Thu Jan 04, 2018 8:40 am
[arpruss – Wed Jan 03, 2018 6:06 pm] –
I added a no-wait option for output/feature host-to-device, so that the USB HID handler silently updates the output/feature buffers in the background without polling being needed to ensure that the sketch doesn’t miss data.

And added a keyboardwithleds example that echoes keyboard LED status to serial.

Great job!


arpruss
Sun Jan 07, 2018 4:17 pm
I’ve changed the main class from USBDevice to USBHIDDevice and its instance from USB to USBHID. I am going to try to make this the last change that breaks existing code that depends on the high level functions in the library, but it’s needed to future compatibility with some non-HID devices.

arpruss
Sun Jan 07, 2018 5:22 pm
I’ve integrated a simple xbox360 controller emulator. See the x360 example.

It’s not composited with serial support, unlike the standard USBHID stuff.


arpruss
Sun Jan 07, 2018 5:43 pm
I’ve also dumped USB MIDI into the USBHID library (which is somewhat poorly named now). See the mididemo example.

arpruss
Sun Jan 07, 2018 6:47 pm
And I just tried serial/HID composite on a Win 8.1 machine. With the Maple serial driver installed, HID doesn’t work. Without the Maple serial driver, serial doesn’t work. :-(

I also added a setSerial() method that lets you turn off the CompositeSerial support, which might be useful for OSes like Win 8.1. Just call USBHID.setSerial(0) before USBHID.begin().


arpruss
Sat Jan 20, 2018 3:31 am
Added boot keyboard support. See the BootKeyboard example.

arpruss
Sun Jan 21, 2018 3:12 pm
I’ve made the OUTPUT and FEATURE report APIs a bit nicer to use. As a result, I was able to make both Keyboard and BootKeyboard support LEDs more simply. You can now do:
USBHID.begin(HID_KEYBOARD);
Keyboard.begin();
...
ledState = Keyboard.getLEDs();

arpruss
Thu Feb 01, 2018 4:05 am
[RogerClark – Wed Dec 13, 2017 10:45 pm] –
Just a thought, but I noticed someone asking about USB Mass storage…

I recall there was some old code from the leaflabs forum, which I tried a long time ago.

I presume that in theory we could add USB mass storage as a library ???

In the “generalizable” branch of the library, I now have working mass storage code. I created a 12K RAM disk hosted on the stm32f1 and successfully formatted it with a hacked version mkdosfs. The API for the mass storage code will change, however.

The “generalizable” branch is meant to allow one to mix and match different “parts” of a composite USB device, e.g., mass storage + hid + serial, or midi + serial, etc. Not all combinations can be expected to work. (E.g., xbox360 + serial doesn’t work.)


RogerClark
Thu Feb 01, 2018 9:38 am
very cool

arpruss
Fri Feb 02, 2018 2:48 am
I have merged in the changes. The new library uses less RAM but can do all sorts of cool stuff, like HID+MassStorage, etc. There are limits to what combinations work, and trial and error may be required. Because there are so many combinations possible, and the changes to the library were so heavy, there is a pretty good chance of bugs. :-( But at least I made the API backwards compatible to the previous version of the library.

The Mass Storage code is based on Joe Ferner’s code. A fun example of the Mass Storage code is in examples/mass, which is probably the world’s most useless USB drive, backed by 12kb of SRAM in the stm32. The drive is pre-formatted to present as a tiny FAT12 disk, and actually seems to work on Windows 10.

Here’s an example for how to set up Keyboard/Mouse/Joystick + MassStorage:
#include <USBHID.h>
#include <USBMassStorage.h>

// supply driveSize, readFunction(offset, buff, len) and writeFunction(offset, buff, len)

void setup() {
MassStorage.setDrive(0, driveSize, readFunction, writeFunction);
MassStorage.registerComponent();
USBHID.setReportDescriptor(HID_KEYBOARD_MOUSE_JOYSTICK);
USBHID.registerComponent();
USBComposite.begin();
Keyboard.println("hello");
}

void loop() {
MassStorage.loop();
}


RogerClark
Fri Feb 02, 2018 5:22 am
Wonderful

I will try it at the weekend, when I get some free time…..


zoomx
Fri Feb 02, 2018 8:10 am
Free time! Free time! My kingdom for free time!

I will try it too!

Edit:

Just a basic test.
Got the library from the generalizable branch (there is not mass storage examples in the master branch)
loaded the mass example it doesn’t compile since in MassStorage.h there is a reference to USBComposite.h but there is only the cpp file.
So I got the missing file from the master branch and it compiles.


michael_l
Fri Feb 02, 2018 12:25 pm
Very nice work.

So it would be possible to get SD card mounted also by just implementing read and write functions ? one could use also spiffs fs and utilize board’s flash memory, although there’s not much of space .


arpruss
Fri Feb 02, 2018 4:07 pm
[michael_l – Fri Feb 02, 2018 12:25 pm] –
So it would be possible to get SD card mounted also by just implementing read and write functions ?

Yes: should be very simple (you also need to read the capacity, of course).

I wanted to try this this morning, but I couldn’t get sdfat (either the official version or victor’s version) to recognize either of the two cards I tried. I think my sd card adapter may be broken.

one could use also spiffs fs and utilize board’s flash memory, although there’s not much of space .

Right.

Also, if you just want the host to have read-only access, you can just use the flash straight with a FAT system, and include a disk image. Might be useful for distributing a small driver or script that goes with a device, I suppose.


michael_l
Fri Feb 02, 2018 4:22 pm
[arpruss – Fri Feb 02, 2018 4:07 pm] –

[michael_l – Fri Feb 02, 2018 12:25 pm] –
So it would be possible to get SD card mounted also by just implementing read and write functions ?

Yes: should be very simple (you also need to read the capacity, of course).

I wanted to try this this morning, but I couldn’t get sdfat (either the official version or victor’s version) to recognize either of the two cards I tried. I think my sd card adapter may be broken.

one could use also spiffs fs and utilize board’s flash memory, although there’s not much of space .

Right.

Also, if you just want the host to have read-only access, you can just use the flash straight with a FAT system, and include a disk image. Might be useful for distributing a small driver or script that goes with a device, I suppose.

I hacked earlier SPIFFS to work with WDxxx SPI flash memories on stm32duino. It works but the code is a bit *couch* sketchy. It’s really not a fast fs but feasible for small projects. Together with MSC that would make a nice addition.

I wonder if current libmaple/stm32duino have ready made functions for reading/writing from flash memory ?


arpruss
Fri Feb 02, 2018 6:46 pm
[michael_l – Fri Feb 02, 2018 4:22 pm] – I wonder if current libmaple/stm32duino have ready made functions for reading/writing from flash memory ?

Reading is just memcpy.

Writing is here: https://github.com/rogerclarkmelbourne/ … ies/EEPROM


arpruss
Sat Feb 03, 2018 4:54 am
I added an SD reader example. It works, but it is ridiculously slow: 11s/mb.

Testing suggests that the low speed is due to SD access rather than due to USB transmission.


michael_l
Sat Feb 03, 2018 7:22 am
Great! I’d like to get mass storage (with SD) with serial working in my project so I’ll be testing your code in the near future.

arpruss
Sat Feb 03, 2018 2:30 pm
[arpruss – Sat Feb 03, 2018 4:54 am] –
I added an SD reader example. It works, but it is ridiculously slow: 11s/mb.

Testing suggests that the low speed is due to SD access rather than due to USB transmission.

I re-ran the tests this morning and was getting 479 kb/s reading, which is way better. I have a wonky SD card breadboard adapter, so maybe when the connection is poor there are a lot of retries. At the current speed, with the card and file I was testing, reads take 50% longer than the built-in card reader on my laptop, which isn’t that bad.


arpruss
Sat Feb 03, 2018 2:34 pm
[michael_l – Fri Feb 02, 2018 4:22 pm] –
I hacked earlier SPIFFS to work with WDxxx SPI flash memories on stm32duino. It works but the code is a bit *couch* sketchy. It’s really not a fast fs but feasible for small projects. Together with MSC that would make a nice addition.

If you port SPIFFS to the internal flash, you should remember that the internal flash can only be written two bytes at a time. The SPIFFS readme suggests that the library assumes you can always turn 1s into 0s. This isn’t correct for the stm32f1 internal flash. You can turn 0xFFFF to anything, but if a memory word holds anything other than 0xFFFF, you can’t write anything to it, not even 0x0000.


arpruss
Sat Feb 03, 2018 4:40 pm
There is one more major USB device type that isn’t yet supported: audio. Anybody want to write a USBAudio plugin?

RogerClark
Sat Feb 03, 2018 8:15 pm
Audio is an interesting thought ..

Perhaps it can be used with the Pig-O-Scope code, which already can read the ADC via DMA.

Audio output is a bit more tricky, as the BluePill etc don’t have a DAC. I know there is code to do clever things with PWM to simulate a DAC but I am not sure of the system overhead

There is also Video or Camera input, as we have code that will read the OV7670 camera, at 320 x 240 at around 11 FPS.
I think the frame speed may be a limitation of the ILI9341, that we use to display the image.
( SteveStrong is the guru this)

Unfortunately I have other more pressing commitments of my time, so I can’t help with this
PS. I WIsh I had time to understand the internals of USB as I have several projects where I need to reverse engineer some USB protocols, but they are all on the back-burner because I don’t have time :-(


michael_l
Sat Feb 03, 2018 9:24 pm
[arpruss – Sat Feb 03, 2018 4:40 pm] –
There is one more major USB device type that isn’t yet supported: audio. Anybody want to write a USBAudio plugin?

Sorry for simple question but what can I do with the USB Audio – and what kind of specifications there are for USB audio interface ?


arpruss
Mon Feb 05, 2018 4:16 am
After a lot of trial and error I managed to find a way to keep the linker from linking in much unneeded code (e.g., if you want to use USBHID, it shouldn’t load mass storage, serial, etc.)

Unfortunately, I had to make some changes to the API, as my previous implementation of USB compositing used classes with virtual functions. But when such a class is initialized, automatically all the virtual functions get linked in, even if they are never used.

Two main changes:
1. USBHID.begin() does not include serial any more. To force serial to be included, use the convenience function USBHID_begin_with_serial() instead. And the USBHID.setSerial() method has been removed.
2. To add a component to the composite device, do: component.registerComponent() instead of the previous USBComposite.add(component). See the mass storage examples.

Also, I renamed the mass storage and x360 classes and/or instances.


Freakeyyy
Tue Feb 13, 2018 9:30 pm
Just got to play with the library, it’s working great, except for Serial. Is it just me or is Serial not working yet ? It shows on Device Manager but doesn’t print anything

arpruss
Wed Feb 14, 2018 2:25 pm
Are you using CompositeSerial instead of Serial as the libraryt requires?
Try the keyboardwithleds example which should echo the keyboard led status to serial.

Cpt.Credible
Wed Feb 28, 2018 4:53 pm
I just got the chance to play with this library today and I love it! I was however wondering, Is this library incompatible with the glorious Francois best (a.k.a. FortySevenEffects) MIDI library? just adding “#include <MIDI.h> in the “midiin.ino” example throws this error:
“‘myMidi midi’ redeclared as a different kind of symbol”
Is there a quick fix to this? do I need to go in and change one of the two libraries?

Aslo, on one of the three computers I have tried it on, the midi device isn’t found by the computer. (a stationary running win10) Its a blue pill board with the wrong resistor on R10 but curiously the Maple serial port shows up and works just fine. could this still be explained by the R10 resistor value? or is there something else wrong?


arpruss
Thu Mar 01, 2018 2:19 pm
[Cpt.Credible – Wed Feb 28, 2018 4:53 pm] –
just adding “#include <MIDI.h> in the “midiin.ino” example throws this error:
“‘myMidi midi’ redeclared as a different kind of symbol”

No need to change the libraries. Just change the example by replacing the midi variable in the example with something else, e.g., usbmidi.

Aslo, on one of the three computers I have tried it on, the midi device isn’t found by the computer. (a stationary running win10) Its a blue pill board with the wrong resistor on R10 but curiously the Maple serial port shows up and works just fine. could this still be explained by the R10 resistor value? or is there something else wrong?

I wouldn’t think the resistor thing would have this kind of effect given that the serial shows up. You might check if joystick shows up (e.g., use the SimpleJoystick example).

For me, the MIDI examples work on Win10pro. But I have occasionally had Windows get confused when switching between different USB devices that all have the same vendor and product ids. So if you plugged the board in in a different mode (e.g., serial or HID), you might have confused Windows. You can try deleting the old driver in the Windows device manager, and then hotplugging again, or changing the product id in the code. E.g., in my midiin example, add midi.setProductId(0x25) before calling midi.begin().


madias
Thu Mar 01, 2018 3:56 pm
Some words about Mass Storage:
Years ago I argued about the benefit of Mass Storage for a simply reason:
You have finished a project for a third person without really MCU/coding knowledge (call this protoype person “Mother”). There is a mistake in the code you have to correct it, simple for you, but the “third person” cannot upload it as we do. So the “project device” has an upload feature (combined buttons on start, on display, whatever), switching the device to Mass Storage and just plugin to computer, upload the new *.bin file -> ready.
So this should be now possible, isn’t it?

Second:
It should also be possible to switch between USB HID states (like switching from USB-MIDI to USB Mass Storage and so on)?

Regards
Matthias


arduinoob
Thu Mar 01, 2018 4:22 pm
I never heard about STM32 before today and I would like to know if the code shared above is compatible with “classic” arduino nano/pro micro.

In fact I would like to use my arduino as an emulated mass storage (like an usb drive) when plugged to a PC providing files stored from a microSD card used with a shield.

sorry for the inconvenience if my message is innapropriate but I can’t find any clue except this page from arduino : https://github.com/arduino/arduino/wiki … ehid-howto

I’m not confident with microcontrollers programming unfortunatelly :(


madias
Thu Mar 01, 2018 4:31 pm
The “classic” Arduino (ATmega 328p) has no USB physicially on chip, so you cannot use this code with this devices. So you’ll need at least a ATmega32u4 (“Arduino Leonardo”)
It’s all written here:
https://github.com/arduino-libraries/MIDIUSB
“This library allows an Arduino board with USB capabilites to act as a MIDI instrument over USB. The library is based on PluggableUSB, so is only compatible with IDE 1.6.6 and nightly builds (AVR core > 1.6.8, SAM core > 1.6.4, SAMD core > 1.6.1)
Furthermore, since PluggableUSB only targets boards with native USB capabilities, this library only supports these boards (eg. Leonardo, Micro, Due, Zero and so on)

But: You can get a STM32 “blue pill” for under 2 Euros on Ebay/Aliexpress, so try it out!

Keep in mind that the “micro” sold on Ebay/Aliexpress is mostly an Atmega 328p!

Edit: This would be your friend, but keep in mind that it costs more than a blue pill!
https://www.aliexpress.com/item/Pro-Mic … 76437.html


arduinoob
Thu Mar 01, 2018 5:03 pm
Thank you madias for your answer !!

I have the version you suggested in the link. I already use the HID.h provided by Arduino to emulate a keyboard but current work seems to only allow keyboard and mouse emulation :-/ Nothing for mass storage emulation ;-(


Cpt.Credible
Thu Mar 01, 2018 7:45 pm
[arpruss – Thu Mar 01, 2018 2:19 pm] –
No need to change the libraries. Just change the example by replacing the midi variable in the example with something else, e.g., usbmidi.

Ehem, cough, yes, of course. :oops: :D

[arpruss – Thu Mar 01, 2018 2:19 pm] –
For me, the MIDI examples work on Win10pro. But I have occasionally had Windows get confused when switching between different USB devices that all have the same vendor and product ids. So if you plugged the board in in a different mode (e.g., serial or HID), you might have confused Windows. You can try deleting the old driver in the Windows device manager, and then hotplugging again, or changing the product id in the code. E.g., in my midiin example, add midi.setProductId(0x25) before calling midi.begin().

I’ll try that!


petr
Thu Mar 01, 2018 11:01 pm
I have just found this thread (was following the libarra’s thread where someone just posted a link here, thanks!) and I must say wonderful work!!

I have an existing device/project using HID RAW for high speed data transfer protocol that is implemented on ATMEGA16U2 using LUFA library. I’ll try porting it to STM32 now thanks to this new library that supports HID RAW, eventually. Thank you again, @arpruss.

Also, the recent work on USB mass storage is exciting. The possible simple file upload for firmware upgrade is just dream come true :)


arpruss
Fri Mar 02, 2018 2:47 am
[petr – Thu Mar 01, 2018 11:01 pm] – I have an existing device/project using HID RAW for high speed data transfer protocol that is implemented on ATMEGA16U2 using LUFA library. I’ll try porting it to STM32 now thanks to this new library that supports HID RAW, eventually.

I should say that HID RAW is not as well tested as other parts of the library. So I won’t be surprised if there are bugs. It’s also set to do host-to-device transmission over the control endpoint, which may not be ideal for speed.


anv
Fri Mar 02, 2018 8:00 am
[madias – Thu Mar 01, 2018 3:56 pm] –
You have finished a project for a third person without really MCU/coding knowledge (call this protoype person “Mother”). There is a mistake in the code you have to correct it, simple for you, but the “third person” cannot upload it as we do. So the “project device” has an upload feature (combined buttons on start, on display, whatever), switching the device to Mass Storage and just plugin to computer, upload the new *.bin file -> ready.

I can think on many uses for USB-Storage. I.e. a data logger that can be read just plugging an usb cable and readig as a read-only disk. There is no need to have a complete filesystem on memory. The FAT structures can be simulated on software.


arpruss
Fri Mar 02, 2018 7:19 pm
[madias – Thu Mar 01, 2018 3:56 pm] – You have finished a project for a third person without really MCU/coding knowledge (call this protoype person “Mother”). There is a mistake in the code you have to correct it, simple for you, but the “third person” cannot upload it as we do. So the “project device” has an upload feature (combined buttons on start, on display, whatever), switching the device to Mass Storage and just plugin to computer, upload the new *.bin file -> ready.
So this should be now possible, isn’t it?

I think you could do this. You’d probably have to have a virtual disk in the upper 64K of flash, and then you have the host write to that disk, and then you flash from it. But you’d need to worry about bricking the device mid-flash. I think the way I’d implement it would be by writing a custom bootloader which first checks if there is data for flashing in the upper 64K of flash, and if so, it flashes that data and marks it erased. To make the custom bootloader as simple as possible, I would store the .bin file in a container that divides it up into 492 byte chunks (say) and adds a 20 byte header to each chunk, to produce a 512 byte sector. The header would have some magic characters as well as information about where in flash the 492 bytes are supposed to go. The bootloader could then just scan the upper 64K of flash for the magic characters, and write any chunks it finds, and then erase their magic characters after writing them. This would save the bootloader from having to understand FAT.


Second:
It should also be possible to switch between USB HID states (like switching from USB-MIDI to USB Mass Storage and so on)?

Yes. I do it in my Gamecube USB adapter, which can emulate both a standard USB HID device (joystick/keyboard/mouse), or an XBox controller, or dual joysticks, and can switch between the devices by software or hard button.

Basically, you just set up one device, call its begin() method, and then call the end() method, set up another device, and call the begin() method. E.g.:
USBHID.begin(HID_KEYBOARD);
...
USBHID.end(HID_KEYBOARD);
MassStorage.setDrive(0, sizeof(image), read, write);
MassStorage.begin();
...
MassStorage.end();
USBHID.begin(HID_JOYSTICK);
...
USBHID.end();


arpruss
Fri Mar 02, 2018 7:25 pm
[arduinoob – Thu Mar 01, 2018 4:22 pm] –
I never heard about STM32 before today and I would like to know if the code shared above is compatible with “classic” arduino nano/pro micro.

No, the code is specific to the STM32F1 platform.


RogerClark
Fri Mar 02, 2018 8:31 pm
IMHO the problem with a USB mass storage bootloader is its size. We can barely squeeze the DFU version into 8k

I Hve tried mass storage bootloaders which don’t implement FAT format storage, which are quite small ( not sure if they are less than 8k) but they need special programs on Windows to upload to a non formatted storage device.
Which only makes them marginally better than the DFU based bootloader.

I suppose DFU needs a driver, but you may as well use HID RAW if you need a special tool to upload.


Cpt.Credible
Sat Mar 03, 2018 8:56 am
I really like the idea of updating firmware via emulated mass storage device! An example sketch or tutorial on how to get this to work would be epic!

nicolas_soundforce
Sat Mar 03, 2018 12:00 pm
This is fantastic, I was using the addMidiBranch until now, I can’t wait to try it out. Thank you so much for the effort!

Is there a way to set the device name in the user program ? So far I was editing the header files. It worked but I am switching often so not very practical.


arpruss
Sat Mar 03, 2018 3:12 pm
[nicolas_soundforce – Sat Mar 03, 2018 12:00 pm] – Is there a way to set the device name in the user program ? So far I was editing the header files. It worked but I am switching often so not very practical.

USBComposite.setManufacturerString("My Garage");
USBComposite.setProductString("My Thingy");


arpruss
Sat Mar 03, 2018 3:17 pm
I noticed that if you had capslock on in my Windows keyboard, the capslock state affected the USB HID keyboard as well. That would probably result in undesired operation. For instance, if your stm32f1 device was a password manager, a capslock state on the host keyboard would mangle things. My quick and dirty fix was to use the LED capslock status in the keyboard code to swap case as needed. Now, Keyboard.println(“Hello world”) will type “Hello world” regardless of the capslock state of a Windows host. It would be nice if someone with a conveniently accessible Linux system were to check if this works for them, too.

If you like this behavior, you must call Keyboard.begin() before calling any keyboard functions. (Normally, Keyboard.begin() is optional, but it’s needed for LED state.)

If you don’t like this behavior, you can call Keyboard.setAdjustForHostCapsLock(false).


vitor_boss
Sat Mar 03, 2018 5:51 pm
Hi, this code could run as HID only? I’m thinking how to improve OpenProg programmer and a STM32 is perfect for that.

http://openprog.altervista.org/OP_eng.html


nicolas_soundforce
Sat Mar 03, 2018 9:32 pm
[arpruss – Sat Mar 03, 2018 3:12 pm] –

[nicolas_soundforce – Sat Mar 03, 2018 12:00 pm] – Is there a way to set the device name in the user program ? So far I was editing the header files. It worked but I am switching often so not very practical.

USBComposite.setManufacturerString("My Garage");
USBComposite.setProductString("My Thingy");


arpruss
Sun Mar 04, 2018 5:18 am
[vitor_boss – Sat Mar 03, 2018 5:51 pm] –
Hi, this code could run as HID only?

Sure. Do you mean raw hid? There is example code for that.


Cpt.Credible
Tue Mar 06, 2018 12:14 pm
I am having a hard time with the issue where Windows no longer detects the USB device.

As mentioned earlier, after mucking about trying to set up MIDI and serial in parallel for debugging, occasionally setting code up that results in “device malfunctioned” And suddenly, for reasons unbeknownst to me, my computer will no longer detect the MIDI USB device. It still detects the Maple Serial device though. And If I plug it into a different machine, it shows up fine as both the maple serial device and the Midi device.

And when I say it doesn’t show up, I mean it doesn’t show up at all. Windows doesn’t acknowledge that it exists at all. no “unknown device” no “device malfunctioned” it is completely invisible to both device manager and the tool USBdeview by Nirsoft.

[arpruss – Thu Mar 01, 2018 2:19 pm] –
You can try deleting the old driver in the Windows device manager, and then hotplugging again, or changing the product id in the code. E.g., in my midiin example, add midi.setProductId(0x25) before calling midi.begin().

As arpruss suggested, changing the product ID to something else using USBComposite.setProductId() allows my computer to detect and use the MIDI device, but that breaks the maple serial driver that is expecting a Product ID of 4. And on the note of deleting drivers, no amount of driver deletion seems to help. I even used USBdeview to uninstall ALL USB devices ever connected to the machine to no avail.

This magical disappearing has happened on 2 of my machines now, one win10 and one win7 and I appreciate that this is not really an issue with this glorious library, more an issue with my ignorance and my PC. But I am tearing out my hair and was wondering if anybody knows how to fix this.

Is the device blacklisted somewhere at a low level? Is it some hardware on the motherboard that has decided to start ignoring this device? should I just give in and use hardware serial for debugging (not optimal as it seems to be blocking and causing audio dropouts (I’m making a synthesizer))

Any insight or help would be greatly appreciated

EDIT:
All tools for removing “ghost devices” and removing all traces of previously connected devices failed, “Ghostbuster” and “USBOblivion”. What worked though was programming the stm32f103c with the midiout example, upon which it erroneously showed up as a Serial device that wouldn’t start. Right clicking and selecting remove device and uninstall driver allowed it to be rediscovered as a midi device.


florisla
Tue Mar 06, 2018 9:04 pm
[Cpt.Credible – Tue Mar 06, 2018 12:14 pm] –
And when I say it doesn’t show up, I mean it doesn’t show up at all. Windows doesn’t acknowledge that it exists at all. no “unknown device” no “device malfunctioned” it is completely invisible to both device manager and the tool USBdeview by Nirsoft.

When it’s gone missing, do you do Action -> Scan for hardware changes? I’ve had to do that on many occasions so Windows would ‘re-discover’ a device for which I removed (disabled + deleted!) the driver.

Also, does a reboot of the PC help at all?


arpruss
Wed Mar 07, 2018 5:49 am
1. You can install the serial driver for a different product id. Just edit the batch file.

2. Have you set your device manager to view hidden devices? https://technet.microsoft.com/en-us/lib … 84583.aspx


Cpt.Credible
Wed Mar 07, 2018 8:19 am
[arpruss – Wed Mar 07, 2018 5:49 am] –
1. You can install the serial driver for a different product id. Just edit the batch file.

That is handy to know!

[arpruss – Wed Mar 07, 2018 5:49 am] –
2. Have you set your device manager to view hidden devices? https://technet.microsoft.com/en-us/lib … 84583.aspx

Yes, and rebooted, but as I mentioned in the edit it seems like somewhere there was something data I couldn’t find in the registry or using any of the USB device fixing tools I have found that made the computer confused about the MIDI device. Making it show up as ONLY the midi device using the midiout example and then uninstalling the incorrectly recognized “Serial device unable to start” in device manager, fixed the situation. I spoke to some other developers familiar with developing USB and the message I got is that this is a known pain in windows and I should be using linux to develop something like that :)

On a related note, is there anything else needed in setup() in the midiin example in order to use serial alongside with midi? should there be a CompositeSerial.begin(250000) or something? or is that all handled in the USBComposite.begin()? should I be able to just add a CompositeSerial.println(“Hello world”) in the main loop?


arpruss
Wed Mar 07, 2018 2:55 pm
[Cpt.Credible – Wed Mar 07, 2018 8:19 am] –
On a related note, is there anything else needed in setup() in the midiin example in order to use serial alongside with midi? should there be a CompositeSerial.begin(250000) or something?

No. See the README file, which alas is still unfinished. CompositeSerial is a plugin, and the only time you call a plugin’s begin() method is if you are making a simple USB device (with only one plugin). Otherwise, you register the plugins with plugin.registerComponent() and call USBComposite.begin().

or is that all handled in the USBComposite.begin()? should I be able to just add a CompositeSerial.println(“Hello world”) in the main loop?

All you need is the CompositeSerial.println(). Note that there already are calls to CompositeSerial.println() in the noteOn and noteOff handlers in the example.


Freakeyyy
Wed Mar 07, 2018 10:19 pm
Hello,

I was wondering what was the difference between “BootKeyboard” and “Keyboard ? Also is it possible to have NKRO capability for the keyboard ? It would be interesting for building mechanical keyboards. Here are some notes regarding nkro https://github.com/tmk/tmk_core/blob/ma … B_NKRO.txt
https://forum.pjrc.com/threads/23993-Te … O-Keyboard


arpruss
Wed Mar 07, 2018 11:22 pm
[Freakeyyy – Wed Mar 07, 2018 10:19 pm] – I was wondering what was the difference between “BootKeyboard” and “Keyboard ?

BootKeyboard cannot be composited with another USB device, but works in system BIOS.

Also is it possible to have NKRO capability for the keyboard ? It would be interesting for building mechanical keyboards.

The default is 6KRO. You can try to increase that to any number you wish, at the expense of slowing down the data transmission and using a bit more memory. To increase it, edit USBHID.h and change the HID_KEYBOARD_ROLLOVER value. This is untested: let me know if it works for you.

It’s possible you will run into trouble above 62. Or above 6. Like I said, it’s not tested.


Cpt.Credible
Thu Mar 08, 2018 4:38 pm
[arpruss – Wed Mar 07, 2018 2:55 pm] –
Note that there already are calls to CompositeSerial.println() in the noteOn and noteOff handlers in the example.

Are we using the same example? I am using https://github.com/arpruss/USBHID_stm32 … midiin.ino
all I can see in the in the noteOn and noteOff handlers are calls to tone() and noTone()

Is there a more recent version of the library I should be using?


arpruss
Fri Mar 09, 2018 3:54 am
[Cpt.Credible – Thu Mar 08, 2018 4:38 pm] –

[arpruss – Wed Mar 07, 2018 2:55 pm] –
Note that there already are calls to CompositeSerial.println() in the noteOn and noteOff handlers in the example.

Are we using the same example? I am using https://github.com/arpruss/USBHID_stm32 … midiin.ino
all I can see in the in the noteOn and noteOff handlers are calls to tone() and noTone()

Is there a more recent version of the library I should be using?

Oh, I guess I had the code inserted for testing purposes, but not committed.


arpruss
Mon Mar 12, 2018 1:30 am
I added the convenience USBComposite.isReady() method for checking if the USB device is connected with the host and configured. Checking this before sending data will prevent some hangs if the USB connection gets disconnected. (Some but not all hangs. There is always a chance of a disconnect between the isReady() call and the transmission.)

madias
Wed Apr 04, 2018 10:56 am
I played a little bit around with this superb approach getting USB HID to work
Board: Maple mini

  • SD-Card example works better as expected (decent speed, even without “ex” – I was even able to play MP3 from card)
    “Consumer” example is tricky on my Macbook ;) (Hitting the two small buttons right (perpetual bootloader) before the light goes out!)
    The mass storage example does not work: Even on Windows or OSX the generated containing device is empty (no files on it). Has anybody checked this?

On OSX (El Captain 10.11.6, Macbook Pro middle 2009) playing with USB-HID can be dangerous. After some examples (I think “consumer”) I wasn’t able to communicate with the maple mini anymore (not even in perpetual bootloader mode or rebooting the system). So I flashed under Windows a simple empty code for getting the maple working again. But this is a OSX specific problem, so it should not matter)

But all in all: Everything is working correct and it’s a major step forward using USB-HID stuff without using an alternative Repro.

So: Thanks Arpuss!


arpruss
Wed Apr 04, 2018 2:56 pm
[madias – Wed Apr 04, 2018 10:56 am] –
The mass storage example does not work: Even on Windows or OSX the generated containing device is empty (no files on it). Has anybody checked this?[/list]

I am pretty sure the image in image.h is empty. But you may be able to copy a small file to the drive from the host. At least, last I was testing it on Win10, I could. It wouldn’t surprise me, however, if some operating systems had trouble with a FAT-12 image that is less than 12K in size.

Of course, any file you copy will disappear when you power off the device, as the storage is in RAM.

On OSX (El Captain 10.11.6, Macbook Pro middle 2009) playing with USB-HID can be dangerous. After some examples (I think “consumer”) I wasn’t able to communicate with the maple mini anymore (not even in perpetual bootloader mode or rebooting the system). So I flashed under Windows a simple empty code for getting the maple working again. But this is a OSX specific problem, so it should not matter)

Maybe setting a different USB product ID from the default one when experimenting would help? I am guessing that OSes get confused when you switch USB device types without changing the vendor/product IDs.


john.carter3
Wed Apr 11, 2018 5:44 pm
[michael_l – Fri Feb 02, 2018 4:22 pm] –
I hacked earlier SPIFFS to work with WDxxx SPI flash memories on stm32duino. It works but the code is a bit *couch* sketchy. It’s really not a fast fs but feasible for small projects. Together with MSC that would make a nice addition.

I wonder if current libmaple/stm32duino have ready made functions for reading/writing from flash memory ?

Do you share the SPIFFS hacked?


arpruss
Sat Apr 14, 2018 3:05 pm
A quick note: The library is now bundled with Roger’s core.

madias
Sat Apr 14, 2018 7:54 pm
+1
For me the USB-HID (library) is one of the best features even a little bluepill can provide making it to an outstanding little beast.

Cpt.Credible
Fri Apr 27, 2018 2:45 pm
[arpruss – Sat Apr 14, 2018 3:05 pm] –
A quick note: The library is now bundled with Roger’s core.

sweet


nicolas_soundforce
Sat May 12, 2018 7:16 am
When I am using the MIDI inputs handlers, the blue pill seems to crash, even when doing nothing in those.
So as soon as the Blue Pill USB MIDI device receives a MIDI message, the main program simply stops running.

Anybody sucesfully used USB MIDI input ? Is this tested ?

I am using the version including in the last repo.

Thanks,
Nicolas.

class myMidi : public USBMidi {
virtual void handleNoteOn(unsigned int channel, unsigned int note, unsigned int velocity) {

}

virtual void handleNoteOff(unsigned int channel, unsigned int note, unsigned int velocity) {

}

virtual void handleProgramChange(unsigned int channel, unsigned int program) {

}
};


arpruss
Sun May 13, 2018 1:37 pm
Does the midi input example code work for you?

Mirko
Thu Jun 07, 2018 11:32 am
Let me start with a big “Thank you” @ arpuss. Your USB HID library is working quite well for me …. had to uninstall the Maple serial driver to get it work but now it is working very well :D THANKS!

I am building a sim racing button box with LCD display, magnetic shifters (joystick buttons) and dual clutch paddles (joystick axis).
While testing the joystick axis I noticed that I can only send values from 0 to 1023 for the joystick movement.
When reading my analog clutch (analogRead) I have a 12bit resolution (0 to 4096) which I would like to retain.

In “Joystick.cpp” you have
void HIDJoystick::X(uint16_t val){
if (val > 1023) val = 1023;
joyReport.x = val;

safeSendReport();
}


Pito
Fri Jun 08, 2018 7:44 am
Started to play with the HID library (so be patient with me, a standard user only).
Tried sdcardreader, mass, absmouse, jigglemouse and mouse jiggler examples.
With Blue103ZET (sdcardreader, STLink upload) and the BluePill (the others, stm32duino bootloader latest).
I uninstalled the HID-bootloader device from my previous exercises.

I got “USB device not recognised” or it installed Maple Serial with SerNum 00000000000000000001 and I see no activity or any special HID device installed (watched with usbdeview).
Win7 64bit here.
Can somebody confirm some of the examples work with Win7 64bit and BPill plz?
What I missed or did wrong way?

PS: I managed to get “mass” working, it even remembers the disk content when plugged off the usb port (powered via stlink) :)
No fun with mouse yet..


Pito
Fri Jun 08, 2018 4:25 pm
With flashed in a mouse demo, when I insert BPill into my notebook, the mouse arrow always jumps into the middle when moved somewhere, so it seems it works somehow.
I get this usbdeview:

Maple Composite.jpg
Maple Composite.jpg (59.32 KiB) Viewed 760 times

ag123
Fri Jun 08, 2018 5:08 pm
wanted to get started playing with this as well, oh btw my guess is if you use a vid/pid that of a mouse / keyboard and show up as a hid, windows may ‘auto install’ the necessary drivers :)

Pito
Fri Jun 08, 2018 6:46 pm
So, tried again with my 103ZET (64kB+512kB of sram and an sdcard socket).
Flashed in the stm32duino bootloader (the generic one). Maple Serial uninstalled (driver deleted).
Compiled (Sloeber) the sdreader demo (set the sdcard’s /CS and the LED pins properly, SdFat (not Ex)), uploaded.

Inserted a 16GB CL10 samsung sdcard into the 103ZET’es socket.

After re-plugging the 103ZET (and cleaning up the old mess with usbdeview), waiting several seconds, I got a window saying the sdcard needs to be reformatted (used in android). I put the sdcard off and reformatted under Win7 (SDformatter). Put the sdcard back into 103ZET, re-plugged and I got again the window saying sdcards needs to be reformatted.

I clicked ok and got the standard Win formatting window offering me beefy 2.92GB/FAT32 size. Ok, understood, started with formatting. After about a ~minute it finished fine :shock: and I re-plugged the 103ZET again.

After about 10 secs waiting I got a window with a new drive E:, opened it, was empty, therefore I started to copy a 160MB large Sloeber zip file on it. The copying started with a standard copy window, indicating 13minutes and 216kB/sec speed. While storing the file I wrote this report :)
It finished ok.

Re-plugged the 103ZET again. Opened E: and checked the file’s sha-1 (took several minutes to read) and it passed.. Nice.. 8-)

PS: I put the sdcard off the 103ZET’es sdcard socket and double checked under Win7 again, the sha-1 passed..


arpruss
Fri Jun 08, 2018 7:04 pm
I am not sure why the reformatting was needed. If you can figure it out, that would be great.

Note that my mouse example is an absolute rather than the more usual relative mouse. (The JiggerMouse example that I added yesterday is a relative mouse.)


ag123
Sat Jun 09, 2018 2:36 am
[Pito – Fri Jun 08, 2018 6:46 pm] –
So, tried again with my 103ZET (64kB+512kB of sram and an sdcard socket).
Flashed in the stm32duino bootloader (the generic one). Maple Serial uninstalled (driver deleted).
Compiled (Sloeber) the sdreader demo (set the sdcard’s /CS and the LED pins properly, SdFat (not Ex)), uploaded.

Inserted a 16GB CL10 samsung sdcard into the 103ZET’es socket.

After re-plugging the 103ZET (and cleaning up the old mess with usbdeview), waiting several seconds, I got a window saying the sdcard needs to be reformatted (used in android). I put the sdcard off and reformatted under Win7 (SDformatter). Put the sdcard back into 103ZET, re-plugged and I got again the window saying sdcards needs to be reformatted.

I clicked ok and got the standard Win formatting window offering me beefy 2.92GB/FAT32 size. Ok, understood, started with formatting. After about a ~minute it finished fine :shock: and I re-plugged the 103ZET again.

After about 10 secs waiting I got a window with a new drive E:, opened it, was empty, therefore I started to copy a 160MB large Sloeber zip file on it. The copying started with a standard copy window, indicating 13minutes and 216kB/sec speed. While storing the file I wrote this report :)
It finished ok.

Re-plugged the 103ZET again. Opened E: and checked the file’s sha-1 (took several minutes to read) and it passed.. Nice.. 8-)

PS: I put the sdcard off the 103ZET’es sdcard socket and double checked under Win7 again, the sha-1 passed..

wow, that’s pretty good, i’m wondering how far we can push the 216 KB/s speed, in theory usb 2.0 full speed is capable of 10 mbps which i’d guess could give closer to 1MB per sec :D


Pito
Sat Jun 09, 2018 7:14 am
It seems the speed is somehow limited with USB and overhead (stm32F103ZET @72MHz).
With SdFat or SdFatEX, and
if (sd.begin(SD_CHIP_SELECT, SD_SCK_MHZ(36)))

ag123
Sat Jun 09, 2018 4:30 pm
i think the ‘reformatting’ issue is probably due to a format that windows don’t recognise or deem corrupt
i’ve had some sd cards with linux partitions which windows give those ‘reformat’ prompts with ‘ordinary’ sd card readers
however, i’m not too sure if there is anything else more than the on disk/card partition (data) format which may cause the prompts

fredbox
Sat Jun 09, 2018 5:16 pm
Back in the days when the original Barnes and Noble Nook was a hot e-reader, there was great interest in booting from a micro sd card. At that time, some observed that class 10 sd cards performed noticeably worse than some class 2 cards. The trick to getting shorter boot times was to use a benchmark utility like CrystalDiskMark and find a card that had good 4K read/write performance. Most all cards had good performance on large files, but only a few had good 4K performance. There was a Sandisk class 2 card that outran them all. This is from nearly 10 years ago, I suspect the sd cards have improved in the meantime.

ag123
Sat Jun 09, 2018 5:46 pm
i’d think at this stage usb mass storage is probably not (yet) tuned/optimised to the max, tuning it is labor intensive involving finding out where are the ‘spaces’ that could be utilized better (e.g. ‘standalone’ mass storage rather than combine with hid / serial etc) . my guess is that if one is able to run it on better hardware e.g. stm32f103 with more sram – the high density series or even for that matter a stm32f407 and pushing the limits of spi so that the speeds between sd cards and stm32 is at least 1 MB per sec, we’d probably see how far usb 2.0 full speed can achieve for usb mass storage.

tuning / optimizing it on the stm32f103 c8 or cb could be rather challenging given its 20k sram limits, if we keep a ‘buffer’ of 4k there is 16k left for ‘everything else’ and usb needs its own buffers. currently my guess is that most of the classes and libraries are pretty much modular than ‘optimised to bare metal’, in a sense if we do dedicated optimization between spi and usb and solely for usb mass storage it could pretty much push the limits of what is possible. but keeping it modular would simplify maintenance, make codes more readable, less bugs etc and that it would be easier to ‘plug and play’ modules

i’m thinking that a usb bus with several devices could also be very busy and could in itself be its own bottleneck rather than stm32 itself
just 2 cents


Pito
Sun Jun 10, 2018 8:40 am
With an old 512MB sdcard:
1. 10MB file copy PC->BlueZET: 33secs, 303kB/sec
2. 10MB file copy BlueZET->PC: 21secs, 476kB/sec
With the 10MB file on the sdcard the E: window appears 3secs after plugging in the BlueZET into the usp port.

ag123
Sun Jun 10, 2018 1:23 pm
that looks pretty fast even in an ‘unoptimised state’, but what seem a little less certain is that vs usb throughput of 10 mbps full speed max, i’m not too sure if usb host multiplex between devices and wait a little in turn for each device etc.

f3flight
Mon Jun 11, 2018 12:53 am
Hi arpruss,

I’m running into an issue when using your lib, basically the device hangs as soon as it goes into any code related to USB. First of all, no matter which example I test, I only see “Maple Serial” in devices (using Windows),so no additional devices appear. If I just use blink example it works ok, so there’s no issue with flashing the chip. However if I use any of the USBComposite examples, the board doesn’t do anything. If I modify example to blick a few times before executing USB function (i.e. before Keyboard.print()), it blinks and then hangs. Commenting use of such USB function makes the device run it’s loop without issues.

Any ideas why this could be? I think the most direct indicator of the issue is that no additional device appears in the system. Could it be because I have not replaced the default 10kOhm resistor R10? As I mentioned before, device shows up as DFU ok (when using bootloader_only bootloader), as well as Serial (when using bootlear+empty scketch type of bootleader), and I can reflash it using Arduino IDE “stm32duino bootloader” mode without issues. I uploaded bootleader using J-Link, if that matters.


Pito
Mon Jun 11, 2018 9:06 am
..you have to uninstall Maple Serial, and delete its driver as well..

viewtopic.php?f=13&t=2926&start=120#p46139


f3flight
Mon Jun 11, 2018 4:32 pm
Pito,

Thank you, that helped!

arpruss, Pito,

Now I’ve found out that USBMIDI is not compatible with other components. WHich is not the case with main Arduino libs, there they’re based on some “pluggableUSB” module and I can instantiate Serial + Keyboard + Mouse + MIDI just by including headers Keyboard.h, Mouse.h MIDIUSB.h and having “Keyboard.begin()…” in my setup. With USBComposite I have this code:

#ifdef _LIBMAPLE_STM32_H_ //my goal is to make the same app compile on stm and arduino so I'm testing this #ifdef thing... works ok
#include <USBComposite.h>
#include <USBMIDI.h>
#endif

void setup() {
USBHID.setReportDescriptor(hidReportKeyboardMouse); // most likely this is not compatible as MIDIUSB is also a HID device?
USBComposite.clear();
CompositeSerial.registerComponent();
USBHID.registerComponent();
//USBMIDI.registerComponent(); // if I uncomment this, the device is not recognized
USBComposite.begin();
}

void loop() {
delay(10000);
}


arpruss
Tue Jun 12, 2018 2:04 pm
I would experiment with the order and combination of components. Try midi+serial and midi+hid.
I think Windows doesn’t recognize all possible combinations.

arpruss
Wed Jun 13, 2018 3:32 pm
I did some experiments with Win10.

HID+MIDI+Serial can’t seem to work all together.

MIDI+Serial works.

MIDI+HID works.

Serial+MID and HID+MIDI didn’t work, due to a bug in the library that required MIDI to be the first registered component. I just fixed the bug. It doesn’t help with HID+MIDI+Serial. Maybe that’s just too much for Windows to handle.


Pito
Wed Jun 13, 2018 4:51 pm
Statistically it is more probable the issue is in the library than in the WinX :)

I think the most attractive combo would be the Serial + Mass Storage..


arpruss
Wed Jun 13, 2018 9:10 pm
[Pito – Wed Jun 13, 2018 4:51 pm] –
I think the most attractive combo would be the Serial + Mass Storage..

That works fine.


arpruss
Wed Jun 13, 2018 10:01 pm
I found why some combinations don’t work and added this to the readme file:

There are 320 bytes of hardware buffer memory available after endpoint 0 is taken into account. The following
are the buffer memory needs of the current components:

* USB Serial: 144 bytes

* USB HID: 64 bytes

* USB Mass Storage: 128 bytes

* USB MIDI: 128 bytes

* XBox360 controller: 64 bytes

This places a limit on what combinations can be used together. For instance, HID+Mass storage+MIDI should be theoretically
OK (320 bytes), but Serial+HID+Mass storage (336 bytes) will fail (and return false from USBComposite.begin()) due to
lack of memory.


arpruss
Thu Jun 14, 2018 9:33 am
I’m adding code to control the buffer sizes. I’ve just added it in the repository to the composite serial code, and may add it to the other plugins, too. For instance, you can now do:
void setup() {
USBHID.setReportDescriptor(hidReportKeyboardMouse);
USBComposite.clear();
USBMIDI.registerComponent(); // 128 bytes of PMA
USBHID.registerComponent(); // 64 bytes of PMA
CompositeSerial.setRXPacketSize(32);
CompositeSerial.setTXPacketSize(32);
CompositeSerial.registerComponent(); // 80 bytes of PMA (cannot control size of control channel PMA)
USBComposite.begin(); // total 272 bytes of PMA, out of 320 available
}

arpruss
Sun Jun 17, 2018 7:57 pm
I’ve added code so you can control packet size in HID and MIDI, too, and some more information on combining plugins has been added to the README.md file.

arpruss
Thu Aug 16, 2018 2:49 pm
I’ve made major revisions to the library to save flash and RAM. Previously, there were lots of convenience instances like BootKeyboard and USBHID defined. In the new version, the only convenience object is USBComposite. Everything else needs to be explicitly instanced. This requires minor rewrites to all code using the library.

See: https://github.com/arpruss/USBHID_stm32 … O-0.90.txt

Also, note that all examples have been updated to the new API.


Leave a Reply

Your email address will not be published. Required fields are marked *