tl;dr: The sample rate of my code seems to be lower than what I expect it to be. How can I fix this?
Director's cut: I am trying to sample audio data and send it via serial. The setup consists of a guitar plugged into an amplifier (about 10x) + low-pass filter (second order, around 1kHz) + voltage divider (centered at 2.5V), that is then connected to and Arduino Uno Rev3. When the Arduino receives a 'cap' command via serial, it enables the interrupt-based function that takes samples and sends them via Serial. With the 10-bit resolution, it gives me a number between 1 and 4 digits. With a baud rate of 115200 and adding 1 byte for the '\n' character, the slowest rate is of 2880 values per second, but most likely around 3.6k values per second (3+1 characters).
From what I understood (not used to working with timer interrupts), I've set up timer1 so that it doesn't have any prescaling, and it should be running pretty close to 2048Hz. The interrupt sequence reads the data at the analog input and sends it via Serial (for now, to the computer; later, a smartphone via Bluetooth).
To check if it is working, I am copying the data received by the computer, putting it into Matlab and running the sound(data, sampleRate)
function. If I run it with 2048 as sampleRate
, I get a clearly higher pitched sound, which indicates that the sample rate is in fact lower. Testing different values, I found that it sounds close enough around 1900.
From what I've read, the serial and the timer interrupt work in parallel, and the serial is faster than the capture. Why am I getting this apparently lower sample rate? How can I fix this?
Code:
// Variables
const int sampleRate = 2048; // Sampling rate
const int numSamples = 2048; // Number of Samples
//volatile int samples[numSamples]; // Data array
int currentSample = 0;
boolean capturing = false; // flags if it is in capture mode
boolean done = false; // flags if the capture is done
char chrCommand; // holds current character read
String strCommand; // joins the complete command string
// Functions
void captureSample();
void readCommand();
void executeCommand();
void setup() {
/****************
* Timer Setup
****************/
cli(); // stop interrupts
// set timer1 interrupt at 2048Hz
TCCR1A = 0; // set the entire TCCR1A register to 0
TCCR1B = 0; // set the entire TCCR1B register to 0
TCNT1 = 0; // initialize counter value to 0
// set compare match register for 2048Hz increments
OCR1A = 7811; // = (16*10^6) / (sampleRate) - 1
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// no prescaling
TCCR1B |= (1 << CS10);
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
sei(); // allow interrupts
/****************
* Serial Setup
****************/
Serial.begin(115200);
pinMode(13,OUTPUT);
}
void loop(){
if(!capturing){
// Case: waiting for command
if(!done){
if(Serial.available() > 0){
readCommand();
executeCommand();
}
}else{
done = false;
}
}
}
/************************
* Function Definitions
************************/
// Timer function
ISR(TIMER1_COMPA_vect){
if(capturing){
captureSample();
}
}
void captureSample(){
//samples[currentSample] = analogRead(0);
Serial.println(analogRead(0));
++currentSample %= numSamples;
if(currentSample == 0)
{
done = true;
capturing = false;
}
}
void readCommand(){
strCommand = "";
while(Serial.available() > 0)
{
chrCommand = ((byte)Serial.read());
if(chrCommand == '\n')
{
break;
} else
{
strCommand += chrCommand;
}
delay(1);
}
}
void executeCommand(){
// Command cap = capture
if(strCommand == "cap"){
capturing = true;
return;
}
// Command mov = move
if(strCommand == "mov"){
// get the motor movement in the following command
readCommand();
moveMotor();
return;
}
if(strCommand == "clr"){
done = false;
capturing = false;
for(int i = 0; i < 2; ++i){
digitalWrite(13,HIGH);
delay(50);
digitalWrite(13,LOW);
delay(50);
}
return;
}
}