Leonardo bootloader hell; Leonardo has no serial number on USB

I’m an (un)happy owner of three Leonardo boards now. I tried to use all of them at once via an usb hur but run into this problem which prevents me from normally using even one.
I found many posts on this topic but none of them really provides any solution so I decided to go a bit deeper with a hope that it may have a simple solution. So far that’s not true…

To briefly describe the problem:

  • When I plug in Leonardo first time, start the Arduino IDE I’m able to complile and download a sketch.
  • My second attempt is already likely to fail with an error message that the board cannot be found. (Sometimes it even works the second time and fails the third time…)
  • Every later attempt results the same way. Manual resetting of the board doesn’t help much but with pushing further I find that 1) the serial port is no longer shown in the menu 2) checking for the serial port in the OS reveals that now it has a different name associated 3) sometimes even the IDE crashes while attepting to invoke the loadin process

My system is OpenSUSE 13.1 and Arduino 1.0.5 but according to the posts I’ve seen the same issue is happening on every platform (at least I’ve seen posts for WinXP/Win7).

Well I’m not an experienced C programmer. This is how far I could go with this problem so far.

The only thing I could thnik of was that the same device is always detected as a different new HW. While the drivers are available the device itself is detected and configured again and again with every restart. For this reason it often gets a different port number/name assigned. Arduino IDE is not prepared for a device that is always changing it’s port and I can understand why is it so. But the problem is still there :frowning:

I had a similar experience with my FT4232 board. After reconfiguring it and assigning a serial number to it all my problems were solved. The board work like charm and the problem never ever returned. So why not try the same with Leonardo?

I checked the serial number reported by my Leonardo boards and it’s “0”. Hmm, could I change that? The bootloader (Caterina - reminds me of my first grilfriend…) is using the LUFA library to work with USB and emulate a serial port. After some time spent I was able to complile Caterina with support for reporting a correct serial number. All the support is already built in, I only needed the LUFA sources, a simple modification and some hours spent to figure out how to modify and compile the stuff. For those interested: Look for lines beginning with .SerialNumStrIndex in hardware/arduino/bootloaders/caterina/Descriptors.c and change the value to USE_INTERNAL_SERIAL. It will do the trick. You need to upload the recompiled bootloader with an ISP programmer of some kind. AVRISPMKII, DRAGON, homemade programmer, whatever you have nearby. Once I was able to compile the code the update worked without any issue.
Piece of cake, let’s do the same for the same piece of code in the Arduino library linked to my sketch and we are done! Well, not so fast…

After some searching I found my little baby here: hardware/arduino/cores/arduino/USBDesc.h and USBCore.cpp. But hey! This thing is using a completely different code to do the same thing! :frowning:

With a bit of hacking around I was able to squeeze out some serial number from this code also. My modifications:

  1. USBDesc.h: Added a single line to the end: “#define ISERIAL 3”
  2. USBCore.cpp:
    added lines:
const u16 STRING_ISERIAL[21] = { (3<<8) | (2+2*20), '1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0' };

//  DEVICE DESCRIPTOR
const DeviceDescriptor USB_DeviceDescriptor =
	D_DEVICE(0x00,0x00,0x00,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,ISERIAL,1);
//  D_DEVICE(0x00,0x00,0x00,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,0,1);

const DeviceDescriptor USB_DeviceDescriptorA =
	D_DEVICE(DEVICE_CLASS,0x00,0x00,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,ISERIAL,1);
//  D_DEVICE(DEVICE_CLASS,0x00,0x00,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,0,1);

updated this part of SendDescriptor():

else if (USB_STRING_DESCRIPTOR_TYPE == t)
{
	if (setup.wValueL == 0)
		desc_addr = (const u8*)&STRING_LANGUAGE;
	else if (setup.wValueL == IPRODUCT) 
		desc_addr = (const u8*)&STRING_IPRODUCT;
	else if (setup.wValueL == IMANUFACTURER)
		desc_addr = (const u8*)&STRING_IMANUFACTURER;
	else if (setup.wValueL == ISERIAL)
		desc_addr = (const u8*)&STRING_ISERIAL;
	else
	return false;
}

With this modification the compiled sketch also provides some serial number (hardcoded).

By my opinion it could work if:

  1. Both the bootloader and the adruino sketch uses the same USB library. Maybe putting together a compatible bootloader which is using the other lib?
  2. Both the bootloader and the arduino sketch reports the same VID/PID and serial number. Teaching this other library (I’m not sure about it’s origin.) to use the serial number burned in the AVR like LUFA does shouldn’t be too hard.

Please comment if you agree with my conclusions or if you’ve got further with solving this issue! It’s really annoying to have restart the IDE after every download and open my sketch again :frowning:

Interesting; sounds like SUSE and Arduino are "conspiring" to behave badly WRT the serial number being zero.
The big problem is that Arduinos don't really have a machine-readable serial number anyway :frowning:

Well, that little modification made my Leonardo to report a serial number with LUFA (boot loader):

e325:~ # lsusb -v | grep -A 20 Arduino
Bus 001 Device 082: ID 2341:0036 Arduino SA 
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            2 Communications
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0         8
  idVendor           0x2341 Arduino SA
  idProduct          0x0036 
  bcdDevice            0.01
  iManufacturer           2 Arduino LLC
  iProduct                1 Arduino Leonardo
  iSerial               220 748323630353515002A0
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           62
    bNumInterfaces          2
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0x80
      (Bus Powered)
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         2 Communications
      bInterfaceSubClass      2 Abstract (modem)

In case of the other driver it looks like this:

e325:~ # lsusb -v | grep -A 20 Arduino
Bus 001 Device 083: ID 2341:8036 Arduino SA Leonardo (CDC ACM, HID)
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0        64
  idVendor           0x2341 Arduino SA
  idProduct          0x8036 Leonardo (CDC ACM, HID)
  bcdDevice            1.00
  iManufacturer           1 Arduino LLC
  iProduct                2 Arduino Leonardo
  iSerial                 3 12345678901234567890
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength          100
    bNumInterfaces          3
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0x80
      (Bus Powered)
    MaxPower              500mA
    Interface Association:
      bLength                 8
      bDescriptorType        11
      bFirstInterface         0
      bInterfaceCount         2
      bFunctionClass          2 Communications
      bFunctionSubClass       2 Abstract (modem)
      bFunctionProtocol       1 AT-commands (v.25ter)

Many USB capable AVRs have a unique ID burned in. On those which have none it could be solved also by taking some part of the program memory in bootloader section or storing a serial number in EEPROM. 4 bytes SN would be more than sufficient for most of users.

As I was walking through the forums it doesn't seem like it's only my problem. I've seen similar complains from users using other Linux distros and also Windows. My old problem with the FTDI chip was also not Linux specific. That time I was trying to develop on Win XP.

Many USB capable AVRs have a unique ID burned in.

I checked; not the 32u4 :frowning:

When Unos first started shipping, they had a serial number in the first few bytes of EEPROM (at the time, this was mostly so that you could pick a unique ethernet address.) I don’t know whether they are still doing that (and in any case, it doesn’t look like either the bootloader or sketch-time USB code look for one…)