/***********************************************************************
*
* first version ultrasound detector
* using higher sample rate code by Frank Boesing
*
* https://forum.pjrc.com/threads/38988-Bat-detector
*
* Frank DD4WH 2016_10_31
*
* first experiment
*/
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <Metro.h>
#include "font_Arial.h"
#include <ILI9341_t3.h>
#include <XPT2046_Touchscreen.h>
#define BACKLIGHT_PIN 0
#define TFT_DC 20
#define TFT_CS 21
#define TFT_RST 32 // 255 = unused. connect to 3.3V
#define TFT_MOSI 7
#define TFT_SCLK 14
#define TFT_MISO 12
#define CS_PIN 8
#define TIRQ_PIN 2
XPT2046_Touchscreen ts(CS_PIN);
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO);
Metro five_sec=Metro(2000); // Set up a 0.5 second Metro
// this audio comes from the codec by I2S2
AudioInputI2S i2s_in;
AudioRecordQueue Q_in_L;
AudioRecordQueue Q_in_R;
AudioPlayQueue Q_out_L;
AudioPlayQueue Q_out_R;
AudioAnalyzeFFT256 myFFT;
AudioOutputI2S i2s_out;
AudioConnection patchCord1(i2s_in, 0, Q_in_L, 0);
AudioConnection patchCord2(i2s_in, 1, Q_in_R, 0);
AudioConnection patchCord5(Q_out_R,0,myFFT,0);
AudioConnection patchCord3(Q_out_L, 0, i2s_out, 1);
AudioConnection patchCord4(Q_out_R, 0, i2s_out, 0);
AudioControlSGTL5000 sgtl5000_1; //xy=265.212
int idx_t = 0;
int idx = 0;
int64_t sum;
float32_t mean;
int n_L;
int n_R;
long int n_clear;
int8_t mic_gain = 0; // start detecting with this MIC_GAIN in dB 1MIN TO 7MAX
int peak[512];
int barm[512];
ulong samp_ptr = 0;
bool FFT_state = false;
//const int myInput = AUDIO_INPUT_LINEIN;
const int myInput = AUDIO_INPUT_MIC;
// We're only processing one buffer at a time so the
// number of samples is fixed at 128
#define BUFFER_SIZE 128
float32_t float_buffer_L [BUFFER_SIZE];
float32_t float_buffer_R [BUFFER_SIZE];
float32_t float_buffer_L_3 [BUFFER_SIZE];
float32_t float_buffer_R_3 [BUFFER_SIZE];
void setup() {
Serial.begin(115200);
delay(1000);
ts.begin();
// Audio connections require memory. and the record queue
// uses this memory to buffer incoming audio.
AudioMemory(100);
// Enable the audio shield. select input. and enable output
sgtl5000_1.enable();
sgtl5000_1.inputSelect(myInput);
sgtl5000_1.volume(0.5);
sgtl5000_1.adcHighPassFilterDisable(); // does not help too much!
setI2SFreq (96000); // this works perfectly
// setI2SFreq (192000); this sucks with a Teensy 3.5 (because of the slow display driver)
AudioNoInterrupts();
sgtl5000_1.micGain (mic_gain);
AudioInterrupts();
pinMode( BACKLIGHT_PIN, OUTPUT );
analogWrite( BACKLIGHT_PIN, 1023 );
tft.begin();
tft.setRotation( 3 );
tft.fillScreen(ILI9341_BLACK);
tft.setCursor(10, 1);
tft.setTextSize(2);
tft.setTextColor(ILI9341_WHITE);
tft.setFont(Arial_14);
tft.print("Floating point audio processing");
/****************************************************************************************
* begin to queue the audio from the audio library
****************************************************************************************/
delay(100);
Q_in_L.begin();
Q_in_R.begin();
} // END SETUP
int16_t *sp_L;
int16_t *sp_R;
void loop() {
if(ts.touched()){
tft.fillScreen(ILI9341_BLUE);
}
elapsedMicros usec = 0;
/**********************************************************************************
* Get samples from queue buffers
**********************************************************************************/
// this is supposed to prevent overfilled queue buffers
if (Q_in_L.available() > 3 || Q_in_R.available() > 3) {
Q_in_L.clear();
Q_in_R.clear();
n_clear ++; // just for debugging to check how often this occurs
}
// is there at least one buffer in each channel available ?
if (Q_in_L.available() >= 1 && Q_in_R.available() >= 1)
{
sp_L = Q_in_L.readBuffer();
sp_R = Q_in_R.readBuffer();
// convert to float
arm_q15_to_float (sp_L, float_buffer_L, BUFFER_SIZE); // convert int_buffer to float 32bit
arm_q15_to_float (sp_L, float_buffer_R, BUFFER_SIZE); // convert int_buffer to float 32bit
Q_in_L.freeBuffer();
Q_in_R.freeBuffer();
/**************************************************************************
* From here, all the 32 bit float audio processing can start
* ************************************************************************/
/**************************************************************************
* END of 32 bit float audio processing
* ************************************************************************
*/
sp_L = Q_out_L.getBuffer();
sp_R = Q_out_R.getBuffer();
arm_float_to_q15 (float_buffer_L, sp_L, BUFFER_SIZE);
arm_float_to_q15 (float_buffer_R, sp_R, BUFFER_SIZE);
Q_out_L.playBuffer(); // play it !
Q_out_R.playBuffer(); // play it !
/**********************************************************************************
* PRINT ROUTINE FOR ELAPSED MICROSECONDS
**********************************************************************************/
sum = sum + usec;
idx_t++;
if (idx_t > 1000) {
tft.fillRect(240,50,90,20,ILI9341_BLACK);
tft.setCursor(240, 50);
mean = sum / idx_t;
tft.print (mean);
Serial.print (mean);
Serial.print (" microsec for 2 stereo blocks ");
Serial.println();
idx_t = 0;
sum = 0;
}
}
/**********************************************************************************
* PRINT ROUTINE FOR AUDIO LIBRARY PROCESSOR AND MEMORY USAGE
**********************************************************************************/
if (five_sec.check() == 1)
{
Serial.print("Proc = ");
Serial.print(AudioProcessorUsage());
Serial.print(" (");
Serial.print(AudioProcessorUsageMax());
Serial.print("), Mem = ");
Serial.print(AudioMemoryUsage());
Serial.print(" (");
Serial.print(AudioMemoryUsageMax());
Serial.println(")");
Serial.print("Cleared the audio buffer ");
Serial.print(n_clear); Serial.println (" times. ");
/* tft.fillRect(100,120,200,80,ILI9341_BLACK);
tft.setCursor(10, 120);
tft.setTextSize(2);
tft.setTextColor(ILI9341_WHITE);
tft.setFont(Arial_14);
tft.print ("Proc = ");
tft.setCursor(100, 120);
tft.print (AudioProcessorUsage());
tft.setCursor(180, 120);
tft.print (AudioProcessorUsageMax());
tft.setCursor(10, 150);
tft.print ("Mem = ");
tft.setCursor(100, 150);
tft.print (AudioMemoryUsage());
tft.setCursor(180, 150);
tft.print (AudioMemoryUsageMax());
*/
AudioProcessorUsageMaxReset();
AudioMemoryUsageMaxReset();
}
spectrum();
}
void spectrum() { // spectrum analyser code by rheslip - modified
if (myFFT.available()) {
int scale;
scale = 2;
for (int16_t x=2; x < 100; x+=1) {
int bar = (abs(myFFT.output[x]) * scale);
if (bar >180) bar=180;
// this is a very simple IIR filter to smooth the reaction of the bars
bar = 0.05 * bar + 0.95 * barm[x];
// if (bar > peak[x]) peak[x]=bar;
// tft.drawFastVLine(x, 210-bar,bar, ILI9341_PURPLE);
// tft.drawFastVLine(x*2+10, 210-bar,bar, ILI9341_PINK);
tft.drawPixel(x*2+10, 210-barm[x], ILI9341_BLACK);
tft.drawPixel(x*2+10, 210-bar, ILI9341_WHITE);
// tft.drawFastVLine(x*2+10, 20, 210-bar-20, ILI9341_BLACK);
// tft.drawPixel(x*2+10,209-peak[x], ILI9341_YELLOW);
if(peak[x]>0) peak[x]-=1;
barm[x] = bar;
}
} //end if
} // end void spectrum
// sample rate routine by Frank Boesing
void setI2SFreq(int freq) {
typedef struct {
uint8_t mult;
uint16_t div;
} tmclk;
const int numfreqs = 14;
const int samplefreqs[numfreqs] = { 8000, 11025, 16000, 22050, 32000, 44100, (int)44117.64706 , 48000, 88200, (int)44117.64706 * 2, 96000, 176400, (int)44117.64706 * 4, 192000};
#if (F_PLL==16000000)
const tmclk clkArr[numfreqs] = {{16, 125}, {148, 839}, {32, 125}, {145, 411}, {64, 125}, {151, 214}, {12, 17}, {96, 125}, {151, 107}, {24, 17}, {192, 125}, {127, 45}, {48, 17}, {255, 83} };
#elif (F_PLL==72000000)
const tmclk clkArr[numfreqs] = {{32, 1125}, {49, 1250}, {64, 1125}, {49, 625}, {128, 1125}, {98, 625}, {8, 51}, {64, 375}, {196, 625}, {16, 51}, {128, 375}, {249, 397}, {32, 51}, {185, 271} };
#elif (F_PLL==96000000)
const tmclk clkArr[numfreqs] = {{8, 375}, {73, 2483}, {16, 375}, {147, 2500}, {32, 375}, {147, 1250}, {2, 17}, {16, 125}, {147, 625}, {4, 17}, {32, 125}, {151, 321}, {8, 17}, {64, 125} };
#elif (F_PLL==120000000)
const tmclk clkArr[numfreqs] = {{32, 1875}, {89, 3784}, {64, 1875}, {147, 3125}, {128, 1875}, {205, 2179}, {8, 85}, {64, 625}, {89, 473}, {16, 85}, {128, 625}, {178, 473}, {32, 85}, {145, 354} };
#elif (F_PLL==144000000)
const tmclk clkArr[numfreqs] = {{16, 1125}, {49, 2500}, {32, 1125}, {49, 1250}, {64, 1125}, {49, 625}, {4, 51}, {32, 375}, {98, 625}, {8, 51}, {64, 375}, {196, 625}, {16, 51}, {128, 375} };
#elif (F_PLL==180000000)
const tmclk clkArr[numfreqs] = {{46, 4043}, {49, 3125}, {73, 3208}, {98, 3125}, {183, 4021}, {196, 3125}, {16, 255}, {128, 1875}, {107, 853}, {32, 255}, {219, 1604}, {214, 853}, {64, 255}, {219, 802} };
#elif (F_PLL==192000000)
const tmclk clkArr[numfreqs] = {{4, 375}, {37, 2517}, {8, 375}, {73, 2483}, {16, 375}, {147, 2500}, {1, 17}, {8, 125}, {147, 1250}, {2, 17}, {16, 125}, {147, 625}, {4, 17}, {32, 125} };
#elif (F_PLL==216000000)
const tmclk clkArr[numfreqs] = {{32, 3375}, {49, 3750}, {64, 3375}, {49, 1875}, {128, 3375}, {98, 1875}, {8, 153}, {64, 1125}, {196, 1875}, {16, 153}, {128, 1125}, {226, 1081}, {32, 153}, {147, 646} };
#elif (F_PLL==240000000)
const tmclk clkArr[numfreqs] = {{16, 1875}, {29, 2466}, {32, 1875}, {89, 3784}, {64, 1875}, {147, 3125}, {4, 85}, {32, 625}, {205, 2179}, {8, 85}, {64, 625}, {89, 473}, {16, 85}, {128, 625} };
#endif
for (int f = 0; f < numfreqs; f++) {
if ( freq == samplefreqs[f] ) {
while (I2S0_MCR & I2S_MCR_DUF) ;
I2S0_MDR = I2S_MDR_FRACT((clkArr[f].mult - 1)) | I2S_MDR_DIVIDE((clkArr[f].div - 1));
return;
}
}
}