Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

tlv320dac.c

Go to the documentation of this file.
00001 
00044 #include <cfg/os.h>
00045 #include <cfg/clock.h>
00046 #include <dev/board.h>
00047 #include <dev/irqreg.h>
00048 #include <dev/twif.h>
00049 
00050 #include <stdlib.h>
00051 #include <string.h>
00052 
00053 #include <sys/event.h>
00054 #include <sys/timer.h>
00055 
00056 #include "tlv320dac.h"
00057 
00058 #include <stdio.h> //DEBUG
00059 
00060 #ifndef TWI_SLA_DAC
00061 #define TWI_SLA_DAC     0x1A
00062 #endif
00063 
00064 /*
00065  * Initial volume.
00066  */
00067 #ifndef TLV320DAC_VOL
00068 #define TLV320DAC_VOL   0x18
00069 #endif
00070 
00071 /*
00072  * Number of PCM buffers.
00073  */
00074 #ifndef SAMPLE_BUFFERS
00075 #if defined (AT91SAM9260_EK)
00076 #define SAMPLE_BUFFERS  32
00077 #else
00078 #define SAMPLE_BUFFERS  3
00079 #endif
00080 #endif
00081 
00082 /*
00083  * Select I2S pins.
00084  */
00085 #if defined(AT91SAM7X_EK)   /* _EK */
00086 
00087 #define DACI2S_PIO_ID   PIOA_ID
00088 #define DACI2S_PINS_A   _BV(PA23_TD_A) | _BV(PA21_TF_A) | _BV(PA22_TK_A)
00089 #define DACI2S_PINS_B   0
00090 
00091 #elif defined (AT91SAM9260_EK) /* _EK */
00092 
00093 #define DACI2S_PIO_ID   PIOB_ID
00094 #define DACI2S_PINS_A   _BV(PB18_TD0_A) | _BV(PB17_TF0_A) | _BV(PB16_TK0_A)
00095 #define DACI2S_PINS_B   0
00096 
00097 #else                           /* _EK */
00098 #warning "Unknown target board"
00099 #endif                          /* _EK */
00100 
00101 /*
00102  * Determine PIO used by I2S.
00103  */
00104 #if DACI2S_PIO_ID == PIOA_ID    /* DACI2S_PIO_ID */
00105 #define DACI2S_PDR  PIOA_PDR
00106 #define DACI2S_ASR  PIOA_ASR
00107 #define DACI2S_BSR  PIOA_BSR
00108 #elif DACI2S_PIO_ID == PIOB_ID  /* DACI2S_PIO_ID */
00109 #define DACI2S_PDR  PIOB_PDR
00110 #define DACI2S_ASR  PIOB_ASR
00111 #define DACI2S_BSR  PIOB_BSR
00112 #endif                          /* DACI2S_PIO_ID */
00113 
00117 static HANDLE i2s_que;
00118 
00122 #define PCM_CHANS   2
00123 
00127 #define PCM_BITS    16
00128 
00132 typedef struct _PCM_BUFFER {
00133     u_short *wbf_dat;           
00134     int wbf_siz;                
00135     int wbf_len;                
00136 } PCM_BUFFER;
00137 
00138 /* PCM buffer queue. */
00139 static PCM_BUFFER pcm_bufq[SAMPLE_BUFFERS];
00140 /* PCM buffer read index. */
00141 static volatile u_int brd_idx;
00142 /* PCM buffer write index. */
00143 static u_int bwr_idx;
00144 
00150 static void I2sPdcFill(void)
00151 {
00152     if (brd_idx != bwr_idx) {
00153         if (inr(SSC_TNCR) == 0) {
00154             if (++brd_idx >= SAMPLE_BUFFERS) {
00155                 brd_idx = 0;
00156             }
00157             outr(SSC_TNPR, (u_int) pcm_bufq[brd_idx].wbf_dat);
00158             outr(SSC_TNCR, pcm_bufq[brd_idx].wbf_len);
00159         }
00160     }
00161 }
00162 
00168 static void I2sInterrupt(void *arg)
00169 {
00170     I2sPdcFill();
00171     NutEventPostFromIrq(&i2s_que);
00172 }
00173 
00183 u_char Tlv320DacReadReg(u_int reg)
00184 {
00185     return 0xFF;
00186 }
00187 
00196 void Tlv320DacWriteReg(u_int reg, u_int val)
00197 {
00198     u_char txdata[2];
00199 
00200     txdata[0] = (u_char)(reg << 1) | (u_char)(val >> 8);
00201     txdata[1] = (u_char)val;
00202     TwMasterTransact(TWI_SLA_DAC, txdata, 2, NULL, 0, 0);
00203 }
00204 
00212 static int Tlv320I2sEnable(u_int rate)
00213 {
00214     /* Enable SSC clock. */
00215     outr(PMC_PCER, _BV(SSC_ID));
00216 
00217     /* Select SSC peripheral functions. */
00218     outr(DACI2S_ASR, DACI2S_PINS_A);
00219     outr(DACI2S_BSR, DACI2S_PINS_B);
00220 
00221     /* Enable SSC peripheral pins. */
00222     outr(DACI2S_PDR, DACI2S_PINS_A | DACI2S_PINS_B);
00223 
00224     /* Configure 16-bit stereo I2S transmit format. */
00225     outr(SSC_CMR, 0);
00226     outr(SSC_TCMR,              /* Set transmit clock mode. */
00227         SSC_CKS_TK |            /* Use external clock at TK. */
00228         SSC_START_EDGE_RF |     /* Start transmission on any edge. */
00229         (1 << SSC_STTDLY_LSB)); /* Delay start by 1 cycle. */
00230     outr(SSC_TFMR,              /* Set transmit frame mode. */
00231         ((PCM_BITS - 1) << SSC_DATLEN_LSB) |   /* Transmit 16 bits. */
00232         SSC_MSBF);              /* Most significant bit first. */
00233 
00234     /* Enable transmitter in PDC mode. */
00235     outr(SSC_PTCR, PDC_TXTEN);
00236     outr(SSC_CR, SSC_TXEN);
00237 
00238     return 0;
00239 }
00240 
00246 static int Tlv320I2sDisable(void)
00247 {
00248     /* Disable all interrupts. */
00249     outr(SSC_IDR, 0xFFFFFFFF);
00250 
00251     /* Disable SSC interrupt. */
00252     NutIrqDisable(&sig_SSC);
00253 
00254     /* Disable SSC clock. */
00255     outr(PMC_PCDR, _BV(SSC_ID));
00256 
00257     /* Reset receiver and transmitter. */
00258     outr(SSC_CR, SSC_SWRST | SSC_RXDIS | SSC_TXDIS);
00259     outr(SSC_RCMR, 0);
00260     outr(SSC_RFMR, 0);
00261     outr(SSC_PTCR, PDC_RXTDIS);
00262     outr(SSC_PTCR, PDC_TXTDIS);
00263     outr(SSC_TNCR, 0);
00264     outr(SSC_TCR, 0);
00265 
00266     return 0;
00267 }
00268 
00276 static int Tlv320I2sInit(u_int rate)
00277 {
00278     /* Register SSC interrupt handler. */
00279     NutRegisterIrqHandler(&sig_SSC, I2sInterrupt, 0);
00280 
00281     Tlv320I2sDisable();
00282     Tlv320I2sEnable(rate);
00283 
00284     /* Enable SSC interrupt. */
00285     NutIrqEnable(&sig_SSC);
00286 
00287     return 0;
00288 }
00289 
00290 int Tlv320DacSetRate(u_int rate)
00291 {
00292     switch(rate) {
00293     case 8000:
00294 #ifdef AT91SAM7X_EK
00295         Tlv320DacWriteReg(DAC_SRATE, (3 << DAC_SRATE_SR_LSB));
00296 #else
00297         Tlv320DacWriteReg(DAC_SRATE, (3 << DAC_SRATE_SR_LSB) | DAC_SRATE_USB);
00298 #endif
00299         break;
00300     case 8021:      
00301         Tlv320DacWriteReg(DAC_SRATE, (11 << DAC_SRATE_SR_LSB) | DAC_SRATE_BOSR | DAC_SRATE_USB);
00302         break;
00303     case 44100:     
00304         Tlv320DacWriteReg(DAC_SRATE, (8 << DAC_SRATE_SR_LSB) | DAC_SRATE_BOSR | DAC_SRATE_USB);
00305         break;
00306     case 48000:     
00307         Tlv320DacWriteReg(DAC_SRATE, (0 << DAC_SRATE_SR_LSB) | DAC_SRATE_USB);
00308         break;
00309     case 88200:     
00310         Tlv320DacWriteReg(DAC_SRATE, (15 << DAC_SRATE_SR_LSB) | DAC_SRATE_BOSR | DAC_SRATE_USB);
00311         break;
00312     case 96000:     
00313         Tlv320DacWriteReg(DAC_SRATE, (7 << DAC_SRATE_SR_LSB) | DAC_SRATE_USB);
00314         break;
00315     default:        
00316         return -1;
00317     }
00318     return 0;
00319 }
00320 
00328 int Tlv320DacInit(u_int rate)
00329 {
00330     /* Initialize TWI. */
00331     TwInit(0);
00332 
00333     Tlv320DacWriteReg(DAC_RESET, 0);
00334     /* Power down line in. */
00335     Tlv320DacWriteReg(DAC_PWRDN, DAC_PWRDN_LINE);
00336     Tlv320DacWriteReg(DAC_PWRDN, 0);
00337     /* Set sampling rate. */
00338     if (Tlv320DacSetRate(rate)) {
00339         Tlv320DacWriteReg(DAC_RESET, 0);
00340         return -1;
00341     }
00342     Tlv320DacWriteReg(DAC_ANA_PATH, DAC_ANA_PATH_DAC | DAC_ANA_PATH_INSEL | DAC_ANA_PATH_MICB);
00343     Tlv320DacWriteReg(DAC_DIG_PATH, 0);
00344     /* I2S master. */
00345     Tlv320DacWriteReg(DAC_DAI_FMT, DAC_DAI_FMT_MS | DAC_DAI_FMT_FOR_I2S);
00346     Tlv320DacWriteReg(DAC_DI_ACT, DAC_DI_ACT_ACT);
00347 
00348     Tlv320DacWriteReg(DAC_LHP_VOL, DAC_LHP_VOL_LRS | (0x60 << DAC_LHP_VOL_LHV_LSB));
00349 
00350     /* Initialize I2S. */
00351     return Tlv320I2sInit(rate);
00352 }
00353 
00359 static int Tlv320DacStart(void)
00360 {
00361     NutIrqDisable(&sig_SSC);
00362     I2sPdcFill();
00363     outr(SSC_IER, SSC_ENDTX);
00364     outr(SSC_CR, SSC_TXEN);
00365     NutIrqEnable(&sig_SSC);
00366 
00367     return 0;
00368 }
00369 
00375 int Tlv320DacFlush(void)
00376 {
00377     int rc = 0;
00378 
00379     while (bwr_idx != brd_idx) {
00380         Tlv320DacStart();
00381         if ((rc = NutEventWait(&i2s_que, 500)) != 0) {
00382             break;
00383         }
00384     }
00385     return rc;
00386 }
00387 
00396 int Tlv320DacWrite(void *buf, int len)
00397 {
00398     u_int idx;
00399 
00400     /* Move to the next buffer to write to. */
00401     idx = bwr_idx + 1;
00402     if (idx >= SAMPLE_BUFFERS) {
00403         idx = 0;
00404     }
00405 
00406     /* If all buffers are filled, wait for an event posted by the
00407        interrupt routine. */
00408     while (idx == brd_idx) {
00409         if (NutEventWait(&i2s_que, 100)) {
00410             Tlv320DacStart();
00411         }
00412     }
00413 
00414     /*
00415      * Check, if the current buffer size is too small or not allocated.
00416      */
00417     if (pcm_bufq[idx].wbf_siz < len) {
00418         if (pcm_bufq[idx].wbf_siz) {
00419             free(pcm_bufq[idx].wbf_dat);
00420             pcm_bufq[idx].wbf_siz = 0;
00421         }
00422         pcm_bufq[idx].wbf_dat = malloc(len * 2);
00423         if (pcm_bufq[idx].wbf_dat == NULL) {
00424             /* Out of memory. */
00425             return -1;
00426         }
00427         pcm_bufq[idx].wbf_siz = len;
00428     }
00429 
00430     /*
00431      * At this point we got an available buffer with sufficient size.
00432      * Move the data to it, set the number of valid bytes and update
00433      * the write (producer) index.
00434      */
00435     memcpy(pcm_bufq[idx].wbf_dat, buf, len * 2);
00436     pcm_bufq[idx].wbf_len = len;
00437     bwr_idx = idx;
00438 
00439     return 0;
00440 }
00441 
00452 int Tlv320DacSetVolume(int left, int right)
00453 {
00454     /* Cut to limits. */
00455     if (left > DAC_MAX_VOLUME) {
00456         left = DAC_MAX_VOLUME;
00457     }
00458     else if (left < DAC_MIN_VOLUME) {
00459         left = DAC_MIN_VOLUME;
00460     }
00461     if (right > DAC_MAX_VOLUME) {
00462         right = DAC_MAX_VOLUME;
00463     }
00464     else if (right < DAC_MIN_VOLUME) {
00465         right = DAC_MIN_VOLUME;
00466     }
00467     Tlv320DacWriteReg(DAC_LHP_VOL, (u_int)(left + 121));
00468     Tlv320DacWriteReg(DAC_RHP_VOL, (u_int)(right + 121));
00469 
00470     return 0;
00471 }

Generated on Fri Feb 23 17:28:49 2007 for SAM Internet Radio by  doxygen 1.4.4