Plays USB Audio packets through external DAC (Cirrus Logic CS4344). Simple demo code, don't expect a sophisticated I2S library. HW setup: mbed DIP 5 (I2STX_SDA) -> DAC SDIN (Serial Audio Data Input) mbed DIP 6 (I2STX_WS) -> DAC LRCK (Left Right Clock) mbed DIP 7 (I2STX_CLK) -> DAC SCLK (External Serial Clock Input) mbed DIP 30 (I2SRX_CLK) -> DAC MCLK (Master Clock) also needed an extra USB connector wired to mbed. Does not work with built-in USB. Code needs a bit of clean up.

Dependencies:   mbed

I2S.cpp

Committer:
csorbag
Date:
2012-04-16
Revision:
1:12e8ee1b7ea2
Parent:
0:bf9e7b99dda5

File content as of revision 1:12e8ee1b7ea2:

#include "I2S.h"
#include "MODDMA.h"


volatile uint32_t counter=0;

DigitalOut led3(LED3);

//Serial *global_out;
MODDMA dma;
MODDMA_Config *dmaconfig;

void TC0_callback(void);
void TC1_callback(void);
void TC2_callback(void);

#define BUFFER_SIZE 2048

int16_t buffer[BUFFER_SIZE];

int16_t transferSize;

int16_t *bufferStart, *nextToPlay;
volatile int16_t playing = 0;

volatile int16_t moreToPlay=0;

void setup(Serial *out) {

global_out = out;

    bufferStart = nextToPlay = (int16_t *)buffer;

    LPC_SC->PCONP |= 1 <<27; // Enable I2S
    LPC_SC->PCLKSEL1 |= 1 << 22; // Set Clock to CCLK
    // Reset i2s
    LPC_I2S->I2SDAO = (1 << 4);
    LPC_I2S->I2SDAO = 0;

    
    
    LPC_I2S->I2SDAO = 1 /* Number of bytes 16bit */ | 0xF << 6 /* Word select half perion - 1 */;// | 1 << 3 /* Stop bit */;
    LPC_I2S->I2SDAI = 1 /* Number of bytes 16bit */ | 0xF << 6 /* Word select half perion - 1 */;// | 1 << 3 /* Stop bit */;
    
    
    LPC_PINCON->PINSEL0 |= 01 << 14 /* I2STX_CLK */ | 01 << 16 /* I2STX_WS */ | 01 << 18 /* I2STX_SDA */;
    LPC_PINCON->PINSEL0 |= 01 << 8 /* I2SRX_CLK */ | 01 << 10 /* I2SRX_WS */ | 01 << 12 /* I2SRX_SDA */;

    // Set all to neither pull-up, nor pull-down
    LPC_PINCON->PINMODE0 |= 2 << 14 /* I2STX_CLK */ | 2 << 16 /* I2STX_WS */ | 2 << 18 /* I2STX_SDA */;
    LPC_PINCON->PINMODE0 |= 2 << 8 /* I2SRX_CLK */ | 2 << 10 /* I2SRX_WS */ | 2 << 12 /* I2SRX_SDA */;
    
    
    // Cirrus Logic CS4344 specific frequency settings
    LPC_I2S->I2STXRATE = 125 /* Y_divider */ | 4 << 8 /* X_divider */;
    LPC_I2S->I2SRXRATE = 125 /* Y_divider */ | 32 << 8 /* X_divider */;
    
    int rxbitrate = 1;
    LPC_I2S->I2STXBITRATE = 1;
    LPC_I2S->I2SRXBITRATE = rxbitrate;
    

    LPC_I2S->I2STXMODE  = (0 << 0) | (1 << 3);
    LPC_I2S->I2SRXMODE  = (0 << 0) | (1 << 3);
  
  
    // Start trasnmit    
    LPC_I2S->I2SDAO &= (~(1 << 3));
    LPC_I2S->I2SDAI &= (~(1 << 3));

    LPC_I2S->I2SDMA1 = (1 << 1) /* Enable transit */ | (0 << 16) /* Transmit FIFO level */;


    out->printf("I2S Setup complete\n");
        
    dmaconfig = new MODDMA_Config;
    dmaconfig
     ->channelNum    ( MODDMA::Channel_0 )
//     ->srcMemAddr    ( (uint32_t) &buffer1 )
     ->dstMemAddr    ( 0 )
     //->transferSize  ( 2500 )
     ->transferType  ( MODDMA::m2p )
     ->transferWidth ( 1 )
     ->srcConn       ( 0 )
     ->dstConn       ( MODDMA::I2S_Channel_0 )
     ->dmaLLI        ( 0 )
     ->attach_tc     ( &TC1_callback )
    ;

    out->printf("DMA Setup complete\n");

}


void play(int16_t *buf,int16_t length) {


    moreToPlay = 1;
    
    if (nextToPlay - bufferStart + length >= BUFFER_SIZE) {
        nextToPlay = bufferStart;
    }  
    
    memcpy(nextToPlay,buf,length*sizeof(int16_t));
    
    transferSize=length;
    
    
    // Wait for end of playing previous packet
    while (playing) {};
    
    playing = 1;
    moreToPlay = 0;

    dmaconfig->srcMemAddr    ( (uint32_t) nextToPlay );
    dmaconfig->transferSize  ( length / 2);
    nextToPlay+=length*sizeof(int16_t);
    

    dma.Prepare(dmaconfig);
    
    
}



void TC1_callback(void) {
    
       // Get configuration pointer.
    MODDMA_Config *config = dma.getConfig();
    
    // Finish the DMA cycle by shutting down the channel.
    dma.Disable( (MODDMA::CHANNELS)config->channelNum() );
   

    // Clear DMA IRQ flags.
    if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq(); 
    
    playing = 0;

    if (!moreToPlay) {
        LPC_I2S->I2STXFIFO = 0x0;
        led3 = !led3;
    }
}