That was easy ;-)
You print the current position in the encoder callback. At high encoder speeds the printing is not yet done when it tries to invoke the callback again. This will basically lock the system.
I moved the printing to loop which fixes it. Here the recording of a 3'000'000 step move with 500kHz count rate. Works perfectly, no counts lost.
(left->EncSim output, right -> output of your code)

Here the changed code:
Code:
#include "stepper_n_encoder_v2.h"
void doincrement(bool adir);
//// imperial 32 TPI
// int N = 293;
// int D = 2000;
//// imperial 8 TPI
// int N = 293;
// int D = 500;
//// imperial 6 TPI
// int N = 781;
// int D = 1000;
// Note: 17 May 2022, N & D were calculated off line. The value of microsteps is embedded in the ratio. To
// add one's own feeds or threads, we need to calculate using the required # of microsteps! This functionality
// is not in the code base yet.
#ifdef imperial
uint16_t myidx = 1;
float TPI = impthread[myidx].tpi;
int N = impthread[myidx].N;
int D = impthread[myidx].D;
int ustep = impthread[myidx].ustep; // added for future capability
float tenpitch_error_percent = impthread[myidx].error;
#endif
OneShotTimer t1(PIT); // for stepper pulse
OneShotTimer t2(PIT); // for measuring speed.
// XPT2046_Touchscreen ts(TOUCH_CS);
// ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCK, TFT_MISO);
void onEncoderChanged(int value, int delta)
{
// volatile int mydelta = -delta;
if (delta > 0)
{
if (delta > 1)
{
Serial.printf("fault! delta = %i\n", delta);
errorcount += 1;
}
else
{
// delta = 1
myacc = myacc + delta * N;
if (myacc >= D) // works for positive accumulation only
{
myacc = myacc - D;
mydir = CCW;
doincrement(mydir);
}
}
}
if (delta < 0)
{
if (delta < -1)
{
Serial.printf("fault! delta = %i\n", delta);
errorcount += 1;
}
else
{
// delta = -1
myacc = myacc + delta * N;
if (myacc <= D)
{
myacc = myacc + D;
mydir = CW;
doincrement(mydir);
}
}
}
val1 = value;
//Serial.printf("Count = %i\n", value);
}
// void onEncoderError() don't know how it is used, nor what to look for!
void pulseme() // turns off stepper pulse after time out
{
digitalWriteFast(PUL, LOW);
// digitalWriteFast(LED_BUILTIN, LOW);
}
void doincrement(bool adir) // sets direction and turns on stepper pulse
{
digitalWriteFast(DIR, adir); // set direction
delayNanoseconds(100); // can improve stepper speed by doing this, but is dangerous...
digitalWriteFast(PUL, HIGH);
t1.trigger(steplen); // switch off after steplen us (2us)
}
void myms() // xxms timer callback for estimating spindle speed and step rate
{
val2 = (uint32_t)SpindleEnc.getValue(); // read encoder for current position
// we know the time was 20 ms
cps = 50.0f * ((int)val2 - valstart) / (float)encoder_resolution;
; // rev per second 50 = 1/0.02
sps = cps * (float)encoder_resolution * (float)N / (float)D; // steps/second
myrpm = -cps * 60.0f;
timeout = true;
}
void readconsole()
{
if (Serial.available())
{
int incomingByte = Serial.read(); // read the incoming byte
char c = (char)incomingByte;
// Parse the command.
if ((c != '\n') & (c != '\r'))
{
Serial.println();
Serial.print(F("key pressed: "));
if (c == ' ')
Serial.println(F("[space]"));
else
Serial.println(c);
if (c == 'r') // reset the counter
{
SpindleEnc.setValue(0); // wait til we get the right syntax!
Serial.printf("Reset spindle counter to 0\n");
} // add more commands as you see fit
}
}
}
void setup()
{
while (!Serial && millis() < 4000)
;
if (CrashReport)
Serial.println(CrashReport);
for (int i = 5; i < 8; i++) pinMode(i, OUTPUT); // init these pins to outputs
t1.begin(pulseme); // set up t1 callback function
t2.begin(myms); // set up t2 callback function
digitalWriteFast(DIR, CW); // sets direction of rotation LOW =CW, HIGH=CCW
digitalWriteFast(ENA, LOW); // active low signal, enables the stepper controller
// Use luni's SW encoder
SpindleEnc.begin(0, 1, CountMode::full); // encoder on pins 0,1 count all e3dges of the quadrature signal
SpindleEnc.attachCallback(onEncoderChanged);
myacc = 0; // Bresenham accumulator
oldrpm = 0.0f;
timeout = true; // so we start measuring speed right away
// if (0){ // prevent all tft writess for debug!!!
// if (!initMyDisplay(3))
// {
// Serial.println("Display failed to initialize");
// while(1);
// }
// if (!mainscreen())
// {
// Serial.println("Failed to send first message to display");
// while(1);
// }
// }
errorcount = 0;
displaycount = 0;
first = true;
// Eventually all this will be selected via the touch panel
Serial.printf("TPI = %3.1f, usteps/step = %i\n", TPI, ustep);
Serial.printf("N = %i, D = %i\n", N, D);
Serial.printf("Ten pitch error as per cent of pitch = %4.2f\n", tenpitch_error_percent);
}
void loop()
{
if (timeout) // if no timeout, skip this
{
timeout = false; // determine how many counts we get in 20ms, this is the base for a speed estimate
t2.trigger(20ms); // set timer to go off in 20ms
valstart = val1; // save current position
}
if ((myrpm == 0.0f) && (first))
{
Serial.printf("%7.1f%\tRPM\n", -myrpm); // there's a zero bug of some sort
// displayRPM(-myrpm);
first = false;
}
if (myrpm != 0)
{
first = true;
Serial.printf("pos: %d, RPM: %7.1f\n", SpindleEnc.getValue(), myrpm);
// displayRPM(myrpm);
}
delay(200);
// readconsole();
}