I need some help.
My I2S appears to be partly working and I can't figure out what wrong.
I have a custom K64 board that I2S is driving a TI audio chip.
I have read and studied AN4369, AN4520, AN4800, and the code associated with AN4369.
My K64 is running at 120 mhz. I have 2 audio buffers that hold 1024 (L and R) 16 bit audio values. I have DMA set to load 4 bytes every load sequence and request an interrupt every 1024 events.
For the test, I am using a sample rate of 8000 hz and a MCLK of 12.288 Mhz. Given I want a frame size of 2 words (4 bytes) - my bit rate is 256000 hz. I have verified the bit freq and the MCLK freq with the logic probe capture shown below.
I instrumented my DMA IRQ to toggle an output to show when my DMA interrupts are occurring ... last logic line on image below.
Here is my code .. I hate posting code ... but I can't see my problem
<code>
void Set_Dma_Mux( void )
{
SIM_SCGC6 |= SIM_SCGC6_DMAMUX_MASK ;
DMAMUX_CHCFG0 = 0; // disable the channel to configure it
DMAMUX_CHCFG0 = DMAMUX_CHCFG_SOURCE(13) ; //I2S0 Transmit .. page 95
DMAMUX_CHCFG0 |= DMAMUX_CHCFG_ENBL_MASK ; // enable the mux
}
void Init_Audio_DMA(void)
{
// setup the DMA channels ( CH0 = playback )
DMA_CR = 0 | DMA_CR_EDBG_MASK; // Stall DMA transfers when debugger is halted (avoid noise) // no minor loop mapping
DMA_DCHPRI15 = 0; // DMA Errors as reset makes priority value equal to chan# -- so make chan 15 priority 0 --- now all unique
DMA_DCHPRI0 = 15; // cannot be pre-empeted, can pre-empt, highest priority
// fill the TCD area
DMA_TCD0_SADDR = (dword)Audio1 ; // alternated with Audio_Source_Blk_B
DMA_TCD0_SOFF = 4; // 2 words offset
DMA_TCD0_ATTR = DMA_ATTR_SMOD(0) | DMA_ATTR_SSIZE(1) | DMA_ATTR_DMOD(0) | DMA_ATTR_DSIZE(1); // no circular addressing S&D, 16 bit S&D
DMA_TCD0_NBYTES_MLNO = 4; // 2 16bit sample every minor loop
DMA_TCD0_SLAST = 0; // not needed -- IRQ will set new start
DMA_TCD0_DADDR = (dword) &I2S0_TDR0; // the FTM Channel 0 duty value
DMA_TCD0_DOFF = 0;
DMA_TCD0_CITER_ELINKNO = AUDIO_SIZE; // total samples
DMA_TCD0_DLASTSGA = 0; // no final last adjustment ( does not move )
DMA_TCD0_CSR = DMA_CSR_INTMAJOR_MASK ; // interrupt when done
DMA_TCD0_BITER_ELINKNO = AUDIO_SIZE; // no chan links, total samples
// configure DMA_MUX to trigger DMA channel 0
Set_Dma_Mux();
// moved to start Audio
// DMA_ERQ = DMA_ERQ_ERQ0_MASK ; // now enable chan0 for triggers
// Install DMA0 Major loop complete IRQ
NVIC_SetPriority(DMA0_IRQn, AudioDMA_Priority);
NVIC_EnableIRQ(DMA0_IRQn);
}
void Init_I2S_Clock(void)
{
// note ... for 11.2896 clock
// use system clock ... 120 mhz ... Delta FQ = 17.623 with FS = 205 and DS = 2179
// use Xtal ... 25 mhz --- Delta 40.591 with FS = 89 and DS = 473
// ???? Xtal is more stable than System Clock????
// I2S_MCR_MICS == 0 --- System Clock -- 120mhz
// I2S_MCR_MICS == 1 --- Xtal --- 25 mhz
// Select input clock 0 and output enable
I2S0_MCR = I2S_MCR_MICS(0) | I2S_MCR_MOE_MASK; // page 167 .. MICS selection ... 0 == SYSTEM CLK!!!! -- 120mhz ... clk divider enabled
// reference only ... based on 96 mhz clock
// Divide to get the 11.2896 MHz from 96MHz (96* (2/17))
// I2S0_MDR = I2S_MDR_FRACT(1) | I2S_MDR_DIVIDE(16);
// Divide to get the 12.2880 MHz from 96MHz (96* (16/125))
// I2S0_MDR = I2S_MDR_FRACT(15) | I2S_MDR_DIVIDE(124);
//I2S0_MDR = I2S_MDR_FRACT(205-1) | I2S_MDR_DIVIDE(2179-1); // see above
I2S0_MDR = I2S_MDR_FRACT(64-1) | I2S_MDR_DIVIDE(625-1); // gives 12.288(48 KHz * 256) .. multiple of 8khz
}
void Init_I2S(void)
{
// NOTE ... MUTE pin init earlier and set to 0 (mute)
// enable system clock to the I2S module
SIM_SCGC6 |= SIM_SCGC6_I2S_MASK;
Init_I2S_Clock(); // sets up I2S_MCLK
PORTE_PCR6 |= PORT_PCR_MUX(0x04); // SCLK
PORTE_PCR12 |= PORT_PCR_MUX(0x04); // BCLK
PORTE_PCR11 |= PORT_PCR_MUX(0x04); // LR_CLK
PORTE_PCR10 |= PORT_PCR_MUX(0x04); // Data OUT to codex
// turn xmit OFF - return to reset conditions
I2S0_TCSR = I2S_TCSR_FR_MASK | I2S_TCSR_SR_MASK; // software reset, fifo reset and Xmit disabled
// wait until off .. if current frame active
while(I2S0_TCSR & I2S_TCSR_TE_MASK)
{
__asm__ __volatile__ ("nop");
}; // wait until reset is done
I2S0_TCR1 = I2S_TCR1_TFW(I2S_FRAME_SIZE*2); // set FIFO watermark .. so frame can load
// note MSEL = 0 for BUS Clk
// = 1 for MCLK
// MCLK == 11.2896
// BLK divide to get to 44100 ...
// BLK for sample rate of 8khz ... bitclk = 8000 * 16 * 2 = 256000 .. so must divide mclk 12.288mhz / 256000 ... by 48
I2S0_TCR2 = I2S_TCR2_SYNC(0) | // use asynchronous mode
I2S_TCR2_MSEL(1) | // use MCLK
I2S_TCR2_BCP_MASK | // BCLK polarity: Bit clock is active low with drive outputs on falling edge and sample inputs on rising edge.
I2S_TCR2_BCD_MASK | // BCLK Master out
I2S_TCR2_DIV(24-1); // divide internal master clock to generate bit clock divide buy (DIV+1)*2
I2S0_TCR3 = I2S_TCR3_TCE_MASK; // transmit data channel is enabled
I2S0_TCR4 = I2S_TCR4_FRSZ(I2S_FRAME_SIZE-1) | // frame size in words less 1
I2S_TCR4_SYWD((I2S_FRAME_SIZE*16)-1) | // number of bits in frame sync
I2S_TCR4_MF_MASK | // MSB first
I2S_TCR4_FSE_MASK | // Frame sync one bit before the frame
// sync polarity HI
I2S_TCR4_FSD_MASK; // WCLK is generated internally (master mode)
I2S0_TCR5 = I2S_TCR5_W0W(16-1) | // bits per word, first frame
I2S_TCR5_WNW(16-1) | // bits per word, nth frame
I2S_TCR5_FBT(0x0f); // index of MSB bit
I2S0_TMR = 0; // No word mask
} /* end init() */
void Start_I2S_Audio(void)
{
AudioMutePIN = 1;
DMA_SERQ = DMA_SERQ_SERQ(0) ; // now enable chan0 for triggers
I2S0_TCSR = I2S_TCSR_TE_MASK | // enable xmit
I2S_TCSR_FR_MASK | // fifo reset
I2S_TCSR_DBGE_MASK | // debug enabled
I2S_TCSR_BCE_MASK | // bit clock enabled
I2S_TCSR_FRDE_MASK; // fifo watermark - DMA
}
</code>
I any one is knowledgeable in K64 I2S setup, please have a look and tell me where I've gone wrong.
Thanks in advance for any help or comments.
Joe
Solved! Go to Solution.
Found my issue -- solved.
Well what was the fix?
I'm not grasping something about this I2S device.
Why are there 2 TDR registers? (TRD0 and TDR1)
Why are there 2 I2S0_TXD pins on the device? (I2S0_TXD0 and I2S0_TXD1)
I'm only using the TRD0 register and the I2S0_TXD0 pin -- I'm expecting a 2 channel (stereo) output. Is this assumption incorrect?
I tried an experiment to help isolate my issue.
I removed DMA from the picture altogether. I set a loop where the cpu looks at the I2S_TCSR_FRF flag (fifo watermark says load data) and loads a left channel 16 bit value followed by a right channel 16 bit value.
while(1)
{
R1 = I2S0_TCSR;
R2 = I2S0_TFR0;
if(R1 & I2S_TCSR_FRF_MASK)
{
I2S0_TDR0 = 0xff00;
I2S0_TDR0 = 0x8001;
}
}
My understanding of how I programmed the I2S was I wanted a frame of 32 bits where the first 16 bits where L channel and the last 16 bits was the R channel.
I captured the I2S0_TFR0 to see what the FIFO pointers are.
I'm puzzled -- since the I2S_TCSR_FRF_MASK is set (watermark level reached) but the I2S0_TFR0 register shows WFP (write fifo pointer) is 9 and RFP (read fifo pointer) is 1.
As you can see by the capture of the I2S0_TXD0 pin -- the I2S device outputs two of the L channel data (0xff00) and none of the R channel data (0x8001). The L/R Frame line is not indicating the frame properly (L/R) .. it shows a continuous L -- which is what is being sent.
Only 2 samples are xmitted (both L channel value) and then nothing else -- why??
Can anyone with Kinetis I2S experience please comment?
Thanks.
Joe