#include <Arduino.h>
#include <Audio.h>
#include "setI2SFreq.h"
unsigned int sample_rate_real;
#ifdef __IMXRT1062__
// For set_audioClock on T4.x
#include <utility/imxrt_hw.h>
// Teensy 4.0, 4.1
int setI2SFreq(int freq) {
int n1;
// PLL between 27*24 = 648MHz und 54*24=1296MHz
//>>> Fudge to handle 8kHz - El Supremo
if(freq > 8000) {
n1 = 4; //SAI prescaler 4 => (n1*n2) = multiple of 4
} else {
n1 = 8;
}
int n2 = 1 + (24000000 * 27) / (freq * 256 * n1);
//>>> El Supremo - make sure n2 fits into 6 bits
if(n2 > 63) {
// n2 must fit into a 6-bit field
Serial.printf("ERROR: n2 exceeds 63 - %d\n",n2);
return 0;
}
double C = ((double)freq * 256 * n1 * n2) / 24000000;
// Serial.printf("%6d : n1 = %d, n2 = %d, C = %12.6f ",freq,n1,n2,C);
int c0 = C;
int c2 = 10000;
int c1 = C * c2 - (c0 * c2);
// Serial.printf("c0 = %d, c1 = %d, c2 = %d\n",c0,c1,c2);
set_audioClock(c0, c1, c2, true);
CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_SAI1_CLK_PRED_MASK | CCM_CS1CDR_SAI1_CLK_PODF_MASK))
| CCM_CS1CDR_SAI1_CLK_PRED(n1 - 1) // &0x07
| CCM_CS1CDR_SAI1_CLK_PODF(n2 - 1); // &0x3f
//START//Added afterwards to make the SAI2 function at the desired frequency as well.
CCM_CS2CDR = (CCM_CS2CDR & ~(CCM_CS2CDR_SAI2_CLK_PRED_MASK | CCM_CS2CDR_SAI2_CLK_PODF_MASK))
| CCM_CS2CDR_SAI2_CLK_PRED(n1 - 1) // &0x07
| CCM_CS2CDR_SAI2_CLK_PODF(n2 - 1); // &0x3f)
//END//Added afterwards to make the SAI2 function at the desired frequency as well.
// For compatibility with my T3.6 version
return freq;
}
#else
// Assume it is T3.6
int 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==168000000)
const tmclk clkArr[numfreqs] = {{32, 2625}, {21, 1250}, {64, 2625}, {21, 625}, {128, 2625}, {42, 625}, {8, 119}, {64, 875}, {84, 625}, {16, 119}, {128, 875}, {168, 625}, {32, 119}, {189, 646} };
#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 round(((float)F_PLL / 256.0) * clkArr[f].mult / clkArr[f].div); //return real freq
}
}
return 0;
}
#endif
void set_sample_rate(int sr)
{
switch(sr) {
case SAMPLE_RATE_8K:
sample_rate_real = 8000;
break;
case SAMPLE_RATE_11K:
sample_rate_real = 11025;
break;
case SAMPLE_RATE_16K:
sample_rate_real = 16000;
break;
case SAMPLE_RATE_22K:
sample_rate_real = 22050;
break;
case SAMPLE_RATE_32K:
sample_rate_real = 32000;
break;
case SAMPLE_RATE_44K:
sample_rate_real = 44100;
break;
case SAMPLE_RATE_48K:
sample_rate_real = 48000;
break;
case SAMPLE_RATE_88K:
sample_rate_real = 88200;
break;
case SAMPLE_RATE_96K:
sample_rate_real = 96000;
break;
case SAMPLE_RATE_176K:
sample_rate_real = 176400;
break;
case SAMPLE_RATE_192K:
sample_rate_real = 192000;
break;
}
AudioNoInterrupts();
sample_rate_real = setI2SFreq(sample_rate_real);
if(sample_rate_real == 0) {
Serial.printf("ERROR: failed to set sampling frequency\n");
while(1);
}
delay(200); // this delay seems to be very essential !
AudioInterrupts();
delay(20);
} // END function set_sample_rate