Topic: Option to Not include all the USB libraries (Leonardo & compatibles) (Read 5645 times)previous topic - next topic

I've been working with a Leonardo compatible (Sparkfun Pro Micro, using the 32u4) and with the 1.0.1 version of the IDE I had the opportunity to compare the ProMicro and Leonardo build processes. What I was a bit dismayed to find was that all the USB libraries are loaded regardless of whether they are needed or used.

In other words, even if your sketch does not use keyboard, mouse, or Serial classes, when the sketch is compiled all the libraries for keyboard, mouse, and CDC serial are included. It seems that this is controled in a bunch of core files which are testing " if defined(USBCON) ...." This is defined in Avrdude's conf file, and I believe it would apply for any Avr chip that has on-board USB.

It also concerns me for the future, if more native USB functions are added (eg. joystick, midi, are two I've seen requested) then it seems likely these might be added the same way as the existing functions, and would end up being part of every sketch whether used / needed or not.

The reason I find this excessive is that the USB libraries seem to add about 3kB to the size of the sketch. So if your project does not use any of the USB routines, you're wasting about 10% of the available flash space for un-needed code.

When the USB libraries are not included, the only drawback I have encountered is that the board does not auto-reset when you try and load a new sketch. This is a minor inconvenience though as you have already got the 1.0.1 IDE set to let the Leonardo board fall-back on a manual reset incase the auto-reset does not work. (This seems to be hardcoded to the Leonardo board however, rather than being common to any board using the 32u4. It would be nice to expand that fall-back upload method to be based on the chip type rather than the bootloader name.)

I understand that for friendliness and compatibility it would be preferable to keep the USB libraries being always-loaded as a default behavior, but it would be great to have the option to override that behavior and have the libraries omitted. Perhaps change the core files from testing USBCON to testing some other build-time define, which would be included in the boards.txt file by default? Then overriding it would mean only editing boards.txt rather than having to go through a half-dozen or so core files?

In the future, we'd like to find a way to control which USB libraries / classes / capabilities are loaded in a sketch. In particular, we'd like to avoid loading the HID (mouse and keyboard) support if you don't use it - allowing for other USB classes on those endpoints. Currently, there's a Mouse.begin() and Keyboard.begin() function; ideally, if you didn't call those, the Mouse and Keyboard classes wouldn't be loaded (avoided both the flash and endpoint usage). The hope is to change the core in the future to work that way. We try to avoid using preferences in the boards.txt file to control things that aren't actually related to the board (otherwise, the number of boards needed would expand exponentially as you added preferences).

As you say, CDC is used for the auto-reset, so we might not disable that by default.

Why not include USB stuff as libraries instead of as a part of the core? The IDE already searches for #include to see if you want to compile in a library, so just strip those classes from the core and add them as libraries into the libraries folder.

I think the auto-reset thing is a bad design, I'd rather use a button on HWB, I do on all my own designs, I own a Teensy++ and I've actually soldered a tiny tactile switch between HWB and GND. The HWB pin doesn't do anything else so it's not even considered a waste.

That would be much more elegant and friendly if it could omit the HID stuff until added by a .begin() statement. My mindset was more in coming at it from a 'hacking' perspective and what would be easiest for an 'advanced' user to modify, while leaving it all simple and unchanged by default.

What I have found as a relatively straightforward hack is in the core files, in main.cpp if I comment out the USB.attach() line, the USB is never initialized and the compiler optimizes away all the USB code even though it was included in the sources. So there's no HID but also no CDC either, and the compiled sketch is about 3kB smaller. There's also about 50bytes of RAM freed up.

Anyhow, thanks for the replies! If I can help somehow I will, but my C / C++ are not great.

I think it's a good idea to include HID only when used but agree with mellis: CDC should always be included by default to preserve auto-reset for new users. That's been a core feature of Arduino for years and I think it's a very nice UX choice. With no CDC there's no serial port and no way to do the auto-reset from the IDE using the existing scheme without custom drivers.

That's not to say that there's not some value for advanced users in being able to strip CDC, too (as Steph has already done). I'd be interested in a clean way for doing this that doesn't involve modifying the core.

I'm still playing around a bit with this. I do agree with the way it's shaping up, that CDC should be kept in to preserve the auto-reset, but maybe an override could exist for advanced users. However, HID could / should be automatically included only if it is utilized in a sketch.

In the meantime, here's what I have figured out through experimentation: To remove all USB libraries, comment out the USB.attach(); line in cores/arduino/main.cppTo keep USB but omit the HID component, leave main.cpp alone and edit cores/arduino/USBDesc.h and comment out the line #define HID_ENABLEDAnd finally, if you want HID but not CDC, do like the above line, but comment out the #define CDC_ENABLED line instead.

By comparison of sketch sizes, here is what I get for my current project:All USB libraries: 30,356 bytesCDC but no HID: 29,838 bytesHID but no CDC: 29,742 bytesNo USB at all: 27,632 bytes

I don't know how thorough or effective it is to remove the #HID_ENABLED or #CDC_ENABLED defines - that was obvious and easy but either it's not very effective, or there's just a lot of overhead for USB regardless of what you do with it.

There's a gotcha here for some users: Windows matches drivers based in part on how many and which endpoints are presented by the device. What this means is that, all else being equal, Windows thinks that a device with just CDC is different than a device with CDC and HID and may refuse to load the correct driver.

Linux and OS X don't have this problem.

This only gets more complicated when you introduce other types of endpoints (ie joystick or MIDI). The fix is pretty straightforward: you can modify "Arduino Leonardo.inf" in the drivers folder to match the new endpoints but that's an advanced topic AND the old settings will often hang around in the registry. I'm still interested in a solution to this because I agree it would be great to omit unused USB device type libraries and support new ones but it's tricky to do cross-platform.

I wanted to mention that there is a case where omitting HID support is functionally required - or at least, much more convenient than the alternatives. I am controlling an Arduino Micro-based device from an Android tablet, and if I don't un-define HID_ENABLED, the Micro is claimed as an HID input device by Android. When this happens, the Android on-screen keyboard is disabled because Android's Linux kernel thinks there is a physical keyboard connected, and typing becomes impossible. There does not seem to be a way to make Android ignore the Micro without rooting the tablet, which I would prefer not to require users to do. So in this case, it is necessary to disable HID support in order to avoid rendering the tablet unusable while the Arduino is connected.

This thread was the most relevant hit for my searches while I was trying to resolve this problem, so I want to include a description of the solution here (on Linux):

Edit /usr/share/arduino/hardware/arduino/cores/arduino/USBDesc.h, and comment out the line

#define HID_ENABLED

so that it reads instead:

/* #define HID_ENABLED */

This is part of the code that gets compiled into each sketch to enable USB support, and this change will prevent HID support from being compiled into future sketches. You will need to be root or use sudo in order to write your changes to the file. (Is it necessary to restart the Arduino IDE after making this change? Not sure.) On Windows or OS X, you will need to figure out where Arduino's support files are installed and edit the analogous file.

I tried your fix as I am working on a arduino/android project and I still have the device showing up as a keyboard to the device. I am using a mac btw. Has anyone had any luck?

I've just used this fix to disable HID and it definitely removes the HID endpoints when attached to an OS X system. I don't have an android device around to check it out on that, but I don't see why it would be different.

After you make this change, you have to rebuild the Arduino distribution (using "ant"), then run the modified IDE (using "ant run"), and then rebuild your sketch in the new IDE.

Has anybody bricked their Leonardo doing this? If so how do you get back to square one? I was cautiously going through these options to reduce the size of my sketch when I noticed that the PC (win 7 and IDE 1.0.6) was no longer talking to the Leonardo!! and did not show up as the COM4 connection that it had been. So I cant upload any new sketches.

As I have a spare Uno I loaded that with the Arduino ISP and tried to re burn the bootloader to the Leonardo to no avail