⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ac97_example.c

📁 Sharp LH7A400 BSP平台无关部分的代码,有很高的参考价值,尤其是系统架构设计上,设计成移植度很高的BSP.
💻 C
字号:
/***********************************************************************
 * $Workfile:   ac97_example.c  $
 * $Revision:   1.0  $
 * $Author:   WellsK  $
 * $Date:   Oct 23 2003 08:41:08  $
 *
 * Project: AC97 DMA mode driver example (with streaming)
 *
 * Description:
 *     A AC97 driver (DMA mode) example using streaming. In this
 *     example, the 16-bit mono audio data will be converted to 16-bit
 *     AC97 stereo data as needed by the DMA controller. This type of
 *     transfer is useful for streaming based audio.
 *
 * Revision History:
 * $Log:   //smaicnt2/pvcs/VM/sharpmcu/archives/sharpmcu/software/csps/lh7a400/bsps/sdk7a400/examples/ac97_dma_stream/ac97_example.c-arc  $
 * 
 *    Rev 1.0   Oct 23 2003 08:41:08   WellsK
 * Initial revision.
 * 
 *
 ***********************************************************************
 * SHARP MICROELECTRONICS OF THE AMERICAS MAKES NO REPRESENTATION
 * OR WARRANTIES WITH RESPECT TO THE PERFORMANCE OF THIS SOFTWARE,
 * AND SPECIFICALLY DISCLAIMS ANY RESPONSIBILITY FOR ANY DAMAGES, 
 * SPECIAL OR CONSEQUENTIAL, CONNECTED WITH THE USE OF THIS SOFTWARE.
 *
 * SHARP MICROELECTRONICS OF THE AMERICAS PROVIDES THIS SOFTWARE SOLELY 
 * FOR THE PURPOSE OF SOFTWARE DEVELOPMENT INCORPORATING THE USE OF A 
 * SHARP MICROCONTROLLER OR SYSTEM-ON-CHIP PRODUCT. USE OF THIS SOURCE
 * FILE IMPLIES ACCEPTANCE OF THESE CONDITIONS.
 *
 * COPYRIGHT (C) 2001 SHARP MICROELECTRONICS OF THE AMERICAS, INC.
 *     CAMAS, WA
 **********************************************************************/

#include "abl_types.h"
#include "abl_irq_fiq.h"
#include "abl_arm922t_cp15_driver.h"
#include "lh7a400_ac97_driver.h"
#include "lh7a400_timer_driver.h"
#include "lh7a400_int_driver.h"
#include "lh7a400_csc_driver.h"
#include "lh7a400_dma_driver.h"
#include "sdk7a400_cpld_driver.h"
#include "ibugle.h"

/* Size of the local DMA buffers in bytes - this size is smaller than
   the sample that needs to be played */
#define DMA_BUFF_SIZE 0x4000

/* Number of DMA flip/flop buffers */
#define DMA_BUFFS 3

/* Type used for DMA streaming control */
typedef struct
{
    UNS_8 dmabuff[DMA_BUFF_SIZE];   /* DMA buffer */
    UNS_32 bytes;                   /* Bytes of data in this buffer */
} DMA_TAG_T;

/* DMA buffer and control data */
STATIC DMA_TAG_T dmacbuff[DMA_BUFFS];

/* Flag indicating that all the data has been processed */
STATIC volatile BOOL_32 dcomplete;

/* Next buffer and control data to use and set */
STATIC volatile INT_32 dmabuf_use, dmabuf_set, dmabufs_used;

/* Audio stream data input index pointer */
STATIC INT_32 dindex;

/***********************************************************************
 *
 * Function: dma_buff_fill
 *
 * Purpose: DMA buffer background fill task
 *
 * Processing:
 *     This function simply formats and moves audio data into the DMA
 *     buffers as DMA buffer space becomes available. The data is
 *     formatted to 'stereo' data from a single mono source. Once all
 *     the data has been converted, the dcomplete flag will be set to
 *     TRUE.
 *
 * Parameters: None
 *
 * Outputs: None
 *
 * Returns: Nothing
 *
 * Notes: None
 *
 **********************************************************************/
void dma_buff_fill(void)
{
    INT_32 index;

    while (dmabufs_used < DMA_BUFFS)
    {
        if (dcomplete == TRUE)
        {
            /* No more data, just clear next buffer */
            dmacbuff[dmabuf_set].bytes = 0;
        }
        else
        {
            /* Copy data into buffer */
            index = 0;
            while ((index < (DMA_BUFF_SIZE - 4)) &&
                (dcomplete == FALSE))
            {
                /* Convert to 'stereo' */
                dmacbuff[dmabuf_set].dmabuff[index] = 
                    dmacbuff[dmabuf_set].dmabuff[index + 2] =
                    ibugle[dindex];
                dmacbuff[dmabuf_set].dmabuff[index + 1] = 
                    dmacbuff[dmabuf_set].dmabuff[index + 3] =
                    ibugle[dindex + 1];
                index = index + 4;

                dindex = dindex + 2;
                if (dindex >= (IBUGLE_NUM_SAMPLES * 2))
                {
                    dcomplete = TRUE;
                }
            }

            /* Set count in buffer */
            dmacbuff[dmabuf_set].bytes = index;
        }

        /* Set next buffer */
        dmabufs_used++;
        dmabuf_set++;
        if (dmabuf_set >= DMA_BUFFS)
        {
            dmabuf_set = 0;
        }
    }
}

/***********************************************************************
 *
 * Function: dma_ac97_callback
 *
 * Purpose: DMA/AC97 callback function
 *
 * Processing:
 *     This function is called by the DMA driver when it needs a new
 *     buffer of data or is stalled, and will provide the next buffer
 *     address and size generated with the background dma_buff_fill()
 *     function.
 *
 * Parameters:
 *     buff : Pointer to where to place the DMA buffer address
 *     bytes: Pointer to where the 'bytes' are stored (As an input,
 *            the value at this address will contain the number of
 *            bytes that occured on the last DMA transfer. As an
 *            output, it will contain the number of bytes in the
 *            DMA buffer pointed to by buff.
 *     abort: Pointer to an abort flag (As an input, this flag signals
 *            that a transfer was aborted due to an error, or has
 *            completed. As an output, the DMA driver is told that
 *            this transfer is the last transfer.)
 *
 * Outputs: None
 *
 * Returns: Nothing
 *
 * Notes:
 *     This is the sequence of how callback function will work:
 *      Called by DMA on stall to get initial buffer and size
 *      Called by DMA on next buffer to get next buffer and size
 *      Repeatedly called by DMA to get next buffer and size unless
 *          *abort = TRUE
 *      On the last 'next' buffer, set *abort = TRUE
 *      When the last transfer is complete, the driver will call this
 *          function one more time with *abort = TRUE
 *
 **********************************************************************/
void dma_ac97_callback(UNS_32 *buff, UNS_32 *bytes, BOOL_32 *abort)
{
    /* Examine the abort flag passed from the DMA driver. If this flag
       is TRUE, then a transfer error occured or the DMA driver is
       signalling that the transfer is complete. In this example, the
       flag serves no real purpose, as the audio stream is tolerant of
       occasional errors */
    if (*abort == FALSE)
    {
        /* Release previously used buffer */
        if (*bytes > 0)
        {
            dmabufs_used--;

            /* Use next buffer */
            dmabuf_use++;
            if (dmabuf_use >= DMA_BUFFS)
            {
                dmabuf_use = 0;
            }
        }

        /* Get next buffer address and size */
        *bytes = dmacbuff[dmabuf_use].bytes;
        *buff = (UNS_32) cp15_map_virtual_to_physical(
            (UNS_32 *) &dmacbuff[dmabuf_use].dmabuff);

        /* Signal the end of the transfer is stream complete if all the
           data has been transferred */
        *abort = FALSE;
        if ((dcomplete == TRUE) && (*bytes == 0))
        {
            *abort = TRUE;
        }
    }
}

/***********************************************************************
 *
 * Function: c_entry
 *
 * Purpose: DMA mode AC97 driver example
 *
 * Processing:
 *     See function. This example sets up the CODEC to play a stereo
 *     sample on the PCM output.
 *
 * Parameters: None
 *
 * Outputs: None
 *
 * Returns: Always returns 1
 *
 * Notes: None
 *
 **********************************************************************/
int c_entry(void)
{
    INT_32 ac97dev1, iter, xa;
    AC97_VOLUME_T vol;
    AC97_MIX_GAIN_T mix;
    AC97_TONE_T tone;
    AC97_CHANNEL_CONFIG_T chcfg;
    DMAC_CHANNEL_T dmach;

    /* Disable interrupts */
    disable_irq_fiq();

    /* Set virtual address of MMU table (needed for VIC driver
       functions) */
    cp15_set_vmmu_addr((UNS_32 *) cp15_get_ttb());

    /* Initialize CPLD */
    cpld_init();

    /* Initialize interrupt system */
    int_initialize(0xC0000000);

    /* Install standard IRQ dispatcher at ARM IRQ vector */
    int_install_handler(IRQ_VEC, (PFV) irq_dispatcher);

    /* Open the AC97 controller channel #1 */
    if ((ac97dev1 = ac97_open(AAC, 0)) == (INT_32) NULL)
    {
        return 0;
    }

    /* Reset AC97 CODEC power and allow a small delay (300mS) for
       device to re-initialize correctly */
    ac97_ioctl(ac97dev1, AC97_DO_RESET, 1);
    timer_wait_us(TIMER1, (300 * 1000));

    /* Make sure all DMA channels are disabled */
    for (dmach = DMAC_USB_TX; dmach <= DMAC_AAC_TX2; dmach++)
    {
        dmac_stop(dmach);
    }    

    /* Enable DMA clock */
    csc_enable_dma(TRUE);

    /* Install DMA handler in the IRQ dispatcher */
    int_install_irq_handler(INT_DMAINTR, (PFV) dmac_isr);

    /* Enable DMA interrupts */
    int_enable(INT_DMAINTR);
    
    /* Enable IRQ interrupts in the ARM core */
    enable_irq();

    /* Set CODEC volumes to MAX (all CODEC outputs) */
    vol.mute   = FALSE;
    vol.left   = AC97_MAX_VOL;
    vol.right  = AC97_MAX_VOL;
    vol.select = MASTER_OUT;
    ac97_ioctl(ac97dev1, AC97_SET_VOL, (INT_32) &vol);
    vol.select = AUX_OUT;
    ac97_ioctl(ac97dev1, AC97_SET_VOL, (INT_32) &vol);
    vol.select = MONO_OUT;
    ac97_ioctl(ac97dev1, AC97_SET_VOL, (INT_32) &vol);

    /* Mute all CODEC mixer channels */
    mix.mute   = FALSE;
    mix.left   = AC97_MIX_GN_MIN;
    mix.right  = AC97_MIX_GN_MIN;
    for (xa = BEEP_OUT; xa < PCM_OUT; xa++)
    {
        mix.select = (AC97_MIX_GAIN_SEL_T) xa;
        ac97_ioctl(ac97dev1, AC97_SET_MIXGAIN, (INT_32) &mix);
    }

    /* Set PCM output channel to max gain in mixer (volume) */
    mix.mute   = FALSE;
    mix.left   = AC97_REC_GN_MAX;
    mix.right  = AC97_REC_GN_MAX;
    mix.select = PCM_OUT;
    ac97_ioctl(ac97dev1, AC97_SET_MIXGAIN, (INT_32) &mix);

    /* Set bass and treble tone control to bypass */
    tone.bass_gain = AC97_TONE_BYPASS;
    tone.treble_gain = AC97_TONE_BYPASS;
    ac97_ioctl(ac97dev1, AC97_SET_TONE, (INT_32) &tone);

    /* Play sample using DMA (must use compact mode) */
    chcfg.srate = BPSEC_8000;
    chcfg.ssize = BPSAM_16;
    chcfg.channels = 2;
    chcfg.compact = TRUE;
    chcfg.dir = PLAYBACK;
    chcfg.tmode = AC97_DMA;

    /* Play sample 3 times at different rates */
    for (iter = 0; iter < 3; iter++)
    {
        /* Configure the AC97 for DMA audio playback. The DMA channel
           will be returned by this call when tmode is set to AC97_DMA
           as the transfer mode */
        dmach = (DMAC_CHANNEL_T)
            ac97_ioctl(ac97dev1, AC97_SET_CHANNEL, (INT_32) &chcfg);

        /* Before starting the audio stream, preprocess some data into
           the DMA buffers */
        dindex = dmabuf_use = dmabuf_set = dmabufs_used = 0;
        dcomplete = FALSE;
        dma_buff_fill();
        
        /* For the selected DMA channel, start the transfer */
        dmac_start_using_cb(dmach, (DMACFUNC_T) dma_ac97_callback,
            TRUE);

        /* Check for DMA sample to complete by monitoring the DMA
           status */
        while (dmac_get_status(dmach) != DMAC_STATE_IDLE)
        {
            /* Process some more audio data into the DMA buffers in
               the background as space becomes available */
            dma_buff_fill();
        }

        /* Next sample rate */
        chcfg.srate++;
    }

    /* Disable DMA clock */
    csc_enable_dma(FALSE);

    /* Disable DMA interrupt in the interrupt controller */
    int_disable(INT_DMAINTR);

    /* Disable ARM core IRQ interrupts */
    disable_irq();

    return 1;
}

#ifndef __GNUC__
/* With ARM and GHS toolsets, the entry point is main() - this will
   allow the linker to generate wrapper code to setup stacks, allocate
   heap area, and initialize and copy code and data segments. For GNU
   toolsets, the entry point is through __start() in the crt0_gnu.asm
   file, and that startup code will setup stacks and data */
int main(void)
{
    return c_entry();
}
#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -