ESP32 hardware timer. Can anyone explain why one code works and the other don't?

This code works:

#define LED 2

hw_timer_t *blinkTimer = NULL;
volatile bool toggle=0;
volatile bool flip=0;

void IRAM_ATTR blink(){
  toggle=!toggle;
  if (toggle){ // controversial if statement
    timerAlarmWrite(blinkTimer, 500000, true);
  }
  else if (!toggle){
    timerAlarmWrite(blinkTimer, 1500000, true);
  }
}

void setup() {
  Serial.begin(57600);
  pinMode(LED, OUTPUT);
  blinkTimer = timerBegin(0, 80, true);
  timerAttachInterrupt(blinkTimer, &blink, true);
  timerAlarmWrite(blinkTimer, 0, false); // controversial line
  timerAlarmEnable(blinkTimer);
}

void loop() {
  if (flip!=toggle){
    flip=toggle;
    digitalWrite(LED,toggle);
    Serial.println(toggle);
  }
}

This code does not work. "If statement" relocated.

 #define LED 2

hw_timer_t *blinkTimer = NULL;
volatile bool toggle=0;
volatile bool flip=0;

void IRAM_ATTR blink(){
  toggle=!toggle;
}

void setup() {
  Serial.begin(57600);
  pinMode(LED, OUTPUT);
  blinkTimer = timerBegin(0, 80, true);
  timerAttachInterrupt(blinkTimer, &blink, true);
  timerAlarmWrite(blinkTimer, 0, false); // controversial line
  timerAlarmEnable(blinkTimer);
}

void loop() {
  if (flip!=toggle){
    if (toggle){ // controversial if statement
      timerAlarmWrite(blinkTimer, 500000, true);
    }
    else if (!toggle){
      timerAlarmWrite(blinkTimer, 1500000, true);
    }
    flip=toggle;
    digitalWrite(LED,toggle);
    Serial.println(toggle);
  }
}

The 2nd code can be made to work if the controversial line is revised:

#define LED 2

hw_timer_t *blinkTimer = NULL;
volatile bool toggle=0;
volatile bool flip=0;

void IRAM_ATTR blink(){
  toggle=!toggle;
}

void setup() {
  Serial.begin(57600);
  pinMode(LED, OUTPUT);
  blinkTimer = timerBegin(0, 80, true);
  timerAttachInterrupt(blinkTimer, &blink, true);
  timerAlarmWrite(blinkTimer, 10, true); // controversial line
  timerAlarmEnable(blinkTimer);
}

void loop() {
  if (flip!=toggle){
    if (toggle){ // controversial if statement
      timerAlarmWrite(blinkTimer, 500000, true);
    }
    else if (!toggle){
      timerAlarmWrite(blinkTimer, 1500000, true);
    }
    flip=toggle;
    digitalWrite(LED,toggle);
    Serial.println(toggle);
  }
}

Please, explain the purpose of your sketch.

Bug is in the above.
Change it to: (tested in my ESP32 Dev Module)
===> timerAlarmWrite(blinkTimer, 10, true); // controversial line

from ChatGPT
true : This argument sets whether the timer should automatically reload and continue running after it triggers. When set to true , it indicates that the timer should automatically restart after each timeout, creating a repeating timer that triggers periodically.

If set to false , the timer would trigger once and then stop.

1 Like

I don't know if I can express in words what happens,
but I will try.
In the second code, which works, you change the timer values inside the interrupt routine.
Inside an interrupt routine, new interrupts are blocked, so you can change the value of timerAlarmWrite(), which was zero initially.

In the first case, which doesn't work, as the timer value is zero and the interrupt is always enabled, ESP keeps making interrupts at such a high speed that it doesn't allow new values to be loaded with timerAlarmWrite().

Another thing you did was set the timer reload condition to false in the setup() function.

I will put here 2 codes that work,
the first written in the correct way to prevent new interrupts, and the second without this protection, but it also works, (I don't even think it should).
But none of them works with the reload set to false.

#define LED 2
hw_timer_t *blinkTimer  = NULL;
volatile bool toggle = 0;
volatile bool flip = 0;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;

void IRAM_ATTR blink() {
  toggle = !toggle;
}

void setup() {
  Serial.begin(9600);
  pinMode(LED, OUTPUT);
  blinkTimer  = timerBegin(0, 80, true);
  timerAttachInterrupt(blinkTimer , &blink, true);
  timerAlarmWrite(blinkTimer , 10000, true);
  timerAlarmEnable(blinkTimer );
}

void loop() {
  if (flip != toggle) {
    portENTER_CRITICAL(&timerMux);
     if (toggle){
      timerAlarmWrite(blinkTimer , 500000, true);
    }
    else{
      timerAlarmWrite(blinkTimer , 1500000, true);
    }
    portEXIT_CRITICAL(&timerMux);
    flip = toggle;
    Serial.println(toggle);
  }
}

and

#define LED 2

hw_timer_t *blinkTimer = NULL;
volatile bool toggle=0;
volatile bool flip=0;

void IRAM_ATTR blink(){
  toggle=!toggle;
}

void setup() {
  Serial.begin(57600);
  pinMode(LED, OUTPUT);
  blinkTimer = timerBegin(0, 80, true);
  timerAttachInterrupt(blinkTimer, &blink, true);
  timerAlarmWrite(blinkTimer, 10000, true); // controversial line
  timerAlarmEnable(blinkTimer);
}

void loop() {
  if (flip!=toggle){
    if (toggle){ // controversial if statement
      timerAlarmWrite(blinkTimer, 500000, true);
    }
    else if (!toggle){
      timerAlarmWrite(blinkTimer, 1500000, true);
    }
    flip=toggle;
    digitalWrite(LED,toggle);
    Serial.println(toggle);
  }
}
1 Like

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