Issue with timings on the ESP32 C3 supermini

Hi all,

I am trying the code below and I am having some strange output behaviour. Can anyone please guide me to with could be causing this? I know that 99.9% this is not the correct way of how this should be coded, but I am not a seasoned programmer and I want to keep the code as simple as possible. Attached please also find samples of when the pulse is not showing correctly. The pulses should all look alike (same delay and same on-time). Please note that the ISRs are never triggered simultaneously.

How the program should work: I have two inputs and two outputs. The input 1 will trigger ISR OutputPin_1_ISR, while input 2 will trigger ISR OutputPin_2_ISR. Once the respective ISR is executed, it will trigger the respective output according to the pre-defined delay (defined by Pulse_Delay_currentTime and Pulse_Delay_lastTime) and on-time/pulse-high (defined by Pulse_currentTime and Pulse_lastTime).




#define Input_Pin_1 2
#define Input_Pin_2 3
#define Output_Pin_1 8
#define Output_Pin_2 9

int pulseWidth = 2500;

unsigned long Pulse_currentTime_1 = 0;
volatile unsigned long Pulse_lastTime_1 = 0;

unsigned long Pulse_currentTime_2 = 0;
volatile unsigned long Pulse_lastTime_2 = 0;

volatile int Flag_Pulse_1 = 0;
volatile int Flag_Pulse_2 = 0;

unsigned long Pulse_Delay_currentTime_1 = 0;
volatile unsigned long Pulse_Delay_lastTime_1 = 0;

unsigned long Pulse_Delay_currentTime_2 = 0;
volatile unsigned long Pulse_Delay_lastTime_2 = 0;

volatile int Flag_Pulse_Delay_1 = 1;
volatile int Flag_Pulse_Delay_2 = 1;

unsigned long delay_time = 500;

void setup()
{

pinMode(Input_Pin_1, INPUT_PULLUP);
pinMode(Input_Pin_2, INPUT_PULLUP);

pinMode(Output_Pin_1, OUTPUT);
pinMode(Output_Pin_2, OUTPUT);

attachInterrupt(digitalPinToInterrupt(Input_Pin_1), OutputPin_1_ISR, FALLING);
attachInterrupt(digitalPinToInterrupt(Input_Pin_2), OutputPin_2_ISR, FALLING);
}

void loop()
{
// PULSE OUTPUT 1

if (Flag_Pulse_1 == 1)
{
Pulse_Delay_currentTime_1 = micros();
if ((Pulse_Delay_currentTime_1 - Pulse_Delay_lastTime_1) >= delay_time)
{
Flag_Pulse_Delay_1 = 0;
}
if(Flag_Pulse_Delay_1 == 0)
{
digitalWrite(Output_Pin_1, HIGH);
Pulse_currentTime_1 = micros();
if ((Pulse_currentTime_1 - Pulse_lastTime_1) >= pulseWidth)
{
digitalWrite(Output_Pin_1, LOW);
Flag_Pulse_1 = 0;
Flag_Pulse_Delay_1 = 1;
}
}
}

// PULSE OUTPUT 2

if (Flag_Pulse_2 == 1)
{
Pulse_Delay_currentTime_2 = micros();
if ((Pulse_Delay_currentTime_2 - Pulse_Delay_lastTime_2) >= delay_time)
{
Flag_Pulse_Delay_2 = 0;
}
if(Flag_Pulse_Delay_2 == 0)
{
digitalWrite(Output_Pin_2, HIGH);
Pulse_currentTime_2 = micros();
if ((Pulse_currentTime_2 - Pulse_lastTime_2) >= pulseWidth)
{
digitalWrite(Output_Pin_2, LOW);
Flag_Pulse_2 = 0;
Flag_Pulse_Delay_2 = 1;
}
}
}
}

void OutputPin_1_ISR()
{
Flag_Pulse_1 = 1;
Flag_Pulse_Delay_1 = 1;
Pulse_lastTime_1 = micros();
Pulse_Delay_lastTime_1 = micros();
}

void OutputPin_2_ISR()
{
Flag_Pulse_2 = 1;
Flag_Pulse_Delay_2 = 1;
Pulse_lastTime_2 = micros();
Pulse_Delay_lastTime_2 = micros();
}

Please explain what you expected to happen and describe what happened instead.

An overview of the project goals would be useful.

Definitely, sorry for not mentioning this straight away. So basically I have two inputs and two outputs. The inputs will trigger separate ISRs. Once the ISR is executed, it will trigger the respective output according to the pre-defined delay and on-time (pulse high).

How about the other question?

I moved your topic to a more appropriate forum category @techgzt .

The Nano ESP32 category you chose is only used for discussions directly related to the Arduino Nano ESP32 board.

In the future, please take the time to pick the forum category that best suits the subject of your question. There is an "About the _____ category" topic at the top of each category that explains its purpose.

Thanks in advance for your cooperation.

I tried removing all the micros() and instead used delayMicroseconds() in the ISRs. It looks like it is working fine this way. So i am assuming the issue is with the micros(). The only issue is that i don't want the program to delay in the ISRs (or any other part for that matter) as this will delay other processes (ex: calculating the RPM which i still need to include)

UPDATE: I tried this code on a standard ESP32 (Wroom 32) and it performed the same. Tried on the Arduino Nano and somehow it looks like it is performing better ... not sure why. Anyways, I still plan to use the Arduino Nano for the final project. The only problem is that I am still noticing some random glitches, like the one show below. Any clue of what could be causing this issue?

nothing?

you are using an ESP32C3 where the RMT has two output channels
maybe worth looking at that

e.g. 100kHz three phase signal on a ESP32S3 which has four output channels and supports synchronization

Hi horace. Thanks for the reply. I am currently using the Arduino Nano, not the ESP32C3. In the code, I am just using micros() to read the current time/value. I don't know that could be causing the random "glitches" in the output waveforms.

running your code on an ESP32 - only modification is to pins

#define Input_Pin_1 2                   
#define Input_Pin_2 3                  
#define Output_Pin_1 4            
#define Output_Pin_2 5       

using a dual pulse generator outputting 200Hz square waves into pins 2 and 3 pins 4 and 5 look stable

output pulse widths are 2mSec

is that what you expect?

I can see no sign of "glitches" - could you trigger source be the problem?

if you require a 2mSec pulse output when triggered it is probably simpler to use a hardware timer

1 Like

using a hardware timer

// ESP32 dual pulses on trigger
// https://forum.arduino.cc/t/issue-with-timings-on-the-esp32-c3-supermini/1335761/12

// output is LOW
// on trigger input falling edge interrupt is generated
// GPIO ISR set output HIGH and starts timer alarm
// timer alarm timesout and generates interrupt
// timer ISR set output LOW

#define Input_Pin_1 22  // input pins
#define Input_Pin_2 23
#define Output_Pin_1 4  // output pins
#define Output_Pin_2 5

hw_timer_t *timer1 = NULL;
hw_timer_t *timer2 = NULL;

// interrupt counters
volatile int int1, int2, int3, int4;

// trigger input 1 interrupt - output 1 HIGH and start timer
void IRAM_ATTR OutputPin_1_ISR() {
  int1++;
  digitalWrite(Output_Pin_1, HIGH);
  timerWrite(timer1, 0);  // clear timer counter
  timerAlarm(timer1, 100, false, 0);
}

// output 1 timer interrupt - output 1 LOW
void IRAM_ATTR onTimer1() {
  int2++;
  digitalWrite(Output_Pin_1, LOW);
}

// trigger input 2 interrupt - output 2 HIGH and start timer
void IRAM_ATTR OutputPin_2_ISR() {
  int4++;
  digitalWrite(Output_Pin_2, HIGH);
  timerWrite(timer2, 0);  // clear timer counter
  timerAlarm(timer2, 200, false, 0);
}

// output 2 timer interrupt - output 2 LOW
void IRAM_ATTR onTimer2() {
  int3++;
  digitalWrite(Output_Pin_2, LOW);
}

void setup() {
  Serial.begin(115200);
  delay(2000);
  Serial.println("ESP32 dual pulses on trigger");
  pinMode(Input_Pin_1, INPUT_PULLUP); // setup digital IO
  pinMode(Input_Pin_2, INPUT_PULLUP);
  pinMode(Output_Pin_1, OUTPUT);
  pinMode(Output_Pin_2, OUTPUT);
  digitalWrite(Output_Pin_1, LOW);
  digitalWrite(Output_Pin_2, LOW);
  Serial.println("enable timers");
  // Set timer frequency to 100KHzhz
  if ((timer1 = timerBegin(100000)) != NULL)
    Serial.println("Timer1 initialized");
  else Serial.println("Timer1 failed");
  if ((timer2 = timerBegin(100000)) != NULL)
    Serial.println("Timer2 initialized");
  else Serial.println("Timer2 failed");
  // Attach onTimer function to our timer.
  timerAttachInterrupt(timer1, &onTimer1);
  timerAttachInterrupt(timer2, &onTimer2);
  delay(1000);
  attachInterrupt(digitalPinToInterrupt(Input_Pin_1), OutputPin_1_ISR, FALLING);
  attachInterrupt(digitalPinToInterrupt(Input_Pin_2), OutputPin_2_ISR, FALLING);
  Serial.println("interrupts enabled");
}

// display interrupt counters every second
void loop() {
  static long timer1 = millis();
  if (millis() - timer1 > 1000) {
    Serial.printf("%d %d %d %d\n", int1, int2, int3, int4);
    timer1 = millis();
  }
  return;
}

oscilloscope output

yellow trigger input 200Hz pulses
blue output 1 - 1mSec wide pulses
purple output 2 - 2mSec wide pulses

detailed view

serial monitor output

ESP32 dual pulses on trigger
enable timers
Timer1 initialized
Timer2 initialized
interrupts enabled
200 200 200 200
400 400 400 400
601 600 600 601
801 801 800 801
1001 1001 1001 1001
1201 1201 1201 1201
1401 1401 1401 1401
1602 1601 1601 1602
1802 1802 1801 1802
2002 2002 2002 2002