@ -30,10 +30,14 @@
//#include "memcpy_interleave.h"
# include <arm_math.h>
# if defined(__IMXRT1062__)
# include "utility/imxrt_hw.h"
# endif
//Here's the function to change the sample rate of the system (via changing the clocking of the I2S bus)
//https://forum.pjrc.com/threads/38753-Discussion-about-a-simple-way-to-change-the-sample-rate?p=121365&viewfull=1#post121365
float setI2SFreq ( const float freq_Hz ) {
# if defined(KINETISK)
int freq = ( int ) freq_Hz ;
typedef struct {
uint8_t mult ;
@ -71,6 +75,7 @@ float setI2SFreq(const float freq_Hz) {
}
}
return 0.0f ;
# endif
}
static inline int32_t f32_to_i32 ( float32_t f ) {
@ -103,10 +108,9 @@ void AudioOutputI2S_F32::begin(void)
// TODO: should we set & clear the I2S_TCSR_SR bit here?
config_i2s ( ) ;
CORE_PIN22_CONFIG = PORT_PCR_MUX ( 6 ) ; // pin 22, PTC1, I2S0_TXD0
# if defined(KINETISK)
CORE_PIN22_CONFIG = PORT_PCR_MUX ( 6 ) ; // pin 22, PTC1, I2S0_TXD0
dma . TCD - > SADDR = i2s_tx_buffer ;
dma . TCD - > SOFF = 4 ;
dma . TCD - > ATTR = DMA_TCD_ATTR_SSIZE ( 2 ) | DMA_TCD_ATTR_DSIZE ( 2 ) ;
@ -121,13 +125,32 @@ void AudioOutputI2S_F32::begin(void)
//dma.TCD->BITER_ELINKNO = sizeof(i2s_tx_buffer) / 2; //original
dma . TCD - > BITER_ELINKNO = I2S_BUFFER_TO_USE_BYTES / 4 ;
dma . TCD - > CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR ;
# endif
dma . triggerAtHardwareEvent ( DMAMUX_SOURCE_I2S0_TX ) ;
update_responsibility = update_setup ( ) ;
dma . enable ( ) ;
I2S0_TCSR = I2S_TCSR_SR ;
I2S0_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE ;
# elif defined(__IMXRT1062__)
CORE_PIN7_CONFIG = 3 ; //1:TX_DATA0
dma . TCD - > SADDR = i2s_tx_buffer ;
dma . TCD - > SOFF = 2 ;
dma . TCD - > ATTR = DMA_TCD_ATTR_SSIZE ( 1 ) | DMA_TCD_ATTR_DSIZE ( 1 ) ;
dma . TCD - > NBYTES_MLNO = 2 ;
dma . TCD - > SLAST = - sizeof ( i2s_tx_buffer ) ;
dma . TCD - > DOFF = 0 ;
dma . TCD - > CITER_ELINKNO = sizeof ( i2s_tx_buffer ) / 2 ;
dma . TCD - > DLASTSGA = 0 ;
dma . TCD - > BITER_ELINKNO = sizeof ( i2s_tx_buffer ) / 2 ;
dma . TCD - > DADDR = ( void * ) ( ( uint32_t ) & I2S1_TDR0 + 2 ) ;
dma . TCD - > CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR ;
dma . triggerAtHardwareEvent ( DMAMUX_SOURCE_SAI1_TX ) ;
dma . enable ( ) ;
I2S1_RCSR | = I2S_RCSR_RE | I2S_RCSR_BCE ;
I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE ;
# endif
update_responsibility = update_setup ( ) ;
dma . attachInterrupt ( isr ) ;
// change the I2S frequencies to make the requested sample rate
@ -141,7 +164,7 @@ void AudioOutputI2S_F32::begin(void)
void AudioOutputI2S_F32 : : isr ( void )
{
# if defined(KINETISK)
# if defined(KINETISK) || defined(__IMXRT1062__)
int32_t * dest ;
audio_block_f32_t * blockL , * blockR ;
uint32_t saddr , offsetL , offsetR ;
@ -359,7 +382,7 @@ void AudioOutputI2S_F32::update(void)
}
}
# if defined(KINETISK) || defined(KINETISL)
// MCLK needs to be 48e6 / 1088 * 256 = 11.29411765 MHz -> 44.117647 kHz sample rate
//
# if F_CPU == 96000000 || F_CPU == 48000000 || F_CPU == 24000000
@ -407,8 +430,11 @@ void AudioOutputI2S_F32::update(void)
# endif
# endif
# endif
void AudioOutputI2S_F32 : : config_i2s ( void )
{
# if defined(KINETISK) || defined(KINETISL)
SIM_SCGC6 | = SIM_SCGC6_I2S ;
SIM_SCGC7 | = SIM_SCGC7_DMA ;
SIM_SCGC6 | = SIM_SCGC6_DMAMUX ;
@ -446,6 +472,66 @@ void AudioOutputI2S_F32::config_i2s(void)
CORE_PIN23_CONFIG = PORT_PCR_MUX ( 6 ) ; // pin 23, PTC2, I2S0_TX_FS (LRCLK)
CORE_PIN9_CONFIG = PORT_PCR_MUX ( 6 ) ; // pin 9, PTC3, I2S0_TX_BCLK
CORE_PIN11_CONFIG = PORT_PCR_MUX ( 6 ) ; // pin 11, PTC6, I2S0_MCLK
# elif defined(__IMXRT1062__)
CCM_CCGR5 | = CCM_CCGR5_SAI1 ( CCM_CCGR_ON ) ;
// if either transmitter or receiver is enabled, do nothing
if ( I2S1_TCSR & I2S_TCSR_TE ) return ;
if ( I2S1_RCSR & I2S_RCSR_RE ) return ;
//PLL:
int fs = AUDIO_SAMPLE_RATE_EXACT ;
// PLL between 27*24 = 648MHz und 54*24=1296MHz
int n1 = 4 ; //SAI prescaler 4 => (n1*n2) = multiple of 4
int n2 = 1 + ( 24000000 * 27 ) / ( fs * 256 * n1 ) ;
double C = ( ( double ) fs * 256 * n1 * n2 ) / 24000000 ;
int c0 = C ;
int c2 = 10000 ;
int c1 = C * c2 - ( c0 * c2 ) ;
set_audioClock ( c0 , c1 , c2 ) ;
// clear SAI1_CLK register locations
CCM_CSCMR1 = ( CCM_CSCMR1 & ~ ( CCM_CSCMR1_SAI1_CLK_SEL_MASK ) )
| CCM_CSCMR1_SAI1_CLK_SEL ( 2 ) ; // &0x03 // (0,1,2): PLL3PFD0, PLL5, PLL4
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
// Select MCLK
IOMUXC_GPR_GPR1 = ( IOMUXC_GPR_GPR1
& ~ ( IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL_MASK ) )
| ( IOMUXC_GPR_GPR1_SAI1_MCLK_DIR | IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL ( 0 ) ) ;
CORE_PIN23_CONFIG = 3 ; //1:MCLK
CORE_PIN21_CONFIG = 3 ; //1:RX_BCLK
CORE_PIN20_CONFIG = 3 ; //1:RX_SYNC
int rsync = 0 ;
int tsync = 1 ;
I2S1_TMR = 0 ;
//I2S1_TCSR = (1<<25); //Reset
I2S1_TCR1 = I2S_TCR1_RFW ( 1 ) ;
I2S1_TCR2 = I2S_TCR2_SYNC ( tsync ) | I2S_TCR2_BCP // sync=0; tx is async;
| ( I2S_TCR2_BCD | I2S_TCR2_DIV ( ( 1 ) ) | I2S_TCR2_MSEL ( 1 ) ) ;
I2S1_TCR3 = I2S_TCR3_TCE ;
I2S1_TCR4 = I2S_TCR4_FRSZ ( ( 2 - 1 ) ) | I2S_TCR4_SYWD ( ( 32 - 1 ) ) | I2S_TCR4_MF
| I2S_TCR4_FSD | I2S_TCR4_FSE | I2S_TCR4_FSP ;
I2S1_TCR5 = I2S_TCR5_WNW ( ( 32 - 1 ) ) | I2S_TCR5_W0W ( ( 32 - 1 ) ) | I2S_TCR5_FBT ( ( 32 - 1 ) ) ;
I2S1_RMR = 0 ;
//I2S1_RCSR = (1<<25); //Reset
I2S1_RCR1 = I2S_RCR1_RFW ( 1 ) ;
I2S1_RCR2 = I2S_RCR2_SYNC ( rsync ) | I2S_RCR2_BCP // sync=0; rx is async;
| ( I2S_RCR2_BCD | I2S_RCR2_DIV ( ( 1 ) ) | I2S_RCR2_MSEL ( 1 ) ) ;
I2S1_RCR3 = I2S_RCR3_RCE ;
I2S1_RCR4 = I2S_RCR4_FRSZ ( ( 2 - 1 ) ) | I2S_RCR4_SYWD ( ( 32 - 1 ) ) | I2S_RCR4_MF
| I2S_RCR4_FSE | I2S_RCR4_FSP | I2S_RCR4_FSD ;
I2S1_RCR5 = I2S_RCR5_WNW ( ( 32 - 1 ) ) | I2S_RCR5_W0W ( ( 32 - 1 ) ) | I2S_RCR5_FBT ( ( 32 - 1 ) ) ;
# endif
}