SAMV71 Xplained Ultra Software Package 1.5

main.c

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------- */
00002 /*                  Atmel Microcontroller Software Support                      */
00003 /*                       SAM Software Package License                           */
00004 /* ---------------------------------------------------------------------------- */
00005 /* Copyright (c) 2015, Atmel Corporation                                        */
00006 /*                                                                              */
00007 /* All rights reserved.                                                         */
00008 /*                                                                              */
00009 /* Redistribution and use in source and binary forms, with or without           */
00010 /* modification, are permitted provided that the following condition is met:    */
00011 /*                                                                              */
00012 /* - Redistributions of source code must retain the above copyright notice,     */
00013 /* this list of conditions and the disclaimer below.                            */
00014 /*                                                                              */
00015 /* Atmel's name may not be used to endorse or promote products derived from     */
00016 /* this software without specific prior written permission.                     */
00017 /*                                                                              */
00018 /* DISCLAIMER:  THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR   */
00019 /* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */
00020 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE   */
00021 /* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,      */
00022 /* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
00023 /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,  */
00024 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    */
00025 /* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING         */
00026 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */
00027 /* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                           */
00028 /* ---------------------------------------------------------------------------- */
00029 
00030 /**
00031  * \page ssc_dma_audio SSC with DMA Audio Example
00032  *
00033  * \section Purpose
00034  *
00035  * This example uses the Synchronous Serial Controller (SSC) of an SAMV7x
00036  * microcontroller to output an audio stream through the on-board WM8904 CODEC.
00037  *
00038  * \section Requirements
00039  *
00040  * This package can be used with SAM V71 Xplained Ultra board with external
00041  * codec WM8904 components.
00042  *
00043  * \section Description
00044  * This program plays a WAV file from PC via Line-In. The audio stream is
00045  * sent through the SSC interface connected to the on-board WM8904, enabling
00046  * the sound to be audible using a pair of headphones.
00047  *
00048  * \section Usage
00049  *  -# Build the program and download it inside the SAM V71 Xplained Ultra board.
00050  *     Please refer to the Getting Started with SAM V71 Microcontrollers.pdf
00051  * -# On the computer, open and configure a terminal application
00052  *    (e.g. HyperTerminal on Microsoft Windows) with these settings:
00053  *   - 115200 baud rate
00054  *   - 8 bits of data
00055  *   - No parity
00056  *   - 1 stop bit
00057  *   - No flow control
00058  * -# Start the application.
00059  * -# In the terminal window, the following text should appear:
00060  *    \code
00061  *     -- SSC DMA Audio Example xxx --
00062  *      -- SAMxxxxx-xx
00063  *     -- Compiled: xxx xx xxxx xx:xx:xx --
00064  *    \endcode
00065  * The user can then choose any of the available options to perform the
00066  * described action.
00067  *
00068  * \section References
00069  * - ssc_dma_audio/main.c
00070  * - ssc.c
00071  * - twi.c
00072  * - twid.c
00073  * - xdmac.c
00074  * - xdmad.c
00075  */
00076 
00077 /**
00078  * \file
00079  *
00080  * This file contains all the specific code for the SSC audio example.
00081  */
00082 
00083 
00084 /*----------------------------------------------------------------------------
00085  *        Headers
00086  *----------------------------------------------------------------------------*/
00087 
00088 #include "board.h"
00089 
00090 /*----------------------------------------------------------------------------
00091  *        Local definitions
00092  *----------------------------------------------------------------------------*/
00093 #define I2S_SLAVE_TX_SETTING     ((SSC_TCMR_CKS_TK) |     \
00094             (SSC_TCMR_CKO_NONE) |                        \
00095             (SSC_TCMR_START_TF_EDGE) |                   \
00096             (SSC_TCMR_STTDLY(1)) |                       \
00097             (SSC_TCMR_PERIOD(0)))
00098 
00099 #define I2S_SLAVE_TX_FRM_SETTING ((SSC_TFMR_DATLEN(BITS_BY_SLOT - 1)) | \
00100             (SSC_TFMR_MSBF) |                                          \
00101             (SSC_TFMR_DATNB(SLOT_BY_FRAME - 1)) |                      \
00102             (SSC_TFMR_FSOS_NONE))
00103 
00104 
00105 #define I2S_SLAVE_RX_SETTING     ((SSC_RCMR_CKS_TK) |   \
00106             (SSC_RCMR_CKO_NONE) |                      \
00107             (SSC_RCMR_CKI) |                           \
00108             (SSC_RCMR_START_RF_EDGE) |                 \
00109             (SSC_RCMR_STTDLY(1)) |                     \
00110             (SSC_RCMR_PERIOD(0)))
00111 
00112 #define I2S_SLAVE_RX_FRM_SETTING ((SSC_RFMR_DATLEN(BITS_BY_SLOT - 1)) | \
00113             (SSC_RFMR_MSBF) |                                          \
00114             (SSC_RFMR_DATNB(SLOT_BY_FRAME - 1)) |                      \
00115             (SSC_RFMR_FSOS_NONE))
00116 
00117 
00118 /** Master clock frequency in Hz */
00119 #define SSC_MCK                 BOARD_MCK
00120 
00121 /** MAX size of the recorded sound */
00122 #define MAX_RECORD_SIZE         0xFFFFFFFF
00123 
00124 /** MAX size of one DMA transfer */
00125 #define MAX_DMA_SIZE            0x1000
00126 
00127 /** TWI clock */
00128 #define TWI_CLOCK               400000
00129 
00130 /** WAV feature. */
00131 #define SAMPLE_RATE             (48000)
00132 #define SLOT_BY_FRAME           (1)
00133 #define BITS_BY_SLOT            (16)
00134 
00135 /** DMA Descriptor */
00136 #define TOTAL_Buffers            4
00137 #define AUDIO_IF                SSC
00138 
00139 /*----------------------------------------------------------------------------
00140  *        Local variables
00141  *----------------------------------------------------------------------------*/
00142 
00143 /** List of pins to configure. */
00144 static const Pin pinsSsc[] = {PIN_TWI_TWD0, PIN_TWI_TWCK0, PIN_SSC_TD,
00145             PIN_SSC_TK, PIN_SSC_TF, PIN_SSC_RD,  PIN_SSC_RK, PIN_SSC_RF, PIN_PCK2};
00146 
00147 /** Global DMA driver for all transfer */
00148 static sXdmad dmad;
00149 /** DMA channel for RX */
00150 static uint32_t sscDmaRxChannel;
00151 /** DMA channel for TX */
00152 static uint32_t sscDmaTxChannel;
00153 
00154 static sXdmadCfg xdmadCfg;
00155 
00156 COMPILER_ALIGNED(32) static LinkedListDescriporView1 dmaWriteLinkList[TOTAL_Buffers];
00157 COMPILER_ALIGNED(32) static LinkedListDescriporView1 dmaReadLinkList[TOTAL_Buffers];
00158 
00159 /** TWI instance*/
00160 static Twid twid;
00161 
00162 static uint16_t AudioBuffer[TOTAL_Buffers*MAX_DMA_SIZE * (BITS_BY_SLOT / 8)];
00163 
00164 static uint8_t buf_flag = 1;
00165 
00166 static bool cpu_flag = false;
00167 
00168 static uint32_t AudioNextBuffer[TOTAL_Buffers] = {0};
00169 
00170 /*----------------------------------------------------------------------------
00171  *        Local functions
00172  *----------------------------------------------------------------------------*/
00173 
00174 /**
00175  * ISR for DMA interrupt
00176  */
00177 void XDMAC_Handler(void)
00178 {
00179     XDMAD_Handler(&dmad);
00180 }
00181 
00182 /**
00183  * \brief TWI interrupt handler. Forwards the interrupt to the TWI driver handler.
00184  */
00185 void TWIHS0_Handler(void)
00186 {
00187     TWID_Handler(&twid);
00188 }
00189 
00190 /*
00191  * \brief Callback function for SSC Rx.
00192  * */
00193 static void sscDmaRxClk(uint32_t Channel, void* pArg)
00194 {
00195     /*dummy*/
00196     Channel = Channel;
00197     pArg = pArg;
00198 
00199     if (cpu_flag) {
00200         if (AudioNextBuffer[buf_flag] == 0)
00201             AudioNextBuffer[buf_flag] = (dmad.pXdmacs->XDMAC_CHID[sscDmaRxChannel].XDMAC_CNDA);
00202         else {
00203             TRACE_WARNING("DMA is faster than CPU-%d\n\r",buf_flag);
00204             AudioNextBuffer[buf_flag] = (dmad.pXdmacs->XDMAC_CHID[sscDmaRxChannel].XDMAC_CNDA);
00205         }
00206     }
00207 
00208     buf_flag++;
00209     if (buf_flag == TOTAL_Buffers) {
00210         buf_flag = 0;
00211         /*CPU starts to handle AudioNextBuffer, the first data are abandoned*/
00212         cpu_flag = true;
00213     }
00214 }
00215 
00216 /**
00217  * \brief DMA driver configuration
00218  */
00219 static void Dma_configure(void)
00220 {
00221     sXdmad *pDmad = &dmad;
00222 
00223     /* Driver initialize */
00224     XDMAD_Initialize( pDmad, 0);
00225     /* Configure TWI interrupts */
00226     NVIC_ClearPendingIRQ(XDMAC_IRQn);
00227     NVIC_EnableIRQ(XDMAC_IRQn);
00228     /* Allocate DMA channels for SSC */
00229     sscDmaTxChannel = XDMAD_AllocateChannel(pDmad, XDMAD_TRANSFER_MEMORY, ID_SSC);
00230     sscDmaRxChannel = XDMAD_AllocateChannel(pDmad, ID_SSC, XDMAD_TRANSFER_MEMORY);
00231     if (sscDmaTxChannel == XDMAD_ALLOC_FAILED
00232             || sscDmaRxChannel == XDMAD_ALLOC_FAILED) {
00233         printf("xDMA channel allocation error\n\r");
00234         while (1);
00235     }
00236 
00237     XDMAD_SetCallback( pDmad, sscDmaRxChannel, sscDmaRxClk, 0);
00238     XDMAD_PrepareChannel(pDmad, sscDmaTxChannel);
00239     XDMAD_PrepareChannel(pDmad, sscDmaRxChannel);
00240 }
00241 
00242 
00243 /**
00244  * \brief Receive and play audio with DMA.
00245  */
00246 static void PlayRecording(void)
00247 {
00248     uint16_t *src;
00249     uint8_t i;
00250     uint32_t xdmaCndc;
00251 
00252     src = &AudioBuffer[0];
00253     for (i = 0; i < TOTAL_Buffers; i++) {
00254         dmaReadLinkList[i].mbr_ubc = XDMA_UBC_NVIEW_NDV1
00255             | XDMA_UBC_NDE_FETCH_EN
00256             | XDMA_UBC_NSEN_UPDATED
00257             | XDMAC_CUBC_UBLEN(MAX_DMA_SIZE);
00258         dmaReadLinkList[i].mbr_sa  = (uint32_t)&(AUDIO_IF->SSC_RHR);
00259         dmaReadLinkList[i].mbr_da = (uint32_t)(src);
00260         if (i == (TOTAL_Buffers - 1))
00261             dmaReadLinkList[i].mbr_nda = (uint32_t)&dmaReadLinkList[0];
00262         else
00263             dmaReadLinkList[i].mbr_nda = (uint32_t)&dmaReadLinkList[i + 1];
00264         src += MAX_DMA_SIZE;
00265     }
00266 
00267     xdmadCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN
00268         | XDMAC_CC_MBSIZE_SINGLE
00269         | XDMAC_CC_DSYNC_PER2MEM
00270         | XDMAC_CC_CSIZE_CHK_1
00271         | XDMAC_CC_DWIDTH_HALFWORD
00272         | XDMAC_CC_SIF_AHB_IF1
00273         | XDMAC_CC_DIF_AHB_IF1
00274         | XDMAC_CC_SAM_FIXED_AM
00275         | XDMAC_CC_DAM_INCREMENTED_AM
00276         | XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber(ID_SSC, XDMAD_TRANSFER_RX));
00277     xdmaCndc = XDMAC_CNDC_NDVIEW_NDV1
00278         | XDMAC_CNDC_NDE_DSCR_FETCH_EN
00279         | XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED
00280         | XDMAC_CNDC_NDDUP_DST_PARAMS_UPDATED;
00281 
00282     SCB_CleanDCache_by_Addr((uint32_t *)dmaReadLinkList, sizeof(dmaReadLinkList));
00283 
00284     /*XDMAC_CIE_BIE make interrupts can be generated on per block basis*/
00285     XDMAD_ConfigureTransfer( &dmad, sscDmaRxChannel, &xdmadCfg, xdmaCndc,
00286             (uint32_t)&dmaReadLinkList[0], XDMAC_CIE_BIE);
00287 
00288 
00289     src = &AudioBuffer[0];
00290     for (i = 0; i < TOTAL_Buffers; i++) {
00291         dmaWriteLinkList[i].mbr_ubc = XDMA_UBC_NVIEW_NDV1
00292             | XDMA_UBC_NDE_FETCH_EN
00293             | XDMA_UBC_NSEN_UPDATED
00294             | XDMAC_CUBC_UBLEN(MAX_DMA_SIZE);
00295         dmaWriteLinkList[i].mbr_sa = (uint32_t)(src);
00296         dmaWriteLinkList[i].mbr_da = (uint32_t)&(AUDIO_IF->SSC_THR);
00297         if (i == (TOTAL_Buffers - 1))
00298             dmaWriteLinkList[i].mbr_nda = (uint32_t)&dmaWriteLinkList[0];
00299         else
00300             dmaWriteLinkList[i].mbr_nda = (uint32_t)&dmaWriteLinkList[i + 1];
00301         src += MAX_DMA_SIZE;
00302     }
00303 
00304     xdmadCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN
00305         | XDMAC_CC_MBSIZE_SINGLE
00306         | XDMAC_CC_DSYNC_MEM2PER
00307         | XDMAC_CC_CSIZE_CHK_1
00308         | XDMAC_CC_DWIDTH_HALFWORD
00309         | XDMAC_CC_SIF_AHB_IF1
00310         | XDMAC_CC_DIF_AHB_IF1
00311         | XDMAC_CC_SAM_INCREMENTED_AM
00312         | XDMAC_CC_DAM_FIXED_AM
00313         | XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber(ID_SSC, XDMAD_TRANSFER_TX));
00314     xdmaCndc = XDMAC_CNDC_NDVIEW_NDV1
00315         | XDMAC_CNDC_NDE_DSCR_FETCH_EN
00316         | XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED
00317         | XDMAC_CNDC_NDDUP_DST_PARAMS_UPDATED;
00318 
00319     SCB_CleanDCache_by_Addr((uint32_t *)dmaWriteLinkList, sizeof(dmaWriteLinkList));
00320     XDMAD_ConfigureTransfer( &dmad, sscDmaTxChannel, &xdmadCfg, xdmaCndc,
00321             (uint32_t)&dmaWriteLinkList[0], XDMAC_CIE_LIE);
00322 
00323     SSC_EnableReceiver(AUDIO_IF);
00324     XDMAD_StartTransfer( &dmad, sscDmaRxChannel);
00325 
00326 
00327     Wait(300);
00328     /* Enable playback(SSC TX) */
00329     SSC_EnableTransmitter(AUDIO_IF);
00330     XDMAD_StartTransfer( &dmad, sscDmaTxChannel);
00331 
00332 }
00333 
00334 /*----------------------------------------------------------------------------
00335  *         Global functions
00336  *----------------------------------------------------------------------------*/
00337 /**
00338  * \brief Application entry point for ssc_dam_audio example.
00339  *
00340  * \return Unused (ANSI-C compatibility).
00341  */
00342 int main( void )
00343 {
00344     uint16_t data = 0;
00345     /* Disable watchdog */
00346     WDT_Disable(WDT);
00347 
00348     /* Enable I and D cache */
00349     SCB_EnableICache();
00350     SCB_EnableDCache();
00351 
00352     /* Output example information */
00353     printf("-- SSC DMA Audio Example %s --\n\r", SOFTPACK_VERSION);
00354     printf("-- %s\n\r", BOARD_NAME);
00355     printf("-- Compiled: %s %s With %s--\n\r", __DATE__, __TIME__, COMPILER_NAME);
00356 
00357     /* Configure systick for 1 ms. */
00358     printf( "Configure system tick to get 1ms tick period.\n\r" );
00359     if (TimeTick_Configure())
00360         printf("-F- Systick configuration error\n\r" );
00361 
00362     /* Configure all pins */
00363     PIO_Configure(pinsSsc, PIO_LISTSIZE(pinsSsc));
00364 
00365     /* Configure SSC */
00366     SSC_Configure(AUDIO_IF , 0 , SSC_MCK);
00367     SSC_ConfigureReceiver(AUDIO_IF,I2S_SLAVE_RX_SETTING,I2S_SLAVE_RX_FRM_SETTING);
00368     SSC_DisableReceiver(AUDIO_IF);
00369     SSC_ConfigureTransmitter(AUDIO_IF,I2S_SLAVE_TX_SETTING,I2S_SLAVE_TX_FRM_SETTING);
00370     SSC_DisableTransmitter(AUDIO_IF);
00371 
00372     /* Configure DMA */
00373     Dma_configure();
00374 
00375     /* Configure and enable the TWI (required for accessing the DAC) */
00376     PMC_EnablePeripheral(ID_TWIHS0);
00377     TWI_ConfigureMaster(TWIHS0, TWI_CLOCK, BOARD_MCK);
00378     TWID_Initialize(&twid, TWIHS0);
00379     /* Configure TWI interrupts */
00380     NVIC_ClearPendingIRQ(TWIHS0_IRQn);
00381     NVIC_EnableIRQ(TWIHS0_IRQn);
00382 
00383     /* check that WM8904 is present */
00384     WM8904_Write(&twid, WM8904_SLAVE_ADDRESS, 22, 0);
00385     data=WM8904_Read(&twid, WM8904_SLAVE_ADDRESS, 0);
00386     if (data != 0x8904) {
00387         printf("WM8904 not found!\n\r");
00388         while (1);
00389     }
00390     /* Initialize the audio DAC */
00391     WM8904_Init(&twid, WM8904_SLAVE_ADDRESS, PMC_MCKR_CSS_SLOW_CLK);
00392 
00393     /* Enable the DAC master clock */
00394     PMC_ConfigurePCK2(PMC_MCKR_CSS_SLOW_CLK, PMC_MCKR_PRES_CLK_1);
00395     printf("Insert Line-in cable with PC Headphone output\n\r");
00396     PlayRecording();
00397 
00398     while (1) {
00399         if (cpu_flag == true) {
00400             if (AudioNextBuffer[(buf_flag + (TOTAL_Buffers - 1)) %
00401                 (TOTAL_Buffers)] != 0) {
00402                 /* If data received need to be handled by CPU,
00403                  * cache coherence operation is necessary */
00404                 SCB_InvalidateDCache_by_Addr((uint32_t *)AudioNextBuffer[buf_flag - 1],
00405                                             MAX_DMA_SIZE * (BITS_BY_SLOT / 8));
00406                     /* The users can handle the received data here. */
00407                 AudioNextBuffer[(buf_flag + (TOTAL_Buffers - 1)) % (TOTAL_Buffers)] = 0;
00408             } else {
00409                 TRACE_DEBUG("AudioNextBuffer[%d] is empty\n\r",
00410                             (buf_flag+(TOTAL_Buffers - 1)) % (TOTAL_Buffers));
00411             }
00412         }
00413     }
00414 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines