Arduino FFFT Lib and SD Card

Hi I am working on a speech recognition project for my arduino. I want to have my arduino use ELM Chan's ffft library because it seems to work great with the parts I have. The example for the fft sampling to the computer works fine and im currently trying to expand the original code to store 1024 values stored from the arduino into an SD card, to access them later. My code is getting stuck somewhere because it won't do anything when I open up the serial monitor. I have NO IDEA what is wrong with it, but I think something might be happening in the adcInit() or ISR(ADC_vect) functions.

Any help would be GREATLY appreciated!
Thanks :slight_smile:
Judd

And here is my code:

#include "SD.h"
#include "stdint.h"
#include "ffft.h"

#define IR_AUDIO 0

volatile byte pos = 0;
volatile long zero = 0;

int count;
int nextCount;
int incomingByte;
int16_t capture[FFT_N];
complex_t bfly_buff[FFT_N];
uint16_t spektrum[FFT_N/2];
uint16_t signal[(FFT_N/2)*16]; // this allows 64 bit resolution per bin and 16 sets of bins

// FFT_N = 128

void setup() {
Serial.begin(115200);
Serial.println("Start of Sketch.");
pinMode(8, OUTPUT);
pinMode(10, OUTPUT);
digitalWrite(8, HIGH);
delay(1000);
digitalWrite(8, LOW);
delay(1000);
while(!Serial) {
digitalWrite(8, HIGH);
}
digitalWrite(8, LOW);
Serial.println("Initializing SD card...");
digitalWrite(8, HIGH);
delay(100);
digitalWrite(8, LOW);
delay(1000); // must have delay here
if(!SD.begin(10)) {
Serial.println("Card failed, or not present");
while(1 == 1) {
digitalWrite(8, HIGH);
delay(100);
digitalWrite(8, LOW);
delay(100);
}
}
digitalWrite(8, HIGH);
delay(1000);
digitalWrite(8, LOW);
delay(100);
Serial.println("Card initialized.");
delay(100); // here too
adcInit();
adcCalb();
}

void loop() {
if (Serial.available() > 0) {
incomingByte = Serial.read();
}
if(incomingByte == 'H') {
digitalWrite(8, HIGH);
}
if(incomingByte == 'L') {
digitalWrite(8, LOW);
}
for(count = 0; count < (FFT_N/2)16; count++) {
if(pos == FFT_N) {
fft_input(capture, bfly_buff);
fft_execute(bfly_buff);
fft_output(bfly_buff, spektrum);
pos = 0;
}
for(nextCount = 0; nextCount < FFT_N/2; nextCount++) {
signal[((count
(FFT_N/2))+1)+nextCount] = spektrum[nextCount];
}
File dataFile = SD.open("Voice Recognition.txt", FILE_WRITE);
}
}

ISR(ADC_vect) {
for(pos = 0; pos < 128; pos++) {
capture[pos] = ADC;
if(capture[pos] == -1 || capture[pos] == 1) {
capture[pos] = 0;
}
}
Serial.println("Done.");
return;
}

void adcInit() {
ADMUX = _BV(REFS0) | IR_AUDIO; // | _BV(ADLAR);
ADCSRA = _BV(ADSC) | _BV(ADEN) | _BV(ADATE) | _BV(ADIE) | _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0);
sei();
}

void adcCalb() {
long midl = 0;
for (byte i = 0; i < 2; i++) {
pos = 0;
delay(100);
midl += capture[0];
delay(900);
}
zero = -midl/2;
}

Read this first: How to post code properly

Pete

Im really sorry! (Im a newb here)

Here is the (better) code:

#include "SD.h"
#include "stdint.h"
#include "ffft.h"

#define IR_AUDIO 0

volatile byte pos = 0;
volatile long zero = 0;

int count;
int nextCount;
int incomingByte;
int16_t capture[FFT_N];
complex_t bfly_buff[FFT_N];
uint16_t spektrum[FFT_N/2];
uint16_t signal[(FFT_N/2)*16]; // this allows 64 bit resolution per bin and 16 sets of bins

// FFT_N = 128

void setup() {
  Serial.begin(115200);
  Serial.println("Start of Sketch.");
  pinMode(8, OUTPUT);
  pinMode(10, OUTPUT);
  digitalWrite(8, HIGH);
  delay(1000);
  digitalWrite(8, LOW);
  delay(1000);
  while(!Serial) {
    digitalWrite(8, HIGH);
  }
  digitalWrite(8, LOW);
  Serial.println("Initializing SD card...");
  digitalWrite(8, HIGH);
  delay(100);
  digitalWrite(8, LOW);
  delay(1000);                   // must have delay here
  if(!SD.begin(10)) {
    Serial.println("Card failed, or not present");
    while(1 == 1) {
      digitalWrite(8, HIGH);
      delay(100);
      digitalWrite(8, LOW);
      delay(100);
    }
  }
  digitalWrite(8, HIGH);
  delay(1000);
  digitalWrite(8, LOW);
  delay(100);
  Serial.println("Card initialized.");
  delay(100);                    // here too
  adcInit();
  adcCalb();
}

// in ISR(ADC_vect) the program freezes at 12 positions but does not continue to the next 116 and does not
// return to the loop function

void loop() {
  if (Serial.available() > 0) {
    incomingByte = Serial.read();
  }
  if(incomingByte == 'H') {
    digitalWrite(8, HIGH);
  }
  if(incomingByte == 'L') {
    digitalWrite(8, LOW);
  }
  for(count = 0; count < (FFT_N/2)*16; count++) {
      if(pos == FFT_N) {
      fft_input(capture, bfly_buff);
      fft_execute(bfly_buff);
      fft_output(bfly_buff, spektrum);
      pos = 0;
    }
    for(nextCount = 0; nextCount < FFT_N/2; nextCount++) {
      signal[((count*(FFT_N/2))+1)+nextCount] = spektrum[nextCount];
    }
    File dataFile = SD.open("Voice Recognition.txt", FILE_WRITE);
  }
}

ISR ADC_vect() {
  for(pos = 0; pos < 128; pos++) {
    capture[pos] = ADC;
    if(capture[pos] == -1 || capture[pos] == 1) {
      capture[pos] = 0;
    }
  }
  Serial.println("Done.");
  return;
}

void adcInit() {
  ADMUX = _BV(REFS0) | IR_AUDIO; // | _BV(ADLAR); 
  ADCSRA = _BV(ADSC) | _BV(ADEN) | _BV(ADATE) | _BV(ADIE) | _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0);
  sei();
}

void adcCalb() {
  long midl = 0;
  for (byte i = 0; i < 2; i++) {
    pos = 0;
    delay(100);
    midl += capture[0];
    delay(900);
  }
  zero = -midl/2;
}

it sounds like you have gotten the ffft library to work on its own, have you also successfully used the SD card library on its own?

The SD card library works fine, it's just that when I use both together in this sketch, the arduino freezes. I've also tried removing the SD library completely but that doesn't seem to do anything to the code.

I've tried troubleshooting it by removing everything in the loop function, except for a Serial print in the loop. When I test it out, the code makes it to the loop, Serial prints exactly 12 times every time, and then stops printing halfway through the thirteenth word.

Thanks,

Judd

remove evrything from the ADC_vect, and see what happens. im guessing the Serail.print in there might be having some troubles.

Which Arduino are you using?
The SD library needs 512 bytes of static ram for a buffer. The signal array is 1024 bytes, and the others are at least 896 bytes (don't know the size of complex_t). Altogether they will easily use up the 2kB of static ram available in a 328-based Arduino such as a Nano or UNO.

Pete

good point. where is FFT_N defined?

@el_supremo: I'm using Arduino UNO rev 2 with a atmega328 with optiboot bootloader from sparkfun. Are you saying that my Arduino can't handle all of the things I've put into the code? Would it be possible to use 2 Arduino boards; one to print the fft values to another and then another to store them to an SD card?

@g_u_e_s_t: FFT_N is defined in ffft.h. FFT_N = 128. I'll try removing everything from ADC_vect but I think all my values for signal[] will be screwed up.

Thanks for the help,

Judd

I made a typo in the code section:

ISR ADC_vect() should be ISR(ADC_vect), it still has problems though. I removed all the code in ISR(ADC_vect) and still nothing is happening. I even removed all of the SD card references, uploaded that and still nothing happened!

However, when I used the original code and deleted the signal[] variable, the code started to work perfectly, but froze up after a little bit. Here is the new code, and the results I got after in the Serial monitor:

#include "SD.h"
#include "stdint.h"
#include "ffft.h"

#define IR_AUDIO 0

volatile byte pos = 0;
volatile long zero = 0;

int count;
int nextCount;
int incomingByte;
int16_t capture[FFT_N];
complex_t bfly_buff[FFT_N];
uint16_t spektrum[FFT_N/2];
//uint16_t signal[(FFT_N/2)*16]; // this allows 64 bit resolution per bin and 16 sets of bins

// FFT_N = 128

void setup() {
  Serial.begin(115200);
  Serial.println("Start of Sketch.");
  pinMode(8, OUTPUT);
  pinMode(10, OUTPUT);
  digitalWrite(8, HIGH);
  delay(1000);
  digitalWrite(8, LOW);
  delay(1000);
  while(!Serial) {
    digitalWrite(8, HIGH);
  }
  digitalWrite(8, LOW);
  Serial.println("Initializing SD card...");
  digitalWrite(8, HIGH);
  delay(100);
  digitalWrite(8, LOW);
  delay(1000);                   // must have delay here
  if(!SD.begin(10)) {
    Serial.println("Card failed, or not present");
    while(1 == 1) {
      digitalWrite(8, HIGH);
      delay(100);
      digitalWrite(8, LOW);
      delay(100);
    }
  }
  digitalWrite(8, HIGH);
  delay(1000);
  digitalWrite(8, LOW);
  delay(100);
  Serial.println("Card initialized.");
  delay(100);                    // here too
  adcInit();
  adcCalb();
}

void loop() {
  for(count = 0; count < (FFT_N/2)*16; count++) {
      if(pos == FFT_N) {
      fft_input(capture, bfly_buff);
      fft_execute(bfly_buff);
      fft_output(bfly_buff, spektrum);
      pos = 0;
    }
    for(nextCount = 0; nextCount < FFT_N/2; nextCount++) {
      //signal[((count*(FFT_N/2))+1)+nextCount] = spektrum[nextCount];
    }
    File dataFile = SD.open("Voice Recognition.txt", FILE_WRITE);
    if(dataFile) {
      Serial.println("File Opened.");
    } else {
      Serial.println("Error opening File.");
    }
  }
}

ISR(ADC_vect) {
  for(pos = 0; pos < 128; pos++) {
    capture[pos] = ADC;
    if(capture[pos] == -1 || capture[pos] == 1) {
      capture[pos] = 0;
    }
  }
  Serial.println("Done.");
  return;
}

void adcInit() {
  ADMUX = _BV(REFS0) | IR_AUDIO; // | _BV(ADLAR); 
  ADCSRA = _BV(ADSC) | _BV(ADEN) | _BV(ADATE) | _BV(ADIE) | _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0);
  sei();
}

void adcCalb() {
  long midl = 0;
  for (byte i = 0; i < 2; i++) {
    pos = 0;
    delay(100);
    midl += capture[0];
    delay(900);
  }
  zero = -midl/2;
}

Here are the results from the Serial monitor:

Start of Sketch.
Initializing SD card...
Card initialized.
Done.
Done.
Done.
Don

Thanks for all your help!

Judd

Are you saying that my Arduino can't handle all of the things I've put into the code?

Yes. In fact, the FFFT library also has data for a Hamming window which in your case (FFT_N=128) is another 256 bytes on top of what I've already mentioned.
Splitting the problem across two Arduinos is one way to solve the issue. But if you're going to have to buy another Arduino anyway, you might as well get one that has a lot more static ram and then you can just use your existing code without having to add a lot more functionality which will in turn require a lot more debugging :slight_smile:

Pete

El_supremo: would it be possible to "turn on" certain parts of the code at a time, so that my Arduino doesn't have to multitask? Maybe that would decrease the RAM usage. I was also wondering, would decreasing the size of FFT_N work too? I don't need 128 bins of variables, maybe just 32 or even 16. Would this work with my UNO's RAM?

I also have a chipKIT max32. Would that board be compatible with my code and libraries? If not, what would I have to change?

Thanks,

Judd

The amount of ram used by the FFFT code is approximately FFT_N * 25 bytes.
BUT, the FFFT library seems to require that FFT_N be at least 64 which would use 1600 bytes, plus the 512 needed by SD would be 2112. So it doesn't look like you can use the FFFT library and the SD library at the same time on a 328-based Arduino.

I'm not familiar with the chipKIT max32 so I can't help there.

Pete

this FHT library can give you frequency bins, if thats what youre looking for, and takes up a lot less memory. the tables are stored in program memory, and not SRAM.

http://wiki.openmusiclabs.com/wiki/ArduinoFHT

there is a table showing how many bytes eacy FHT_N requires.

I've already tried the FHT library, unfortunately it doesn't work for my application. I'm going to buy an Arduino DUE since it has 96KB SRAM instead of 2KB, and has more I/O pins, which I will later need.

Does the Arduino DUE has different SD card pins, and if it does, what would I have to change in the SD card library in order for the Arduino to work with my standard data logged shield?

Thank you for all of your help,

Judd

96kB sram should be enough for a while :slight_smile:
Don't forget that the Due is a 3.3V device. If your audio input is currently 5V you will have to take that into account and redesign the input.

Pete

If I have a capacitor between the microphone output and the Arduino board input will that be OK for the circuit? I'm using a sparkfun microphone breakout board:

Is the existing code compatible and is my shield compatible with the Arduino DUE? I'm using the Adafruit GPS logger shield:

Thanks,

Judd

The microphone should be OK with a Due since it is supposed to work with 2.7 - 5.5V

But I don't think the GPS shield is compatible with a DUE. I'm pretty sure that both the pinout and voltage on the shield don't match a DUE.

Pete

Thanks Pete, I'll buy new equipment. Before I buy my DUE, I wanted to do a compiling check, to make sure that everything works fine in the software for the Arduino. I came across one error when I compiled for the DUE. It said the that there was an error in the SD library; avr/pgmspace.h library couldn't be found. Is there any way to fix this problem?

Thanks

Judd

I haven't used the Due. Are you using the 1.5.2 version of the IDE for the Due? If not, give it a try. The Due is not an Atmel processor and may have different libraries set up in the IDE.

Pete