# ssc_i2s.c File Reference

## Detailed Description

SSC I2S example driver.

This file defines a useful set of functions for the SSC I2S interface on AVR32 devices. The driver handles normal polled usage and direct memory access (PDC) usage.

- Compiler: IAR EWAVR32 and GNU GCC for AVR32
- Supported devices: All AVR32 devices with an SSC module can be used.
- AppNote:

Author:
  Atmel Corporation: http://www.atmel.com
  Support and FAQ: http://support.atmel.no/

Definition in file ssc_i2s.c.

`#include "compiler.h"`
`#include "ssc_i2s.h"`

Go to the source code of this file.

## Functions
static int | set_clock_divider (volatile avr32_ssc_t *ssc, unsigned int bit_rate, unsigned int pba_hz)
| Sets the clock divider (DIV-field in CMR-register).
void | ssc_i2s_disable_interrupts (volatile avr32_ssc_t *ssc, unsigned long int_mask)
| Disables the specified SSC interrupts.
void | ssc_i2s_enable_interrupts (volatile avr32_ssc_t *ssc, unsigned long int_mask)
| Enables the specified SSC interrupts.
unsigned long | ssc_i2s_get_status (volatile avr32_ssc_t *ssc)
| Returns the SSC status.
int | ssc_i2s_init (volatile avr32_ssc_t *ssc, unsigned int sample_frequency, unsigned int data_bit_res, unsigned int frame_bit_res, unsigned char mode, unsigned int pba_hz)
| Sets up registers and intializes SSC for use as I2S.
void | ssc_i2s_reset (volatile avr32_ssc_t *ssc)
| Resets the SSC module.
int | ssc_i2s_transfer (volatile avr32_ssc_t *ssc, unsigned int data)
| Transfers a single message of data.

## Function Documentation

static int set_clock_divider | ( | volatile avr32_ssc_t * | ssc,
|  | unsigned int | bit_rate,
|  | unsigned int | pba_hz |
| ) |  |  | `[static]`

Sets the clock divider (DIV-field in CMR-register).

This function sets the DIV field in the CMR-register to correct divider so that the divided clock runs at the specified rate.

Note:
  Clock divider is always rounded down, this means that the desired clock will be correct or faster than desired clock rate.

Parameters:

  | ssc | pointer to the correct volatile avr32_ssc_t struct
  | bit_rate | desired clock rate (bit rate)
  | pba_hz | PBA bus speed in Hz

Returns:
  Status or error code

Return values:

  | SSC_I2S_OK | on success
  | SSC_I2S_ERROR_ARGUMENT | on invalid arguments

Todo:
  check input values

Definition at line 67 of file ssc_i2s.c.

References SSC_I2S_OK.

Referenced by ssc_i2s_init().

    00070 {
    00073   ssc->cmr = ((pba_hz + bit_rate) / (2 * bit_rate)) << AVR32_SSC_CMR_DIV_OFFSET;
    00074
    00075   return SSC_I2S_OK;
    00076 }

void ssc_i2s_disable_interrupts | ( | volatile avr32_ssc_t * | ssc,
|  | unsigned long | int_mask |
| ) |  |  |

Disables the specified SSC interrupts.

Parameters:

  | ssc | Base address of the SSC instance.
  | int_mask | Bit-mask of SSC interrupts (`AVR32_SSC_IDR_x_MASK`).

Definition at line 309 of file ssc_i2s.c.

    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 }

void ssc_i2s_enable_interrupts | ( | volatile avr32_ssc_t * | ssc,
|  | unsigned long | int_mask |
| ) |  |  |

Enables the specified SSC interrupts.

Parameters:

  | ssc | Base address of the SSC instance.
  | int_mask | Bit-mask of SSC interrupts (`AVR32_SSC_IER_x_MASK`).

Definition at line 320 of file ssc_i2s.c.

    00321 {
    00322   ssc->ier = int_mask;
    00323 }

unsigned long ssc_i2s_get_status | ( | volatile avr32_ssc_t * | ssc | ) |

Returns the SSC status.

Parameters:

  | ssc | Base address of the SSC instance.

Returns:
  The SSC Status Register.

Definition at line 326 of file ssc_i2s.c.

Referenced by main().

    00327 {
    00328   return ssc->sr;
    00329 }

int ssc_i2s_init | ( | volatile avr32_ssc_t * | ssc,
|  | unsigned int | sample_frequency,
|  | unsigned int | data_bit_res,
|  | unsigned int | frame_bit_res,
|  | unsigned char | mode,
|  | unsigned int | pba_hz |
| ) |  |  |

Sets up registers and intializes SSC for use as I2S.

Parameters:

  | ssc | Pointer to the correct volatile avr32_ssc_t struct
  | sample_frequency | The sample frequency given in Hz
  | data_bit_res | Number of significant data bits in an I2S channel frame
  | frame_bit_res | Total number of bits in an I2S channel frame
  | mode | I2S-mode SSC_I2S_MODE_STEREO_OUT Two output channels. SSC_I2S_MODE_SLAVE_STEREO_OUT Two output channels controlled by the DAC. SSC_I2S_MODE_STEREO_OUT_MONO_IN Two output, one input channel. SSC_I2S_MODE_RIGHT_IN. Right channel in. Used because one SSC only can manage one input channel at a time.
  | pba_hz | The clock speed of the PBA bus in Hz.

Returns:
  Status

Return values:

  | SSC_I2S_OK | when no error occured.
  | SSC_I2S_ERROR_ARGUMENT | when invalid arguments are passed

Todo:
  check input values

Definition at line 86 of file ssc_i2s.c.

References set_clock_divider(), SSC_I2S_MODE_RIGHT_IN, SSC_I2S_MODE_SLAVE_STEREO_OUT, SSC_I2S_MODE_STEREO_OUT, SSC_I2S_MODE_STEREO_OUT_MONO_IN, SSC_I2S_OK, and ssc_i2s_reset().

Referenced by main().

    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 }

void ssc_i2s_reset | ( | volatile avr32_ssc_t * | ssc | ) |

Resets the SSC module.

Parameters:

  | ssc | pointer to the correct volatile avr32_ssc_t struct

Definition at line 79 of file ssc_i2s.c.

Referenced by ssc_i2s_init().

    00080 {
    00081   /* Software reset SSC */
    00082   ssc->cr = AVR32_SSC_CR_SWRST_MASK;
    00083 }

int ssc_i2s_transfer | ( | volatile avr32_ssc_t * | ssc,
|  | unsigned int | data |
| ) |  |  |

Transfers a single message of data.

Parameters:

  | ssc | Pointer to the correct volatile avr32_ssc_t struct
  | data | The data to transfer

Returns:
  Status

Return values:

  | SSC_I2S_OK | when no error occured.
  | SSC_I2S_TIMEOUT | when a timeout occured while trying to transfer

Definition at line 290 of file ssc_i2s.c.

References SSC_I2S_OK, SSC_I2S_TIMEOUT, and SSC_I2S_TIMEOUT_VALUE.

Referenced by main().

    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 }