1

I'm trying to design a simple Arduino interrupt service routine that uses a function pointer in it so that it can effectively be modified from the main() function. The following is my code.

#include <stdio.h>
#include <util/delay.h>
#include "gpio.h"        // "gpio.h" is my own library that contains the
                         // definitions of digital_write, digital_read,
                         // pin_mode, analog_write, etc.
                         // It also configures all the timer/counter
                         // circuits to operate in fast-PWM mode
                         // with an undivided input clock signal.
                         // This library has been tested.

/* Two interrupt service routines */

void INT_1(void);
void INT_2(void);

/* Function pointer to choose any one of the above defined ISRs */

void (* interrupt)(void) = NULL;

/* main */

int main(void) {

    pin_mode(3, OUTPUT);
    pin_mode(4, OUTPUT);

    cli();
    TIMSK0 |= _BV(TOIE0);     // Enable Timer0 overflow interrupt
    sei();

    while(1)
    {
        interrupt = INT_1;    // For 10 ms, INT_1 executes on interrupt
        _delay_ms(10);

        interrupt = INT_2;    // For next 10 ms, INT_2 executes on interrupt
        _delay_ms(10);
    }

    return 0;
}

ISR(TIMER0_OVF_vect) {        // Execute the function pointed to by
                              // "interrupt" on every overflow on timer 0
    if(interrupt != NULL)
    {
        interrupt();
    }
}

void INT_1(void) {

    digital_write(3, LOW);
    digital_write(4, HIGH);
}

void INT_2(void) {

    digital_write(3, HIGH);
    digital_write(4, LOW);
}

LEDs are connected to pins 3 and 4. These should light up alternately for 10 milliseconds each. However, on flashing this program onto the Arduino, I see that each LED lights up for approximately 2 seconds. Can anyone tell me why?

2 Answers2

1

As usual, you have to use volatile modifier for variable used in both ISR and rest of code.

The void (* volatile interrupt)(void) = NULL; should do the trick.

My code (compiled in PlatformIO)

#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdlib.h>

/* Two interrupt service routines */

void INT_1(void);
void INT_2(void);

/* Function pointer to choose any one of the above defined ISRs */

void (* volatile interrupt)(void) = NULL;

/* main */

int main(void) {
    DDRB = _BV(PB5);

    TCCR0B = _BV(CS00);      // enable timer, overflow every 256 clock cycles
    TIMSK0 = _BV(TOIE0);     // Enable Timer0 overflow interrupt
    sei();

    while(1)
    {
        cli();
        interrupt = INT_1;    // For 10 ms, INT_1 executes on interrupt
        sei();
        _delay_ms(10);

        cli();
        interrupt = INT_2;    // For next 10 ms, INT_2 executes on interrupt
        sei();
        _delay_ms(10);
    }
    return 0;
}

ISR(TIMER0_OVF_vect) {        // Execute the function pointed to by
                              // "interrupt" on every overflow on timer 0
    if(interrupt != NULL)
    {
        interrupt();
    }
}

void INT_1(void) {
    PORTB |= _BV(PB5);
}

void INT_2(void) {
    PORTB &= ~_BV(PB5);
}

And commands:

[Fri Oct 21 19:29:40 2016] Processing uno (platform: atmelavr, board: uno)
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Collected 0 compatible libraries
Looking for dependencies...
Project does not have dependencies
avr-gcc -o .pioenvs/uno/src/main.o -c -std=gnu11 -g -Os -Wall -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DPLATFORMIO=030100 -DARDUINO_ARCH_AVR -DARDUINO_AVR_UNO -Isrc src/main.c
avr-gcc -o .pioenvs/uno/firmware.elf -Os -mmcu=atmega328p -Wl,--gc-sections,--relax .pioenvs/uno/src/main.o -L.pioenvs/uno -Wl,--start-group -lm -Wl,--end-group
Checking program size .pioenvs/uno/firmware.elf
text       data     bss     dec     hex filename
296           0       2     298     12a .pioenvs/uno/firmware.elf
avr-objcopy -O ihex -R .eeprom .pioenvs/uno/firmware.elf .pioenvs/uno/firmware.hex
KIIV
  • 3,534
  • 2
  • 18
  • 23
  • @KennethGoveas It works for me: Without volatile it's not working, with volatile it's working. Tested. – KIIV Oct 20 '16 at 22:30
  • 8 How are you compiling and uploading? – Kenneth Goveas Oct 21 '16 at 07:11
  • In clasic Arduino IDE. However in pure C (PlatformIO CLI) it's working too. I'll update code into the answer. – KIIV Oct 21 '16 at 17:28
  • Notice that you must make the assignments to the `interrupt` global variable *atomic* (e.g. via `cli(); ... sei();`)! Else you have a race condition and the ISR may try to jump to a broken/invalid function pointer. – JimmyB Nov 05 '18 at 12:18
0

I am not able to see you timer values in your code.it will take 0 default and will overflow after 256 counts(8 bit) and then your timer ISR will serviced and depending upon the value of your function pointer Interrupt it will jump to corresponding function (INT0 or INT1) and probably it will jump to the same function at every time and you wont get the result as per your expectation.