Go Down

Topic: Keyboard library failing after reset (Read 444 times) previous topic - next topic

bobbaddeley

I'm using my Leonardo as a Keyboard, sending keystrokes to my computer regularly. Occasionally it stops sending keystrokes, though I have no indication that the Arduino code has failed. This is a permanent failure until I unplug the Arduino, though the computer still sees the HID Keyboard, or if I unplug the keyboard from the computer and plug it back in, after which it functions again. I thought I could occasionally reset the Arduino and that would induce the keyboard to behave again. Sadly, neither of the following two methods solve the problem. They do reset the Arduino, but the keyboard->computer connection remains visible but not functioning, and won't work until something is unplugged and plugged back in.

Code: [Select]
void softReset(){
asm volatile("  jmp 0");
}

void hardReset(){
cli();
wdt_enable(WDTO_1S);
while(1);
}


I also tried putting Keyboard.end() before Keyboard.begin() in the setup(){}, hoping that it would kill the Keyboard on a reboot, but it had no effect.

How do I get the Leonardo to restart the USB Keyboard section of the chip? Note that this is installed in a difficult place to reach and having physical access to do anything is pretty much out of the picture, and I'd REALLY like to avoid having a pin connected to the reset line of the atmega chip.

econjack

I'm pretty sure the problem is with the statement at line 53 in your code. I'd be a little more confident, however, if I could see your code.

bobbaddeley

#2
Feb 12, 2015, 04:53 am Last Edit: Feb 12, 2015, 04:59 am by bobbaddeley
Ok, here is how you can replicate the problem. I have one computer (A) connected over a serial port to the Serial1 of the Leonardo (the Rx and Tx pins). Then I have another computer (B) connected to the Leonardo by the USB. Computer B has notepad running and the cursor focused on it and that's all. Computer A is sending characters every once in a while. Here is the code I am using, slimmed down to the bare minimum.

Code: [Select]
#include <avr/wdt.h>

void setup() {
  wdt_disable();
  Serial1.begin(115200);
  while(!Serial1){;}
  //Keyboard.end();
  Keyboard.begin();
  delay(1000);
  Serial1.println("setup complete");
}

char inChar;

void loop() {
  if(Serial1.available() > 0) {
    inChar = Serial1.read();
    if(inChar == 'R') {
      hardReset();
    }
    else if (inChar == 'r'){
      softReset();
    }
    else {
      Serial1.println(inChar);
      Keyboard.print(inChar);
    }
  }

 
void softReset(){
  Serial1.println("soft reset");
  delay(1000);
  asm volatile("  jmp 0");
}

void hardReset(){
  Serial1.println("hard reset");
  delay(1000);
  cli();
  wdt_enable(WDTO_1S);
  while(1);
}


Send a few characters first, like 123. You'll note that on computer B notepad will say 123 and on computer A it will also say 123. Perfect. now send an r (The hard reset isn't quite working, but that's a separate issue). You'll see that on computer A it will say "soft reset" followed a couple seconds later by "setup complete". Now send characters again. If you send 456, then computer A will show 456 on the serial line, but computer B will NOT have any new characters. It will sit there stupid and though it says a HID keyboard is plugged in, it won't have any new characters, and the only way to get it to resume correct behavior is to unplug/plug the computer B USB cable, which in this installation is not an option.

econjack

It would help if all the code is there. It helps if we can compile the code. Evidently you have a Keyboard object from somewhere, and a USBDevice object also defined somewhere. Where are the appropriate header files?

bobbaddeley

That is all the code. The Keyboard library is a library that's part of the Arduino IDE. See File/Examples/09.USB/Keyboard/KeyboardSerial

bobbaddeley

I believe I've found a solution. I discovered some low level commands for Atmel chips, and one of them disables the USB. By calling that right before the reset, it will act like it unplugs the device from computer B, then when it resets, it acts like it's plugging back in. When it comes back up, commands sent over serial work again. Here's the revised reset function with the USB disabling:

Code: [Select]
void softReset(){
  Serial1.println("resetting");
  USBCON&= ~(1<<USBE);
  delay(5);
  asm volatile("  jmp 0");
}

Go Up