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

Committer:
csorbag
Date:
Mon Apr 16 08:32:38 2012 +0000
Revision:
1:12e8ee1b7ea2
Parent:
0:bf9e7b99dda5

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
csorbag 0:bf9e7b99dda5 1 #include "I2S.h"
csorbag 0:bf9e7b99dda5 2 #include "MODDMA.h"
csorbag 0:bf9e7b99dda5 3
csorbag 0:bf9e7b99dda5 4
csorbag 0:bf9e7b99dda5 5 volatile uint32_t counter=0;
csorbag 0:bf9e7b99dda5 6
csorbag 0:bf9e7b99dda5 7 DigitalOut led3(LED3);
csorbag 0:bf9e7b99dda5 8
csorbag 0:bf9e7b99dda5 9 //Serial *global_out;
csorbag 0:bf9e7b99dda5 10 MODDMA dma;
csorbag 0:bf9e7b99dda5 11 MODDMA_Config *dmaconfig;
csorbag 0:bf9e7b99dda5 12
csorbag 0:bf9e7b99dda5 13 void TC0_callback(void);
csorbag 0:bf9e7b99dda5 14 void TC1_callback(void);
csorbag 0:bf9e7b99dda5 15 void TC2_callback(void);
csorbag 0:bf9e7b99dda5 16
csorbag 0:bf9e7b99dda5 17 #define BUFFER_SIZE 2048
csorbag 0:bf9e7b99dda5 18
csorbag 0:bf9e7b99dda5 19 int16_t buffer[BUFFER_SIZE];
csorbag 0:bf9e7b99dda5 20
csorbag 0:bf9e7b99dda5 21 int16_t transferSize;
csorbag 0:bf9e7b99dda5 22
csorbag 0:bf9e7b99dda5 23 int16_t *bufferStart, *nextToPlay;
csorbag 0:bf9e7b99dda5 24 volatile int16_t playing = 0;
csorbag 0:bf9e7b99dda5 25
csorbag 0:bf9e7b99dda5 26 volatile int16_t moreToPlay=0;
csorbag 0:bf9e7b99dda5 27
csorbag 0:bf9e7b99dda5 28 void setup(Serial *out) {
csorbag 0:bf9e7b99dda5 29
csorbag 0:bf9e7b99dda5 30 global_out = out;
csorbag 0:bf9e7b99dda5 31
csorbag 0:bf9e7b99dda5 32 bufferStart = nextToPlay = (int16_t *)buffer;
csorbag 0:bf9e7b99dda5 33
csorbag 0:bf9e7b99dda5 34 LPC_SC->PCONP |= 1 <<27; // Enable I2S
csorbag 0:bf9e7b99dda5 35 LPC_SC->PCLKSEL1 |= 1 << 22; // Set Clock to CCLK
csorbag 0:bf9e7b99dda5 36 // Reset i2s
csorbag 0:bf9e7b99dda5 37 LPC_I2S->I2SDAO = (1 << 4);
csorbag 0:bf9e7b99dda5 38 LPC_I2S->I2SDAO = 0;
csorbag 0:bf9e7b99dda5 39
csorbag 0:bf9e7b99dda5 40
csorbag 0:bf9e7b99dda5 41
csorbag 0:bf9e7b99dda5 42 LPC_I2S->I2SDAO = 1 /* Number of bytes 16bit */ | 0xF << 6 /* Word select half perion - 1 */;// | 1 << 3 /* Stop bit */;
csorbag 0:bf9e7b99dda5 43 LPC_I2S->I2SDAI = 1 /* Number of bytes 16bit */ | 0xF << 6 /* Word select half perion - 1 */;// | 1 << 3 /* Stop bit */;
csorbag 0:bf9e7b99dda5 44
csorbag 0:bf9e7b99dda5 45
csorbag 0:bf9e7b99dda5 46 LPC_PINCON->PINSEL0 |= 01 << 14 /* I2STX_CLK */ | 01 << 16 /* I2STX_WS */ | 01 << 18 /* I2STX_SDA */;
csorbag 0:bf9e7b99dda5 47 LPC_PINCON->PINSEL0 |= 01 << 8 /* I2SRX_CLK */ | 01 << 10 /* I2SRX_WS */ | 01 << 12 /* I2SRX_SDA */;
csorbag 0:bf9e7b99dda5 48
csorbag 0:bf9e7b99dda5 49 // Set all to neither pull-up, nor pull-down
csorbag 0:bf9e7b99dda5 50 LPC_PINCON->PINMODE0 |= 2 << 14 /* I2STX_CLK */ | 2 << 16 /* I2STX_WS */ | 2 << 18 /* I2STX_SDA */;
csorbag 0:bf9e7b99dda5 51 LPC_PINCON->PINMODE0 |= 2 << 8 /* I2SRX_CLK */ | 2 << 10 /* I2SRX_WS */ | 2 << 12 /* I2SRX_SDA */;
csorbag 0:bf9e7b99dda5 52
csorbag 0:bf9e7b99dda5 53
csorbag 0:bf9e7b99dda5 54 // Cirrus Logic CS4344 specific frequency settings
csorbag 0:bf9e7b99dda5 55 LPC_I2S->I2STXRATE = 125 /* Y_divider */ | 4 << 8 /* X_divider */;
csorbag 0:bf9e7b99dda5 56 LPC_I2S->I2SRXRATE = 125 /* Y_divider */ | 32 << 8 /* X_divider */;
csorbag 0:bf9e7b99dda5 57
csorbag 0:bf9e7b99dda5 58 int rxbitrate = 1;
csorbag 0:bf9e7b99dda5 59 LPC_I2S->I2STXBITRATE = 1;
csorbag 0:bf9e7b99dda5 60 LPC_I2S->I2SRXBITRATE = rxbitrate;
csorbag 0:bf9e7b99dda5 61
csorbag 0:bf9e7b99dda5 62
csorbag 0:bf9e7b99dda5 63 LPC_I2S->I2STXMODE = (0 << 0) | (1 << 3);
csorbag 0:bf9e7b99dda5 64 LPC_I2S->I2SRXMODE = (0 << 0) | (1 << 3);
csorbag 0:bf9e7b99dda5 65
csorbag 0:bf9e7b99dda5 66
csorbag 0:bf9e7b99dda5 67 // Start trasnmit
csorbag 0:bf9e7b99dda5 68 LPC_I2S->I2SDAO &= (~(1 << 3));
csorbag 0:bf9e7b99dda5 69 LPC_I2S->I2SDAI &= (~(1 << 3));
csorbag 0:bf9e7b99dda5 70
csorbag 0:bf9e7b99dda5 71 LPC_I2S->I2SDMA1 = (1 << 1) /* Enable transit */ | (0 << 16) /* Transmit FIFO level */;
csorbag 0:bf9e7b99dda5 72
csorbag 0:bf9e7b99dda5 73
csorbag 0:bf9e7b99dda5 74 out->printf("I2S Setup complete\n");
csorbag 0:bf9e7b99dda5 75
csorbag 0:bf9e7b99dda5 76 dmaconfig = new MODDMA_Config;
csorbag 0:bf9e7b99dda5 77 dmaconfig
csorbag 0:bf9e7b99dda5 78 ->channelNum ( MODDMA::Channel_0 )
csorbag 0:bf9e7b99dda5 79 // ->srcMemAddr ( (uint32_t) &buffer1 )
csorbag 0:bf9e7b99dda5 80 ->dstMemAddr ( 0 )
csorbag 0:bf9e7b99dda5 81 //->transferSize ( 2500 )
csorbag 0:bf9e7b99dda5 82 ->transferType ( MODDMA::m2p )
csorbag 0:bf9e7b99dda5 83 ->transferWidth ( 1 )
csorbag 0:bf9e7b99dda5 84 ->srcConn ( 0 )
csorbag 0:bf9e7b99dda5 85 ->dstConn ( MODDMA::I2S_Channel_0 )
csorbag 0:bf9e7b99dda5 86 ->dmaLLI ( 0 )
csorbag 0:bf9e7b99dda5 87 ->attach_tc ( &TC1_callback )
csorbag 0:bf9e7b99dda5 88 ;
csorbag 0:bf9e7b99dda5 89
csorbag 0:bf9e7b99dda5 90 out->printf("DMA Setup complete\n");
csorbag 0:bf9e7b99dda5 91
csorbag 0:bf9e7b99dda5 92 }
csorbag 0:bf9e7b99dda5 93
csorbag 0:bf9e7b99dda5 94
csorbag 0:bf9e7b99dda5 95 void play(int16_t *buf,int16_t length) {
csorbag 0:bf9e7b99dda5 96
csorbag 0:bf9e7b99dda5 97
csorbag 0:bf9e7b99dda5 98 moreToPlay = 1;
csorbag 0:bf9e7b99dda5 99
csorbag 0:bf9e7b99dda5 100 if (nextToPlay - bufferStart + length >= BUFFER_SIZE) {
csorbag 0:bf9e7b99dda5 101 nextToPlay = bufferStart;
csorbag 0:bf9e7b99dda5 102 }
csorbag 0:bf9e7b99dda5 103
csorbag 0:bf9e7b99dda5 104 memcpy(nextToPlay,buf,length*sizeof(int16_t));
csorbag 0:bf9e7b99dda5 105
csorbag 0:bf9e7b99dda5 106 transferSize=length;
csorbag 0:bf9e7b99dda5 107
csorbag 0:bf9e7b99dda5 108
csorbag 0:bf9e7b99dda5 109 // Wait for end of playing previous packet
csorbag 0:bf9e7b99dda5 110 while (playing) {};
csorbag 0:bf9e7b99dda5 111
csorbag 0:bf9e7b99dda5 112 playing = 1;
csorbag 0:bf9e7b99dda5 113 moreToPlay = 0;
csorbag 0:bf9e7b99dda5 114
csorbag 0:bf9e7b99dda5 115 dmaconfig->srcMemAddr ( (uint32_t) nextToPlay );
csorbag 0:bf9e7b99dda5 116 dmaconfig->transferSize ( length / 2);
csorbag 0:bf9e7b99dda5 117 nextToPlay+=length*sizeof(int16_t);
csorbag 0:bf9e7b99dda5 118
csorbag 0:bf9e7b99dda5 119
csorbag 0:bf9e7b99dda5 120 dma.Prepare(dmaconfig);
csorbag 0:bf9e7b99dda5 121
csorbag 0:bf9e7b99dda5 122
csorbag 0:bf9e7b99dda5 123 }
csorbag 0:bf9e7b99dda5 124
csorbag 0:bf9e7b99dda5 125
csorbag 0:bf9e7b99dda5 126
csorbag 0:bf9e7b99dda5 127 void TC1_callback(void) {
csorbag 0:bf9e7b99dda5 128
csorbag 0:bf9e7b99dda5 129 // Get configuration pointer.
csorbag 0:bf9e7b99dda5 130 MODDMA_Config *config = dma.getConfig();
csorbag 0:bf9e7b99dda5 131
csorbag 0:bf9e7b99dda5 132 // Finish the DMA cycle by shutting down the channel.
csorbag 0:bf9e7b99dda5 133 dma.Disable( (MODDMA::CHANNELS)config->channelNum() );
csorbag 0:bf9e7b99dda5 134
csorbag 0:bf9e7b99dda5 135
csorbag 0:bf9e7b99dda5 136 // Clear DMA IRQ flags.
csorbag 0:bf9e7b99dda5 137 if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq();
csorbag 0:bf9e7b99dda5 138
csorbag 0:bf9e7b99dda5 139 playing = 0;
csorbag 0:bf9e7b99dda5 140
csorbag 0:bf9e7b99dda5 141 if (!moreToPlay) {
csorbag 0:bf9e7b99dda5 142 LPC_I2S->I2STXFIFO = 0x0;
csorbag 0:bf9e7b99dda5 143 led3 = !led3;
csorbag 0:bf9e7b99dda5 144 }
csorbag 0:bf9e7b99dda5 145 }