AnsweredAssumed Answered

K64 - I2S + DMA

Question asked by joe hinkle on Aug 1, 2016
Latest reply on Aug 2, 2016 by joe hinkle

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.

 

I2S.png

 

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

Outcomes