Skip to content

timerAttachInterrupt with object method callback #8422

Closed
@radiantBear

Description

@radiantBear

Board

ESP32-D0WD-V3

Device Description

Just a plain module on a breadboard

Hardware Configuration

Nothing is connected.

Version

latest master (checkout manually)

IDE Name

Arduino IDE

Operating System

Windows 10

Flash frequency

Presumably 80MHz; not relevant to issue

PSRAM enabled

yes

Upload speed

921600

Description

I'm trying to use timer interrupts and alarms within a class to contain its update needs. The function to call is a method in the class. But when passing that into timerAttachInterrupt() I'm getting this error: Invalid use of non-static member function 'void Test::testFn()'.

However, I cannot simply make the method static because I need to modify other members specific to my object instance.

To get around this issue in the past, I've passed a lambda function as a callback with this specified, and then used that to call the class method ([&]() {update();}). However, when I try that with timerAttachInterrupt(), I get the error: Cannot convert 'Test::Test()::<lambda()>' to 'void (*)()'.

I found a similar issue from a few years ago (#3465), and tried using <FunctionalInterrupt.h> and the example in the Ticker library as suggested. (I also tried commenting on that issue, but it's marked as closed, so I'm creating a new issue.) However, their suggested code produces the error Invalid use of member function 'void Test::testFn()' (did you forget the '()' ?), and I'm not sure how to remedy that. Nothing I've found searching online forums has provided any explanation of what's failing in this case either.

How can timer interrupts be done within classes? I can't make the timer ISR method static as I want it to be object dependant to process the attribute values for the particular object.

P.S.
Interestingly, attachInterrupt() (located in FunctionalInterrupt.h) does at least allow the use of lambda function callbacks, which timerAttachInterrupt() does not. I assume this is because that function uses the type std::function<void(void)> for its callback, while timerAttachInterrupt() uses void (*fn)(void), though I don't know why this difference exists. Would it be possible to change timerAttachInterrupt() to use the same callback type?

Sketch

#include "esp_timer.h"

class Test {
    public:
        Test(void) {
            esp_timer_handle_t testTimer;
            esp_timer_create_args_t timerConfig;
            timerConfig.arg = 0;
            timerConfig.callback = reinterpret_cast<esp_timer_cb_t>(testFn);
            timerConfig.dispatch_method = ESP_TIMER_TASK;
            timerConfig.name = "Test_Timer";
            esp_timer_create(&timerConfig, &testTimer);
            esp_timer_start_periodic(testTimer, 1000000);
        }

        void testFn(void) {
            Serial.print("Test succeeded! Time elapsed: ");
            Serial.printf("%lu.%03lu sec\n", millis() / 1000, millis() % 1000);
        }
};

void setup() {
    // put your setup code here, to run once:

    Serial.begin(115200);
    while(!Serial);

    Test justATestObject;
}

void loop() {
    // put your main code here, to run repeatedly:
}

Debug Message

Invalid use of member function 'void Test::testFn()' (did you forget the '()' ?)

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.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions