Arduino Leonardo (HID) sketch does not start without reset

I reviewed a question with a similar title, but since I do not need serial communication, it did not help (unless I missed something)
(similar question)

Summary: The sketch initializes a PAJ0762 sensor and the Keyboard and when there is a gesture, it prints to the keyboard.

It works fine when started from the IDE. However, if the IDE is closed, the Arduino disconnected, and reconnected, the sketch does not seem to start (or at least the sensor is not read). I did have a keyboard.println in the loop, and that does start printing, but gestures are not being recognized. No errors either.


/**
 * Demonstration of PAJ7620 Gesture Recogniser module
 */

// INCLUDES
// Arduino Wire library is for communicating with any I2C device
#include <Wire.h>
// PAJ7620 library, based on datasheet as described at
// https://www.epsglobal.com/Media-Library/EPSGlobal/Products/files/pixart/PAJ7620F2.pdf?ext=.pdf
#include "src/PAJ7620/paj7620.h"
#include <HID.h>
#include "Keyboard.h"

bool useHID = true;

void setup() {
   if (useHID)
    Keyboard.begin();
  else
    Serial.begin(9600); 
  
  // Initialise the sensor
  int error = paj7620Init();
  if (error) {
    if (!useHID) {
      Serial.print(F("Initialisation error code: "));
      Serial.println(error);
    }else{
      Keyboard.println("Initialisation error code: ");
      Keyboard.println(error);
    }
  } else {
    if (!useHID)
      Serial.println(F("Ready!"));
    else
      Keyboard.println("Ready!");
  }
}

void loop() {

  // Create a variable to hold the value of any gesture recognised
  byte gesture;
  // Error variable holds any error code
  int error;
  // Read Reg 0x43 of Bank 0 to get result of any recognised gesture, and store in 'gesture' variable
  error = paj7620ReadReg(0x43, 1, &gesture);

  if (!error) {
    switch (gesture) {
      case GES_RIGHT_FLAG:
        if (useHID)
          Keyboard.println(F("PAJ7620_RIGHT"));
        else
          Serial.println(F("Right"));
        break;
      case GES_LEFT_FLAG:
        if (useHID)
          Keyboard.println(F("PAJ7620_LEFT"));
        else
          Serial.println(F("Left"));
        break;
      case GES_UP_FLAG:
        if (useHID)
          Keyboard.println(F("PAJ7620_UP"));
        else
          Serial.println(F("Up"));
        break;
      case GES_DOWN_FLAG:
        if (useHID)
          Keyboard.println(F("PAJ7620_DOWN"));
        else
          Serial.println(F("Down"));
        break;
      case GES_FORWARD_FLAG:
        if (useHID)
          Keyboard.println(F("PAJ7620_FORWARD"));
        else
          Serial.println(F("Forward"));
        break;
      case GES_BACKWARD_FLAG:
        if (useHID)
          Keyboard.println(F("PAJ7620_BACKWARD"));
        else
          Serial.println(F("Backward")); 
        break;
      // Library also defines GES_CLOCKWISE_FLAG GES_COUNT_CLOCKWISE_FLAG and GES_WAVE_FLAG, but I found these unreliable
      default:
        break;
    }
  } else {
    if (!useHID) {
      Serial.print(F("Error code: "));
      switch (error) {
        case 0:
          break;
        case 1:
          Serial.println(F(" 1: data exceeds buffer capacity"));
          break;
        case 2:
          Serial.println(F(" 2: address byte followed by NACK "));
          break;
        case 3:
          Serial.println(F(" 3: data byte followed by NACK "));
          break;
        case 4:
          Serial.println(F(" 4: other error (bus arbitration, ..."));
          break;
        case 5:
          Serial.println(F(" 5: time-out "));
          break;
      }
    } else {
      Keyboard.println(F("Error code: "));
      switch (error) {
        case 0:
          break;
        case 1:
          Keyboard.println(F(" 1: data exceeds buffer capacity"));
          break;
        case 2:
          Keyboard.println(F(" 2: address byte followed by NACK "));
          break;
        case 3:
          Keyboard.println(F(" 3: data byte followed by NACK "));
          break;
        case 4:
          Keyboard.println(F(" 4: other error bus arbitration, ..."));
          break;
        case 5:
          Keyboard.println(F(" 5: time-out "));
          break;
      }
    }
  }
  // Introduce small delay before next polling the sensor
  delay(100);
  
}

Note, the code is from existing projects by others, with slight modifications.

Note: The Arduino is original from Arduino, but it is the same behavior for clones.

Please help me understand what I am doing wrong.

You started a topic in the Uncategorised category of the forum

Your topic has been moved to a relevant category. Please be careful in future when deciding where to start new topics

Further observation:
It seems when the Arduino is powered up, the code does indeed start to execute, but the sensor may not be in a valid state (such that it does not register the gestures). As a test, if I call

void loop(
 ... other code ...
     paj7620Init();
... other code ...
}

then it works fine. My understanding of microcontrollers and how they behave on power-up, is limited. The brute-force call to init on every loop proves where the source of error is, but is not an optimal solution. I found something called the WatchdogTimer, which may help detect when the Arduino has been power-cycled, so that I can call init on the sensor only after a power-cycle. But I could not find a good example I could follow for this concept.

We can't see the code that is in/src.

  1. If you wrote that code yourself, post it.
  2. If you modified an existing library that you found on the web, post that code and a link to the original.
  3. If you use a verbatim copy of something that you found on the web, post the link.

Verbatim copy from the following link
https://github.com/playfultechnology/arduino-gesture-recogniser

Curious why the code of the library is relevant. Please explain if possible. The issue here is that the sensor is not working after a power cycle. The library has only three methods, init, read and write.

Also, who is 'we'? Are you a team or is this just the way you communicate?

Thanks for the link.

A board with 32U4 processor can be tricky when it comes to serial prints when you don't have a serial connection open. As it sounds like you use the board stand-alone, I wanted to see the what the library does. It has some unconditional serial prints in the paj7620Init() function. You can try to comment them out and see if it solves the issue. After that, I do not know if I can help further as I do not have the sensor.

"We" is those that encounter this topic and mostly those that try to help.

There is one possible thing that you can try to add some debugging. You can flash the built-in LED (in your switch/case) if a gesture is detected.

EDIT: The correct solution is to introduce a delay before init is called in the setup.

void setup() {
  ...
  // Initialize the sensor
  delay(10000);
  int error = paj7620Init();
  ...
}

Now, when the Arduino is powered up, and setup is called, the delay allows the sensor to count its arms and legs (or whatever it does to initialize itself), and when the init is called after this delay it works. If it is called without the delay, it does not work, an error is returned.

**Wrong solution (ignore) **
Thank you for your help. I believe I have understood the root problem, and the work-around.
Root problem: When an Arduino board is powered up, it continues execution from where it was (loop), when it was un-powered. Meanwhile, the sensor itself is no longer initialized (due to the power-cut). So, the loop keeps running but the sensor does not respond.

Solution (or work-around): Simply re-initialize the sensor periodically (in my case every 5 seconds). Now, when the Arduino is re-powered, within a maximum delay of 5 seconds, the sensor will again work, and the loop will now pick up any sensor output as before.

Other options: If there is anyway to detect, in the 'loop', that the Arduino had been un-powered, then we could only reinitialize the sensor upon such a detection. However, I could not find any way to do that. WatchdogTimer was suggested, but I could not use it. I would welcome any suggestions for this (detect power-cycle, in the 'loop').

I have some doubts that that is the case. The below sketch will blink the built-in LED a couple of times (and stay on after that) after a reset of the board.

const uint8_t ledPin = LED_BUILTIN;
int ledState = LOW;

void setup()
{
  pinMode(ledPin, OUTPUT);

  for (uint8_t cnt = 0; cnt < 10; cnt++)
  {
    digitalWrite(ledPin, ledState);
    ledState = !ledState;
    delay(500);
  }
}

void loop()
{
}

On my Leonardo it will always flash after a power cycle.

It might be that the sensor needs some time to "warm up"; it might help if you delay the call to paj7620Init() in setup() (start with e.g. 5 seconds).

As I have some doubts about your root cause I do not think that it is useful. There is a register called MCUSR (see 32U4 datasheet) that contains a number of flags that indicate the cause of the reset (power on, usb reset, watchdog, ...). Unfortunately that register seems to be cleared by the bootloader so you can't use it.

An LED does not need initialization. The gesture sensor does. This is why your LED keeps flashing after a power cycle, while the gesture sensor does not work.

You are missing the point that I was trying to make: the micro does not continue from the point where the power was disconnected, it starts from the beginning.

The code demonstrates that the micro always goes through setup().

1 Like

I am using Leonardo (original, not a clone), and it does not run setup if I simply unplug and plug it back (USB).
If I hit reset, it does run setup.

What is your evidence of this ?

It turns out sterretje was right, the sensor does indeed need time to 'warm up' after power is reconnected. Since I did not expect this, I did not wait, and the resulting behavior led me to believe that startup was not called. I was wrong.

You were right, the sensor does indeed need warmup, and if I delay the call to init (tried 10 seconds, and it now works).

I am appending my 'solution' with the correct solution. Thank you.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.