Skip to content

timerAttachInterrupt(timer, onTimerISR, true); ISR is called immediately on timerAlarmEnable, not after the time #7336

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
1 task done
mianos opened this issue Oct 10, 2022 · 6 comments
Assignees
Labels
Area: Peripherals API Relates to peripheral's APIs.
Milestone

Comments

@mianos
Copy link

mianos commented Oct 10, 2022

Board

ESP32 Dev Module

Device Description

Tried on, Heltec Lora 32. Lilygo bare ESP and TTGO ESP32 LCD

Hardware Configuration

None, stanadlone

Version

v2.0.5

IDE Name

Platformio

Operating System

Windows

Flash frequency

40Mhz

PSRAM enabled

yes

Upload speed

115200

Description

On timer ISR is called as soon as the timer is enabled, not after the time.
Connecting an oscilloscope to pin 18 I can see it's only about 20uS between zcisr and onTimerISR no matter what the delay is.

The sketch in the following block is the ESP32 version.
The same thing in ESP8266 works:

#include <Arduino.h>

static volatile int zloops;
static volatile int loops;
static volatile int cycle_time = 100;

static const uint8_t GPIO_Pin = 5;
static const uint8_t Control_Pin = 4;

IRAM_ATTR void zcisr() {
  // 5 per uSec so 200 per mS
  // so 100ms is 100 * 200
  zloops++;
  // notes:
  // 100hz, two waves
  // 10mS of time
  // 100 divisions?
  // 500 divisions? then simple 0-500 for the timer
  //
//  for (auto ii = 0; ii < ipins_size; ii++) {
//    digitalWrite(ipins[ii], HIGH);
//  }
  timer1_write(cycle_time * 50); // (2500000 / 5) ticks per us from TIM_DIV16 == 500,000 us interval
  digitalWrite(Control_Pin, HIGH);
}

void IRAM_ATTR onTimerISR() {
//  for (auto ii = 0; ii < ipins_size; ii++) {
//    digitalWrite(ipins[ii], LOW);
//  }
  loops++;
  digitalWrite(Control_Pin, LOW);
}


void setup() {
  Serial.begin(115200);
  Serial.printf(" connect\n");
  tzset();

  pinMode(GPIO_Pin, INPUT_PULLUP);

  attachInterrupt(GPIO_Pin, zcisr, RISING);

  pinMode(Control_Pin, OUTPUT);
  timer1_attachInterrupt(onTimerISR);
  timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE);
  /* Dividers:
  TIM_DIV1 = 0,   //80MHz (80 ticks/us - 104857.588 us max)
  TIM_DIV16 = 1,  //5MHz (5 ticks/us - 1677721.4 us max)
  TIM_DIV256 = 3  //312.5Khz (1 tick = 3.2us - 26843542.4 us max)
  Reloads:
  TIM_SINGLE	0 //on interrupt routine you need to write a new value to start the timer again
  TIM_LOOP	1 //on interrupt the counter will start with the same value again
  */
}


void loop() {
  Serial.printf("loops %d zloops %d\n", loops, zloops);
  delay(1000);
}

Sketch

#include <Arduino.h>


static volatile int loops;
static volatile int zloops;
static volatile uint64_t rval;

volatile SemaphoreHandle_t timerSemaphore;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
portMUX_TYPE zcrMux = portMUX_INITIALIZER_UNLOCKED;

hw_timer_t * timer = NULL;

static const uint8_t control_pin = 18;
static const uint8_t zero_crossing_pin = 22;


hw_timer_t * zcrtimer = NULL;


IRAM_ATTR void zcisr() {
  portENTER_CRITICAL_ISR(&zcrMux);
  zloops++;
  portEXIT_CRITICAL_ISR(&zcrMux);
  digitalWrite(control_pin, HIGH);
  timerAlarmEnable(timer);
}

IRAM_ATTR void onTimerISR() {
  portENTER_CRITICAL_ISR(&timerMux);
  loops++;
  portEXIT_CRITICAL_ISR(&timerMux);
  digitalWrite(control_pin, LOW);
}


void setup() {
  Serial.begin(115200);

  pinMode(control_pin, OUTPUT);
  timer = timerBegin(0, 80, true);
  timerAttachInterrupt(timer, onTimerISR, true);
  timerAlarmWrite(timer, 3000, true);
#if 0
  pinMode(zero_crossing_pin, INPUT_PULLUP);
  attachInterrupt(zero_crossing_pin, zcisr, RISING);
#else
  // If no real zero crossing hardware set a 100Hz repeating timer
  zcrtimer = timerBegin(1, 80, true);
  timerAttachInterrupt(zcrtimer, zcisr, true);
  timerAlarmWrite(zcrtimer, 10000, true);
  timerAlarmEnable(zcrtimer);
#endif
}


void loop() {
  int l_loops, l_zloops, l_rval;
  portENTER_CRITICAL(&timerMux);
    l_loops = loops;
    l_rval = rval;
  portEXIT_CRITICAL(&timerMux);
  portENTER_CRITICAL(&zcrMux);
    l_zloops = zloops;
  portEXIT_CRITICAL(&zcrMux);
  Serial.printf("counts %d zloops %d rval %d\n", l_loops, l_zloops, l_rval);
  delay(1000);
}

Debug Message

No debug messages. Just does not work.

Other Steps to Reproduce

No response

I have checked existing issues, online documentation and the Troubleshooting Guide

  • I confirm I have checked existing issues, online documentation and Troubleshooting guide.
@mianos mianos added the Status: Awaiting triage Issue is waiting for triage label Oct 10, 2022
@P-R-O-C-H-Y P-R-O-C-H-Y self-assigned this Oct 10, 2022
@VojtechBartoska VojtechBartoska added Status: Needs investigation We need to do some research before taking next steps on this issue Area: Peripherals API Relates to peripheral's APIs. and removed Status: Awaiting triage Issue is waiting for triage labels Oct 10, 2022
@VojtechBartoska VojtechBartoska added this to the 3.0.0 milestone Oct 10, 2022
@mrengineer7777
Copy link
Collaborator

mrengineer7777 commented Oct 13, 2022

Direct hardware access of the timers on the ESP32 is possible but tricky. I believe one of the hardware timers on the ESP32 is used for generating system ticks. I suspect you are accidentally modifying that timer. You may need to dig into ESP-IDF to determine which hardware timer they are using.

We use the arduino-esp32 "Ticker" class. Works great for our needs.

@Dork57
Copy link

Dork57 commented Oct 17, 2022

I had a similar issue.
Did you try timerRestart(myTimer); befor timerAlarmWrite(...);?
This works for me.

@sweetlilmre
Copy link
Contributor

What is happening here is that you are enabling the timer, but the period has already expired.

I tested your code and observed similar behaviour to what you have described. I used esp_timer_get_time() to measure the time between enabling the timer and the interrupt firing and this was about 5us on my board. In my experience this aligns to what I've seen in terms of overhead between the interrupt occurring and the handler getting invoked.

Thinking about it for a bit I added a timerWrite(timer, 0); call just before setting timerAlarmEnable(timer); This resulted in a the interrupt firing at 3011 which is what you want. Which is what TimerRestart() does as per @Dork57 's answer.

@mianos
Copy link
Author

mianos commented Oct 27, 2022

Awesome. I'll try this today. Thanks.

@sweetlilmre
Copy link
Contributor

@mianos did this work for you and if so, can you close the issue?

@mianos
Copy link
Author

mianos commented Oct 28, 2022

No time. I assume this is the fix. Closing.

@mianos mianos closed this as completed Oct 28, 2022
Repository owner moved this from Todo to Done in Arduino ESP32 Core Project Roadmap Oct 28, 2022
@VojtechBartoska VojtechBartoska removed the Status: Needs investigation We need to do some research before taking next steps on this issue label Nov 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: Peripherals API Relates to peripheral's APIs.
Projects
Development

No branches or pull requests

6 participants