How to use a c++ class as wrapper for timer-interrupts on RP2040 (RPPico)

136 Views Asked by At

I want to write a C++ wrapper class which can be used to handle multiple timer interrupts in parallel.

For one interrupt at a time i have a working solution similar to this one: Use lambda function as microcontroller interrupts handler

My wrapper class looks like this:

class Rp2040RepeatingTimer {
private:
    struct repeating_timer _repeating_timer;  /* Config for repeating timer*/
    std::function<void()> _callback;
    static Rp2040RepeatingTimer* _instance;

    static bool timerHandler(struct repeating_timer *t){
        if (_instance){
            _instance->_callback();
        }
        return true;
    }

public:
    Rp2040RepeatingTimer(std::function<void()> _callback) : _callback(_callback) {
        _instance = this;
    }

    bool start(const int32_t intervall);
    bool stop();
};

My test program looks like this:

Rp2040RepeatingTimer* Rp2040RepeatingTimer::_instance = nullptr;
    
int main(){
    stdio_init_all();

    // Handle interrupt
    // This lambda function is never called when timer1 occurs
    Rp2040RepeatingTimer timer1([]() {
        printf("GOTCHA 1");
    });

    Rp2040RepeatingTimer timer2([]() {
        printf("GOTCHA 2");
    });

    timer1.start(500);
    timer2.start(1000);

    while(1){}
}

Nevertheless, in this case all class instances share the same static value for the instance, which makes it impossible to use this solution for handling multiple timers. Any ideas how to adopt it for multiple interrupt handlers in parallel?

1

There are 1 best solutions below

0
Vanessa 0 On

Thanks to @TerenceSimpson I was able to figure out a working solution for my problem. The idea was to use the user_data-pointer of the interrupt handler to pass the corresponding timer obejct (which in return stores the function pointer to the user-callback).

My timer.hpp file for class declaration:

class Rp2040RepeatingTimer {
private:
    struct repeating_timer _repeating_timer;    /* Config for repeating timer*/ 
    std::function<void()> _callback;            /* function pointer to user callback */
    static bool timerHandler(struct repeating_timer *t); /* Timer ISR */

public:
    Rp2040RepeatingTimer(){
        /* Set pointer to current timer object as user data to pass to the timer ISR */
        _repeating_timer.user_data = this; 
    }

    bool start(const int32_t intervall, const std::function<void()> &callback); 
    bool stop();
};

My timer.cpp file for function defintion:

/* Timer ISR - Call stored user callback gathered from user_data */
bool Rp2040RepeatingTimer::timerHandler(struct repeating_timer *t){
    static_cast<Rp2040RepeatingTimer*>(t->user_data)->_callback();
    return true;
}

bool Rp2040RepeatingTimer::start(const int32_t intervall, const std::function<void()> &callback){
    _callback = callback;
    return add_repeating_timer_ms(intervall, timerHandler, this, &_repeating_timer);
}   

bool Rp2040RepeatingTimer::stop(){
    return cancel_repeating_timer(&_repeating_timer);
}

My main.cpp for testing:

void callback1(){
    printf("\nGOTCHA 1");
}

void callback2(){
    printf("\nGOTCHA 2");
}


int main(){
    stdio_init_all();

    Rp2040RepeatingTimer timer1;
    Rp2040RepeatingTimer timer2;

    if(timer1.start(500, callback1)){
        printf("\nTimer 1 started");
    }  
    if(timer2.start(1000, callback2)){
        printf("\nTimer 2 started");
    }    

    while(1){}
}