Missing encoder interrupts

I have an encoder which fires ~100 times per second and I am using the following code to sample an analog input and send the time/voltage pair over serial every time the encoder interrupt fires. However when I look at the deltas in the timestamps of the of the data points I receive, it is clear that it is sometimes missing one or more ticks. Is there something in my code that could be stopping it from properly detecting interrupts?

#include <Adafruit_TiCoServo.h>
Adafruit_TiCoServo victor;
 
union voltage_tag {
  byte b[2];
  unsigned int val;
 } voltage;
 
union time_tag {
  byte b[4];
  unsigned long val;
} time;
 

volatile unsigned long tick = 0;

void setup()
{
  Serial.begin(57600);
  victor.attach(9);
  victor.write(180);
  attachInterrupt(0, blink, RISING);
}

void loop()
{
  if (millis() > 8000) {
    victor.write(93);
  }
  if (tick != 0) {
    time.val = tick;
    tick = 0;
    
    voltage.val = analogRead(0);
    
    Serial.write(voltage.b[0]);
    Serial.write(voltage.b[1]);
    Serial.write(time.b[0]);
    Serial.write(time.b[1]);
    Serial.write(time.b[2]);
    Serial.write(time.b[3]);
  }
}

void blink()
{
  tick = micros();
}

Here is a snapshot of the values coming from the encoder:

Are you sure you're missing interrupts? Could it be that you're catching all the interrupts, but that sometimes there are two interrupts between successive printing steps so that one just doesn't get printed? Could it be that the interrupt fires between the read and the Serial steps so that part of one stamp comes from one interrupt and part comes from another?

How many characters are being sent each time you print your data? How often are you printing your data? How many characters is that every second? Now, how many characters per second can be sent at 57600 baud?

Regards,
Ray L.

RayLivingston:
How many characters are being sent each time you print your data? How often are you printing your data? How many characters is that every second? Now, how many characters per second can be sent at 57600 baud?

Exactly what you see in the code. 6 bytes every tick. ~600 bytes per second. A baud rate of 57600 can handle >5000 bytes per second.

lemiant:
I have an encoder which fires ~100 times per second

Is it a mechanical rotary encoder?

Or is it an opto-electronical encoder with its own current supply pin and electronics in it?

It's an opto-electronical encoder.

How many characters are being sent each time you print your data? How often are you printing your data? How many characters is that every second? Now, how many characters per second can be sent at 57600 baud?

This is the point: I had exactly the same problem. Get rid of the serial instructions

Regards

if (millis() > 8000) {

This is NOT how you use millis().

Look at several things at a time.

...R

The Serial object uses its own interrupts so while the code is processing your calls to Serial, which has disabled the interrupts, your ISR's are ignored because Serial is sucking up all the cycles and your signals go unprocessed

Robin2:

if (millis() > 8000) {

This is NOT how you use millis().

Look at several things at a time.

...R

There's absolutely nothing wrong with using it like that, and that statement will execute as expected - i.e. the code in the if clause will not execute until at least 8 seconds after reset or power-up.

Regards,
Ray L.

lemiant:
It’s an opto-electronical encoder.

OK, so I suppose that your encoder is free of bouncing effects.

Here is your code rewritten with some corrections by me:

#include <Adafruit_TiCoServo.h>
Adafruit_TiCoServo victor;
 
union voltage_tag {
  byte b[2];
  unsigned int val;
 } voltage;
 
union time_tag {
  byte b[4];
  unsigned long val;
} time;
 

volatile unsigned long tick = 0;

void setup()
{
  Serial.begin(57600);
  victor.attach(9);
  victor.write(180);
  attachInterrupt(0, blink, RISING);
}

boolean servoSettingFinished=false;
void loop()
{
  if (!servoSettingFinished && millis() > 8000) 
  {
    victor.write(93);
    servoSettingFinished=true;
  }
  if (tick != 0) 
  {
    noInterrupts();  
    time.val = tick;
    tick = 0;
    interrupts();
    voltage.val = analogRead(0);
    
    Serial.write(voltage.b[0]);
    Serial.write(voltage.b[1]);
    Serial.write(time.b[0]);
    Serial.write(time.b[1]);
    Serial.write(time.b[2]);
    Serial.write(time.b[3]);
  }
}

void blink()
{
  tick = micros();
}

These are the two corrections I did:

  1. If you want to set the servo to a new value 8 seconds after the program has started, then do it once. I don’t know how long “victor.write(93);” may need, but it looks as if it just needs to be done once and not everytime the loop starts.

  2. When you access “volatile” variables from your normal code that are bigger in size than one byte, you need to block interrupts when reading and resetting the volatile variable.

Perhaps give it a try!
Result?

With the encoder firing ~600 times a second the processing of all of the Serial calls (interrupts) using max baud rate (115200) should fit between two consecutive ticks easy, but I am too lazy to do the actual math.
Just a thought.

How does disabling the encoder interrupt help?
It continues to run so the app will still miss the "ticks".

How does disabling the encoder interrupt help?
It continues to run so the app will still miss the "ticks".

If an interrupt happens which changes "ticks" while you are using/copying it. It can be corrupted.

Mark

RayLivingston:
i.e. the code in the if clause will not execute until at least 8 seconds after reset or power-up.

Yes.

...R