This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Is it possible to use a private method of a C++ class as an ISR? In other words, is it possible to encapsulate the ISR inside of a C++ class?

Other Parts Discussed in Thread: CCSTUDIO, MSP430G2553

Folks,

It would be neat to be able to make the ISR a private method on a class, and to make the variables (e.g. counters) used by the ISR private fields on the same class. That would encapsulate the ISR inside of the class. The information from the ISR will be available through public getter methods.

I wrote the following quick test class. To my surprise, it had compiled (CCStudio 6.1.0.00104). I was expecting that the compiler would demand that I make the ISRs and private fields static.  Why didn't it complain?  Where will the ISR call be routed at runtime (there may be multiple instances)?

class InterruptHandler {
public:
	bool GetNMIFlag() { return m_nmiFlag; }
	bool GetWDTFlag() { return m_wdtFlag; }

private:
	bool m_nmiFlag, m_wdtFlag;

	// PURPOSE: Keep track of button presses
	#pragma vector=NMI_VECTOR
	__interrupt void nmi_isr(void) {
		m_nmiFlag = true;
		__bic_SR_register_on_exit(LPM4_bits);	// exit the LPM on return from the ISR
	}

	// PURPOSE:	Keep track of time while napping. Allow cyclic wake up.
	#pragma vector=WDT_VECTOR
	__interrupt void wdt_isr(void) {
		m_wdtFlag = true;
		__bic_SR_register_on_exit(LPM3_bits);	// exit the LPM on return from the ISR
	}
};

Of course, I can call the interrupt handler object from a free-standing ISR function, but that doesn't completely encapsulate the interrupt handling.

Any suggestion, insight or reference is really appreciated!

Cheers,
- Nick

  • In C++, accesses to member variables go through the this pointer, which is an implicit parameter to non-static member functions. In other words, the following two functions are essentially the same:

    void C::member(int x)
    {
        var = x;
    }
    
    void C_member(C* this, int x)
    {
        this->var = x;
    }

    An interrupt function must not have any parameters (because the CPU will not provide any when calling it).
    This also applies to the implicit this parameter.

    In other words, you cannot make a member function an interrupt handler, because you have no (valid) this.
    (The compiler should have complained.)

    What you can do, however, is to use a static member function, which does not have a this pointer:

    class C {
        static interrupt void isr(void);
    };
    
    #pragma ...
    __interrupt void C::isr(void)
    {
        C* the_object = ...;
        the_object->some_member_function();
    }

    If you want to call some 'real' member function, you need to get the object pointer from somewhere, probably from a global variable.

  • Nick Alexeev said:
    I wrote the following quick test class. To my surprise, it had compiled (CCStudio 6.1.0.00104). I was expecting that the compiler would demand that I make the ISRs and private fields static.  Why didn't it complain?

    I compiled that example, and under CCS Project Properties -> CCS Build -> MSP430 Compiler -> Advanced Options -> Assembler Options ticked the "Keep the generated assembly language (.asm) file (--keep_asm, -k)" option. I wanted to check the generated assembler for the nmi_isr and wdt_isr functions to check for how the implicit "this" parameter to the class instance was handled.

    However, the generated assembly file didn't contain the nmi_isr and wdt_isr functions. Realized that this was because there was no reference to the nmi_isr and wdt_isr functions, and so the compiler realized it didn't need to generate any code for these functions.

    The example was then changed to add a constructor to reference the nmi_isr and wdt_isr functions, to force the compiler to attempt to generate the assembler for the functions:

    #include <msp430.h> 
    
    class InterruptHandler {
    public:
        bool GetNMIFlag() { return m_nmiFlag; }
        bool GetWDTFlag() { return m_wdtFlag; }
        InterruptHandler();
    
    private:
        bool m_nmiFlag, m_wdtFlag;
    
        // PURPOSE: Keep track of button presses
        #pragma vector=NMI_VECTOR
        __interrupt void nmi_isr(void) {
            m_nmiFlag = true;
            __bic_SR_register_on_exit(LPM4_bits);   // exit the LPM on return from the ISR
        }
    
        // PURPOSE: Keep track of time while napping. Allow cyclic wake up.
        #pragma vector=WDT_VECTOR
        __interrupt void wdt_isr(void) {
            m_wdtFlag = true;
            __bic_SR_register_on_exit(LPM3_bits);   // exit the LPM on return from the ISR
        }
    
    };
    
    InterruptHandler::InterruptHandler()
    {
    	typedef void (InterruptHandler::*isr_func)(void);
    	volatile isr_func isr_reference;
    	isr_reference = &InterruptHandler::nmi_isr;
    	isr_reference = &InterruptHandler::wdt_isr;
    }
    
    InterruptHandler theIsr;
    
    /*
     * main.c
     */
    int main(void) {
        WDTCTL = WDTPW | WDTHOLD;	// Stop watchdog timer
    	
    	return theIsr.GetWDTFlag() + theIsr.GetNMIFlag();
    }
    

    Now that the compiler is attempting to generate the nmi_isr and wdt_isr functions, the example fails to compile reporting:

    Building file: ../main.cpp
    Invoking: MSP430 Compiler
    "/opt/ti/ti_ccs6_1_1/ccsv6/tools/compiler/ti-cgt-msp430_4.4.6/bin/cl430" -vmsp --abi=eabi --use_hw_mpy=none --include_path="/opt/ti/ti_ccs6_1_1/ccsv6/ccs_base/msp430/include" --include_path="/opt/ti/ti_ccs6_1_1/ccsv6/tools/compiler/ti-cgt-msp430_4.4.6/include" --advice:power=all -g --define=__MSP430G2553__ --diag_warning=225 --display_error_number --diag_wrap=off --printf_support=minimal -k --preproc_with_compile --preproc_dependency="main.pp" "../main.cpp"
    "../main.cpp", line 14 (col. 22): error #833: no parameters allowed for interrupt functions such as '_ZN16InterruptHandler7nmi_isrEv'

    >> Compilation failure
    "../main.cpp", line 21 (col. 22): error #833: no parameters allowed for interrupt functions such as '_ZN16InterruptHandler7wdt_isrEv'
    "../main.cpp", line 16 (col. 34): error #1358: intrinsic (__bic_SR_register_on_exit) only available within interrupt routines
    3 errors detected in the compilation of "../main.cpp".

**Attention** This is a public forum