Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of audio_FFT by
main.cpp@0:5b7b619f59cd, 2010-03-21 (annotated)
- Committer:
- jcobb
- Date:
- Sun Mar 21 18:06:46 2010 +0000
- Revision:
- 0:5b7b619f59cd
- Child:
- 1:9935872e58f9
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| jcobb | 0:5b7b619f59cd | 1 | |
| jcobb | 0:5b7b619f59cd | 2 | #define SAMPLE_RATE 48000 |
| jcobb | 0:5b7b619f59cd | 3 | |
| jcobb | 0:5b7b619f59cd | 4 | #include "mbed.h" |
| jcobb | 0:5b7b619f59cd | 5 | #include "adc.h" |
| jcobb | 0:5b7b619f59cd | 6 | |
| jcobb | 0:5b7b619f59cd | 7 | //Going to use the Mellen FFT rather than STM, as the STM (port by Igor) won't compile |
| jcobb | 0:5b7b619f59cd | 8 | //extern "C" void cr4_fft_256_stm32(void *pssOUT, void *pssIN, uint16_t Nbin); |
| jcobb | 0:5b7b619f59cd | 9 | extern "C" void fftR4(short *y, short *x, int N); |
| jcobb | 0:5b7b619f59cd | 10 | |
| jcobb | 0:5b7b619f59cd | 11 | //use the LED as a bargraph |
| jcobb | 0:5b7b619f59cd | 12 | DigitalOut l1(LED1); |
| jcobb | 0:5b7b619f59cd | 13 | DigitalOut l2(LED2); |
| jcobb | 0:5b7b619f59cd | 14 | DigitalOut l3(LED3); |
| jcobb | 0:5b7b619f59cd | 15 | DigitalOut l4(LED4); |
| jcobb | 0:5b7b619f59cd | 16 | |
| jcobb | 0:5b7b619f59cd | 17 | //set up a timer for timing FFT's |
| jcobb | 0:5b7b619f59cd | 18 | Timer timer; |
| jcobb | 0:5b7b619f59cd | 19 | |
| jcobb | 0:5b7b619f59cd | 20 | //Set up filesystem so we can write some useful files |
| jcobb | 0:5b7b619f59cd | 21 | |
| jcobb | 0:5b7b619f59cd | 22 | LocalFileSystem local("local"); |
| jcobb | 0:5b7b619f59cd | 23 | FILE *fp; |
| jcobb | 0:5b7b619f59cd | 24 | |
| jcobb | 0:5b7b619f59cd | 25 | //Set up a global buffer for audio data so interrupt can access it |
| jcobb | 0:5b7b619f59cd | 26 | int Counter = 0; |
| jcobb | 0:5b7b619f59cd | 27 | int16_t Buffer[5000]; |
| jcobb | 0:5b7b619f59cd | 28 | |
| jcobb | 0:5b7b619f59cd | 29 | //Initialise ADC to maximum SAMPLE_RATE and cclk divide set to 1 |
| jcobb | 0:5b7b619f59cd | 30 | ADC adc(SAMPLE_RATE, 1); |
| jcobb | 0:5b7b619f59cd | 31 | |
| jcobb | 0:5b7b619f59cd | 32 | //Functions to write 16 bit audio data and 32 bit headers to files in au format (cf sndRecorder Cookbook) |
| jcobb | 0:5b7b619f59cd | 33 | void fwrite16(uint16_t v) |
| jcobb | 0:5b7b619f59cd | 34 | { |
| jcobb | 0:5b7b619f59cd | 35 | uint8_t *b = (uint8_t *)&v; |
| jcobb | 0:5b7b619f59cd | 36 | |
| jcobb | 0:5b7b619f59cd | 37 | fprintf(fp,"%c%c", b[1], b[0]); |
| jcobb | 0:5b7b619f59cd | 38 | } |
| jcobb | 0:5b7b619f59cd | 39 | void fwrite32(uint32_t v) |
| jcobb | 0:5b7b619f59cd | 40 | { |
| jcobb | 0:5b7b619f59cd | 41 | uint8_t *b = (uint8_t *)&v; |
| jcobb | 0:5b7b619f59cd | 42 | |
| jcobb | 0:5b7b619f59cd | 43 | fprintf(fp,"%c%c%c%c", b[3], b[2], b[1], b[0]); |
| jcobb | 0:5b7b619f59cd | 44 | } |
| jcobb | 0:5b7b619f59cd | 45 | |
| jcobb | 0:5b7b619f59cd | 46 | //Our interrupt handler for audio sampling |
| jcobb | 0:5b7b619f59cd | 47 | void sample_ADC(int chan, uint32_t value) { |
| jcobb | 0:5b7b619f59cd | 48 | |
| jcobb | 0:5b7b619f59cd | 49 | float s; |
| jcobb | 0:5b7b619f59cd | 50 | s = adc.read(p20); |
| jcobb | 0:5b7b619f59cd | 51 | int16_t b = (s -2048)*16; |
| jcobb | 0:5b7b619f59cd | 52 | Buffer[Counter] = b; |
| jcobb | 0:5b7b619f59cd | 53 | Counter += 1; |
| jcobb | 0:5b7b619f59cd | 54 | /* bar graph */ |
| jcobb | 0:5b7b619f59cd | 55 | int g = abs(s-2048); |
| jcobb | 0:5b7b619f59cd | 56 | l1 = g > 0.1f*2048; |
| jcobb | 0:5b7b619f59cd | 57 | l2 = g > 0.3f*2048; |
| jcobb | 0:5b7b619f59cd | 58 | l3 = g > 0.6f*2048; |
| jcobb | 0:5b7b619f59cd | 59 | l4 = g > 0.8f*2048; |
| jcobb | 0:5b7b619f59cd | 60 | } |
| jcobb | 0:5b7b619f59cd | 61 | |
| jcobb | 0:5b7b619f59cd | 62 | int main() { |
| jcobb | 0:5b7b619f59cd | 63 | |
| jcobb | 0:5b7b619f59cd | 64 | //Prepare for burst mode on all ADC pins and set up interrupt handler (using ADC library from Simon Blandford |
| jcobb | 0:5b7b619f59cd | 65 | adc.append(sample_ADC); |
| jcobb | 0:5b7b619f59cd | 66 | adc.startmode(0,0); |
| jcobb | 0:5b7b619f59cd | 67 | adc.burst(1); |
| jcobb | 0:5b7b619f59cd | 68 | adc.setup(p20,1); |
| jcobb | 0:5b7b619f59cd | 69 | |
| jcobb | 0:5b7b619f59cd | 70 | //introduce a delay as initial waveform has bias whilst decoupling cap charges |
| jcobb | 0:5b7b619f59cd | 71 | wait(1); |
| jcobb | 0:5b7b619f59cd | 72 | |
| jcobb | 0:5b7b619f59cd | 73 | //start the interrupt and wait for about 4096 samples |
| jcobb | 0:5b7b619f59cd | 74 | adc.interrupt_state(p20,1); |
| jcobb | 0:5b7b619f59cd | 75 | wait(0.1); |
| jcobb | 0:5b7b619f59cd | 76 | |
| jcobb | 0:5b7b619f59cd | 77 | //Finsh up - Unset pin 20 |
| jcobb | 0:5b7b619f59cd | 78 | adc.interrupt_state(p20,0); |
| jcobb | 0:5b7b619f59cd | 79 | adc.setup(p20,0); |
| jcobb | 0:5b7b619f59cd | 80 | int actual_rate = adc.actual_sample_rate(); |
| jcobb | 0:5b7b619f59cd | 81 | |
| jcobb | 0:5b7b619f59cd | 82 | //for debugging tell the terminal sample rate and how many samples we took |
| jcobb | 0:5b7b619f59cd | 83 | printf("Requested max sample rate is %u, actual max sample rate is %u.\n", |
| jcobb | 0:5b7b619f59cd | 84 | SAMPLE_RATE, actual_rate); |
| jcobb | 0:5b7b619f59cd | 85 | printf("We did %i samples\n",Counter); |
| jcobb | 0:5b7b619f59cd | 86 | |
| jcobb | 0:5b7b619f59cd | 87 | //write original audio file to filesytem so we can load on PC and see what's there (cf sndRecorder Cookbook) |
| jcobb | 0:5b7b619f59cd | 88 | fp = fopen("/local/out.au", "w"); |
| jcobb | 0:5b7b619f59cd | 89 | fprintf(fp,".snd"); |
| jcobb | 0:5b7b619f59cd | 90 | fwrite32(24); |
| jcobb | 0:5b7b619f59cd | 91 | fwrite32(-1); |
| jcobb | 0:5b7b619f59cd | 92 | fwrite32(3); |
| jcobb | 0:5b7b619f59cd | 93 | fwrite32(48000); |
| jcobb | 0:5b7b619f59cd | 94 | fwrite32(1); |
| jcobb | 0:5b7b619f59cd | 95 | int writeCount = 0; |
| jcobb | 0:5b7b619f59cd | 96 | while(writeCount <=Counter) { |
| jcobb | 0:5b7b619f59cd | 97 | fwrite16(Buffer[writeCount]); |
| jcobb | 0:5b7b619f59cd | 98 | writeCount+=1; |
| jcobb | 0:5b7b619f59cd | 99 | } |
| jcobb | 0:5b7b619f59cd | 100 | |
| jcobb | 0:5b7b619f59cd | 101 | //Not using the STM FFT, but leave code here for the moment |
| jcobb | 0:5b7b619f59cd | 102 | |
| jcobb | 0:5b7b619f59cd | 103 | /* |
| jcobb | 0:5b7b619f59cd | 104 | //now do a fft of the initial 1024 samples |
| jcobb | 0:5b7b619f59cd | 105 | #define N 256 //Number of points |
| jcobb | 0:5b7b619f59cd | 106 | uint32_t x[N], y[N]; // input and output arrays |
| jcobb | 0:5b7b619f59cd | 107 | int16_t real[N], imag[N]; // real and imaginary arrays |
| jcobb | 0:5b7b619f59cd | 108 | memset(real, 0, sizeof(real)); |
| jcobb | 0:5b7b619f59cd | 109 | memset(imag, 0, sizeof(imag)); |
| jcobb | 0:5b7b619f59cd | 110 | // real[1]=SHRT_MAX; |
| jcobb | 0:5b7b619f59cd | 111 | // Fill the input array |
| jcobb | 0:5b7b619f59cd | 112 | for (int i=0; i<N; i++) |
| jcobb | 0:5b7b619f59cd | 113 | { |
| jcobb | 0:5b7b619f59cd | 114 | x[i] = (((uint16_t)(Buffer[i])) | ((uint32_t)(0<<16))); |
| jcobb | 0:5b7b619f59cd | 115 | } |
| jcobb | 0:5b7b619f59cd | 116 | timer.reset(); |
| jcobb | 0:5b7b619f59cd | 117 | timer.start(); |
| jcobb | 0:5b7b619f59cd | 118 | cr4_fft_256_stm32(y, x, N); //computes the FFT of the x[N] samples |
| jcobb | 0:5b7b619f59cd | 119 | printf("ST32 fft up took %i\n",timer.read_us()); |
| jcobb | 0:5b7b619f59cd | 120 | FILE* log = fopen("/local/stm32.txt","w"); |
| jcobb | 0:5b7b619f59cd | 121 | for (int i=0; i<N; i++) |
| jcobb | 0:5b7b619f59cd | 122 | { |
| jcobb | 0:5b7b619f59cd | 123 | fprintf(log, "%d: %d, %d -> %d, %d\n", i, Buffer[i], 0 , int16_t(y[i] & 0xFFFF), int16_t(y[i] >> 16)); |
| jcobb | 0:5b7b619f59cd | 124 | } |
| jcobb | 0:5b7b619f59cd | 125 | fclose(log); |
| jcobb | 0:5b7b619f59cd | 126 | |
| jcobb | 0:5b7b619f59cd | 127 | //compute frequencies and magnitudes of result |
| jcobb | 0:5b7b619f59cd | 128 | FILE* spectrum = fopen("/local/stm32Spec.txt","w"); |
| jcobb | 0:5b7b619f59cd | 129 | for (int i=0; i<N/2; i++) |
| jcobb | 0:5b7b619f59cd | 130 | { |
| jcobb | 0:5b7b619f59cd | 131 | float real = int16_t(y[i] & 0xFFFF)* int16_t(y[i] & 0xFFFF); |
| jcobb | 0:5b7b619f59cd | 132 | float imag = int16_t(y[i] >> 16)* int16_t(y[i] >> 16); |
| jcobb | 0:5b7b619f59cd | 133 | fprintf(spectrum, "%d -> %f\n", int(SAMPLE_RATE/N*i),sqrt(imag+real)); |
| jcobb | 0:5b7b619f59cd | 134 | } |
| jcobb | 0:5b7b619f59cd | 135 | fclose(spectrum); |
| jcobb | 0:5b7b619f59cd | 136 | */ |
| jcobb | 0:5b7b619f59cd | 137 | |
| jcobb | 0:5b7b619f59cd | 138 | //now lets try mellen fft |
| jcobb | 0:5b7b619f59cd | 139 | timer.reset(); |
| jcobb | 0:5b7b619f59cd | 140 | timer.start(); |
| jcobb | 0:5b7b619f59cd | 141 | #define MN 1024 /*Number of points*/ |
| jcobb | 0:5b7b619f59cd | 142 | short mx[MN*2]; // input data 16 bit, 4 byte aligned x0r,x0i,x1r,x1i,.... |
| jcobb | 0:5b7b619f59cd | 143 | short my[MN*2]; // output data 16 bit,4 byte aligned y0r,y0i,y1r,y1i,.... |
| jcobb | 0:5b7b619f59cd | 144 | for (int i=0;i<MN*2;i++) mx[i]=0; |
| jcobb | 0:5b7b619f59cd | 145 | for (int i=0;i<MN;i=i+1) |
| jcobb | 0:5b7b619f59cd | 146 | { mx[i*2]=Buffer[i];} |
| jcobb | 0:5b7b619f59cd | 147 | printf("Mellen set up took %i\n",timer.read_us()); |
| jcobb | 0:5b7b619f59cd | 148 | //call functions |
| jcobb | 0:5b7b619f59cd | 149 | timer.reset(); |
| jcobb | 0:5b7b619f59cd | 150 | timer.start(); |
| jcobb | 0:5b7b619f59cd | 151 | fftR4(my, mx, MN); |
| jcobb | 0:5b7b619f59cd | 152 | printf("Mellen fft took %i\n",timer.read_us()); |
| jcobb | 0:5b7b619f59cd | 153 | FILE* mlog = fopen("/local/mellen.csv","w"); |
| jcobb | 0:5b7b619f59cd | 154 | |
| jcobb | 0:5b7b619f59cd | 155 | //now write a CSV file to filesytem of frequency vs amplitude |
| jcobb | 0:5b7b619f59cd | 156 | for (int i=0; i<MN; i=i+2) |
| jcobb | 0:5b7b619f59cd | 157 | { |
| jcobb | 0:5b7b619f59cd | 158 | // fprintf(mlog, "%d: %d -> %d\n", i, mx[i], my[i]); |
| jcobb | 0:5b7b619f59cd | 159 | fprintf(mlog, "%d,%f\n", int(actual_rate/MN/2*i),sqrt(float( (my[i]*my[i]) +(my[i+1]*my[i+1]) ) ) ); |
| jcobb | 0:5b7b619f59cd | 160 | } |
| jcobb | 0:5b7b619f59cd | 161 | fclose(mlog); |
| jcobb | 0:5b7b619f59cd | 162 | |
| jcobb | 0:5b7b619f59cd | 163 | |
| jcobb | 0:5b7b619f59cd | 164 | } |
| jcobb | 0:5b7b619f59cd | 165 | |
| jcobb | 0:5b7b619f59cd | 166 | |
| jcobb | 0:5b7b619f59cd | 167 | |
| jcobb | 0:5b7b619f59cd | 168 | |
| jcobb | 0:5b7b619f59cd | 169 |
