A timer seems to run faster when using classes. In a C version, it works as expected

1

A timer in Arduino seems to run faster when using classes. But in a C version (with the same values), it works as expected.

  1. I coded a quick and dirty version for a NEC infrared protocol decoder on Arduino UNO (kind of plain C, no classes). It worked.

  2. I coded a class in C++ (encapsulating data) for the same problem, but Timer1 seems to run a lot faster. In the C version I got 13500 microseconds for a run, which is Ok and expected. In the C++ version I got 5 microseconds. It makes no sense.

  3. I rewrite the C version in a module (*.cpp and *.h; though it's cpp I'm not using classes) and it still worked.

The ISRs runs in both C and C++, but for a unknown reason the Timer1 runs faster, or it's not running whatsoever.

// C version of the initializer function:
void ir_init(  IR_Nek* self, uint8_t pin, uint8_t address )
{
    self->pin = pin;
    self->address = address;

    self->bits = 0;
    self->error = false;
    self->done = false;

    TCCR1A = 0;
    TCCR1B = 0;                                    
    TCNT1  = 0;                                    
    TIMSK1 = 1;                                    

    pinMode( self->pin, INPUT );
}


// C version of the NEC core decoder:
void ir_decode_isr( IR_Nek* self )
{
    static uint8_t state = 0;
    static uint8_t bit_counter = 0;
    uint16_t period = 0;

    digitalWrite( 13, HIGH );

    switch( state ){

        case 0:
            self->error = false;

            TCNT1 = 0;
            TCCR1B = 2;
            state = 1;

            break;

        case 1:
            period = TCNT1 >> 1;
            TCNT1 = 0;

            if( 13000 < period and period < 14000 ){
                state = 2;
                self->done = false;
                bit_counter = 32;
                self->bits = 0L;
            } else{
                state = 0;
                self->error = true;
                TCCR1B = 0;
            }
            break;

        case 2:
        {

            period = TCNT1 >> 1;
            TCNT1 = 0;

            uint8_t bit_val;
            if( 1000 < period and period < 1300 ){
                bit_val = 0;
            } else if( 2100 < period and period < 2400 ){
                bit_val = 1;
            } else{
                state = 0;
                self->error = true;
                TCCR1B = 0;
            }

            self->bits |= bit_val ? 0x00000001 : 0x00000000;
            if( bit_counter > 1 ) self->bits <<= 1;

            --bit_counter;
            if( bit_counter == 0 ){
                TCCR1B = 0;
                state = 0;
                self->error = false;
                self->done = true;
            }

            break;
        }

        default:
            TCCR1B = 0;
            state = 0;
            self->done = false;
            self->error = true;
            break;

    } // switch

    digitalWrite( 13, LOW );
}


// C++ constructor:
IR_Nek::IR_Nek( uint8_t pin, uint8_t address ) :
    pin{pin}, address{address}
{
    this->bits = 0;
    this->error = false;
    this->done = false;

    TCCR1A = 0;
    TCCR1B = 0;                                    
    TCNT1  = 0;                                    
    TIMSK1 = 1;                                    

    pinMode( this->pin, INPUT );
}


// C++ version of the NEC core decoder
void IR_Nek::decode_isr()
{
    static uint8_t state = 0;
    static uint8_t bit_counter = 0;
    uint16_t period = 0;

    switch( state ){

        case 0:
            this->error = false;

            TCNT1 = 0;
            TCCR1B = 2;
            state = 1;

            break;

        case 1:
            period = TCNT1 >> 1;
            TCNT1 = 0;

            if( 13000 < period and period < 14000 ){
                state = 2;
                this->done = false;
                bit_counter = 32;
                this->bits = 0L;
            } else{
                state = 0;
                this->error = true;
                TCCR1B = 0;
            }
            break;

        case 2:
        {

            period = TCNT1 >> 1;
            TCNT1 = 0;

            uint8_t bit_val;
            if( 1000 < period and period < 1300 ){
                bit_val = 0;
            } else if( 2100 < period and period < 2400 ){
                bit_val = 1;
            } else{
                state = 0;
                this->error = true;
                TCCR1B = 0;
            }

            this->bits |= bit_val ? 0x00000001 : 0x00000000;
            if( bit_counter > 1 ) this->bits <<= 1;

            --bit_counter;
            if( bit_counter == 0 ){
                TCCR1B = 0;
                state = 0;
                this->error = false;
                this->done = true;
            }

            break;
        }

        default:
            TCCR1B = 0;
            state = 0;
            this->done = false;
            this->error = true;
            break;

    } // switch
}

I expect something between 13000 and 14000 microseconds, but I get 5.

c++
timer
arduino

1 Answer

1

I don't know anything about Arduino, but I'm going to guess the difference is because you call digitalWrite( 13, HIGH ); at the top of ir_decode_dsr(), but neglect to do so at the top of IR_Nek::decode_isr().

answered on Stack Overflow Aug 3, 2019 by Jeremy Friesner

User contributions licensed under CC BY-SA 3.0