Interupt question

This is a two part question on using interupts.
If I use an interrupt routine triggered by a data pin what happens if that pin is triggered again while I'm in the routine?
Do I need to disable interupts while in the routine?
The second part of my question is this:
While in the routine can I read data on the same pin that triggered the interupt? (poll it in a loop)
Or do I have to use a different pin for triggering the interrupt than I use for reading incomming data while in the interupt routine?

What I want to do is play a song while at the same time listed for new song requests.
So I want the data pin to trigger an interupt that runs a routine to read incomming data on the same pin that triggered it.

sbennett1298:
This is a two part question on using interupts.
If I use an interrupt routine triggered by a data pin what happens if that pin is triggered again while I'm in the routine? Nothing
Do I need to disable interupts while in the routine? No, but other interrupts that occur will be queued and will happen after your routine
The second part of my question is this:
While in the routine can I read data on the same pin that triggered the interupt? (poll it in a loop) Yes, but spend as little time in your interrupt routine as possible
Or do I have to use a different pin for triggering the interrupt than I use for reading incomming data while in the interupt routine? Do you mean you want to use the UART Rx line as the interrupt source? This is not a good idea.

What I want to do is play a song while at the same time listed for new song requests.
So I want the data pin to trigger an interupt that runs a routine to read incomming data on the same pin that triggered it.

It would be better to check each time when you enter your loop if there is any new data in the buffer. Serial data is slow and you don't want to leave your code hanging in an interrupt routine waiting for data to arrive. Also while in the interrupt you will not get any serial data, as it relies on interrupts to transfer from the register to the buffer, which you effectively block by leaving your interrupt hanging.

No I'm not reading serial data. I want to trigger an interrupt when a particular data pin goes LOW.
Then inside the interrupt routine I want to count the number of times that same data pin goes LOW.
It will go LOW between 1 and 21 times followed by a 1/5 second pause then go LOW between 1 and 10 times.
The whole process takes about 2 seconds. I want the routine to return two ints. Number of LOWS before the pause and number of LOWs after the pause.

My fear is that the LOWS will trigger more interrupts. So I should disable interrupts while in the routine?
If it matters I'm using the UNO.
-Steve

Having an interrupt routine take up 2s is a definite no, things like the millis() function rely on interrupts and if you have an interrupt blocking it millis (and other functions) will effectively never count on (I'm assuming you were planning to use millis to measure your pause etc. :wink: ).
The way to do this would be to use a counter which gets incremented by your interrupt routine on a falling edge, you just need to think of a way to differentiate between edges before and after the pause, but you would need to provide a bit more info on how your input signal is going to look.

If I use an interrupt routine triggered by a data pin what happens if that pin is triggered again while I'm in the routine?
Do I need to disable interupts while in the routine?

This is configurable.

Actually, interrupts are disabled when the interrupt hits. If you want them enabled, you have to enable them in the ISR code. Or, you can use the ISR_NOBLOCK attribute and the macro will automatically stick the sei instruction at the beginning of your ISR code.

But then, if you're executing the same code while you're executing that code, you'll have to have some sort of global volatile state variable anyway, so you know you're supposed to be incrementing the counter instead of playing the song.

You could use the attachInterrupt() function inside the ISR and change which code gets executed when the pin goes low. Or you could just use detachInterrupt() and then enable interrupts and then poll the pin while in the ISR.

The problem with disabling interrupts and polling the pin while in the interrupt service routine is that the interrupt enable flag is global. That means ALL interrupts are disabled. Your timer interrupts won't fire, so how are you going to time the 1/5 second between pulse counts?

I agree with Toby and Delta_G. Conventional wisdom is you should spend as little time in the ISR as possible. For good reason. But it would be relatively simple to use a state variable and time stamps in the ISR to do your counts in global variables.

Thanks to everyone who responded. This post is to all of you. No I am not using the milis() function to time my pulses but I wish I had. I'm a total newbie and didn't even know about milis(). My code just polls and counts polling loops.
The thing that is tripping me up is the function that plays music doesn't return until the song ends and so I cannot poll until the song is over. Can I use millis() to get a time stamp while in the ISR? If I understand correctly millis() will not increment inside the ISR but that is OK if I just want to get one time stamp that tells me when the interrupt occurred and then get out.

Would this work? Could I store a time stamp in a global array each time the interrupt is triggered by a falling edge and then let the main loop process the array of time stamps between songs?

-Steve

I just did this test to see if millis() would work in a ISR and to see if the ISR would kill the music.
It failed on both counts.
A few interrupts was ok but if I sent too many music was killed.
At the end of the song when I printed the array holding the time stamps every time stamp was the same.
Here is my test code.
#include <MusicPlayer.h>
#include <newSDlib.h>
#include <pins_config.h>
#include <vs10xx.h>
#include <Fat16.h>
#include <Fat16Util.h>
#include <NewSPI.h>
#include <arduino.h>
#include "pins_config.h"
#include "vs10xx.h"
#include "newSDLib.h"
#include "MusicPlayer.h"
MusicPlayer myplayer;
int pin = 40; //interrupt pin
volatile int state = LOW;
volatile int isrindx;
volatile int stamparray[300];

void setup()
{
Serial.begin(9600);
myplayer.begin();//will initialize the hardware and set default mode to be normal.
pinMode(pin, OUTPUT);
attachInterrupt(4, isr, RISING);
}
void loop()
{
isrindx = 0;
//myplayer.addToPlaylist("test1.mp3");
myplayer.addToPlaylist("test.mp3");
myplayer.playList();//There are two songs in the playlist.
for(int i = 0; i < isrindx; i++){

Serial.println(stamparray[1]);
//Serial.print(" ");

}
while(1);
}
void isr()
{
stamparray[isrindx] = millis();
isrindx++;
}

Your code looks good to me. There are three things I can think of that might cause you to get the same time stamp for all of your interrupts.

  1. The interrupts come so fast and furious that they're actually within the same millisecond.

  2. Your time stamp array is an array of ints, and millis() returns an unsigned long. I would think it would store the lsw of the long, though, so I don't think this is the problem.

  3. myplayer.playList() somehow is messing with the timer0 timing system. This is my vote.

If the issue is indeed a problem with myplayer, I guess you can spend all the time you want inside the isr(), since it's messing with the timer interrupts anyway. As long as it doesn't mess with playing the song. And as long as you return before myplayer is done playing the song.

If you leave the interrupts disabled in the isr, and just loop and count the pulses, does it mess with the song that is playing? I'm wondering if myplayer.playList() needs the interrupts enabled to play the song.

I can think of two other ways to do it, but they require some more programming.

The interupts are not comming fast and it only takes a few of them to crash the music player.
I will try #2 and change the timestamp to unsigned long. If that doesn't work I'm left with two choices.

  1. Just accept the fact I cannot queue songs until the playlist has ended.
  2. Add a second Arduino. One for queuing song requests and the other for playing them.

I think your third idea may be spot on because sending too many interupts crashes the player.
-Steve

I'm afraid don't get your code.

First of all at the beginning of loop you assign isrindx to 0. Then you do a for loop over isrindx, which is of course 0, so the loop never happens. Then you put in an infinite loop, stopping your program there. Are you sure you haven't mistaken your program crashing for a mistake in the code?

Could you explain better what the program is supposed to do, especially the source of the input signal, your code doesn't correspond to what you described earlier, and then what it currently does.

Oh and the reason it just prints the same timestamp is you are printing stamparray[1] not stamparray

Tobyb121,

First of all thank you for catching my typo. That explains why it kept printing the same number over and over.
I meant to type stamparray NOT stamparray[1]. Thanks for catching that.
Next the code I posted was not intended to do what I described (count pulses.) The code I posted was just a test intended to tell me:
1) Will the song continue to play while I am in the ISR?
2) Will the millis() function work inside the ISR?
Lastly...For this test I used the example code that came with the Music shield. The example code had the while(1) at the end of the main loop so that the song would play once and stop instead of playing over and over forever.
Oh and lastly again...isrindx is not zero when the print loop happens because during my test I am triggering interrupts and it gets incremented by the ISR code.
Anyway my test proved to me the ISR can be called a few times without interrupting the song but if a stream of pulses start coming fast like they will be in my implementation the song gets killed so this approach is not going work.
-Steve

Ooops another typo. I mean it should be stamparray NOT stamparray[1]

Why does my "bracket i bracket" keep disappearing in these posts?

Italics = [i]This is in italics[/i]

LOL OK get it now

So, when you changed it to i instead of 1, did you get different values in the array? What was isrindx? Could you add a debug Serial.print(isrindx) and post a copy of the serial monitor trace?

if you use code tags, the brackets don't turn into italics.

One other question... are you using pin 19 on an arduino mega 2560?

I've just had a look at the music shield reference page and it looks like pin 4 may be in use:
http://www.seeedstudio.com/wiki/Music_Shield_V2.0#Interface_Function
Have you tried using another pin (looks like the only ones it doesn't use are D9 and A4 and A5).