Pages: [1] 2 3   Go Down
Author Topic: USBKeyboard.h occasionally hangs  (Read 3508 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 22
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

OK, time for a bit of help… I have been putting a lot of time into building an old school Arcade Emulator (MAME) with custom controllers using arcade joysticks and buttons.  Most people simply wire up the PCB from a USB Keyboard or buy a micro controller based input board.  Call me old school but neither one has the entirely custom built by me feel and for some reason I have it in my head that I need to use an Arduino in my build! LOL  Unfortunately it seems that my USB HID based controller sporadically hangs and I am looking for someone who might have some experience with the usbkeyboard.h library (aka Virtual Keyboard).  I got my library from here (http://code.google.com/p/vusb-for-arduino/)

So where am I at?  So far I have a “stand alone” arduino on my bread board with the custom controller wired up.  (Note I have also tested this with a Duemilanove board) The buttons and joysticks are basic micro switches which I am using to pull digital pins down to ground with the internal pull up resistors enabled.  I have also built the USB circuit from Practical Arduino here (www.practicalarduino.com/projects/virtual-usb-keyboard)  

Finally I have a resistor ladder connected to a dip switch to allow the “custom controller” to be setup as “player 1”, “player 2”, “player 3” or “player 4” mode.  This input is checked on startup and is used to output the appropriate “key strokes” based on witch player the controller is intended to be emulating.  In theory I would have one USB board per player because of the number of inputs I require.

I will post my code in a follow-up post as I got a message that I exceeded the maximum allowed length.  Note, I am NOT a programmer by trade but do have a bit of basic experience whenever my hobbies call for it.  While it all seems to work, occasionally it seems that the “LED” will stay on and Keystrokes stop being sent to the PC.   It can hang anywhere from just a couple seconds after initialization to a couple of minutes and does not appear to have any consistency.  I have tried on multiple computers ranging from Windows 7 to Windows XP all with the same results.   If anyone sees any reason why this might hang, PLEASE PLEASE PLEASE let me know. smiley-wink  

Finally, does this sound like the right way to accomplish my goal of producing keyboard keystrokes when a button is pushed?

Thanks,
Dave


Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 22
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here is my code

My Sketch

Code:
// Derived from this project
// http://www.practicalarduino.com/projects/virtual-usb-keyboard

// Requires the use of the "UsbKeyboard" library available from
// http://code.google.com/p/vusb-for-arduino/

#include "UsbKeyboard.h"

/*
============== PIN CONNECTIONS ==============
 D0  - PLAYER COIN SLOT
 D1  - PLAYER START BUTTON
 D2  - USB (D+)
 D3  - OTHER (ESCAPE)
 D4  - USB (D-)
 D5  - USB (RESET)
 D6  - OTHER (TAB)
 D7  - OTHER (ENTER)
 D8  - PLAYER DOWN
 D9  - PLAYER LEFT
 D10 - PLAYER RIGHT
 D11 - PLAYER UP
 D12 - PLAYER SW1
 D13 - LED
 A0(D14)  - PLAYER SW2
 A1(D15)  - PLAYER SW3
 A2(D16)  - PLAYER SW4
 A3(D17)  - PLAYER SW5
 A4(D18)  - PLAYER SW6
 A5  - DIP (PLAYER NUMBER SELECTION)
 =============================================
 */

// the number of the pushbutton pin
const int buttonPin0 = 0;     
const int buttonPin1 = 1;     
const int buttonPin3 = 3;     
const int buttonPin6 = 6;   
const int buttonPin7 = 7;     
const int buttonPin8 = 8; 
const int buttonPin9 = 9; 
const int buttonPin10 = 10; 
const int buttonPin11 = 11;   
const int buttonPin12 = 12;   
const int buttonPin14 = 14;   
const int buttonPin15 = 15;   
const int buttonPin16 = 16;   
const int buttonPin17 = 17;   
const int buttonPin18 = 18;   

// Use the on-board LED as an activity display
int ledPin = 13;             

// variable for reading the pushbutton status
int buttonState0 = 0;         
int buttonState1 = 0;         
int buttonState3 = 0;         
int buttonState6 = 0;         
int buttonState7 = 0;         
int buttonState8 = 0;         
int buttonState9 = 0;         
int buttonState10 = 0;         
int buttonState11 = 0;         
int buttonState12 = 0;         
int buttonState14 = 0;         
int buttonState15 = 0;         
int buttonState16 = 0;         
int buttonState17 = 0;         
int buttonState18 = 0;         
long counter = 0;

int playerPin = 5;            // switch circuit input connected to analog pin
int playerNumber = 0;         // variable used to hold the player button selected
//                            // this will be set during the startup by reading the dip switch


/**
 * Configure button inputs and set up the USB connection to the host
 */
void setup()
{

  // open the serial port at 9600 bps:   
  Serial.begin(9600);


  // Check the dip settings to find out the player mode selected
  playerNumber  = checkPlayerMode(playerPin);

  // Set up the activity display LED
  pinMode (ledPin, OUTPUT);
  digitalWrite (ledPin, LOW);

  // initialize the pushbutton pin as an input:
  pinMode(buttonPin0, INPUT);     
  pinMode(buttonPin1, INPUT);     
  pinMode(buttonPin3, INPUT);     
  pinMode(buttonPin6, INPUT);     
  pinMode(buttonPin7, INPUT);     
  pinMode(buttonPin8, INPUT);     
  pinMode(buttonPin9, INPUT);     
  pinMode(buttonPin10, INPUT);     
  pinMode(buttonPin11, INPUT);     
  pinMode(buttonPin12, INPUT);     
  pinMode(buttonPin14, INPUT);     
  pinMode(buttonPin15, INPUT);     
  pinMode(buttonPin16, INPUT);     
  pinMode(buttonPin17, INPUT);     
  pinMode(buttonPin18, INPUT);   

  // enable the internal pull-up resistor
  digitalWrite(buttonPin0, HIGH); 
  digitalWrite(buttonPin1, HIGH); 
  digitalWrite(buttonPin3, HIGH); 
  digitalWrite(buttonPin6, HIGH); 
  digitalWrite(buttonPin7, HIGH); 
  digitalWrite(buttonPin8, HIGH); 
  digitalWrite(buttonPin9, HIGH); 
  digitalWrite(buttonPin10, HIGH); 
  digitalWrite(buttonPin11, HIGH); 
  digitalWrite(buttonPin12, HIGH); 
  digitalWrite(buttonPin14, HIGH); 
  digitalWrite(buttonPin15, HIGH); 
  digitalWrite(buttonPin16, HIGH); 
  digitalWrite(buttonPin17, HIGH); 
  digitalWrite(buttonPin18, HIGH); 


  // Disable timer0 since it can mess with the USB timing. Note that
  // this means some functions such as delay() will no longer work.
  TIMSK0&=!(1<<TOIE0);

  // Clear interrupts while performing time-critical operations
  cli();

  // Force re-enumeration so the host will detect us
  usbDeviceDisconnect();
  delayMs(250);
  usbDeviceConnect();

  // Set interrupts again
  sei();

  // initialization period....
 
  // just wait for a while before begining the main loop
  // I found that if I entered the main loop and sent a keystroke
  // before the USB finished connecting it would cause the connection to fail
  // therefore I just sit here for 10 seconds calling the usbkeyboard.update function
  for (int initCounter = 0; initCounter < 100; initCounter++)  {
    delayMs(100);   
    UsbKeyboard.update();
  }
}

void loop()
{
  UsbKeyboard.update();
 
  // Read the inputs from the various digital pins
  buttonState0 = digitalRead(buttonPin0);   
  buttonState1 = digitalRead(buttonPin1);   
  buttonState3 = digitalRead(buttonPin3);   
  buttonState6 = digitalRead(buttonPin6);   
  buttonState7 = digitalRead(buttonPin7);   
  buttonState8 = digitalRead(buttonPin8);   
  buttonState9 = digitalRead(buttonPin9);   
  buttonState10 = digitalRead(buttonPin10);   
  buttonState11 = digitalRead(buttonPin11);   
  buttonState12 = digitalRead(buttonPin12);   
  buttonState14 = digitalRead(buttonPin14);   
  buttonState15 = digitalRead(buttonPin15);   
  buttonState16 = digitalRead(buttonPin16);   
  buttonState17 = digitalRead(buttonPin17);   
  buttonState18 = digitalRead(buttonPin18);   


  // ================================ PIN 0 ======================================
  if (buttonState0 == LOW) {
    digitalWrite (ledPin, HIGH);
    if (playerNumber == 1) {
      UsbKeyboard.sendKeyStroke(KEY_5);   //PLAYER 1 COIN (5)
    }
    else if (playerNumber == 2) {
      UsbKeyboard.sendKeyStroke(KEY_6);   //PLAYER 2 COIN (6)
    }
    else if (playerNumber == 3) {
      UsbKeyboard.sendKeyStroke(KEY_7);   //PLAYER 3 COIN (7)
    }
    else if (playerNumber == 4) {
      UsbKeyboard.sendKeyStroke(KEY_8);   //PLAYER 4 COIN (8)
    }
  }
  else {
    //digitalWrite (ledPin, LOW);
  }
 
  // ================================ PIN 1 ======================================
  if (buttonState1 == LOW) {
    digitalWrite (ledPin, HIGH);
    if (playerNumber == 1) {
      UsbKeyboard.sendKeyStroke(KEY_1);   //PLAYER 1 START (1)
    }
    else if (playerNumber == 2) {
      UsbKeyboard.sendKeyStroke(KEY_2);   //PLAYER 2 START (2)
    }
    else if (playerNumber == 3) {
      UsbKeyboard.sendKeyStroke(KEY_3);   //PLAYER 3 START (3)
    }
    else if (playerNumber == 4) {
      UsbKeyboard.sendKeyStroke(KEY_4);   //PLAYER 4 START (4)
    }
  }
  else {
    //digitalWrite (ledPin, LOW);
  }
 
 
  // ================================ PIN 3 ======================================
  if (buttonState3 == LOW) {
    digitalWrite (ledPin, HIGH);
    UsbKeyboard.sendKeyStroke(0x29);   // ESCAPE
  }
 
  // ================================ PIN 6 ======================================
  if (buttonState6 == LOW) {
    digitalWrite (ledPin, HIGH);
    UsbKeyboard.sendKeyStroke(0x2B);   // TAB
  }
 
  // ================================ PIN 7 ======================================
  if (buttonState7 == LOW) {
    digitalWrite (ledPin, HIGH);
    UsbKeyboard.sendKeyStroke(0x28);   // ENTER
  }

 
// PINS 8, 9, 10, 11, 12, 14, 15, 16, 17 and 18 removed as they were repetetive and too big to post

  delayMs(100);

}


// Define our own delay function so that we don't have to rely on
// operation of timer0, the interrupt used by the internal delay()
void delayMs(unsigned int ms)
{
  for (int i = 0; i < ms; i++) {
    delayMicroseconds(1000);
  }
}


//deternime the dip settings on the player mode
int checkPlayerMode(int pinNum) {
  int val = 0;         // variable to store the read value
  digitalWrite((14+pinNum), HIGH); // enable the 20k internal pullup
  val = analogRead(pinNum);   // read the input pin


  if( val >= 780 and val <= 880 ) {  // 830
    return 1;
  }
  else if ( val >= 580 and val <= 680 ) { // 630
    return 2;
  }
  else if ( val >= 380 and val <= 480 ) { // 430
    return 3;
  }
  else if ( val >= 180 and val <= 280 ) { // 230
    return 4;
  }
  else if( val >= 0 and val <= 70 )  {
    return 5;
  }
  else
    return 0;  // no button found to have been pushed
}
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 22
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here is the UsbKeyboard.h library file I am using
Code:
/*
 * Based on Obdev's AVRUSB code and under the same license.
 *
 * TODO: Make a proper file header. :-)
 */
#ifndef __UsbKeyboard_h__
#define __UsbKeyboard_h__

#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <string.h>

#include "usbdrv.h"

// TODO: Work around Arduino 12 issues better.
//#include <WConstants.h>
//#undef int()

typedef uint8_t byte;


#define BUFFER_SIZE 4 // Minimum of 2: 1 for modifiers + 1 for keystroke


static uchar    idleRate;           // in 4 ms units


/* We use a simplifed keyboard report descriptor which does not support the
 * boot protocol. We don't allow setting status LEDs and but we do allow
 * simultaneous key presses.
 * The report descriptor has been created with usb.org's "HID Descriptor Tool"
 * which can be downloaded from http://www.usb.org/developers/hidpage/.
 * Redundant entries (such as LOGICAL_MINIMUM and USAGE_PAGE) have been omitted
 * for the second INPUT item.
 */
PROGMEM char usbHidReportDescriptor[35] = { /* USB report descriptor */
  0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
  0x09, 0x06,                    // USAGE (Keyboard)
  0xa1, 0x01,                    // COLLECTION (Application)
  0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
  0x19, 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)
  0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)
  0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
  0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
  0x75, 0x01,                    //   REPORT_SIZE (1)
  0x95, 0x08,                    //   REPORT_COUNT (8)
  0x81, 0x02,                    //   INPUT (Data,Var,Abs)
  0x95, BUFFER_SIZE-1,           //   REPORT_COUNT (simultaneous keystrokes)
  0x75, 0x08,                    //   REPORT_SIZE (8)
  0x25, 0x65,                    //   LOGICAL_MAXIMUM (101)
  0x19, 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated))
  0x29, 0x65,                    //   USAGE_MAXIMUM (Keyboard Application)
  0x81, 0x00,                    //   INPUT (Data,Ary,Abs)
  0xc0                           // END_COLLECTION
};



/* Keyboard usage values, see usb.org's HID-usage-tables document, chapter
 * 10 Keyboard/Keypad Page for more codes.
 */
#define MOD_CONTROL_LEFT    (1<<0)
#define MOD_SHIFT_LEFT      (1<<1)
#define MOD_ALT_LEFT        (1<<2)
#define MOD_GUI_LEFT        (1<<3)
#define MOD_CONTROL_RIGHT   (1<<4)
#define MOD_SHIFT_RIGHT     (1<<5)
#define MOD_ALT_RIGHT       (1<<6)
#define MOD_GUI_RIGHT       (1<<7)

#define KEY_A       4
#define KEY_B       5
#define KEY_C       6
#define KEY_D       7
#define KEY_E       8
#define KEY_F       9
#define KEY_G       10
#define KEY_H       11
#define KEY_I       12
#define KEY_J       13
#define KEY_K       14
#define KEY_L       15
#define KEY_M       16
#define KEY_N       17
#define KEY_O       18
#define KEY_P       19
#define KEY_Q       20
#define KEY_R       21
#define KEY_S       22
#define KEY_T       23
#define KEY_U       24
#define KEY_V       25
#define KEY_W       26
#define KEY_X       27
#define KEY_Y       28
#define KEY_Z       29
#define KEY_1       30
#define KEY_2       31
#define KEY_3       32
#define KEY_4       33
#define KEY_5       34
#define KEY_6       35
#define KEY_7       36
#define KEY_8       37
#define KEY_9       38
#define KEY_0       39

#define KEY_ENTER   40

#define KEY_SPACE   44

#define KEY_F1      58
#define KEY_F2      59
#define KEY_F3      60
#define KEY_F4      61
#define KEY_F5      62
#define KEY_F6      63
#define KEY_F7      64
#define KEY_F8      65
#define KEY_F9      66
#define KEY_F10     67
#define KEY_F11     68
#define KEY_F12     69

#define KEY_ARROW_LEFT 0x50


class UsbKeyboardDevice {
 public:
  UsbKeyboardDevice () {
    PORTD = 0; // TODO: Only for USB pins?
    DDRD |= ~USBMASK;

    cli();
    usbDeviceDisconnect();
    usbDeviceConnect();


    usbInit();
      
    sei();

    // TODO: Remove the next two lines once we fix
    //       missing first keystroke bug properly.
    memset(reportBuffer, 0, sizeof(reportBuffer));      
    usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
  }
    
  void update() {
    usbPoll();
  }
    
  void sendKeyStroke(byte keyStroke) {
    sendKeyStroke(keyStroke, 0);
  }

  void sendKeyStroke(byte keyStroke, byte modifiers) {
      
    while (!usbInterruptIsReady()) {
      // Note: We wait until we can send keystroke
      //       so we know the previous keystroke was
      //       sent.
    }
      
    memset(reportBuffer, 0, sizeof(reportBuffer));

    reportBuffer[0] = modifiers;
    reportBuffer[1] = keyStroke;
        
    usbSetInterrupt(reportBuffer, sizeof(reportBuffer));

    while (!usbInterruptIsReady()) {
      // Note: We wait until we can send keystroke
      //       so we know the previous keystroke was
      //       sent.
    }
      
    // This stops endlessly repeating keystrokes:
    memset(reportBuffer, 0, sizeof(reportBuffer));      
    usbSetInterrupt(reportBuffer, sizeof(reportBuffer));

  }
    
  //private: TODO: Make friend?
  uchar    reportBuffer[4];    // buffer for HID reports [ 1 modifier byte + (len-1) key strokes]

};

UsbKeyboardDevice UsbKeyboard = UsbKeyboardDevice();

#ifdef __cplusplus
extern "C"{
#endif
  // USB_PUBLIC uchar usbFunctionSetup
uchar usbFunctionSetup(uchar data[8])
  {
    usbRequest_t    *rq = (usbRequest_t *)((void *)data);

    usbMsgPtr = UsbKeyboard.reportBuffer; //
    if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){
      /* class request type */

      if(rq->bRequest == USBRQ_HID_GET_REPORT){
/* wValue: ReportType (highbyte), ReportID (lowbyte) */

/* we only have one report type, so don't look at wValue */
        // TODO: Ensure it's okay not to return anything here?    
return 0;

      }else if(rq->bRequest == USBRQ_HID_GET_IDLE){
//            usbMsgPtr = &idleRate;
//            return 1;
return 0;
      }else if(rq->bRequest == USBRQ_HID_SET_IDLE){
idleRate = rq->wValue.bytes[1];
      }
    }else{
      /* no vendor specific requests implemented */
    }
    return 0;
  }
#ifdef __cplusplus
} // extern "C"
#endif


#endif // __UsbKeyboard_h__
« Last Edit: May 22, 2012, 07:49:05 pm by huntd69 » Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 502
Posts: 19080
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

 While it all seems to work, occasionally it seems that the “LED” will stay on and Keystrokes stop being sent to the PC.  

I can't see anything obviously wrong with it ... oh wait. Do you have any debouncing? I would be happier with some sort of debounce on stuff like:

Code:
  if (buttonState1 == LOW) {

I have something similar which never seems to need rebooting (not an arcade game though, that sounds cool).

In my case I threw in quite a long debounce (500 mS) after finding a button press.

You could consider adding a watchdog timer. Every time through the loop you could "pat the dog" and if it doesn't get patted, the whole thing resets. No great harm done.

Having said that I can't see in your sketch where you ever turn the LED off.
Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 22
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

No harm done?! By the time it re-initializes the USB I will have lost the game AND MY QUARTER! LOL smiley-wink

I considered a watchdog, but it would reboot so frequently that it just doesn't seem right.  there must be something going on I am missing.  As for the LED.  hmmm... OK What the... Going back to my original sketch, I just realized that I didn't comment it out for pins 8 and up, but for some reason did pull it out for the earlier pins.  So I've cleaned up my code a bit and fixed my led issue. Still hanging though, again with the LED on. 

Debouncing was my original reason I wanted to use a micro controller, and that's the next evolutionary step.  But until I figure this out I'm not really sure I want to add complexity.  Besides, I have a delay of 100ms at the end of the main loop which is almost like a debounce smiley-wink

BTW, I'm surprised that 500ms delay doesn't cause you problems.  I found that the USB was very picky about waiting to long before sending the next usbkeyboard.update and with 100ms I didn't notice any issues. 

Hmmm, I wonder if forgetting about the LED altogether might help me out... Will have to experiment some more. smiley
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 22
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

So it's most certainly hanging at the sendKeyStroke function.  I tried removing all references to the LED and it continues to occasionally hang.  Then I tried updating my button check code as follows and the light stays on (testing with the up direction).

Code:
   // ================================ PIN 11 ======================================
  if (buttonState11 == LOW) {
    if (playerNumber == 1) {
      digitalWrite (ledPin, HIGH);
      UsbKeyboard.sendKeyStroke(0x52);   //PLAYER 1 UP (UP ARROW)
      digitalWrite (ledPin, LOW);
    }
    else if (playerNumber == 2) {
      UsbKeyboard.sendKeyStroke(KEY_R);   //PLAYER 2 UP (R Key)
    }
    else if (playerNumber == 3) {
      UsbKeyboard.sendKeyStroke(KEY_I);   //PLAYER 3 UP (I Key)
    }
    else if (playerNumber == 4) {
      UsbKeyboard.sendKeyStroke(KEY_Y);   //PLAYER 4 UP (Y Key)
    }
  }

Now something I find VERY interesting is that it might just be a hardware issue.  If it is, I can't for the life of me think of why that might be.  The reason I say this is because I just tried adding a normal momentary push button (like on the arduino itself) directly to the breadboard and everything is stable.  When I switch that input for either a joystick or a simple arcade button just a micro-switch the controller hangs...  The buttons are connected using alligator clip test leads but the board is pretty stable and i'm pretty sure it's not moving.

Here is what I am using for the arcade controls
stick http://www.ebay.ca/itm/Professional-Joystick-Fighting-Stick-Replacement-Game-Arcade-/130701077505?pt=LH_DefaultDomain_0&hash=item1e6e642c01
push button http://www.ebay.ca/itm/NEW-ARCADE-HAPP-BUTTON-BOUTON-U-S-28-mm-START-1P-MICROSWITCH-INCLUDED-PANEL-/170730740297?pt=FR_Jeux_Vid%C3%A9o_Autres_Accessoires&hash=item27c0585a49

As I mention I have no idea if this makes any sense.  Possibly noise being introduced somehow?  Additional resistance of the longer cable run to the arcade controls?

I am at a loss!
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 502
Posts: 19080
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I considered a watchdog, but it would reboot so frequently that it just doesn't seem right.

The watchdog only reboots if something goes wrong, not frequently. I got the impression it froze occasionally.

Well for the debounce, at the very least put in a test for a state change, eg.

Code:
if (buttonState11 == LOW && old_buttonState11 == HIGH) {

Otherwise it may send dozens of keys when you hold down the button. Then take out the delay.

I agree with what you said about the long delay and USB, but in my particular case that delay seemed to work. But I only did that after a keypress.

I agree noise may be an issue, a few decoupling capacitors might help there.
Logged


Offline Offline
Sr. Member
****
Karma: 1
Posts: 322
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Nick,

Do you have an example of how you would set up your watch dog and "pet the dog"?

I understand the concept but don't know all the pieces.

What is lost and what is left when the watch dog bites?  I would assume globals and statics would not loose their values, anything else?  Is there some why for your code to know that the watch dog had to wake it up? 
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 502
Posts: 19080
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Here:

Code:
#include <avr/wdt.h>

void setup ()
{
  Serial.begin (9600);
  wdt_enable(WDTO_1S);  // reset after one second, if no "pat the dog" received
 }  // end of setup

void loop ()
{
 
Serial.println ("Entered loop ...");

Serial.println ("Point A");
delay (500);
Serial.println ("Point B");
delay (400);

wdt_reset();  // give me another second to do stuff (pat the dog)

Serial.println ("Point C");
delay (500);
Serial.println ("Point D");
delay (400);

while (true) ;   // oops, went into a loop
   
}  // end of loop

In setup we tell the watchdog to reset the processor after 1 second. However in the main loop we "pat the dog" by doing wdt_reset(). That gives us another second. So we see in the output window:

Code:
Entered loop ...
Point A
Point B
Point C
Point D
Entered loop ...
Point A
Point B
Point C
Point D
Entered loop ...
Point A
Point B
Point C
Point D
Entered loop ...
Point A
Point B
Point C
Point D

You can see that patting the dog extended our life long enough to get the 4 prints out, but then the processor resets when it hits the infinite loop, and starts again.

So in your case you just do the watchdog setup in the setup function, and pat the dog in the main loop. Now if it gets stuck somewhere inside the USB code the processor just resets. Basically it saves you the effort of doing it yourself.
Logged


Global Moderator
Offline Offline
Brattain Member
*****
Karma: 502
Posts: 19080
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

What is lost and what is left when the watch dog bites?  I would assume globals and statics would not loose their values, anything else?  Is there some why for your code to know that the watch dog had to wake it up? 

Well you are likely to lose the lot, as the initialization stuff will re-initialize global variables. Does it matter? If so, you might be able to work around it by doing something like checking some memory that you malloc. If it has some data in it that you put there (previously), it is probably a watchdog reset. If it has random data, it is probably a cold startup.
Logged


Offline Offline
Sr. Member
****
Karma: 1
Posts: 322
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Nick,
Thank you for your example.  I tried it out and I get different results.  I changed it around a little but got no improvement.

My final code is as follows:
Code:
#include <avr/wdt.h>
void setup () {
  Serial.begin (9600);
  wdt_enable(WDTO_1S);  // reset after one second, if no "pat the dog" received
}  // end of setup

void loop () { 
  Serial.println ("Entered loop ...");

  Serial.println ("Point A"); delay (500);
  Serial.println ("Point B"); delay (400);

  wdt_reset();  // give me another second to do stuff (pat the dog)

  Serial.println ("Point C"); delay (500);
  Serial.println ("Point D"); delay (400);
  Serial.println ("Point E"); delay (400);
  Serial.println ("Point F"); delay (400);
}  // end of loop
I reformatted a little and put more than one statement on a line.  I know that this formatted is discouraged but I wanted to be able to see all the code a once.  I also removed the infinite loop and instead simulated a loop that takes longer to complete than expected.

My results are:
Code:
Entered loop ...
Point A
Point B
Point C
Point D
Point E
It stopped after E as expected. 900 ms had elapsed when "E" was written.  While delaying another 400 ms the 1 second time expired.

However, rather than restart the sketch, the board locked up with the LED (pin 13) flashing rapidly.

The reset button would not work.  A new sketch could not be loaded.  The only way to recover was to remove the power. 

Is there a difference in boards or IDEs that could affect this?  I am using a Nano and 1.0.1.  I also tried 22 with the same results.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 22
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
The watchdog only reboots if something goes wrong, not frequently. I got the impression it froze occasionally.

I guess a more appropriate word might have been sporadically.  I was trying to indicate that it doesn't hang at a consistent point.  ie, everytime i push the up arrow or every 4th time a button is pushed.  It can be up for a few minutes and then fail or fail almost instantly.  It does not fail when no buttons are pushed but will fail anywhere between 10 seconds and 3 minutes of playing a game, um I mean "testing"... smiley-wink LOL

Quote
Well for the debounce, at the very least put in a test for a state change, eg.

Code:
if (buttonState11 == LOW && old_buttonState11 == HIGH) {

Otherwise it may send dozens of keys when you hold down the button. Then take out the delay.

I actually kinda need this.  If I understand correctly, holding down a key on a typical keyboard sends a key, might wait 250 ms and then begins repeatedly sending that keystroke until the key has been released.  Adding button state and only acting on a change of state would result in a single keystroke and Mrs. Pac Man would stop moving and get attacked by a ghost and we can't have that! smiley-wink

Quote
I agree noise may be an issue, a few decoupling capacitors might help there.

I've added an additional Capacitor (220uf) at the point that the USB enters the breadboard.  I also have a 10uf cap on my standalone arduino.  This does not resolve the issue. 

So I have completed some additional troubleshooting and I am wondering if there is a good way to troubleshoot what's happening in the UsbKeyboard.sendKeyStroke(KEY_S); function within the .h file?  if I comment out all the "UsbKeyboard.sendKeyStroke(KEY_WHATEVER);" commands within my sketch, I can not get the sketch to fail with my arcade controller buttons.  Does this rule out noise and point to a problem with the library?
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 502
Posts: 19080
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

However, rather than restart the sketch, the board locked up with the LED (pin 13) flashing rapidly.

The reset button would not work.  A new sketch could not be loaded.  The only way to recover was to remove the power. 

Some bootloaders apparently do not handle the watchdog gracefully. It looks like you have such a one. I would be uploading a new bootloader myself.
Logged


Global Moderator
Offline Offline
Brattain Member
*****
Karma: 502
Posts: 19080
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I actually kinda need this.  If I understand correctly, holding down a key on a typical keyboard sends a key, might wait 250 ms and then begins repeatedly sending that keystroke until the key has been released. 

Can you clarify what you mean by "key"? I thought the game would just have simple buttons.

Quote
I've added an additional Capacitor (220uf) at the point that the USB enters the breadboard.  I also have a 10uf cap on my standalone arduino.  This does not resolve the issue. 

I had in mind 0.1uF for the frequencies we are thinking of, nothing like what you added.

Quote
Does this rule out noise and point to a problem with the library?

Could be a noise/timing issue. Noise could be influencing things. After all USB is pretty fast.
Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 22
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I actually kinda need this.  If I understand correctly, holding down a key on a typical keyboard sends a key, might wait 250 ms and then begins repeatedly sending that keystroke until the key has been released. 

Can you clarify what you mean by "key"? I thought the game would just have simple buttons.

holding down a key on a typical keyboard sends a key aka character, keystroke, etc.  If you hold down the "x" key on the keyboard, one is immediately displayed on the screen, about 250-500 ms later (depending on hardware) more begin being displayed at a constant rate of what appears to me to be about 100 ms

Quote
Quote
I've added an additional Capacitor (220uf) at the point that the USB enters the breadboard.  I also have a 10uf cap on my standalone arduino.  This does not resolve the issue. 

I had in mind 0.1uF for the frequencies we are thinking of, nothing like what you added.

I will try a smaller cap and let you know. would you recommend I use a Ceramic or Electrolytic capacitor?
Logged

Pages: [1] 2 3   Go Up
Jump to: