Help with V-USB Library for Arduino

Hi, I'm trying to follow the instructions in this blog post to create an arduino device that emulates a USB keyboard. I've hit a few bumps in the road and this last one's got me stumped. My best hope is that I'm using the wrong version of the V-USB for Arduino project. I got it from here:

https://code.google.com/archive/p/vusb-for-arduino/

And that required cutting out just the "UsbKeyboard" directory under "Libraries", and then I found that it was built on top of an old version of the USB libraries, and saw guidance from elsewhere to whomp the old copy with new stuff from here:

https://www.obdev.at/products/vusb/download.html

That replaced most of the files in the UsbKeyboard folder. That left a compile error that was pretty easy to sort, but I'm getting this link-time error now, and it's mystifying:

Compiling debug version of 'Sketch1' for 'Arduino/Genuino Uno'

Error compiling for board Arduino/Genuino Uno
Debug build failed for project 'Sketch1'
WInterrupts.c.o (symbol from plugin)*: In function attachInterrupt
(.text+0x0)*: multiple definition of __vector_1
usbdrvasm.S.o*: C:\Program Files (x86)\Arduino\libraries\UsbKeyboard\usbdrvasm16.inc:34: first defined here

cctmpOVV.ltrans0.ltrans.o*: In function __vector_1
WInterrupts.c:309: multiple definition of __vector_1
usbdrvasm.S.o*: C:\Program Files (x86)\Arduino\libraries\UsbKeyboard\usbdrvasm16.inc:34: first defined here

cctmpOVV.ltrans0.ltrans.o*: In function __base_ctor
UsbKeyboard.h:139: undefined reference to usbInit()
UsbKeyboard.h:146: undefined reference to usbSetInterrupt(unsigned char*, unsigned char)

collect2.exe*: error: ld returned 1 exit status

There is no __vector_1 anywhere and I don't see how creative macro's could make it either. The undefined references seem like they should be easier to solve, but I haven't managed it yet.

Any tips would be appreciated.

The error tells you that you have two libraries willing to use the same interrupt

Thanks! That seems to bear out, since when I take the "attachInterrupt" call out of my sketch, the problem goes away. Trouble is, I need it.

How do you go about making the two libraries play nice together? I believe I am only using one interrupt pin (2) for the USB, I would think that would leave the other interrupt pin, 3, available for my own use.

BTW, the other errors were pretty easy to correct by adding

#ifdef __cplusplus
extern "C" {
#endif

to the front of a few function declarations in UsbKeyboard.h.

post your code...

I got it sorted. I’ll post my solution in case it helps anybody else down the road. First off, as somebody who’s used to working at the application level and not at the device level, you really need to change how you think of “library”. At the application level, you can generally be confident that libraries can be brought into your app without a thought that they will mess with another library. In Arduino, that’s so not true. That’s what’s happening here.

For this case, v-usb is natively defining its interaction with the interrupt associated with pin2 on the Uno. The Ps2Keyboard library is using an Arduino library to define its use of whatever pin you assign to it (by the “attachInterrupt” function.) The trouble is that the Arduino library assumes that if you’re using it for one interrupt, you’ll surely want it for both, so it creates the compile-time constructs for both of the interrupt vectors, and that leads to the “multiple definition of __vector_1” error.

Open Source to the rescue! I found this library:

which seems to be an alternative to attachInterrupt and it supports a compile-time directive that lets you tell it which interrupts you’ll be using it with, so the theory is that I could change PS2Keyboard.cpp to not call ‘attachInterrupt’ and call ‘enableInterrupt’ instead, and include this at the head:

#define EI_NOTINT0 1
#include "EnableInterrupt.h"

(“EI_NOTINT0” means “I don’t want the Enable Interrupt library to run Interrupt Zero”.) That should just work. But it didn’t. I got compile time errors that I tracked down to a few blocks like this in EnableInterrupt.h:

#if ! defined(EI_NOTEXTERNAL) && !defined(EI_NOTINT0) && !defined (EI_NOTINT1)
interruptFunctionType functionPointerArrayEXTERNAL[2];
#endif

What I think that’s trying to say is “don’t define functionPointerArrayEXTERNAL unless there’s a consumer for it” and by “consumer for it”, there wouldn’t be one if both EI_NOTINT0 and EI_NOTINT1 were defined. But the code above, confounded by all the negative logic, actually skips the code if either are defined. Fixed it by adding a parenthesis:

#if ! defined(EI_NOTEXTERNAL) && ! ( defined(EI_NOTINT0) && defined (EI_NOTINT1) )

Beware that there are a few spots like that in the code, but hopefully that’ll get fixed in the release version soon so other folks can just swap over to it.

EnableInterrupt.h (62.3 KB)

PS2Keyboard.cpp (13.2 KB)

I’ve just post the solution in another topic :

I know, that this topic is quite old, but I’ve found it looking for a solution for exactly the same problem. (V-USB current version)

Using attachInterrupt on pin 3 (as V-USB is configured for 2) triggers WInterrupts library to load. WInterrupts defines for whatever purposes INT0_vect and INT1_vect. But one of them was already defined by V-USB library (depends on which pin VUSB was configured: pin 2 - INT0 or pin 3 - INT1). So there is the collision.

Probably there is a possibility to modify WInterrupts or VUSB library. But it’s dirty and I do not like to do things that way.

The solution was to not use WInterrupts library. Since attachInterrupt is just an easy way to setup interrupt, it has to be possible to set it by hand, the hard way. And it is!

So I just found some examples of configuring interrupt and make it for INT1. This page is extremely helpful. And my configuration (for FALLING):

// activate external interrupt 1
  EICRA &= ~(bit(ISC10) | bit (ISC11)); // clear existing flags
  EICRA |= (0<<ISC10)|(1<<ISC11);
  EIFR   =  bit (INTF1);    // clear flag for interrupt 1
  EIMSK |=  bit (INT1);     // enable it

and of course:

ISR(INT1_vect) {
  //do something on interrupt
}

And it is awesome now ^^.