Embedded: How replace the interrupt vector call with a lambda (poiner to member) in C++17

50 Views Asked by At

At the moment I have a problem. I want to replace the interrupt vector target call for a peripheral driver. What works for now is this:

namespace test
{
  class PortDriver{
  public:
      using InterruptHandler = void(*)();

      constexpr explicit PortDriver(const uint16_t targetAddress) {
          // Assign the interrupt handler directly to the target address
          *reinterpret_cast<InterruptHandler*>(targetAddress) = irqPort;
      }

      static void irqPort(void) 
      {
          ...
      }
  };

But this is not what I want. I want to instantiate it with a pointer to member function. So when I do this:

    constexpr uint16_t targetAddress1 = 0xFFD8;
    PortDriver<targetAddress1> port1Driver;

    constexpr uint16_t targetAddress2 = 0xFF09;
    PortDriver<targetAddress2> port2Driver;

I want to have two irq functions for the two interrupt vectors I have to be created. Best would be at compile time because of performance issues.

I have no clue if and how this could work. Maybe with a lambda but I dont know how.

It should look like this:

template <uint16_t TargetAddress>
class PortDriver {
public:
    using InterruptHandler = void(*)();
    constexpr explicit PinDriver() {
        // Assign the interrupt handler using a lambda function
        *reinterpret_cast<InterruptHandler*>(TargetAddress) = [this]() { irqHandler(); };
    }

    void irqHandler() {
       ...
    } 
};

but this does not compile

1

There are 1 best solutions below

1
Igor Tandetnik On

Something along these lines, perhaps:

template <uint16_t TargetAddress>
class PortDriver {
public:
    using InterruptHandler = void(*)();

    static void Register() {
        *reinterpret_cast<InterruptHandler*>(TargetAddress) = irqHandlerTrampoline;
    }

    static PortDriver& Instance() {
      static PortDriver driver;
      return driver;
    }

    static void irqHandlerTrampoline() {
      Instance().irqHandler();
    }

    void irqHandler() {
       // ...
    } 
};

// To initialize, call
PortDriver<targetAddress1>::Register();

Basically, turn a driver for each port into a singleton; I assume it doesn't make sense to have multiple drivers per port.