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 Answers 2

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
Sign up to request clarification or add additional context in comments.

4 Comments

@KennethGoveas It works for me: Without volatile it's not working, with volatile it's working. Tested.
8 How are you compiling and uploading?
In clasic Arduino IDE. However in pure C (PlatformIO CLI) it's working too. I'll update code into the answer.
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.
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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.