73 lines
2.3 KiB
C++
73 lines
2.3 KiB
C++
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <math.h>
|
||
|
#include <cstring>
|
||
|
|
||
|
#include "pico/stdlib.h"
|
||
|
|
||
|
#include "hardware/pio.h"
|
||
|
#include "hardware/dma.h"
|
||
|
#include "hardware/adc.h"
|
||
|
#include "hardware/irq.h"
|
||
|
|
||
|
typedef signed int fix15;
|
||
|
|
||
|
// Helpers for 16.15 fixed-point arithmetic
|
||
|
constexpr __always_inline fix15 multiply_fix15(fix15 a, fix15 b) {return (fix15)(((signed long long)(a) * (signed long long)(b)) >> 15);}
|
||
|
constexpr __always_inline fix15 float_to_fix15(float a) {return (fix15)(a * 32768.0f);}
|
||
|
constexpr __always_inline float fix15_to_float(fix15 a) {return (float)(a) / 32768.0f;}
|
||
|
constexpr __always_inline fix15 int_to_fix15(int a) {return (fix15)(a << 15);}
|
||
|
constexpr __always_inline int fix15_to_int(fix15 a) {return (int)(a >> 15);}
|
||
|
|
||
|
constexpr unsigned int SAMPLE_COUNT = 512u;
|
||
|
|
||
|
class ADCFFT {
|
||
|
private:
|
||
|
|
||
|
unsigned int adc_channel;
|
||
|
unsigned int adc_pin;
|
||
|
float sample_rate;
|
||
|
|
||
|
unsigned int log2_samples;
|
||
|
unsigned int shift_amount;
|
||
|
|
||
|
int dma_channel;
|
||
|
|
||
|
// Here's where we'll have the DMA channel put ADC samples
|
||
|
uint8_t sample_array[SAMPLE_COUNT];
|
||
|
|
||
|
// Lookup tables
|
||
|
fix15 sine_table[SAMPLE_COUNT]; // a table of sines for the FFT
|
||
|
fix15 filter_window[SAMPLE_COUNT]; // a table of window values for the FFT
|
||
|
|
||
|
// And here's where we'll copy those samples for FFT calculation
|
||
|
fix15 fr[SAMPLE_COUNT];
|
||
|
fix15 fi[SAMPLE_COUNT];
|
||
|
|
||
|
int max_freq_dex = 0;
|
||
|
|
||
|
void FFT();
|
||
|
void init();
|
||
|
public:
|
||
|
ADCFFT() : ADCFFT(0, 26, 10000.0f) {};
|
||
|
ADCFFT(unsigned int adc_channel, unsigned int adc_pin) : ADCFFT(adc_channel, adc_pin, 10000.0f) {}
|
||
|
ADCFFT(unsigned int adc_channel, unsigned int adc_pin, float sample_rate) :
|
||
|
adc_channel(adc_channel), adc_pin(adc_pin), sample_rate(sample_rate) {
|
||
|
log2_samples = log2(SAMPLE_COUNT);
|
||
|
shift_amount = 16u - log2_samples;
|
||
|
|
||
|
dma_channel = dma_claim_unused_channel(true);
|
||
|
|
||
|
memset(sample_array, 0, SAMPLE_COUNT);
|
||
|
|
||
|
memset(fr, 0, SAMPLE_COUNT * sizeof(fix15));
|
||
|
memset(fi, 0, SAMPLE_COUNT * sizeof(fix15));
|
||
|
|
||
|
init();
|
||
|
};
|
||
|
~ADCFFT();
|
||
|
|
||
|
void update();
|
||
|
float max_frequency();
|
||
|
int get_scaled(unsigned int i, unsigned int scale);
|
||
|
};
|