el_supremo
Well-known member
I've just got a test version of the Talkie library working directly with the Audio board by setting the sampling rate to 8000Hz.
Pete
Pete
The PT8211 "driver" uses oversampling - so, yes, higher samplerates are possible.
I'll extend the table (and see what I can do with the SGTL5000 Settings)
/***********************************************************************
*
* Test higher/lower sample rates
* that Frank B has implemented
*
* https://forum.pjrc.com/threads/38753-Discussion-about-a-simple-way-to-change-the-sample-rate/page2
*
* 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>
#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
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;
int peak[512];
int barm[512];
ulong samp_ptr = 0;
bool FFT_state = false;
const int myInput = AUDIO_INPUT_LINEIN;
// 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);
// 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 (192000);
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() {
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+=2) {
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.2 * bar + 0.8 * 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.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
*/
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, 44117.64706 , 48000, 88200, 44117.64706 * 2, 96000, 176400, 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;
}
}
}
Great !
I've commented out the display only - works.
But a 3.6 is better !
The SGTL5000 can accept an external standard master clock at a multiple of the sampling frequency (i.e. 256*Fs, 385*Fs, 512*Fs). In addition it can take non-standard frequencies and use the internal PLL to derive the audio clocks. The device supports 8.0 kHz, 11.025 kHz, 12 kHz, 16 kHz, 22.05 kHz, 24 kHz, 32 kHz, 44.1kHz, 48 kHz, 96 kHz sampling frequencies.
// This example code is in the public domain.
// I've added a test for different sampling rates
// and allow passthru of line-in instead of mic
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
//const int myInput = AUDIO_INPUT_MIC;
const int myInput = AUDIO_INPUT_LINEIN;
AudioInputI2S audioInput;
AudioOutputI2S audioOutput;
AudioConnection patchCord1(audioInput, 0, audioOutput, 0);
AudioConnection patchCord2(audioInput, 0, audioOutput, 1);
AudioControlSGTL5000 sgtl5000_1;
#include <Arduino.h>
// From FrankB - brilliant!
void setI2SFreq(int freq)
{
typedef struct {
uint8_t mult;
uint16_t div;
} __attribute__((__packed__)) tmclk;
const int numfreqs = 8;
const int samplefreqs[numfreqs] = { 8000, 11025, 16000, 22050, 32000, 44100, 44117 , 48000 };
#if (F_PLL==16000000)
const tmclk clkArr[] = {{16, 125}, {148, 839}, {32, 125}, {145, 411}, {64, 125}, {151, 214}, {12, 17}, {96, 125} };
#elif (F_PLL==72000000)
const tmclk clkArr[] = {{32, 1125}, {49, 1250}, {64, 1125}, {49, 625}, {128, 1125}, {98, 625}, {8, 51}, {64, 375} };
#elif (F_PLL==96000000)
const tmclk clkArr[] = {{8, 375}, {60, 2041}, {16, 375}, {120, 2041}, {32, 375}, {147, 1250}, {2, 17}, {16, 125} };
#elif (F_PLL==120000000)
const tmclk clkArr[] = {{32, 1875}, {29, 1233}, {64, 1875}, {89, 1892}, {128, 1875}, {89, 946}, {8, 85}, {64, 625} };
#elif (F_PLL==144000000)
const tmclk clkArr[] = {{16, 1125}, {40, 2041}, {32, 1125}, {49, 1250}, {64, 1125}, {49, 625}, {4, 51}, {32, 375} };
#elif (F_PLL==180000000)
const tmclk clkArr[] = {{9, 791}, {31, 1977}, {37, 1626}, {62, 1977}, {73, 1604}, {107, 1706}, {16, 255}, {128, 1875} };
#elif (F_PLL==192000000)
const tmclk clkArr[] = {{4, 375}, {30, 2041}, {8, 375}, {60, 2041}, {16, 375}, {120, 2041}, {1, 17}, {8, 125} };
#elif (F_PLL==216000000)
const tmclk clkArr[] = {{17, 1793}, {17, 1301}, {34, 1793}, {49, 1875}, {49, 1292}, {98, 1875}, {8, 153}, {64, 1125} };
#elif (F_PLL==240000000)
const tmclk clkArr[] = {{16, 1875}, {24, 2041}, {32, 1875}, {29, 1233}, {64, 1875}, {89, 1892}, {4, 85}, {32, 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;
}
}
}
void setup(void)
{
Serial.begin(9600);
AudioMemory(8);
sgtl5000_1.enable();
sgtl5000_1.inputSelect(myInput);
// micgain for the MEMS microphone with 67dB preamp should be zero
// micgain for my Sony microphone with no preamp should be 26-30
sgtl5000_1.micGain(0);
sgtl5000_1.volume(0.6);
// setI2SFreq(8000);
}
void loop(void)
{
static int volume;
int n = analogRead(15);
if (n != volume) {
volume = n;
sgtl5000_1.volume(n / 1023.);
}
}
#if defined(AUDIO_PT8211_OVERSAMPLING)
I2S0_TCR2 = I2S_TCR2_SYNC(0) | I2S_TCR2_BCP | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(0);
#else
I2S0_TCR2 = I2S_TCR2_SYNC(0) | I2S_TCR2_BCP | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(3);
#endif
#if (F_CPU == 240000000)
#define F_PLL 240000000
#ifndef F_BUS
#define F_BUS 60000000
//#define F_BUS 80000000 // uncomment these to try peripheral overclocking
//#define F_BUS 120000000 // all the usual overclocking caveats apply...
#endif
#define F_MEM 30000000