Nano ESP32 problem with large number division

As first noted in my other thread, I have some code that I want ported to the Nano ESP32. The code compiles on an Arduino Nano without issue. I have tried to compile and run on the Arduino Nano ESP32 (2 separate boards) and an ESP32 Wroom. The code compiles and says it is uploads, but the Nano ESP32 doesn't really connect back and the ESP32 Wroom just resets constantly.

After removing sections of the code until I solved the issue, I found that it comes down to one calculation being made. This calculation is taking the time between 2 falling edges and getting the frequency of that time. We are dealing with microseconds here, so the calculation is 1000000 / (time between edges).

Sometimes the upload does work, if I try 20 times in a row, but the majority of the time it doesn't.

The offending piece of the code is below:

 freq = 1000000 / rpmDuration;                         // Problem child with ESP32
  afreq = 1000000 / avgRpmDuration;                     // Problem child with ESP32

If I comment those out, the code uploads just fine.

Post your complete code so we can analyze other programming details.

The code is a work in progress...

// Test for reading zero cross and Timing


#define REVS 2
#define PH 3
#define LPIN 13


uint32_t rpmMicros;
uint32_t phMicros;
uint32_t prevRpmMicros;
uint32_t prevPhMicros;
uint32_t rpmDuration;
uint32_t phDuration;
uint32_t prevDisplayMillis;
uint32_t displayMillis;
uint32_t freq = 0;
uint32_t rpm = 0;
uint16_t refresh = 1000;  //refresh in mseconds
float timing = 0;
float degree = 0;
float adegree = 0;
const uint8_t N = 10;
uint32_t arrayRpmDuration[N] = {};
uint32_t sumRpmDuration = 0;
uint32_t arrayPhDuration[N] = {};
uint32_t sumPhDuration = 0;
float avgRpmDuration = 0;
float avgPhDuration = 0;
float avgTiming = 0;
float avgRpm = 0;
float afreq = 0;
uint8_t rsamples = 0;
uint8_t psamples = 0;
uint8_t led = LOW;

// variables for the RPM ISR
volatile unsigned long rpmIsrMicros = 0;
volatile bool rpmNewIsrMicros = false;

// variables for the PH ISR
volatile unsigned long phIsrMicros = 0;
volatile bool phNewIsrMicros = false;

void setup() {
  Serial.begin(115200);
  pinMode(REVS, INPUT);
  pinMode(PH, INPUT);
  pinMode(LPIN, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(REVS), rpmSensorISR, FALLING);
  attachInterrupt(digitalPinToInterrupt(PH), phSensorISR, FALLING);
  prevDisplayMillis = millis();
}

void loop() {
  getPhData();
  getRpmData();
  getCalculations();
  displayMillis = millis();
  if (displayMillis >= prevDisplayMillis + refresh) {
    prevDisplayMillis = millis();
    if (led == LOW) {
      led = HIGH;
    } else {
      led = LOW;
    }
    digitalWrite(LPIN, led); 
    showData();
  }
}

void getRpmData() {
  if (rpmNewIsrMicros == true) {                // ISR flag is true, let's do something
    prevRpmMicros = rpmMicros;                  // save the previous value
    noInterrupts();                             // disables interrups while we save variables
    rpmMicros = rpmIsrMicros;                   // set the global variable for the falling edge to the ISR event time
    rpmNewIsrMicros = false;                    // ISR flag is false, I guess we wait until it is true again.
    interrupts();                               // enables interrupts again
    rpmDuration = (rpmMicros - prevRpmMicros);  // New falling edge - previous falling edge
    arrayRpmDuration[rsamples] = rpmDuration;   // Add reading to the array
    rsamples++;                                 // Increment the array, we are starting at 0
    if (rsamples >= N) {                        // if we have reached the sample size N, array is full, go to the average function
      getArpms();                               //
      rsamples = 0;                             // set samples back to 0 and start over
    }
  }
}

void getPhData() {
  if (phNewIsrMicros == true) {              // ISR flag is true, let's do something
    prevPhMicros = phMicros;                 // save the previous value
    noInterrupts();                          // disables interrups while we save variables
    phMicros = phIsrMicros;                  // set the global variable for the falling edge to the ISR event time
    phNewIsrMicros = false;                  // ISR flag is false, I guess we wait until it is true again.
    interrupts();                            // enables interrupts again
    phDuration = phMicros - rpmMicros;       // New falling edge - previous falling edge
    arrayPhDuration[psamples] = phDuration;  // Add reading to the array
    psamples++;                              // Increment the array, we are starting at 0
    if (psamples >= N) {                     // if we have reached the sample size N, array is full, go to the average function
      getAph();                              //
      psamples = 0;                          // set samples back to 0 and start over
    }
  }
}

void getCalculations() {
  degree = ((rpmDuration * 1000) / 360);                // Calculate how many degrees for timing
  adegree = ((avgRpmDuration * 1000) / 360);            // Average of the above
  timing = ((phDuration * 1000) / degree) - 30;         // timing - phase offset
  avgTiming = ((avgPhDuration * 1000) / adegree) - 30;  // average of the above
  freq = 1000000 / rpmDuration;                         // Problem child with ESP32
  afreq = 1000000 / avgRpmDuration;                     // Problem child with ESP32
  rpm = freq * 60;
  avgRpm = afreq * 60;
}

void getAph() {
  int k{};
  sumPhDuration = 0;
  for (k = 0; k < N; k++) {
    sumPhDuration += arrayPhDuration[k];
  }
  avgPhDuration = (sumPhDuration / N);
}

void getArpms() {
  int m{};
  sumRpmDuration = 0;
  for (m = 0; m < N; m++) {
    sumRpmDuration += arrayRpmDuration[m];  // Sum all the array elements
  }
  avgRpmDuration = (sumRpmDuration / N);  // Divide by the array sample size
}

void showData() {
  Serial.println();
  Serial.println("===============");
  Serial.print("  RPM Duration ");
  Serial.print(rpmDuration);
  Serial.print("  FREQ  ");
  Serial.print(freq);
  Serial.print(" Hz");
  Serial.print("  RPM  ");
  Serial.print(rpm);
  Serial.print("   Timing  ");
  Serial.print(timing);
  Serial.print("*");
  Serial.print("  PHDuration  ");
  Serial.print(phDuration);
  Serial.print(" Avg Timing ");
  Serial.print(avgTiming);
  Serial.print("*");
  Serial.println();

  Serial.println();
}

void rpmSensorISR() {
  rpmIsrMicros = micros();
  rpmNewIsrMicros = true;
}

void phSensorISR() {
  phIsrMicros = micros();
  phNewIsrMicros = true;
}
 freq = 1000000 UL / rpmDuration;  
 afreq = 1000000 UL / avgRpmDuration;   

I very much appreciate the response, but that didn't do it.

EDIT:

Funny thing though, I can multiply by the big number without any issues...

I'm not familiar with ESP Interrupts.

"and the ESP32 Wroom just resets constantly."
I think that it must be kicking out an error log as when/if the loop () doesn't come around in time enough (watchdogging). A Nano/Arduino/328 doesn't have this to manage.

Not sure how that is fixed...
But like I said, randomly it will work. The one I have plugged in, started working after about 10 minutes. I did nothing, was typing up another post and heard the tell tale sign of a USB device connecting on my laptop, low and behold it started working with the code. But if I try and re upload it will not work.

So I've got nothing...

So it's not printing an error log when it "resets constantly"?

The "fix" is placing yield () -- somewhere

The ESP32 Wroom, you can see the reset in the serial monitor. The Nano ESP32 disconnects from serial during the upload and doesn't connect again. In the logs there are no errors, even with all compiler warning enabled.

And I don't know how the NanoESP32 deals with watchdogging.

Where's that?

The other thread? I marked it as solved since it was about getting the average from an ISR. The code in this thread has the averaging in it that works.

One of those may be a strapping pin (boot pin).

I'm guessing you're using the Arduino pin numbering (cf. the GPIO numbering). But if you're using this sketch for both an NanoESP32 and a WROOM type, then that could be confusing/ a problem

This "porting" business is easy - in theory.

I've tried different pins on the Nano ESP32, and tried 32 and 35 on the ESP 32 wroom. I didn't consult the pin out first, so that still may be the case with the wroom.

EDIT:
After consulting the pinout on the ESP32 Wroom, all GPIO pins can be used as interrupts, so 32 and 35 are fair game

I'd like to get this sorted as the Nano ESP32 is a lot faster than the standard Nano (not to mention more external interrupt pins).
The ESP32 can handle the interrupts when pulses are down to 10us apart. The Nano starts hiccupping around 250us apart. Since I will eventually have 6 interrupts that could getting close to 50us apart, the Nano just isn't the right tool. I do have a STM32 Black Pill to try still...

I managed to fix this by moving the computation to a different part of the code.

New code here, but it doesn't resemble the old code all that much. I am getting some practice in with coding. Still lots to do, including adding the average back when I have time.

EDIT: That code is wrong...

I saved the wrong sketch, oops. Guess I have to re write it...

EDIT:
Here is the code

/* 
   Test for reading zero cross and Timing
   */

#define REVS A3
#define PHASE A4
#define LPIN 13

// Combined class for RPM and bemf
class Pulse {
public:
  uint8_t sPin;
  uint8_t pPin;
  volatile bool rpmNewIsrFlag;
  volatile bool phaseNewIsrFlag;
  uint32_t rpmMicros;
  uint32_t prevRpmMicros;
  volatile uint32_t rpmIsrMicros;
  volatile uint32_t phaseIsrMicros;
  uint32_t phaseMicros;
  float freq;
  float degree;
  uint32_t rpm;
  float timing;

  Pulse(uint8_t dSPin, uint8_t dPPin, bool rpmNewIsrFlag, bool phaseNewIsrFlag);

  void begin();
  void rpmData();
};

Pulse::Pulse(uint8_t dRPin, uint8_t dPPin, bool dRpmNewIsrFlag, bool dPhaseNewIsrFlag) {
  sPin = dRPin;
  pPin = dPPin;
  rpmNewIsrFlag = dRpmNewIsrFlag;
  phaseNewIsrFlag = dPhaseNewIsrFlag;
}

void Pulse::begin() {
  pinMode(sPin, INPUT);
  pinMode(pPin, INPUT);
}

void Pulse::rpmData() {
  if (rpmNewIsrFlag == true) {                              // ISR flag is true, let's do stuff
    prevRpmMicros = rpmMicros;                              // Save previous rpmMicros
    noInterrupts();                                         // Turn off interrupts
    rpmMicros = rpmIsrMicros;                               // set rpmMicros to the ISR interrupt time
    rpmNewIsrFlag = false;                                  // ISR flag is false, wait until next time
    interrupts();                                           // Enable interrupts
    freq = (1000000 / (rpmMicros - prevRpmMicros));         // Account for micro seconds
    rpm = (freq * 60);                                      // Converts from ticks per second to ticks per minute
    degree = (((rpmMicros - prevRpmMicros) * 1000) / 360);  // Converts frequency into 360 equal degrees
  }
  if (phaseNewIsrFlag == true) {   //ISR flag us true, let's do stuff
    noInterrupts();                //Disable interrupts
    phaseMicros = phaseIsrMicros;  //Set phaseMicros to the ISR event time
    phaseNewIsrFlag = false;       //Change our ISR flag, guess we wait until its true again
    interrupts();                  //Enable interrupts
    timing = ((((phaseMicros - rpmMicros) * 1000) / degree) - 30);
  }
}

Pulse pulseA(A3, A4, false, false);
//Pulse pulseB(3, 4, false, false);
//Pulse pulseC(5, 6, false, false);


uint32_t displayMillis = 0;
uint32_t prevDisplayMillis = 0;
uint8_t led = LOW;
const uint16_t refresh = 1000;

void setup() {
  Serial.begin(115200);
  pulseA.begin();
  pinMode(LPIN, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(REVS), rpmAISR, FALLING);
  attachInterrupt(digitalPinToInterrupt(PHASE), phaseAISR, FALLING);
  prevDisplayMillis = millis();
}

void loop() {
  pulseA.rpmData();
  displayMillis = millis();
  if (displayMillis >= prevDisplayMillis + refresh) {
    prevDisplayMillis = millis();
    if (led == LOW) {
      led = HIGH;
    } else {
      led = LOW;
    }
    digitalWrite(LPIN, led);
    showData();
  }
}

void rpmAISR() {
  pulseA.rpmIsrMicros = micros();
  pulseA.rpmNewIsrFlag = true;
}

void phaseAISR() {
  pulseA.phaseIsrMicros = micros();
  pulseA.phaseNewIsrFlag = true;
}



void showData() {
  Serial.println();
  Serial.println("===============");
  Serial.print("  FREQ  ");
  Serial.print(pulseA.freq);
  Serial.print(" Hz");
  Serial.print("  RPM  ");
  Serial.print(pulseA.rpm);
  Serial.print("   Timing  ");
  Serial.print(pulseA.timing);
  Serial.print("*");
  Serial.println();
}

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