interrupts from received serial data?

I am currently working on a project to control a Mozzi software engine from an Android device over bluetooth. Thanks to Paul.S I can now call functions from received characters. So I am at the point where I can change the frequency and volume of a sine wave by moving sliders on a Processing for Android program running on my device.
There is a problem with a clicking sound though. Whenever a new slider value is received, the sine frequency updates but I can hear a clicking sound which according to Tim Barass of Mozzi fame may be down to this:

It sounds like the serial read is blocking the processor, stopping it from calculating audio while it waits for (whatever serial is doing).

I would like to know if it would be possible to use an interrupt triggered by serial data coming in to change the frequency. SO when the character that calls the function to update the sine frequency data is called, an interrupt is called which does the job instead of it being done live by serial.read(). Does this make sense to anyone?

Hmm, as in kind of:

If serial coming in
x = 1
delay(20)
if x = 1
Change frequency

Or, do you want the interrupt to constantly control the frequency, and the Serial to constantly control the interrupt?

Or, am I just way off and should log out of the forum? ^^

It would be worthwhile posting your code. You may be doing too much at a time when dealing with the serial input.

Or, do you want the interrupt to constantly control the frequency, and the Serial to constantly control the interrupt?

Yeah something like this. At the moment what happens is that the Android sends an ascii character over bluetooth depending uopn which slider is moved. The arduino then reads the incoming serial data and if it is the character sent by slider one (‘q’) then it jumps to a function which reads the serial port and if the number is below the ascii number for ‘q’ it updates a variable with the sent slider data ( slider data ranges from 0-100 so see why i am using ascii codes that have values above 100) and returns it to the mozzi library’s updatecontrol function to change the sine frequency…

:

int slider1read( int value)
{
 int valuesend=mySerial.read();
  if (valuesend<113)
  {
    value=valuesend;
  }
  return value;
}

So can I make an interrupt to change the frequency??

I have an app on my iPhone with guides, and as I'm a rookie I had to look up interrupt in order to be of any help :stuck_out_tongue: At least I'm trying.. Anyway, I will write down what my guide says. It seems to me that this should be of help, and might eliminate your problem. I might also be wrong.

myguide:
Interrupt

Re-enables interrupts (after they've been disabled by noInterrupts()).
Interrupts allow certain important tasks to happen in the background and are enabled by default. Some functions will not work while interrupts are disabled, and incoming communication may be ignored. Interrupts can slightly disrupt the timing of code, however, and may be disabled for particularly critical sections of code.

Example:
void setup() {}
void loop()
{
noInterrupts();
//critical, time-sensitive code here
interrupts();
//other code here
}

Hope this helps, let me know.

Serial.read() should not block the processor, because it is not waiting for something to arrive. In any case, you should use Serial.available() to see if any characters have been received from the external device.

If you are trying to generate an audio type sine wave using the arduino directly, obviously that is almost a full time task for the arduino processor, so you cannot do much else. You get get frequency generator chips easily, get one of those to do all the busy-work of generating the sine wave and then the arduino just has to tell it what to do.

You also might want to consider the issue of what exactly happens when you change the frequency. You may get a discontinuity in your sine wave. This is going to manifest itself in some kind of "click", depending on your sampling rate this may or may not be noticeable.

Yes, I am using (Serial.available().
The sound generation is done by Tim Barass’ Mozzi library which puts time PWM to Very good use:

There is no problem in the playing of the sine wave and it does change frequency correctly but with slider movement come small clicks otherwise the wave sounds good. The volume slider works well too.
My code is here:

#include <MozziGuts.h>
#include <Oscil.h> // oscillator template
#include <tables/sin512_int8.h> // sine table for oscillator
#include <tables/saw2048_int8.h> // sine table for oscillator
#include <SoftwareSerial.h>
#include <utils.h>
#include <EventDelay.h>
#include <Smooth.h>
#include <mozzi_fixmath.h>
#include <ADSR.h>
#include <mozzi_midi.h>
// use: Oscil <table_size, update_rate> oscilName (wavetable)
Oscil <SIN512_NUM_CELLS, AUDIO_RATE> aSin(SIN512_DATA);
Oscil <SAW2048_NUM_CELLS, AUDIO_RATE> aSaw(SAW2048_DATA);
// use #define for CONTROL_RATE, not a constant
#define CONTROL_RATE 256 // powers of 2 please

int val2;    // sliderread 1 & 2 return variables
int val3;
int f;
int f2;
unsigned char vol;   // volume var
 SoftwareSerial mySerial(10, 7); // RX, TX
 

void setup(){
  startMozzi(CONTROL_RATE); // set a control rate of 64 (powers of 2 please)
  aSin.setFreq(440); // set the frequency with an unsigned int or a float
 
 // Serial.begin(9600);   debug option
  mySerial.begin(38400);
  
}

void updateControl(){
  // put changing controls in here
  

   while(mySerial.available())
 {
   int val=mySerial.read();
  
switch (val)
{
  case 'q':
     f= slider1read(val2);
 
    aSin.setFreq_Q16n16((Q8n0_to_Q16n16(f/6))); 
   break;
   case 'r':
     f2=slider2read(val3);
    vol=(map (f2,0,100,0,255));
   break;
   
   case's':
   pause();
   break;
   
   case 't':
   go();
   break;
   
   default:
   break;
}

 }
}
void go()
{
  vol=100;
}
void pause()
{
  vol=0;
}
int updateAudio(){
  return ((int)aSin.next() * vol>>8); 
  // return ((int)aSaw.next() * vol>>8);
  // return an int signal centred around 0
}


void loop(){
  audioHook(); // required here
}

int slider1read( int value)
{
 int valuesend=mySerial.read();
  if (valuesend<113)
  {
    value=valuesend;
  }
  return value;
}
int slider2read (int value)
{
 int valuesend=mySerial.read();
if(valuesend <114 && valuesend !=113)
{
 value=valuesend;
}
return value;
  
}

What is strange is that Mozzi have no problems with this.

Did you check the forum on his webpage? There are people there having the same issues..

Do you have the ability to know when the sine wave that is currently running does a zero-crossing? Maybe this is already forced in the routines you are using, but if you change frequency mid-cycle, you might be getting noise from that change. If there is no zero-crossing because of a DC offset (or single power supply), at least there would be a point where you reach 0° (360°) or 180° in the waveform.

Did you check the forum on his webpage? There are people there having the same issues..

I put a message up on the Mozzi forum hence the reply from Tim Barass. :slight_smile:

Do you have the ability to know when the sine wave that is currently running does a zero-crossing?

I could find out about zero points... BUT it is also happening on a volume change which I wouldn't have thought was connected with the sine cycle....

BUT it is also happening on a volume change which I wouldn't have thought was connected with the sine cycle....

Doesn't changing the volume change the peak to peak distance? Isn't that a change to the sine cycle? Maybe not, as I don't understand what you are doing.

Yep. As per an invariable usual Paul you're right.
The updateaudio returns the wave which is centred around 0. :
Here it is being updated with the volume sliders' value..:

 return ((int)aSin.next() * vol>>8);