Author Topic: DigiMouse fails to enumerate during boot up, then blocks  (Read 3553 times)

jorgerivera

  • Newbie
  • *
  • Posts: 2
DigiMouse fails to enumerate during boot up, then blocks
« on: October 30, 2013, 12:11:44 pm »
Hello everyone!

I'm using a Digispark device to make a tiny one-button mouse for a project where it will be connected to an embedded device running Linux (MIPS core, full application processor).
When I insert my Digispark in my running device it enumerates and works correctly.
However, when I boot my device with the Digispark plugged-in, crazy stuff happens.

When I boot up, the device tries to enumerate so early that the boot process has not gotten yet to the USB initialization and then never enumerates.

This is my base code:
Code: [Select]
#include "DigiMouse.h"

int buttonPin = 5; //set a button to pin

void setup() {
  // don't need to set anything up to use DigiMouse
  pinMode(buttonPin, INPUT); // For button press
  digitalWrite(buttonPin, HIGH); //pull the button high
}

void loop() {
      DigiMouse.update();
      if (digitalRead(buttonPin) ==  0) {    //if the button goes low (gets pressed)
        DigiMouse.setButtons(4<<0); //middle click
        DigiMouse.delay(300);
        DigiMouse.setButtons(0); //unclick all 
      } 
}

I tried modifying the library to not run the connect/disconnect/usbinit process to enumerate right away, but until I issue an init() command. You can find my mod here. (This is a separate topic, but I think it is not a good idea to do the init in the singleton constructor. Specially if at some point I wish to be able to trigger re-enumeration.)
With the modification and a substantial delay (10s) in setup() before calling DigiMouse.init() it works well. This matches the time after boot where the kernel modules for USB get loaded.
But, what if my setup for one time takes more than 10s? Also, if I hotplug it, it should not have to wait 10s to start working...

I've tried a few things that did not work but got me some information:
  • I tried the same thing in a computer, a BeagleBone and a BeagleBoneBlack. It worked in the three devices.
  • I tried a real mouse (a pretty Logitech wired laptop mouse that I like a lot, if you need to know) and it does work well on boot up.
  • I tried changing the bootloader to use the jumper version. It did not help.
  • I tried changing the function of my button to change the LED state, to check if the device was still running. If I clicked very early, the action worked, but later it stopped working.
  • So, I tried to figure out for how long the device runs after the bad enumeration. It turns out it runs about 150k loop() cycles before it gets stuck (it takes about 3 secs).
  • So, I tried to set the watchdog to reboot or at least trigger re-enumeration of the device after some time. (Re-enumeration works if I run the DigiMouse.init() method as mentioned above.) I saw that something happened (my LED changed state) after the WDT timeout, but it didn't seem try to run the bootloader/setup again.
  • So, I tried to override the WDT ISR with an ISR that called the reboot() function listed in the Tips and Tricks section of the wiki. It seems it doesn't get run either. (I added a LED flash before it runs reboot, and it doesn't happen.)

So... any ideas? I'm trying to figure out if we have a hardware problem in the embedded device, as well, but for now I will need a good workaround in the digispark side that doesn't imply a lenghty and potentially unreliable wait. I really like the idea of using the watchdog, but it doesn't work well.

Thanks for reading, I hope you can help.

Bluebie

  • Sr. Member
  • ****
  • Posts: 486
Re: DigiMouse fails to enumerate during boot up, then blocks
« Reply #1 on: November 02, 2013, 04:02:53 pm »
I wonder if the usb host from your application processor doesn't start sending SOF pulses until it is initialised by the kernel modules. In that case the digispark wouldn't be able to calibrate it's clock speed to be accurate enough for usb at startup and depending if you have upgraded the bootloader or not, it would be at 16.0mhz instead of 16.5, or 16.5 but probably without the necessary precision to reliably do USB.

You might try just letting it initialise normally but calling calibrateOscillator() after 10 seconds.

You might also like to try out Adafruit's Trinket USB Mouse library which may or may not be better: https://github.com/adafruit/Adafruit-Trinket-USB/tree/master/TrinketMouse - it looks like it uses the same calibration technique so if that is the problem it maybe a problem with trinket also.

jorgerivera

  • Newbie
  • *
  • Posts: 2
Re: DigiMouse fails to enumerate during boot up, then blocks
« Reply #2 on: November 02, 2013, 09:03:13 pm »
Bluebie, thanks for your response.

A liltte extra info that might or might not be of help: I switched back the bootloader to the timeout bootloader and it fails differently. It gets stuck in the bootloader. My debug procedure was: I used timeout bootloader with my modified lib and I tried doing some flashing in the setup() before I called DigiMouse.init() and it never flashes. So I'm thinking that the lack of error handling of the V-USB library might be the problem. So, I'm only able to get to actually run the user sketch if I use the jumper bootloader.

When you say let it initialise properly, what do you mean?

I'll try Adafruit's lib. I think it might be a good option!

Again thanks for your response!

Bluebie

  • Sr. Member
  • ****
  • Posts: 486
Re: DigiMouse fails to enumerate during boot up, then blocks
« Reply #3 on: November 02, 2013, 11:09:41 pm »
What I mean is the USB host peripheral in your embedded linux device maybe applying power to the device, while the actual hardware interface is turned off. Generally microcontrollers and microprocessors start with everything switched off to save power by not powering unneeded components. If the USB host peripheral is disabled it would not be outputting Start of Frame pulses over the USB interface, which the digispark (and trinket, and littlewire, etc..) depend on to calibrate their internal clock. Many other devices make use of a precise crystal oscillator to get the necessary timing. Digispark and friends do things a little differently so it can be a little cheaper, simpler, and smaller. I suspect that is where the USB interface is getting confused - digispark isn't calibrating properly because of being powered up before the usb host peripheral in the linux computer.

I've also observed behaviour like this when my usb hub is plugged in while my desktop mac is asleep - computers also do not send SOF pulses when they are sleeping. The spark powers up and doesn't get it's timings right, and then when I wake up the computer later, the usb device isn't working and I need to unplug it and plug it back in again.

It would be really great if someone could contribute a fix to the library so it can calibrate when the SOF pulses start arriving again. I know there is some code in the V-USB world for doing constant calibration, but it makes use of the global timers and could be a little annoying to get it to play nice with the millis, micros, delay, delayMicroseconds, pwm, toneOut(), and other bits and pieces that make use of timers. Perhaps the timer which does millis() would be left alone often enough to be something which could also be used for doing constant clock calibration. Something worth looking in to if anyone is keen on making the USB connection more reliable. It would potentially be helping out not just digispark users, but trinket users also.