Atmel / Arduino: ISR(TIMER0_OVF_vect) won't co

2019-08-02 16:56发布

问题:

I'm currently working on a PWM modulator to "simulate" a car engine ignition commutation. Then, I will use it to drive another microcontroller which handles the conversion from a raw signal (engine's commutator) to a clean output voltage, going through the RPM-counter's galvanometer.

This project is also a pretext for me to learn how to have a better control upon my microcontroller.

Well, I wrote a small program, using timer0 (8 bits), and I need to trigger two interrupt service routines (ISRs):

  • TIMER0_OVF_vect: overflow interruption
  • TIMER0_COMPA_vect: fires on compare

I have the following functions:

void configureTimer0(parameters)
{
    cli();

    // Some maths
    TCCR0A = (1<<WGM01) | (1<<WGM00); // I tried to use the "Fast PWM" waveform generation mode
    TCCR0B &= 0b00110000; // 5th and 4th bits are reserved. Every other bits is set to 0.
    TCNT0 = 0; // Initialize counter value to 0

    TCCR0B |= select_prescaler(prescaler); // Custom function to determine the right prescaler
    OCR0A = ext_OnTicks; // Output compare register is set to a predetermined numbers of ticks

    // Enabling overflows interrupt:
    TIMSK0 |= (1 << TOIE0);
    sei(); // Enable interrupts
}

Then, under certain conditions, I switch the OCIE0 bit in TIMSK0 on and off depending on the situation. However, the overflow interruption is always enabled.

When I try to compile, I end up with these errors:

"C:\Users\UTILIS~1\AppData\Local\Temp\arduino_build_8383\sketch\PWM_modulator.ino.cpp.o" "C:\Users\UTILIS~1\AppData\Local\Temp\arduino_build_8383/..\arduino_cache_395570\core\core_arduino_avr_uno_a94ab6aaf61dfb93b4a8079c694a14c2.a" "-LC:\Users\UTILIS~1\AppData\Local\Temp\arduino_build_8383" -lm
wiring.c.o (symbol from plugin): In function `__vector_16':

(.text+0x0): multiple definition of `__vector_16'

C:\Users\UTILIS~1\AppData\Local\Temp\arduino_build_8383\sketch\PWM_modulator.ino.cpp.o (symbol from plugin):(.text+0x0): first defined here

collect2.exe: error: ld returned 1 exit status

exit status 1
Erreur de compilation pour la carte Arduino/Genuino Uno // Compilation error for Uno board (French)

I tried to compile with ISR(TIMER0_COMPB_vect) instead of ISR(TIMER0_OVF_vect), and it works, but indeed it's not the point of my program.

I also tried ISR(TIMER2_OVF_vect) which is an 8-bit timer as well. I could synchronize Timer0 and Timer2 to achieve the desired effect, however I don't think it is quite clean to do so (and it prevents me to use the Timer2 capabilities).

There is something wrong in my code, but cannot understand where the mistake is hiding. There is definitely something related to the wiring.c.o file.

PS: I've looked for a solution quite a long time since the problem appears, but I could not find any way to ask Google correctly neither the Stack Overflow site. Apologies if I missed the right search string!

回答1:

It is possible to provide your own handler for Timer0 and still use the Arduino environment.

This is done by (optionally) disabling the existing handler for Timer0 in file wiring.c (inside the Arduino installation). Put in conditional compilation, #ifndef / #endif, around the existing handler:

#ifndef _DISABLE_ARDUINO_TIMER0_INTERRUPT_HANDLER_

    #if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
    ISR(TIM0_OVF_vect)
    #else
    ISR(TIMER0_OVF_vect)
    #endif
    {
        // copy these to local variables so they can be stored in registers
        // (volatile variables must be read from memory on every access)
        unsigned long m = timer0_millis;
        unsigned char f = timer0_fract;

        m += MILLIS_INC;
        f += FRACT_INC;
        if (f >= FRACT_MAX) {
            f -= FRACT_MAX;
            m += 1;
        }

        timer0_fract = f;
        timer0_millis = m;
        timer0_overflow_count++;
    }

#endif

For example, on Windows, file wiring.c may be located in folder C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino.

Note that it may be necessary to have administrative privileges to make changes to wiring.c. On Windows this is done by right clicking on the text editor (a text editor that can handle the Unix end-of-line characters - Notepad can not really handle this) and selecting "Run as Adminstrator".

Then, in your source code put these two lines at the top of the file:

#define _DISABLE_ARDUINO_TIMER0_INTERRUPT_HANDLER_

#include <wiring.c>

Note that for other Arduino projects it works exactly as before. The interrupt handler is only disabled if preprocessor symbol _DISABLE_ARDUINO_TIMER0_INTERRUPT_HANDLER_ is defined.

The same procedure may have to be applied to TIMER0_COMPA_vect as well (file Tone.cpp in the same folder).

This was tested with an Arduino Uno equivalent, Arduino IDE 1.8.5, text editor UltraEdit, and Windows 10.



回答2:

You're using the Arduino library, which already defines a handler for the TIMER0_OVF interrupt.

If you want to define your own handler for this interrupt, you will need to build your project standalone, without using the Arduino library or tools.



回答3:

I simply used Timer2 instead of Timer0. Using Timer2, I can still set an overflow AND an output compare interruptions on the same timer, as expected.

This is a rather simple way to workaround this problem, however it might not suit all cases. I may need to rework my code and adapt it to a direct avr-gcc / Atmel Studio compilation process.