Reputation: 33
I have this code:
#include <Arduino.h>
#include "esp_timer.h"
//volatile int iCounter; <-- Uncommenting this line makes iCounter update in myTestFn()
class Test {
public:
Test(void) {
esp_timer_handle_t testTimer;
esp_timer_create_args_t timerConfig;
timerConfig.arg = this;
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 );
}
static void testFn(void *arg) {
Test *obj = (Test *)arg;
obj->myTestFn();
}
void myTestFn(void) {
iCounter = iCounter +1;
Serial.printf("Test succeeded! Counter: %d Time elapsed: %lu.%03lu sec\n", iCounter, millis() / 1000, millis() % 1000);
}
private:
volatile int iCounter; // <-- This does not work, iCounter does not update in myTestFn()
};
void setup() {
Serial.begin(115200);
while(!Serial);
Test justATestObject;
}
void loop() {
}
I expected the iCounter variable to be indexed with each call to myTestFn(), but the value remains 1.
When I move the declaration of iCounter outside the class Test{} it does update (which seems odd to me). How do I get "Test" class member variables to update inside myTestFn()?
Upvotes: 0
Views: 65
Reputation: 106
You almost had the problem in hand and tried to program around it. This is one of those painful impedance mismatches between the C-oriented SDK and C++ dev.
Your problem is that you don't have a class instance from the interrupt context. The interrupt callback is a C function. Your interrupt callback is C++ and because you're using class data, you need a 'this' pointer that you don't have because the interrupt doesn't have a class instance. It works when you move the counter outside the class because it's then a global and not this->iCounter (remember that the 'this' is optional in even vaguely modern C++.)
There are two ways around this that I can think of. I'm typing from memory and the syntax is finicky, so this is more of a "launchpad" answer than a "paste this into your code" answer.
I'm pretty sure that the answer is in this approximate space, though I surely have the precise C++ spellings wrong. Key words like PMF (pointer to [static] member function), capture this, and, generally, interrupt handling in C++ should help further google-fu.
Remember, too, that data that can be touched by an interrupt handler on ESP32 needs to be marked IRAM_ATTR. If you get a (LoadProhibited). Exception was unhandled. when trying to access your instance data, you'll know you've run afoul of this. Running printf in an interrupt handler is a pretty brave thing to do.
Upvotes: 0