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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers I2S.cpp Source File

I2S.cpp

00001 #include "I2S.h"
00002 #include "MODDMA.h"
00003 
00004 
00005 volatile uint32_t counter=0;
00006 
00007 DigitalOut led3(LED3);
00008 
00009 //Serial *global_out;
00010 MODDMA dma;
00011 MODDMA_Config *dmaconfig;
00012 
00013 void TC0_callback(void);
00014 void TC1_callback(void);
00015 void TC2_callback(void);
00016 
00017 #define BUFFER_SIZE 2048
00018 
00019 int16_t buffer[BUFFER_SIZE];
00020 
00021 int16_t transferSize;
00022 
00023 int16_t *bufferStart, *nextToPlay;
00024 volatile int16_t playing = 0;
00025 
00026 volatile int16_t moreToPlay=0;
00027 
00028 void setup(Serial *out) {
00029 
00030 global_out = out;
00031 
00032     bufferStart = nextToPlay = (int16_t *)buffer;
00033 
00034     LPC_SC->PCONP |= 1 <<27; // Enable I2S
00035     LPC_SC->PCLKSEL1 |= 1 << 22; // Set Clock to CCLK
00036     // Reset i2s
00037     LPC_I2S->I2SDAO = (1 << 4);
00038     LPC_I2S->I2SDAO = 0;
00039 
00040     
00041     
00042     LPC_I2S->I2SDAO = 1 /* Number of bytes 16bit */ | 0xF << 6 /* Word select half perion - 1 */;// | 1 << 3 /* Stop bit */;
00043     LPC_I2S->I2SDAI = 1 /* Number of bytes 16bit */ | 0xF << 6 /* Word select half perion - 1 */;// | 1 << 3 /* Stop bit */;
00044     
00045     
00046     LPC_PINCON->PINSEL0 |= 01 << 14 /* I2STX_CLK */ | 01 << 16 /* I2STX_WS */ | 01 << 18 /* I2STX_SDA */;
00047     LPC_PINCON->PINSEL0 |= 01 << 8 /* I2SRX_CLK */ | 01 << 10 /* I2SRX_WS */ | 01 << 12 /* I2SRX_SDA */;
00048 
00049     // Set all to neither pull-up, nor pull-down
00050     LPC_PINCON->PINMODE0 |= 2 << 14 /* I2STX_CLK */ | 2 << 16 /* I2STX_WS */ | 2 << 18 /* I2STX_SDA */;
00051     LPC_PINCON->PINMODE0 |= 2 << 8 /* I2SRX_CLK */ | 2 << 10 /* I2SRX_WS */ | 2 << 12 /* I2SRX_SDA */;
00052     
00053     
00054     // Cirrus Logic CS4344 specific frequency settings
00055     LPC_I2S->I2STXRATE = 125 /* Y_divider */ | 4 << 8 /* X_divider */;
00056     LPC_I2S->I2SRXRATE = 125 /* Y_divider */ | 32 << 8 /* X_divider */;
00057     
00058     int rxbitrate = 1;
00059     LPC_I2S->I2STXBITRATE = 1;
00060     LPC_I2S->I2SRXBITRATE = rxbitrate;
00061     
00062 
00063     LPC_I2S->I2STXMODE  = (0 << 0) | (1 << 3);
00064     LPC_I2S->I2SRXMODE  = (0 << 0) | (1 << 3);
00065   
00066   
00067     // Start trasnmit    
00068     LPC_I2S->I2SDAO &= (~(1 << 3));
00069     LPC_I2S->I2SDAI &= (~(1 << 3));
00070 
00071     LPC_I2S->I2SDMA1 = (1 << 1) /* Enable transit */ | (0 << 16) /* Transmit FIFO level */;
00072 
00073 
00074     out->printf("I2S Setup complete\n");
00075         
00076     dmaconfig = new MODDMA_Config;
00077     dmaconfig
00078      ->channelNum    ( MODDMA::Channel_0 )
00079 //     ->srcMemAddr    ( (uint32_t) &buffer1 )
00080      ->dstMemAddr    ( 0 )
00081      //->transferSize  ( 2500 )
00082      ->transferType  ( MODDMA::m2p )
00083      ->transferWidth ( 1 )
00084      ->srcConn       ( 0 )
00085      ->dstConn       ( MODDMA::I2S_Channel_0 )
00086      ->dmaLLI        ( 0 )
00087      ->attach_tc     ( &TC1_callback )
00088     ;
00089 
00090     out->printf("DMA Setup complete\n");
00091 
00092 }
00093 
00094 
00095 void play(int16_t *buf,int16_t length) {
00096 
00097 
00098     moreToPlay = 1;
00099     
00100     if (nextToPlay - bufferStart + length >= BUFFER_SIZE) {
00101         nextToPlay = bufferStart;
00102     }  
00103     
00104     memcpy(nextToPlay,buf,length*sizeof(int16_t));
00105     
00106     transferSize=length;
00107     
00108     
00109     // Wait for end of playing previous packet
00110     while (playing) {};
00111     
00112     playing = 1;
00113     moreToPlay = 0;
00114 
00115     dmaconfig->srcMemAddr    ( (uint32_t) nextToPlay );
00116     dmaconfig->transferSize  ( length / 2);
00117     nextToPlay+=length*sizeof(int16_t);
00118     
00119 
00120     dma.Prepare(dmaconfig);
00121     
00122     
00123 }
00124 
00125 
00126 
00127 void TC1_callback(void) {
00128     
00129        // Get configuration pointer.
00130     MODDMA_Config *config = dma.getConfig();
00131     
00132     // Finish the DMA cycle by shutting down the channel.
00133     dma.Disable( (MODDMA::CHANNELS)config->channelNum() );
00134    
00135 
00136     // Clear DMA IRQ flags.
00137     if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq(); 
00138     
00139     playing = 0;
00140 
00141     if (!moreToPlay) {
00142         LPC_I2S->I2STXFIFO = 0x0;
00143         led3 = !led3;
00144     }
00145 }