- Main Page
- Related Pages
- Files

# ssc_i2s.c

Go to the documentation of this file.

    00001 /*This file has been prepared for Doxygen automatic documentation generation.*/
    00019 /* Copyright (C) 2006-2008, Atmel Corporation All rights reserved.
    00020  *
    00021  * Redistribution and use in source and binary forms, with or without
    00022  * modification, are permitted provided that the following conditions are met:
    00023  *
    00024  * 1. Redistributions of source code must retain the above copyright notice,
    00025  * this list of conditions and the following disclaimer.
    00026  *
    00027  * 2. Redistributions in binary form must reproduce the above copyright notice,
    00028  * this list of conditions and the following disclaimer in the documentation
    00029  * and/or other materials provided with the distribution.
    00030  *
    00031  * 3. The name of ATMEL may not be used to endorse or promote products derived
    00032  * from this software without specific prior written permission.
    00033  *
    00034  * THIS SOFTWARE IS PROVIDED BY ATMEL ``AS IS'' AND ANY EXPRESS OR IMPLIED
    00035  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    00036  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND
    00037  * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT,
    00038  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    00039  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    00040  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    00041  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    00042  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    00043  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    00044  */
    00045
    00046
    00047 #include "compiler.h"
    00048 #include "ssc_i2s.h"
    00049
    00050
    00067 static int set_clock_divider(volatile avr32_ssc_t *ssc,
    00068                              unsigned int bit_rate,
    00069                              unsigned int pba_hz)
    00070 {
    00073   ssc->cmr = ((pba_hz + bit_rate) / (2 * bit_rate)) << AVR32_SSC_CMR_DIV_OFFSET;
    00074
    00075   return SSC_I2S_OK;
    00076 }
    00077
    00078
    00079 void ssc_i2s_reset(volatile avr32_ssc_t *ssc)
    00080 {
    00081   /* Software reset SSC */
    00082   ssc->cr = AVR32_SSC_CR_SWRST_MASK;
    00083 }
    00084
    00085
    00086 int ssc_i2s_init(volatile avr32_ssc_t *ssc,
    00087                  unsigned int sample_frequency,
    00088                  unsigned int data_bit_res,
    00089                  unsigned int frame_bit_res,
    00090                  unsigned char mode,
    00091                  unsigned int pba_hz)
    00092 {
    00095   /* Reset */
    00096   ssc_i2s_reset(ssc);
    00097
    00098   if (mode == SSC_I2S_MODE_SLAVE_STEREO_OUT)
    00099   {
    00100     ssc->cmr = AVR32_SSC_CMR_DIV_NOT_ACTIVE << AVR32_SSC_CMR_DIV_OFFSET;
    00101
    00102     ssc->tcmr = AVR32_SSC_TCMR_CKS_TK_PIN               << AVR32_SSC_TCMR_CKS_OFFSET    |
    00103                 AVR32_SSC_TCMR_CKO_INPUT_ONLY           << AVR32_SSC_TCMR_CKO_OFFSET    |
    00104                 0                                       << AVR32_SSC_TCMR_CKI_OFFSET    |
    00105                 AVR32_SSC_TCMR_CKG_NONE                 << AVR32_SSC_TCMR_CKG_OFFSET    |
    00106                 AVR32_SSC_TCMR_START_DETECT_ANY_EDGE_TF << AVR32_SSC_TCMR_START_OFFSET  |
    00107                 1                                       << AVR32_SSC_TCMR_STTDLY_OFFSET |
    00108                 0                                       << AVR32_SSC_TCMR_PERIOD_OFFSET;
    00109 #ifdef AVR32_SSC_220_H_INCLUDED
    00110     ssc->tfmr = (data_bit_res - 1)             << AVR32_SSC_TFMR_DATLEN_OFFSET  |
    00111                 0                              << AVR32_SSC_TFMR_DATDEF_OFFSET  |
    00112                 1                              << AVR32_SSC_TFMR_MSBF_OFFSET    |
    00113                 (1 - 1)                        << AVR32_SSC_TFMR_DATNB_OFFSET   |
    00114                 0                              << AVR32_SSC_TFMR_FSLEN_OFFSET   |
    00115                 AVR32_SSC_TFMR_FSOS_INPUT_ONLY << AVR32_SSC_TFMR_FSOS_OFFSET    |
    00116                 0                              << AVR32_SSC_TFMR_FSDEN_OFFSET   |
    00117                 0                              << AVR32_SSC_TFMR_FSEDGE_OFFSET;
    00118 #else
    00119     ssc->tfmr = (data_bit_res - 1)             << AVR32_SSC_TFMR_DATLEN_OFFSET  |
    00120                 0                              << AVR32_SSC_TFMR_DATDEF_OFFSET  |
    00121                 1                              << AVR32_SSC_TFMR_MSBF_OFFSET    |
    00122                 (1 - 1)                        << AVR32_SSC_TFMR_DATNB_OFFSET   |
    00123                 0                              << AVR32_SSC_TFMR_FSLEN_OFFSET   |
    00124                 AVR32_SSC_TFMR_FSOS_INPUT_ONLY << AVR32_SSC_TFMR_FSOS_OFFSET    |
    00125                 0                              << AVR32_SSC_TFMR_FSDEN_OFFSET   |
    00126                 0                              << AVR32_SSC_TFMR_FSEDGE_OFFSET  |
    00127                 0                              << AVR32_SSC_TFMR_FSLENHI_OFFSET;
    00128 #endif
    00129     ssc->cr = AVR32_SSC_CR_TXEN_MASK;
    00130   }
    00131   else
    00132   {
    00133     unsigned long txen_mask = 0x00000000,
    00134                   rxen_mask = 0x00000000;
    00135
    00136     /* Set clock divider */
    00137     set_clock_divider(ssc, 2 * sample_frequency * frame_bit_res, pba_hz);
    00138
    00139     /* SSC can only receive one channel of audio input.  In order
    00140      * to use two inputs, two SSC's must be used. The first (master)
    00141      * deals with both output channels and the left input, and should
    00142      * be set to mode=I2S_STEREO_OUT_MONO_IN, and the second to
    00143      * mode=I2S_RIGHT_IN. The second SSC should be connected to the
    00144      * first SSC's in the following way:
    00145      * master-ssc:TF -> slave-ssc:RF,
    00146      * master-ssc:TK -> slave-ssc:RK
    00147      */
    00148
    00149     /* If only slave I2S SSC, do not set transmit registers */
    00150     if (mode != SSC_I2S_MODE_RIGHT_IN)
    00151     {
    00152
    00153       /* Set transmit clock mode:
    00154        *   CKS - use divided clock,
    00155        *   CKO - transmit continous clock on TK
    00156        *   CKI - shift data on falling clock
    00157        *   CKG - transmit continous clock on TK
    00158        *   START - on falling TF(WS) edge
    00159        *   STTDLY - TF toggles before last bit of last word, not before
    00160        *            first bit on next word. Therefore: delay one cycle.
    00161        *   PERIOD - generate framesync for each sample (FS is generated
    00162        *            every (PERIOD + 1) * 2 clock)
    00163        */
    00164       ssc->tcmr = AVR32_SSC_TCMR_CKS_DIV_CLOCK              << AVR32_SSC_TCMR_CKS_OFFSET    |
    00165                   AVR32_SSC_TCMR_CKO_CONTINOUS_CLOCK_OUTPUT << AVR32_SSC_TCMR_CKO_OFFSET    |
    00166                   0                                         << AVR32_SSC_TCMR_CKI_OFFSET    |
    00167                   AVR32_SSC_TCMR_CKG_NONE                   << AVR32_SSC_TCMR_CKG_OFFSET    |
    00168                   AVR32_SSC_TCMR_START_DETECT_ANY_EDGE_TF   << AVR32_SSC_TCMR_START_OFFSET  |
    00169                   1                                         << AVR32_SSC_TCMR_STTDLY_OFFSET |
    00170                   (frame_bit_res - 1)                       << AVR32_SSC_TCMR_PERIOD_OFFSET;
    00171
    00172       /* Set transmit frame mode:
    00173        *  DATLEN - one sample for one channel
    00174        *  DATDEF - Default to zero,
    00175        *  MSBF - transmit msb first,
    00176        *  DATNB - Transfer two words (left+right),
    00177        *  FSLEN - Frame sync is entire left channel
    00178        *  FSOS - transmit negative pulse on WS (start sync on left channel)
    00179        *  FSDEN - Do not use transmit frame sync data
    00180        *  FSEDGE - detect frame sync positive edge
    00181        */
    00182 #ifdef AVR32_SSC_220_H_INCLUDED
    00183       ssc->tfmr = (data_bit_res - 1)                                 << AVR32_SSC_TFMR_DATLEN_OFFSET                              |
    00184                   0                                                  << AVR32_SSC_TFMR_DATDEF_OFFSET                              |
    00185                   1                                                  << AVR32_SSC_TFMR_MSBF_OFFSET                                |
    00186                   (1 - 1)                                            << AVR32_SSC_TFMR_DATNB_OFFSET                               |
    00187                   (((frame_bit_res - 1)                              << AVR32_SSC_TFMR_FSLEN_OFFSET) & AVR32_SSC_TFMR_FSLEN_MASK) |
    00188                   AVR32_SSC_TFMR_FSOS_NEG_PULSE                      << AVR32_SSC_TFMR_FSOS_OFFSET                                |
    00189                   0                                                  << AVR32_SSC_TFMR_FSDEN_OFFSET                               |
    00190                   1                                                  << AVR32_SSC_TFMR_FSEDGE_OFFSET;
    00191 #else
    00192       ssc->tfmr = (data_bit_res - 1)                                 << AVR32_SSC_TFMR_DATLEN_OFFSET                              |
    00193                   0                                                  << AVR32_SSC_TFMR_DATDEF_OFFSET                              |
    00194                   1                                                  << AVR32_SSC_TFMR_MSBF_OFFSET                                |
    00195                   (1 - 1)                                            << AVR32_SSC_TFMR_DATNB_OFFSET                               |
    00196                   (((frame_bit_res - 1)                              << AVR32_SSC_TFMR_FSLEN_OFFSET) & AVR32_SSC_TFMR_FSLEN_MASK) |
    00197                   AVR32_SSC_TFMR_FSOS_NEG_PULSE                      << AVR32_SSC_TFMR_FSOS_OFFSET                                |
    00198                   0                                                  << AVR32_SSC_TFMR_FSDEN_OFFSET                               |
    00199                   1                                                  << AVR32_SSC_TFMR_FSEDGE_OFFSET                              |
    00200                   ((frame_bit_res - 1) >> AVR32_SSC_TFMR_FSLEN_SIZE) << AVR32_SSC_TFMR_FSLENHI_OFFSET;
    00201 #endif
    00202       txen_mask = AVR32_SSC_CR_TXEN_MASK;
    00203     }
    00204
    00205     /* If receiving data, set receiving clock register */
    00206     if (mode != SSC_I2S_MODE_STEREO_OUT)
    00207     {
    00208       if ( (mode == SSC_I2S_MODE_STEREO_OUT_MONO_IN) || (mode == SSC_I2S_MODE_RIGHT_IN) )
    00209       {
    00210           /* Set receive clock mode:
    00211            *  CKS - left ch uses TK, right (slave) uses RK pin
    00212            *  CKO - No clock output,
    00213            *  CKI - shift data on rising edge,
    00214            *  CKG - No clock output,
    00215            *  START - left ch starts when transmit starts, right starts on
    00216            *          word-select (RF) rising edge
    00217            *  STTDLY - RF toggles before last bit of last word, not before
    00218            *           first bit on next word. Therefore, delay one cycle.
    00219            *  PERIOD - No FS generation
    00220            */
    00221           ssc->rcmr =
    00222             (( mode == SSC_I2S_MODE_RIGHT_IN ? AVR32_SSC_RCMR_CKS_RK_PIN : AVR32_SSC_RCMR_CKS_TK_CLOCK )
    00223                                            << AVR32_SSC_RCMR_CKS_OFFSET)|
    00224             (AVR32_SSC_RCMR_CKO_INPUT_ONLY << AVR32_SSC_RCMR_CKO_OFFSET)|
    00225             (1                             << AVR32_SSC_RCMR_CKI_OFFSET)|
    00226             (AVR32_SSC_RCMR_CKG_NONE       << AVR32_SSC_RCMR_CKG_OFFSET)|
    00227             (( mode == SSC_I2S_MODE_RIGHT_IN ? AVR32_SSC_RCMR_START_DETECT_RISING_RF : AVR32_SSC_RCMR_START_TRANSMIT_START )
    00228                                            << AVR32_SSC_RCMR_START_OFFSET)|
    00229             (1                             << AVR32_SSC_RCMR_STTDLY_OFFSET)|
    00230             (0                             << AVR32_SSC_RCMR_PERIOD_OFFSET);
    00231
    00232           /* Set receive frame mode:
    00233            *  DATLEN - bits per sample
    00234            *  LOOP - no loopback
    00235            *  MSBF - msb first
    00236            *  DATNB - transmit one per sync
    00237            *  FSLEN - no generate framesync
    00238            *  FSOS - do not generate framesync
    00239            *  FSEDGE - detect frame sync positive edge
    00240            */
    00241           ssc->rfmr =
    00242             ((data_bit_res-1)               << AVR32_SSC_RFMR_DATLEN_OFFSET)|
    00243             (0                              << AVR32_SSC_RFMR_LOOP_OFFSET)|
    00244             (1                              << AVR32_SSC_RFMR_MSBF_OFFSET)|
    00245             (0                              << AVR32_SSC_RFMR_DATNB_OFFSET)|
    00246             (0                              << AVR32_SSC_RFMR_FSLEN_OFFSET)|
    00247             (AVR32_SSC_RFMR_FSOS_INPUT_ONLY << AVR32_SSC_RFMR_FSOS_OFFSET)|
    00248             (0                              << AVR32_SSC_RFMR_FSEDGE_OFFSET);
    00249
    00250             rxen_mask = AVR32_SSC_CR_RXEN_MASK;
    00251         }
    00252         else
    00253         {
    00254             ssc->rcmr = AVR32_SSC_RCMR_CKS_TK_CLOCK               << AVR32_SSC_RCMR_CKS_OFFSET    |
    00255                         AVR32_SSC_RCMR_CKO_CONTINOUS_CLOCK_OUTPUT << AVR32_SSC_RCMR_CKO_OFFSET    |
    00256                         0                                         << AVR32_SSC_RCMR_CKI_OFFSET    |
    00257                         AVR32_SSC_RCMR_CKG_NONE                   << AVR32_SSC_RCMR_CKG_OFFSET    |
    00258                         AVR32_SSC_RCMR_START_DETECT_ANY_EDGE_RF   << AVR32_SSC_RCMR_START_OFFSET  |
    00259                         1                                         << AVR32_SSC_RCMR_STTDLY_OFFSET |
    00260                         (frame_bit_res - 1)                       << AVR32_SSC_RCMR_PERIOD_OFFSET;
    00261
    00262 #ifdef AVR32_SSC_220_H_INCLUDED
    00263             ssc->rfmr = (data_bit_res - 1)                                 << AVR32_SSC_RFMR_DATLEN_OFFSET                              |
    00264                         1                                                  << AVR32_SSC_RFMR_MSBF_OFFSET                                |
    00265                         (1 - 1)                                            << AVR32_SSC_RFMR_DATNB_OFFSET                               |
    00266                         (((frame_bit_res - 1)                              << AVR32_SSC_RFMR_FSLEN_OFFSET) & AVR32_SSC_TFMR_FSLEN_MASK) |
    00267                         AVR32_SSC_RFMR_FSOS_NEG_PULSE                      << AVR32_SSC_RFMR_FSOS_OFFSET                                |
    00268                         1                                                  << AVR32_SSC_RFMR_FSEDGE_OFFSET;
    00269 #else
    00270             ssc->rfmr = (data_bit_res - 1)                                 << AVR32_SSC_RFMR_DATLEN_OFFSET                              |
    00271                         1                                                  << AVR32_SSC_RFMR_MSBF_OFFSET                                |
    00272                         (1 - 1)                                            << AVR32_SSC_RFMR_DATNB_OFFSET                               |
    00273                         (((frame_bit_res - 1)                              << AVR32_SSC_RFMR_FSLEN_OFFSET) & AVR32_SSC_TFMR_FSLEN_MASK) |
    00274                         AVR32_SSC_RFMR_FSOS_NEG_PULSE                      << AVR32_SSC_RFMR_FSOS_OFFSET                                |
    00275                         1                                                  << AVR32_SSC_RFMR_FSEDGE_OFFSET                              |
    00276                         ((frame_bit_res - 1) >> AVR32_SSC_RFMR_FSLEN_SIZE) << AVR32_SSC_RFMR_FSLENHI_OFFSET;
    00277 #endif
    00278             rxen_mask = AVR32_SSC_CR_RXEN_MASK;
    00279         }
    00280
    00281       }
    00282     /* Enable transceiver and/or receiver */
    00283     ssc->cr = txen_mask | rxen_mask;
    00284   }
    00285
    00286   return SSC_I2S_OK;
    00287 }
    00288
    00289
    00290 int ssc_i2s_transfer(volatile avr32_ssc_t *ssc, unsigned int data)
    00291 {
    00292   unsigned int timeout = SSC_I2S_TIMEOUT_VALUE;
    00293
    00294   while( ( ssc->sr & (1<<AVR32_SSC_SR_TXRDY_OFFSET) ) == 0 &&
    00295       timeout > 0 ) {
    00296     timeout--;
    00297   }
    00298
    00299   if( timeout <= 0 ) {
    00300     return SSC_I2S_TIMEOUT;
    00301   }
    00302
    00303   ssc->thr = data;
    00304
    00305   return SSC_I2S_OK;
    00306 }
    00307
    00308
    00309 void ssc_i2s_disable_interrupts(volatile avr32_ssc_t *ssc, unsigned long int_mask)
    00310 {
    00311   Bool global_interrupt_enabled = Is_global_interrupt_enabled();
    00312
    00313   if (global_interrupt_enabled) Disable_global_interrupt();
    00314   ssc->idr = int_mask;
    00315   ssc->sr;
    00316   if (global_interrupt_enabled) Enable_global_interrupt();
    00317 }
    00318
    00319
    00320 void ssc_i2s_enable_interrupts(volatile avr32_ssc_t *ssc, unsigned long int_mask)
    00321 {
    00322   ssc->ier = int_mask;
    00323 }
    00324
    00325
    00326 unsigned long ssc_i2s_get_status(volatile avr32_ssc_t *ssc)
    00327 {
    00328   return ssc->sr;
    00329 }