Analogue Input Interupt Help

Ok, so I'm still farily new and inexperienced at writing code. I've got the begginings of a wavetable oscillator sketch going, just with a fixed pitch, contant note on, and 1 potentiometer controlling a wavetable. I've been building it up small steps at a time, and so far everything works. It has to read the pot to decide what blend of wavetable it will use and then do some maths before pumping out numbers to the 8bit DAC, and this runs really slow.

So... I decided to have a crack at interupts for the first time. Thought I'd got the hang of it, but it isnt working.

Here's the slow but working code (I've removed the wavetable figures to save clutter)

void setup()
{
  DDRC = 255;                                         // 8 bit DAC on port C

  Serial.begin(9600);                                 // begin serial communication
}


unsigned int osc1;                                    // final oscillator 1 mix
short mix4;                                           // used to work out which oscillators to mix between

unsigned int two;                                            // floats here avoid calc error when calculating osc1
unsigned int three;                                          
unsigned int four;
unsigned int five;
unsigned int six;
unsigned int sine;
unsigned int out;

short i = 0;                                          // "i" is soon to become the array index, and is set to start at index 0

unsigned char xtwo[256] =                         // xtwo[] is an array that holds the sample data for a x2-base251 wave
{ 
};  

unsigned char xthree[256] =                          // xthree[] is an array that holds the sample data for a x3-base251 wave
{                                           
};  

unsigned char xfour[256] =                             // xfour[] is an array that holds the sample data for a x4-base251 wave
{ 
}; 

unsigned char xfive[256] =                            // xfive[] is an array that holds the sample data for a x5-base251 wave
{
};

unsigned char xsix[256] =                             // xsix[] is an array that holds the sample data for a x6-base251 wave
{
};

unsigned char xsine[256] =                             //sine wave array
{
};

void loop()
{
  int mix = analogRead(A0);                           // potentiometer that controls the blend between xthree and xfive

  mix4 = map(mix, 0, 1024, 0, 4);                     // works out which wavetables will be used (have to map an extra sector to take imaginary number 1024                             

  two = xtwo[i];
  three = xthree[i];                                  // convert array numbers into float to help xoutput calc
  four = xfour[i];
  five = xfive[i];
  six = xsix[i];
  sine = xsine[i];

if(mix4 == 0)
  osc1 = ((two*(255-mix))/255) + ((three*mix)/255);   // calculate the different oscillator mixes
if(mix4 == 1)
  osc1 = ((three*(511-mix))/255) + ((four*(mix-256))/255);
if(mix4 == 2)  
  osc1 = ((four*(767-mix))/255) + ((five*(mix-512))/255);
if(mix4 == 3)
  osc1 = ((five*(1023-mix))/255) + ((six*(mix-768))/255); 
  
  out = (osc1+(sine))/2; 
  
  PORTC = out;                                          // output the mixed signal
  
  i++;                                                // increase i in increments to cycle through the waveforms
  if(i >= 256)                                         // check if the index is at the end of the sample
    i = 0;                                            // if it is, reset the sample to 0

}

Here is my attempt at using an interupt to read the potentiometer and decide on the wavetable mix:

unsigned char xtwo[256] =                             // xtwo[] is an array that holds the sample data for a x2-base251 wave
{ 
};  

unsigned char xthree[256] =                          // xthree[] is an array that holds the sample data for a x3-base251 wave
{                                           
};  

unsigned char xfour[256] =                             // xfour[] is an array that holds the sample data for a x4-base251 wave
{ 
}; 

unsigned char xfive[256] =                            // xfive[] is an array that holds the sample data for a x5-base251 wave
{
};

unsigned char xsix[256] =                             // xsix[] is an array that holds the sample data for a x6-base251 wave
{
};

unsigned char xsine[256] =                             //sine wave array
{
};

long previousTime = 0;        // will store last time LED was updated

int wave = 0;
short waveSelect = 0;                                        // used to work out which oscillators to mix between
short i = 0;                                                 // "i" is soon to become the array index, and is set to start at index 0

unsigned int two;                                            // floats here avoid calc error when calculating osc1
unsigned int three;                                          
unsigned int four;
unsigned int five;
unsigned int six;
unsigned int sine;
volatile unsigned int osc1 = xtwo[i];                         // final oscillator 1 mix,  starts with just xtwo (changed via interupt)
unsigned int out;                                             // total output
boolean change = false;                                       // just to test interupt

void setup()
{
  DDRC = 255;                                         // 8 bit DAC on port C

  Serial.begin(9600);                                 // begin serial communication
  attachInterrupt(A0, waveMixer, CHANGE);                  // interupt: go to the ISR/void called "wave" when pot attached to A0 changes
}

void loop()
{
  two = xtwo[i];                                                  // convert array numbers into int to help xoutput calc
  three = xthree[i];                                
  four = xfour[i];
  five = xfive[i];
  six = xsix[i];

  sine = xsine[i];
  out = (osc1+(sine))/2; 
  PORTC = out;                                               // output the mixed signal before doing anything else for speed and accuracy?
  i++;                                                       // increase i in increments to cycle through the waveforms
  if(i >= 256)                                               // check if the index is at the end of the sample
    i = 0;                                                   // if it is, reset the sample to 0
    
  Serial.println(change);
}

void waveMixer()
{
  wave = analogRead(A0);                                           // potentiometer that controls the blend between xthree and xfive
  waveSelect = map(wave, 0, 1024, 0, 4);                                 // works out which wavetables will be used (have to map an extra sector to take imaginary number 1024  
  
  if(waveSelect == 0)
      osc1 = ((two*(255-wave))/255) + ((three*wave)/255);               // calculate the different oscillator mixes
  if(waveSelect == 1)
      osc1 = ((three*(511-wave))/255) + ((four*(wave-256))/255);
  if(waveSelect == 2)  
      osc1 = ((four*(767-wave))/255) + ((five*(wave-512))/255);
  if(waveSelect == 3)
      osc1 = ((five*(1023-wave))/255) + ((six*(wave-768))/255);
  change = true; 
}

I have used a boolean called "change" to try and work out if the interupt is working, and it doesn't respond.

Cheers for your advice and help in advance

Pete

Is changed declared to be volatile? If it is updated inside an ISR then it needs to be so the rest of the code knows it might change. Otherwise the compiler might just optimize it away.

aha, ok, I'll make change volatile aswell and test that.

What about the rest of the code? With the original code I get my wavetable sound, and I can sweep through it with the Pot, and with the new code where I've tried to integrate an interupt, I barely get any sound, and the pot doesn't change anything.

Any ideas what I've done wrong? I'm sure I have done something wrong, as it's the first time I've programed an interupt.

I don't think this is really the place for an interrupt. What part of the original code was slowing it down? I definitely don't see anything that's going to get any faster with an interrupt.

It has to read the pot to decide what blend of wavetable it will use and then do some maths before pumping out numbers to the 8bit DAC, and this runs really slow.

Your analogRead takes at least 100us, so that's fairly limiting.

  attachInterrupt(A0, waveMixer, CHANGE);                  // interupt: go to the ISR/void called "wave" when pot attached to A0 changes

The above line is completely meaningless. An interrupt is a digital event, dependant upon the pin changing state from one logic level to another. With an analog input signal connected to that pin, it will not produce anything of value, and most definitely not what you seem to think it will.

Analog inputs need to be "read" periodically, like every mSec, or every 10 mSec, from within the loop() function, or a function called by a timer interrupt.

Regards, Ray L.

Look for the end-of-conversion interrupt.

Aha, so I can't create an interupt that is directly triggered by the analogue input. Thankyou very much! Just looked up the end-of-coversion interrupt buisness, think i've found some solutions :D

Thanks again for your help! I'll let you know if/when I've got it working

Would digital encoders make it easier to achieve what I'm trying to do with the pot?

The pot is controlled by a person? You want your code to make a change whenever the pot changes?

Why not just do an analogRead() every so often in your main loop and then make the changes required? Even if you only read the pot a few times per second, the human won't notice that the changes aren't instant.

Hmm, that's a good point. I could just set a timer on it rather than have it check on every pass of the loop. I could even clock it to the loop cycle, say every 20 times through the loop. Trying this would also help reveal if that is a major contribution to the slow execution speed of my code.

Thanks for another useful suggestion!

PS, I just looked back at the code I posted and realised that I've changed the name of some of the variables from the first code to the second.

mix and mix4 in the original code are wave and waveSelect respectively in the later code. Sorry if this has made it more confusing.

Ray: you said that this code:

attachInterrupt(A0, waveMixer, CHANGE);

was meaningless because it is a digital event. So if I was to change the "A0" to a digital pin number, and have a digital controller attached to said pin, would this code be written correctly? I'm still not certain I've written it correctly.

So if I was to change the "A0" to a digital pin number, and have a digital controller attached to said pin, would this code be written correctly?

You have two external interrupt pins; neither is A0. If you're interested in using other pins, you need to look at the pin change interrupts.

was meaningless because it is a digital event. So if I was to change the "A0" to a digital pin number, and have a digital controller attached to said pin, would this code be written correctly? I'm still not certain I've written it correctly.

Only if the pin is one that supports hardware interrupts. Which Arduino board are you using ?

See attachInterrupt()

Mega2560.

I jsut read attachInterrupt() again and reallise I'd missed an important bit of information within the following:

Syntax attachInterrupt(interrupt, ISR, mode) attachInterrupt(pin, ISR, mode) (Arduino Due only) Parameters interrupt: the number of the interrupt (int) pin: the pin number (Arduino Due only)

I'd missed the bit that says "(Arduino Due only). Well that simplifies things a little, I can only use pins 2,3,21,20,19 and 18 (called 0,1,2,3,4 and 5 within the interrupt parameters).

So I've got two roots to follow now.

Root 1: Get some rotary encoders.

Root 2: Set up a periodic analogRead as suggested by MorganS

Gonna get some rotary encoders, that was my plan eventually anyway. But in the mean time, I've already been working on the periodic analogRead code, and have come across a problem I'm struggling to get around.

long previousTime = 0;                                       // will store last time LED was updated
int readWave = 100;
void setup()
{
  DDRC = 255;                                                // 8 bit DAC on port C

  Serial.begin(9600);                                        // begin serial communication
}

short waveSelect;                                            // used to work out which oscillators to mix between
int wave;
int waveMix1;
int waveMix2;

unsigned int two;                                            // wave inegers associated with corresponding array of similar name (xtwo, xthree...)
unsigned int three;                                          
unsigned int four;
unsigned int five;
unsigned int six;

unsigned int wave1;                                           // integers that point to a wave integer associated with one of the arrays (two, three...)
unsigned int wave2;

unsigned int sine;                                            // sine wave array

unsigned int osc1;                                            // final oscillator 1 mix
unsigned int out;                                             // total output

short i = 0;                                          // "i" is soon to become the array index, and is set to start at index 0

unsigned char xtwo[256] =                         // xtwo[] is an array that holds the sample data for a x2-base251 wave
{ 
};  

unsigned char xthree[256] =                          // xthree[] is an array that holds the sample data for a x3-base251 wave
{                                           
};  

unsigned char xfour[256] =                             // xfour[] is an array that holds the sample data for a x4-base251 wave
{ 
}; 

unsigned char xfive[256] =                            // xfive[] is an array that holds the sample data for a x5-base251 wave
{
};

unsigned char xsix[256] =                             // xsix[] is an array that holds the sample data for a x6-base251 wave
{
};

unsigned char xsine[256] =                             //sine wave array
{
};

void loop()
{
  unsigned long currentTime = millis();
  if(currentTime - previousTime >= (readWave))                 //check to see if it's time to play the next sample based on pitch decided by the pitch pot
  {
    wave = analogRead(A0);                                  // potentiometer that controls the blend between xthree and xfive
    previousTime = currentTime;                             // regester the current time in previousMillis 

    waveSelect = map(wave, 0, 1024, 0, 4);                  // works out which wavetables will be used (have to map an extra sector to take imaginary number 1024  

    waveMix1 = (((waveSelect+1)*256-1)-wave);                   //calculates the weight of first wave in osc1
    waveMix2 = (wave-(256*waveSelect));                         //calculates the weight of second wave in osc1
      
  if(waveSelect == 0)                                          //sets up wave1 and wave2 to read the correct integers that correlate with the wave arrays
    {wave1 = two; wave2 = three;}
  if(waveSelect == 1)
    {wave1 = three; wave2 = four;}
  if(waveSelect == 2)  
    {wave1 = four; wave2 = five;}
  if(waveSelect == 3)
    {wave1 = five; wave2 = six;} 
  }

  two = xtwo[i];                                            // convert array numbers into float to help xoutput calc
  three = xthree[i];                                  
  four = xfour[i];
  five = xfive[i];
  six = xsix[i];
  sine = xsine[i];

      Serial.println(wave1);                          // monitoring purposes only
      Serial.println(wave2);
      Serial.println();
      Serial.println(two);
      Serial.println(three);
      Serial.println();
      Serial.println(xtwo[i]);
      Serial.println(xthree[i]);
      Serial.println();
      Serial.println();

  osc1 = (wave1*waveMix1)+(wave2*waveMix2);

  out = (osc1+(sine))/512;                               //mix the wavetables with the sine wave
  
  PORTC = out;                                               // output the mixed signal before doing anything else for speed and accuracy?
  i++;                                                       // increase i in increments to cycle through the waveforms
    if(i >= 256)                                             // check if the index is at the end of the sample
      i = 0;                                                 // if it is, reset the sample to 0  

}

Within the if statement that causes the periodic analogRead, wave1 and wave2 are assigned values of one of the wave integers (two, three,four, five or six). Ideally, what I need is for wave1 and wave2 to only remember that they need to read one of the wave integers on every pass through the loop. What they actually do is store the number that the wave integers represent at the time the if statement is satisfied.

I had expected this might be the case, so I tried again, this time I tried to use blank arrays to attain the wave array data directly. Again I faced a similar problem...

long previousTime = 0;                                       // will store last time LED was updated
int readWave = 100;
void setup()
{
  DDRC = 255;                                                // 8 bit DAC on port C

  Serial.begin(9600);                                        // begin serial communication
}

short waveSelect;                                            // used to work out which oscillators to mix between
int wave;
int waveMix1;
int waveMix2;

unsigned int sine;                                            // sine wave array

unsigned int osc1;                                            // final oscillator 1 mix
unsigned int out;                                             // total output

short i = 0;                                          // "i" is soon to become the array index, and is set to start at index 0

unsigned char wave1[256];
unsigned char wave2[256];

unsigned char xtwo[256] =                         // xtwo[] is an array that holds the sample data for a x2-base251 wave
{ 
};  

unsigned char xthree[256] =                          // xthree[] is an array that holds the sample data for a x3-base251 wave
{                                           
};  

unsigned char xfour[256] =                             // xfour[] is an array that holds the sample data for a x4-base251 wave
{ 
}; 

unsigned char xfive[256] =                            // xfive[] is an array that holds the sample data for a x5-base251 wave
{
};

unsigned char xsix[256] =                             // xsix[] is an array that holds the sample data for a x6-base251 wave
{
};

unsigned char xsine[256] =                             //sine wave array
{
};

void loop()
{
  unsigned long currentTime = millis();
  if(currentTime - previousTime >= (readWave))                 //check to see if it's time to play the next sample based on pitch decided by the pitch pot
  {
    wave = analogRead(A0);                                  // potentiometer that controls the blend between xthree and xfive
    previousTime = currentTime;                             // regester the current time in previousMillis 

    waveSelect = map(wave, 0, 1024, 0, 4);                  // works out which wavetables will be used (have to map an extra sector to take imaginary number 1024  

    waveMix1 = (((waveSelect+1)*256-1)-wave);                   //calculates the weight of first wave in osc1
    waveMix2 = (wave-(256*waveSelect));                         //calculates the weight of second wave in osc1
      
  if(waveSelect == 0)                                          //sets up wave1 and wave2 to read the correct integers that correlate with the wave arrays
    {wave1[i] = xtwo[i]; wave2[i] = xthree[i];}
  if(waveSelect == 1)
    {wave1[i] = xthree[i]; wave2[i] = xfour[i];}
  if(waveSelect == 2)  
    {wave1[i] = xfour[i]; wave2[i] = xfive[i];}
  if(waveSelect == 3)
    {wave1[i] = xfive[i]; wave2[i] = xsix[i];}
  }

      Serial.println(wave1[i]);
      Serial.println(wave2[i]);
      Serial.println();
      Serial.println(xtwo[i]);
      Serial.println(xthree[i]);
      Serial.println();
      Serial.println();

  osc1 = (wave1[i]*waveMix1)+(wave2[i]*waveMix2);

  out = (osc1+(sine))/512;                                   //mix the wavetables with the sine wave
  
  PORTC = out;                                               // output the mixed signal before doing anything else for speed and accuracy?
  i++;                                                       // increase i in increments to cycle through the waveforms
    if(i >= 256)                                             // check if the index is at the end of the sample
      i = 0;                                                 // if it is, reset the sample to 0  
      
}

I replaced wave1 and wave2 with wave1[] and wave2[] and got rid of the variables two,three,four,five and six altogether, reading the wave arrays directly from the new arrays. This results in a number from the array being given every time the if statement is satisfied, and every other run through the loop it gives a 0 (again this was fairly inevitable, but worth a shot).

So, anyone have any ideas on how to designate 2 arrays to read from within an if statement that is only accessed every so often, but keep cycling through the numbers in the designated arrays on every pass through the code?

Hope that actually made sense! Thanks for all your help so far guys! My code is coming along leaps and bounds just from this short thread.

Pete

So, anyone have any ideas on how to designate 2 arrays to read from within an if statement that is only accessed every so often, but keep cycling through the numbers in the designated arrays on every pass through the code?

Hope that actually made sense!

Actually, no, but if you increment a global variable each time through loop() then you can use its current value when the if test becomes true. Is that what you meant ?

Not quite...

I have 5 wave arrays, and (currently) a potentiometer linked to A0. The potentiometer decides 2 things.

1: which two waveforms I am playing 2: what ratio of each waveform is playing (the waveforms are weighted and normalised)

This means if you turn the pot from lowest to highest, you should start with one waveform, blend into the second waveform, then when it is entirely the second waveform it starts to blend from the second into the third and so on, untill it is just the fifth waveform at the end.

So currently I am trying to program the arduino to read the pot every 100milliseconds rather than every time through the loop, because the analogRead is really slowing the code down and stopping me getting very far into the audio range.

My timer is set up using the "if currentTime - previousTime => " system as used on the blink without delay example, and if the "if" is satisfied, the pot is read, the two waveforms are decided, and the mix between these waveforms is decided. The trouble is, I can only get the current sample from each waveform at the time the pot is read. After that the sketch continues to use the same sample. What I need is for the array to be selected within the if statement, then have some extra variable that extracts the numbers from the selected arrays outside of the if statement, during the normal loop.

I have tried to create two empty arrays to see if I can alighn them with the selected arrays, but with no success. Any ideas? All the code showing what I have done is in previous posts.

Sorry, bumping this, totally need help with this :D

Pete