Read an audio signal from the ADC, write it out to a file on the filestytem and perform a 1024 point FFT, writing frequency data to a csv file

Dependencies:   mbed

main.cpp

Committer:
jcobb
Date:
2010-03-21
Revision:
0:5b7b619f59cd

File content as of revision 0:5b7b619f59cd:


#define SAMPLE_RATE   48000

#include "mbed.h"
#include "adc.h"

//Going to use the Mellen FFT rather than STM, as the STM (port by Igor) won't compile
//extern "C" void cr4_fft_256_stm32(void *pssOUT, void *pssIN, uint16_t Nbin);
extern "C" void fftR4(short *y, short *x, int N);

//use the LED as a bargraph
DigitalOut l1(LED1);
DigitalOut l2(LED2);
DigitalOut l3(LED3);
DigitalOut l4(LED4);

//set up a timer for timing FFT's
Timer timer;

//Set up filesystem so we can write some useful files

LocalFileSystem local("local");              
FILE *fp;

//Set up a global buffer for audio data so interrupt can access it
int Counter = 0;
int16_t Buffer[5000];

//Initialise ADC to maximum SAMPLE_RATE and cclk divide set to 1
ADC adc(SAMPLE_RATE, 1);

//Functions to write 16 bit audio data and 32 bit headers to files in au format (cf sndRecorder Cookbook)
void fwrite16(uint16_t v)
{
    uint8_t *b = (uint8_t *)&v;
    
    fprintf(fp,"%c%c", b[1], b[0]);
}
void fwrite32(uint32_t v)
{
    uint8_t *b = (uint8_t *)&v;
    
    fprintf(fp,"%c%c%c%c", b[3], b[2], b[1], b[0]);
}

//Our interrupt handler for audio sampling
void sample_ADC(int chan, uint32_t value) {
    
   float s;
   s = adc.read(p20); 
   int16_t b = (s -2048)*16;
   Buffer[Counter] = b;
   Counter += 1;
    /* bar graph */
    int g = abs(s-2048);
    l1 = g > 0.1f*2048;
    l2 = g > 0.3f*2048;
    l3 = g > 0.6f*2048;
    l4 = g > 0.8f*2048;
}

int main() {

    //Prepare for burst mode on all ADC pins and set up interrupt handler (using ADC library from Simon Blandford
    adc.append(sample_ADC);
    adc.startmode(0,0);
    adc.burst(1);
    adc.setup(p20,1);
    
    //introduce a delay as initial waveform has bias whilst decoupling cap charges
    wait(1);
    
    //start the interrupt and wait for about 4096 samples
    adc.interrupt_state(p20,1);
    wait(0.1);
    
        //Finsh up - Unset pin 20
        adc.interrupt_state(p20,0);
        adc.setup(p20,0);
        int actual_rate = adc.actual_sample_rate();
        
        //for debugging tell the terminal sample rate and how many samples we took
        printf("Requested max sample rate is %u, actual max sample rate is %u.\n",
        SAMPLE_RATE, actual_rate);
        printf("We did %i samples\n",Counter);
        
        //write original audio file to filesytem  so we can load on PC and see what's there (cf sndRecorder Cookbook)
        fp = fopen("/local/out.au", "w");
        fprintf(fp,".snd");
        fwrite32(24);
        fwrite32(-1);    
        fwrite32(3);     
        fwrite32(48000);      
        fwrite32(1);     
        int writeCount = 0;
        while(writeCount <=Counter) {
        fwrite16(Buffer[writeCount]);
        writeCount+=1;
        }
        
        //Not using the STM FFT, but leave code here for the moment
        
        /*
        //now do a fft of the initial 1024 samples
        #define N 256 //Number of points
        uint32_t x[N], y[N]; // input and output arrays 
        int16_t real[N], imag[N]; // real and imaginary arrays 
        memset(real, 0, sizeof(real));
        memset(imag, 0, sizeof(imag));
       // real[1]=SHRT_MAX;
        // Fill the input array 
        for (int i=0; i<N; i++)
        {
            x[i] = (((uint16_t)(Buffer[i])) | ((uint32_t)(0<<16)));
        }
        timer.reset();
        timer.start();
        cr4_fft_256_stm32(y, x, N); //computes the FFT of the x[N] samples
        printf("ST32 fft up took %i\n",timer.read_us());
        FILE* log = fopen("/local/stm32.txt","w");
        for (int i=0; i<N; i++)
        {
            fprintf(log, "%d: %d, %d -> %d, %d\n", i, Buffer[i], 0 , int16_t(y[i] & 0xFFFF), int16_t(y[i] >> 16));
        }
        fclose(log);    
        
        //compute frequencies and magnitudes of result
        FILE* spectrum = fopen("/local/stm32Spec.txt","w");
        for (int i=0; i<N/2; i++)
        {
            float real =  int16_t(y[i] & 0xFFFF)* int16_t(y[i] & 0xFFFF);
            float imag =  int16_t(y[i] >> 16)* int16_t(y[i] >> 16);
            fprintf(spectrum, "%d -> %f\n", int(SAMPLE_RATE/N*i),sqrt(imag+real));
        }
        fclose(spectrum); 
        */

        //now lets try mellen fft
        timer.reset();
        timer.start();
        #define MN 1024 /*Number of points*/
        short mx[MN*2]; // input data 16 bit, 4 byte aligned  x0r,x0i,x1r,x1i,....
        short my[MN*2]; // output data 16 bit,4 byte aligned  y0r,y0i,y1r,y1i,....
        for (int i=0;i<MN*2;i++) mx[i]=0;
        for (int i=0;i<MN;i=i+1)
            { mx[i*2]=Buffer[i];}
        printf("Mellen set up took %i\n",timer.read_us());
        //call functions
        timer.reset();
        timer.start();
        fftR4(my, mx, MN);
        printf("Mellen fft took %i\n",timer.read_us());
        FILE* mlog = fopen("/local/mellen.csv","w");
        
        //now write a CSV file to filesytem of frequency vs amplitude
        for (int i=0; i<MN; i=i+2)
        {
          //  fprintf(mlog, "%d: %d -> %d\n", i, mx[i], my[i]);
            fprintf(mlog, "%d,%f\n", int(actual_rate/MN/2*i),sqrt(float(   (my[i]*my[i])  +(my[i+1]*my[i+1])     ) )   );
        }
        fclose(mlog);    
  
        
}