/*H***************************************************************************
*
* $Archive:: /boards/dsk5509a/examples/dsk_app_idle/dsk_app.c                 $
* $Revision:: 4                                                               $
* $Date:: 11/11/05 3:21p                                                      $
* $Author:: Shilpab                                                           $
*
* DESCRIPTION:
*
*   
* (C) Copyright 2005 by Spectrum Digital Incorporated
* All rights reserved
*
*H***************************************************************************/

/*
 *  ======== dsk_app.c ========
 *
 *  Version 0.90
 *
 *  This example digitally processes audio data from the line input on the
 *  AIC23 codec and plays the result on the line output and headphone output.
 *  It uses the McBSP and DMA to efficiently handle the data transfer without
 *  significant intervention from the DSP.
 *
 *
 *  Data transfer
 *
 *  Audio data is transferred back and forth from the codec through McBSP0,
 *  a bidirectional serial port.  The DMA is configured to take every 16-bit
 *  signed audio sample arriving on McBSP0 and store it in a buffer in memory
 *  until it can be processed.  Once it has been processed, it is sent back out
 *  through McBSP0 to the codec for output.  DMA channel 4 is used for
 *  transmitting data to the codec and channel 5 is used to receive data from
 *  the codec.
 *
 *  The AIC23 codec is configured through the I2C interface.
 *
 *
 *  Program flow
 *
 *  When the program is run, the individual DSP/BIOS modules are initialized
 *  as configured in dsk_app.cdb with the DSP/BIOS configuration tool.  The
 *  main( ) function is then called as the main user thread.  In this example
 *  main( ) performs application initialization and starts the DMA data
 *  transfers.  When main exits, control passes back entirely to DSP/BIOS
 *  which services any interrupts or threads on an as-needed basis.  When
 *  there is no work to be done, the idle thread is run.
 *
 *  The dmaHwiRcv( ) and dmaHwiXmp interrupt service routines are called when
 *  buffers have been transmitted or received. is called when a buffer has been
 *  filled.  It contains a state variable named pingOrPong that indicates
 *  whether the buffer is a PING or PONG buffer.  dmaHwi switches the buffer
 *  state to the opposite buffer and calls the SWI thread processBuffer to
 *  process the audio data.
 */

/*
 *  DSP/BIOS is configured using the DSP/BIOS configuration tool.  Settings
 *  for this example are stored in a configuration file called dsk_app.cdb.
 *  At compile time, Code Composer will auto-generate DSP/BIOS related files
 *  based on these settings.  A header file called dsk_appcfg.h contains the
 *  results of the autogeneration and must be included for proper operation.
 *  The name of the file is taken from dsk_app.cdb and adding cfg.h.
 */
#include "dsk_app_idlecfg.h"

#include "dsk5509.h"
#include "aic23.h"

/*
 *  This program uses Code Composer's Chip Support Library to access
 *  C55x peripheral registers and interrupt setup.  The following
 *  include files are required for the CSL modules.
 */
#include <csl.h>
#include <csl_irq.h>
#include <csl_dma.h>
#include <csl_mcbsp.h>
#include <csl_pwr.h>

/* Constants for buffers */
#define BUFFSIZE          256
#define BUFFERS           3

/* Function prototypes */
void initIrq( void );
void initDma( void );
void initMcbsp( void );
void setDmaSrc( DMA_Handle hDma, Int16 bufnum );
void setDmaDst( DMA_Handle hDma, Int16 bufnum );

/*  Handles  */
DMA_Handle hDmaXmt;
DMA_Handle hDmaRcv;
MCBSP_Handle hMcbsp;

Int32 count = 0;

/*  Config Structures */
/* CSL config structure for DMAs */
static DMA_Config dmaCfgReceive = {
    DMA_DMACSDP_RMK(
        DMA_DMACSDP_DSTBEN_NOBURST,
        DMA_DMACSDP_DSTPACK_OFF,
        DMA_DMACSDP_DST_DARAM,
        DMA_DMACSDP_SRCBEN_NOBURST,
        DMA_DMACSDP_SRCPACK_OFF,
        DMA_DMACSDP_SRC_PERIPH,
        DMA_DMACSDP_DATATYPE_16BIT
    ),                    /* DMACDSP */
    DMA_DMACCR_RMK(
        DMA_DMACCR_DSTAMODE_POSTINC,
        DMA_DMACCR_SRCAMODE_CONST,
        DMA_DMACCR_ENDPROG_OFF,
        DMA_DMACCR_REPEAT_OFF,
        DMA_DMACCR_AUTOINIT_OFF,
        DMA_DMACCR_EN_STOP,
        DMA_DMACCR_PRIO_HI,
        DMA_DMACCR_FS_DISABLE,
        DMA_DMACCR_SYNC_REVT0
    ),                    /* DMACCR */
    DMA_DMACICR_RMK(
        DMA_DMACICR_BLOCKIE_OFF,
        DMA_DMACICR_LASTIE_OFF,
        DMA_DMACICR_FRAMEIE_ON,
        DMA_DMACICR_FIRSTHALFIE_OFF,
        DMA_DMACICR_DROPIE_OFF,
        DMA_DMACICR_TIMEOUTIE_OFF
    ),                   /* DMACICR */
    ( DMA_AdrPtr )( ( Uint32 )( _MCBSP_DRR10_ADDR<<1 ) ), /* DMACSSAL */
    0,                   /* DMACSSAU                      */
    NULL,                /* DMACDSAL, to be loaded by submit  */
    0,                   /* DMACDSAU                      */
    BUFFSIZE,            /* DMACEN                        */
    1,                   /* DMACFN                        */
    0,                   /* DMACFI                        */
    0                    /* DMACEI                        */
};

static DMA_Config dmaCfgTransmit = {
    DMA_DMACSDP_RMK(
        DMA_DMACSDP_DSTBEN_NOBURST,
        DMA_DMACSDP_DSTPACK_OFF,
        DMA_DMACSDP_DST_PERIPH,
        DMA_DMACSDP_SRCBEN_NOBURST,
        DMA_DMACSDP_SRCPACK_OFF,
        DMA_DMACSDP_SRC_DARAM,
        DMA_DMACSDP_DATATYPE_16BIT
    ),                   /* DMACDSP */
    DMA_DMACCR_RMK(
        DMA_DMACCR_DSTAMODE_CONST,
        DMA_DMACCR_SRCAMODE_POSTINC,
        DMA_DMACCR_ENDPROG_OFF,
        DMA_DMACCR_REPEAT_OFF,
        DMA_DMACCR_AUTOINIT_OFF,
        DMA_DMACCR_EN_STOP,
        DMA_DMACCR_PRIO_HI,
        DMA_DMACCR_FS_DISABLE,
        DMA_DMACCR_SYNC_XEVT0
    ),                   /* DMACCR */
    DMA_DMACICR_RMK(
        DMA_DMACICR_BLOCKIE_OFF,
        DMA_DMACICR_LASTIE_OFF,
        DMA_DMACICR_FRAMEIE_ON,
        DMA_DMACICR_FIRSTHALFIE_OFF,
        DMA_DMACICR_DROPIE_OFF,
        DMA_DMACICR_TIMEOUTIE_OFF
    ),                   /* DMACICR */
    NULL,                /* DMACSSAL */
    0,                   /* DMACSSAU                     */
    ( DMA_AdrPtr )( ( Uint32 )( _MCBSP_DXR10_ADDR<<1 ) ),/* DMACDSAL */
    0,                   /* DMACDSAU                     */
    BUFFSIZE,            /* DMACEN                       */
    1,                   /* DMACFN                       */
    0,                   /* DMACFI                       */
    0                    /* DMACEI                       */
};

/* CSL config structure for MCBSP 1 */
static MCBSP_Config mcbspCfg0 = {
    MCBSP_SPCR1_RMK(
        MCBSP_SPCR1_DLB_OFF,                   /* DLB      = 0 */
        MCBSP_SPCR1_RJUST_RZF,                 /* RJUST    = 0 */
        MCBSP_SPCR1_CLKSTP_DISABLE,            /* CLKSTP   = 0 */
        MCBSP_SPCR1_DXENA_NA,                  /* DXENA    = 0 */
        MCBSP_SPCR1_ABIS_DISABLE,              /* ABIS     = 0 */
        MCBSP_SPCR1_RINTM_RRDY,                /* RINTM    = 0 */
        0,                                     /* RSYNCER  = 0 */
        MCBSP_SPCR1_RRST_DISABLE               /* RRST     = 0 */
    ),
    MCBSP_SPCR2_RMK(
        MCBSP_SPCR2_FREE_YES,                  /* FREE     = 1 */
        MCBSP_SPCR2_SOFT_YES,                  /* SOFT     = ` */
        MCBSP_SPCR2_FRST_FSG,                  /* FRST     = 0 */
        MCBSP_SPCR2_GRST_CLKG,                 /* GRST     = 0 */
        MCBSP_SPCR2_XINTM_XRDY,                /* XINTM    = 0 */
        0,                                     /* XSYNCER  = 0 */
        MCBSP_SPCR2_XRST_DISABLE               /* XRST     = 0 */
    ),
    MCBSP_RCR1_RMK(
        MCBSP_RCR1_RFRLEN1_OF( 1 ),            /* RFRLEN1  = 1 */
        MCBSP_RCR1_RWDLEN1_16BIT               /* RWDLEN1  = 2 */
    ),
    MCBSP_RCR2_RMK(
        MCBSP_RCR2_RPHASE_SINGLE,              /* RPHASE   = 0 */
        MCBSP_RCR2_RFRLEN2_OF( 0 ),            /* RFRLEN2  = 0 */
        MCBSP_RCR2_RWDLEN2_8BIT,               /* RWDLEN2  = 0 */
        MCBSP_RCR2_RCOMPAND_MSB,               /* RCOMPAND = 0 */
        MCBSP_RCR2_RFIG_YES,                   /* RFIG     = 0 */
        MCBSP_RCR2_RDATDLY_0BIT                /* RDATDLY  = 0 */
    ),
    MCBSP_XCR1_RMK(
        MCBSP_XCR1_XFRLEN1_OF( 1 ),            /* XFRLEN1  = 1 */
        MCBSP_XCR1_XWDLEN1_16BIT               /* XWDLEN1  = 2 */
    ),
    MCBSP_XCR2_RMK(
        MCBSP_XCR2_XPHASE_SINGLE,              /* XPHASE   = 0 */
        MCBSP_XCR2_XFRLEN2_OF( 0 ),            /* XFRLEN2  = 0 */
        MCBSP_XCR2_XWDLEN2_8BIT,               /* XWDLEN2  = 0 */
        MCBSP_XCR2_XCOMPAND_MSB,               /* XCOMPAND = 0 */
        MCBSP_XCR2_XFIG_YES,                   /* XFIG     = 0 */
        MCBSP_XCR2_XDATDLY_0BIT                /* XDATDLY  = 0 */
    ),
    MCBSP_SRGR1_RMK(
        MCBSP_SRGR1_FWID_OF( 0 ),              /* FWID     = 0 */
        MCBSP_SRGR1_CLKGDV_OF( 0 )             /* CLKGDV   = 0 */
    ),
    MCBSP_SRGR2_RMK(
        MCBSP_SRGR2_GSYNC_FREE,                /* FREE     = 0 */
        MCBSP_SRGR2_CLKSP_RISING,              /* CLKSP    = 0 */
        MCBSP_SRGR2_CLKSM_CLKS,                /* CLKSM    = 0 */
        MCBSP_SRGR2_FSGM_DXR2XSR,              /* FSGM     = 0 */
        MCBSP_SRGR2_FPER_OF( 0 )               /* FPER     = 0 */
    ),
    MCBSP_MCR1_DEFAULT,
    MCBSP_MCR2_DEFAULT,
    MCBSP_PCR_RMK(
        MCBSP_PCR_IDLEEN_RESET,                /* IDLEEN   = 0 */
        MCBSP_PCR_XIOEN_SP,                    /* XIOEN    = 0 */
        MCBSP_PCR_RIOEN_SP,                    /* RIOEN    = 0 */
        MCBSP_PCR_FSXM_EXTERNAL,               /* FSXM     = 0 */
        MCBSP_PCR_FSRM_EXTERNAL,               /* FSRM     = 0 */
        MCBSP_PCR_CLKXM_INPUT,                 /* CLKXM    = 0 */
        MCBSP_PCR_CLKRM_INPUT,                 /* CLKRM    = 0 */
        MCBSP_PCR_SCLKME_NO,                   /* SCLKME   = 0 */
        0,                                     /* DXSTAT   = 0 */
        MCBSP_PCR_FSXP_ACTIVEHIGH,             /* FSXP     = 0 */
        MCBSP_PCR_FSRP_ACTIVEHIGH,             /* FSRP     = 0 */
        MCBSP_PCR_CLKXP_FALLING,               /* CLKXP    = 1 */
        MCBSP_PCR_CLKRP_RISING                 /* CLKRP    = 1 */
    ),
    MCBSP_RCERA_DEFAULT,
    MCBSP_RCERB_DEFAULT,
    MCBSP_RCERC_DEFAULT,
    MCBSP_RCERD_DEFAULT,
    MCBSP_RCERE_DEFAULT,
    MCBSP_RCERF_DEFAULT,
    MCBSP_RCERG_DEFAULT,
    MCBSP_RCERH_DEFAULT,
    MCBSP_XCERA_DEFAULT,
    MCBSP_XCERB_DEFAULT,
    MCBSP_XCERC_DEFAULT,
    MCBSP_XCERD_DEFAULT,
    MCBSP_XCERE_DEFAULT,
    MCBSP_XCERF_DEFAULT,
    MCBSP_XCERG_DEFAULT,
    MCBSP_XCERH_DEFAULT
};

/* Codec configuration settings */
AIC23_Params config = {
    0x001c, // 0 DSK5509_AIC23_LEFTINVOL  Left line input channel volume
    0x001c, // 1 DSK5509_AIC23_RIGHTINVOL Right line input channel volume
    0x00d8, // 2 DSK5509_AIC23_LEFTHPVOL  Left channel headphone volume
    0x00d8, // 3 DSK5509_AIC23_RIGHTHPVOL Right channel headphone volume
    0x0010, // 4 DSK5509_AIC23_ANAPATH    Analog audio path control
    0x0000, // 5 DSK5509_AIC23_DIGPATH    Digital audio path control
    0x0000, // 6 DSK5509_AIC23_POWERDOWN  Power down control
    0x0043, // 7 DSK5509_AIC23_DIGIF      Digital audio interface format
    0x0001, // 8 DSK5509_AIC23_SAMPLERATE Sample rate control
    0x0001  // 9 DSK5509_AIC23_DIGACT     Digital interface activation
};

/*
 * Data buffer declarations - the program uses four logical buffers of size
 * BUFFSIZE, one ping and one pong buffer on both receive and transmit sides.
 */
#pragma DATA_SECTION ( gBuffer, "buffer_sect" );
Int16 gBuffer[BUFFSIZE * BUFFERS];

/* Event IDs, global so they can be set in initIrq( ) and used everywhere */
Uint16 eventIdRcv, eventIdXmt;

/* Active buffer indices */
Int16 gRcvBuf, gXmtBuf;


/* ------------------------Helper Functions ----------------------------- */

/*
 *  initMcbsp( ) - Initialize the McBSP for codec data transfers using the
 *                configuration define at the top of this file.
 */
void initMcbsp( )
{
    /* Open the codec data McBSP */
    hMcbsp = MCBSP_open( MCBSP_PORT0, MCBSP_OPEN_RESET );

    /* Configure the codec to match the AIC23 data format */
    MCBSP_config( hMcbsp, &mcbspCfg0 );

    /* Clear any garbage from the codec data port */
    if ( MCBSP_rrdy( hMcbsp ) )
        MCBSP_read16( hMcbsp );

    /* Start the McBSP running */
    MCBSP_start( hMcbsp, MCBSP_XMIT_START | MCBSP_RCV_START |
        MCBSP_SRGR_START | MCBSP_SRGR_FRAMESYNC, 220 );
}

/*
 *  initIrq( ) - Initialize and enable the DMA receive interrupt using the CSL.
 *              The interrupt service routine for this interrupt is hwiDma.
 */
void initIrq( void )
{
    /* Get Event ID associated with DMA channel interrupt.  Event IDs are a
     * CSL abstraction that lets code describe a logical event that gets
     * mapped to a real physical event at run time.  This helps to improve
     * code portability.
     */
    eventIdRcv = DMA_getEventId( hDmaRcv );
    eventIdXmt = DMA_getEventId( hDmaXmt );

    /* Clear any pending receive channel interrupts ( IFR ) */
    IRQ_clear( eventIdRcv );
    IRQ_clear( eventIdXmt );

    /* Enable receive DMA interrupt ( IMR ) */
    IRQ_enable( eventIdRcv );
    IRQ_enable( eventIdXmt );

    /* Make sure global interrupts are enabled */
    IRQ_globalEnable( );
}

/*
 *  setDmaSrc( ) - Set DMA source address
 */
void setDmaSrc( DMA_Handle hDma, Int16 bufnum )
{
    Uint32 addr;

    /* Set the DMA source address */
    addr = ( ( ( Uint32 )gBuffer + BUFFSIZE * bufnum ) << 1 );
    DMA_RSETH( hDma, DMACSSAL, addr & 0xffff );
    DMA_RSETH( hDma, DMACSSAU, ( addr >> 16 ) & 0xffff );
}

/*
 *  setDmaDst( ) - Set DMA destination address
 */
void setDmaDst( DMA_Handle hDma, Int16 bufnum )
{
    Uint32 addr;

    /* Set the DMA destination address */
    addr = ( ( ( Uint32 )gBuffer + BUFFSIZE * bufnum ) << 1 );
    DMA_RSETH( hDma, DMACDSAL, addr & 0xffff );
    DMA_RSETH( hDma, DMACDSAU, ( addr >> 16 ) & 0xffff );
}

/*
 *  initDma( ) - Initialize the DMA controller.
 */
void initDma( void )
{
    volatile Int16 i;

    /* Open DMA channels */
    hDmaXmt = DMA_open( DMA_CHA5, DMA_OPEN_RESET );
    hDmaRcv = DMA_open( DMA_CHA4, DMA_OPEN_RESET );

    /* Configure DMA channels */
    DMA_config( hDmaXmt, &dmaCfgTransmit );
    DMA_config( hDmaRcv, &dmaCfgReceive );

    /* Set initial buffer pointers */
    gXmtBuf = 0;
    gRcvBuf = BUFFERS - 1;
    setDmaSrc( hDmaXmt, gXmtBuf );
    setDmaDst( hDmaRcv, gRcvBuf );

    /* Clear the DMA status registers to receive new interrupts */
    i = DMA_RGETH( hDmaRcv, DMACSR );
    i = DMA_RGETH( hDmaXmt, DMACSR );

    /* Put the DMA in FREE mode */
    DMA_FSET( DMAGCR, FREE, 1 );

    /* Start the DMA */
    DMA_start( hDmaRcv );
    DMA_start( hDmaXmt );
}


/* ------------------------------- Threads ------------------------------ */

/*
 *  processBuffer( ) - Process audio data once it has been received.
 */
void processBuffer( void )
{
    Int16 bufnum, i;
    Int16 *pdata, dummy;

    /* Figure out which buffer was received */
    bufnum = SWI_getmbox( );

    /* Set the DMA source address */
    pdata = ( Int16 * )( ( Uint32 )gBuffer + BUFFSIZE * bufnum );

#if( 0 )
    /* Swap left/right data */
    for ( i = 0; i < ( BUFFSIZE >> 1 ); i++ )
    {
        dummy = *pdata;
        *pdata++ = *pdata;
        *pdata++ = dummy;
    }
#endif
}

void idleMode( void )
{
    PWR_powerDown( PWR_WAKEUP_MI );
}

/* ---------------------- Interrupt Service Routines -------------------- */

/*
 *  dmaHwiRcv( ) - Interrupt service routine for the DMA receive transfer.  It
 *                is triggered when a complete frame of data has been received
 *                from the codec and is ready in memory.  The ISR is set in the
                  CDB file at Scheduling --> HWI --> HWI_INT14.
 */
void dmaHwiRcv( void )
{
    Int16 bufin = gRcvBuf;

    /* Set DMA destination to next buffer */
    if ( ++gRcvBuf >= BUFFERS )
        gRcvBuf = 0;
    setDmaDst( hDmaRcv, gRcvBuf );

    /* Restart DMA */
    DMA_start( hDmaRcv );

    /* Notify processBufferSwi( ) that there is data to process */
    SWI_or( &processBufferSwi, bufin );

    /* Read DMA status register to clear it so new interrupts will be seen */
    DMA_RGETH( hDmaRcv, DMACSR );
}

/*
 *  dmaHwiRcv( ) - Interrupt service routine for the DMA transmit transfer.  It
 *                is triggered when a complete frame of data has been sent to
 *                the codec.  The ISR is set in the CDB file at
 *                Scheduling --> HWI --> HWI_INT15.
 */
void dmaHwiXmt( void )
{
    count++;
    /* Set DMA source to next buffer */
    if ( ++gXmtBuf >= BUFFERS )
        gXmtBuf = 0;
    setDmaSrc( hDmaXmt, gXmtBuf );

    /* Restart DMA */
    DMA_start( hDmaXmt );

    /* Read DMA status register to clear it so new interrupts will be seen */
    DMA_RGETH( hDmaXmt, DMACSR );
}


/* --------------------------- main( ) function -------------------------- */

/*
 *  main( ) - The main user task.  Performs application initialization and
 *           starts the data transfer.
 */
void main( )
{
    /* Initialize the board support library, must be called first */
    DSK5509_init( );

    /* Enable codec data path */
    DSK5509_rset( DSK5509_MISC, 1 );

    /* Clear buffers */
    memset( ( void * )gBuffer, 0, BUFFSIZE * BUFFERS );

    /* Configure the codec */
    AIC23_setParams( &config );

    /* Disable global interrupts during setup */
    IRQ_globalDisable( );

    /* Initialize the EDMA controller */
    initDma( );

    /* Initialize McBSP0 for audio transfers */
    initMcbsp( );

    /* Initialize interrupts */
    initIrq( );

    /* Configure Idle Control Register ( I/O Address 0x0001 ) */
    PWR_RSET( ICR, PWR_ICR_RMK( PWR_ICR_CPUI_CPU_DISABLED,
                               PWR_ICR_DMAI_DMA_ACTIVE,
                               PWR_ICR_CACHEI_CACHE_ACTIVE,
                               PWR_ICR_PERI_ALL_ACTIVE,
                               PWR_ICR_CLKGENI_CLKGEN_RUNNING,
                               PWR_ICR_EMIFI_EMIF_ACTIVE
                               ) );

    /* Re-enable global interrupts */
    IRQ_globalEnable( );
}
