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

📄 sound.c

📁 基于TI公司Cortex-M3的uart超级通信开发
💻 C
📖 第 1 页 / 共 3 页
字号:

    //
    // Set the FIFO trigger limit
    //
    I2SRxFIFOLimitSet (I2S0_BASE, 4);

    //
    // Enable the I2S Rx controller.
    //
    I2SRxEnable(I2S0_BASE);

    //
    // Disable all DMA attributes.
    //
    uDMAChannelAttributeDisable(UDMA_CHANNEL_I2S0RX, UDMA_ATTR_ALL);
    }

    //
    // Enable the I2S interrupt on the NVIC
    //
    IntEnable(INT_I2S0);
}

//*****************************************************************************
//
//! Handles the I2S sound interrupt.
//!
//! This function services the I2S interrupt and will call the callback function
//! provided with the buffer that was given to the SoundBufferPlay() or
//! SoundBufferRead() functions to handle emptying or filling the buffers and
//! starting up DMA transfers again.  It is solely the responsibility of the
//! callback functions to continuing sending or receiving data to or from the
//! audio codec.
//!
//! \return None.
//
//*****************************************************************************
void
SoundIntHandler(void)
{
    unsigned long ulStatus;
    unsigned long *pulTemp;

    //
    // Get the interrupt status and clear any pending interrupts.
    //
    ulStatus = I2SIntStatus(I2S0_BASE, 1);

    //
    // Clear out any interrupts.
    //
    I2SIntClear(I2S0_BASE, ulStatus);

    //
    // Handle the RX channel interrupt
    //
    if(HWREGBITW(&g_ulDMAFlags, FLAG_RX_PENDING))
    {
        //
        // If the RX DMA is done, then start another one using the same
        // RX buffer.  This keeps the RX running continuously.
        //
        if(uDMAChannelModeGet(UDMA_CHANNEL_I2S0RX | UDMA_PRI_SELECT) ==
           UDMA_MODE_STOP)
        {
            //
            // Save a temp pointer so that the current pointer can be set to
            // zero before calling the callback.
            //
            pulTemp = g_sInBuffers[0].pulData;

            //
            // If at the mid point the refill the first half of the buffer.
            //
            if(g_sInBuffers[0].pfnBufferCallback)
            {
                g_sInBuffers[0].pulData = 0;

                g_sInBuffers[0].pfnBufferCallback(pulTemp, BUFFER_EVENT_FULL);
            }
        }
        else if(uDMAChannelModeGet(UDMA_CHANNEL_I2S0RX | UDMA_ALT_SELECT) ==
                UDMA_MODE_STOP)
        {
            //
            // Save a temp pointer so that the current pointer can be set to
            // zero before calling the callback.
            //
            pulTemp = g_sInBuffers[1].pulData;

            //
            // If at the mid point the refill the first half of the buffer.
            //
            if(g_sInBuffers[1].pfnBufferCallback)
            {
                g_sInBuffers[1].pulData = 0;
                g_sInBuffers[1].pfnBufferCallback(pulTemp, BUFFER_EVENT_FULL);
            }
        }

        //
        // If there are no more scheduled buffers then there are no more
        // pending DMA transfers.
        //
        if((g_sInBuffers[0].pulData == 0) && (g_sInBuffers[1].pulData == 0))
        {
            HWREGBITW(&g_ulDMAFlags, FLAG_RX_PENDING) = 0;
        }
    }

    //
    // Handle the TX channel interrupt
    //
    if(HWREGBITW(&g_ulDMAFlags, FLAG_TX_PENDING))
    {
        //
        // If the TX DMA is done, then call the callback if present.
        //
        if(uDMAChannelModeGet(UDMA_CHANNEL_I2S0TX | UDMA_PRI_SELECT) ==
           UDMA_MODE_STOP)
        {
            //
            // Save a temp pointer so that the current pointer can be set to
            // zero before calling the callback.
            //
            pulTemp = g_sOutBuffers[0].pulData;

            //
            // If at the mid point then refill the first half of the buffer.
            //
            if((g_sOutBuffers[0].pfnBufferCallback) &&
               (g_sOutBuffers[0].pulData != 0))
            {
                g_sOutBuffers[0].pulData = 0;
                g_sOutBuffers[0].pfnBufferCallback(pulTemp, BUFFER_EVENT_FREE);
            }
        }

        //
        // If the TX DMA is done, then call the callback if present.
        //
        if(uDMAChannelModeGet(UDMA_CHANNEL_I2S0TX | UDMA_ALT_SELECT) ==
           UDMA_MODE_STOP)
        {
            //
            // Save a temp pointer so that the current pointer can be set to
            // zero before calling the callback.
            //
            pulTemp = g_sOutBuffers[1].pulData;

            //
            // If at the mid point then refill the first half of the buffer.
            //
            if((g_sOutBuffers[1].pfnBufferCallback) &&
               (g_sOutBuffers[1].pulData != 0))
            {
                g_sOutBuffers[1].pulData = 0;
                g_sOutBuffers[1].pfnBufferCallback(pulTemp, BUFFER_EVENT_FREE);
            }
        }

        //
        // If no more buffers are pending then clear the flag.
        //
        if((g_sOutBuffers[0].pulData == 0) && (g_sOutBuffers[1].pulData == 0))
        {
            HWREGBITW(&g_ulDMAFlags, FLAG_TX_PENDING) = 0;
        }
    }
}

//*****************************************************************************
//
//! Starts playback of a song.
//!
//! \param pusSong is a pointer to the song data structure.
//! \param ulLength is the length of the song data structure in bytes.
//!
//! This function starts the playback of a song or sound effect.  If a song
//! or sound effect is already being played, its playback is canceled and the
//! new song is started.
//!
//! \return None.
//
//*****************************************************************************
void
SoundPlay(const unsigned short *pusSong, unsigned long ulLength)
{
    //
    // Set the format of the audio stream.
    //
    SoundSetFormat(48000, 16, 2);

    //
    // Save the music buffer.
    //
    g_ulMusicCount = 0;
    g_ulMusicSize = ulLength * 2;
    g_pusMusic = pusSong;
    g_ulPlaying = 0;

    g_sOutBuffers[0].pulData = 0;
    g_sOutBuffers[1].pulData = 0;

    if(SoundNextTone() != 0)
    {
        SoundBufferPlay(g_pulTxBuf, g_ulSize, BufferCallback);
        SoundBufferPlay(g_pulTxBuf, g_ulSize, BufferCallback);
    }
}

//*****************************************************************************
//
//! Configures the I2S peripheral for the given audio data format.
//!
//! \param ulSampleRate is the sample rate of the audio to be played in
//! samples per second.
//! \param usBitsPerSample is the number of bits in each audio sample.
//! \param usChannels is the number of audio channels, 1 for mono, 2 for stereo.
//!
//! This function configures the I2S peripheral in preparation for playing
//! and recording audio data of a particular format.
//!
//! \return None.
//
//*****************************************************************************
void
SoundSetFormat(unsigned long ulSampleRate, unsigned short usBitsPerSample,
               unsigned short usChannels)
{
    unsigned long ulFormat;
    unsigned long ulDMASetting;

    //
    // Save these values for use when configuring I2S.
    //
    g_usChannels = usChannels;
    g_usBitsPerSample = usBitsPerSample;

    I2SMasterClockSelect(I2S0_BASE, 0);

    //
    // Always use have the controller be an I2S Master.
    //
    ulFormat = I2S_CONFIG_FORMAT_I2S | I2S_CONFIG_CLK_MASTER;

    //
    // Mono or Stereo formats.
    //
    if(g_usChannels == 1)
    {
        if(g_usBitsPerSample == 8)
        {
            ulFormat |= I2S_CONFIG_WIRE_SIZE_8 | I2S_CONFIG_MODE_MONO |
                        I2S_CONFIG_SAMPLE_SIZE_8;
        }
        else if(g_usBitsPerSample == 16)
        {
            ulFormat |= I2S_CONFIG_WIRE_SIZE_16 | I2S_CONFIG_MODE_MONO |
                        I2S_CONFIG_SAMPLE_SIZE_16;
        }
        else if(g_usBitsPerSample == 24)
        {
            ulFormat |= I2S_CONFIG_WIRE_SIZE_24 | I2S_CONFIG_MODE_MONO |
                        I2S_CONFIG_SAMPLE_SIZE_24;
        }
        else
        {
            ulFormat |= I2S_CONFIG_WIRE_SIZE_32 | I2S_CONFIG_MODE_MONO |
                        I2S_CONFIG_SAMPLE_SIZE_32;
        }
    }
    else
    {
        if(g_usBitsPerSample == 8)
        {
            ulFormat |= I2S_CONFIG_WIRE_SIZE_8 | I2S_CONFIG_MODE_COMPACT_8 |
                        I2S_CONFIG_SAMPLE_SIZE_8;
        }
        else if(g_usBitsPerSample == 16)
        {
            ulFormat |= I2S_CONFIG_WIRE_SIZE_16 | I2S_CONFIG_MODE_COMPACT_16 |
                        I2S_CONFIG_SAMPLE_SIZE_16;
        }
        else if(g_usBitsPerSample == 24)
        {
            ulFormat |= I2S_CONFIG_WIRE_SIZE_24 | I2S_CONFIG_MODE_DUAL |
                        I2S_CONFIG_SAMPLE_SIZE_24;
        }
        else
        {
            ulFormat |= I2S_CONFIG_WIRE_SIZE_32 | I2S_CONFIG_MODE_DUAL |
                        I2S_CONFIG_SAMPLE_SIZE_32;
        }
    }

    //
    // Configure the I2S TX and RX format.
    //
    I2STxConfigSet(I2S0_BASE, ulFormat);
    ulFormat = (ulFormat & ~I2S_CONFIG_FORMAT_MASK) | I2S_CONFIG_FORMAT_LEFT_JUST;
    I2SRxConfigSet(I2S0_BASE, ulFormat);

    //
    // Internally both are masters but the pins may not be driven out.
    //
    I2SMasterClockSelect(I2S0_BASE, I2S_TX_MCLK_INT | I2S_RX_MCLK_INT);

    //
    // Set the MCLK rate and save it for conversion back to sample rate.
    // The multiply by 8 is due to a 4X oversample rate plus a factor of two
    // since the data is always stereo on the I2S interface.
    //
    g_ulSampleRate = SysCtlI2SMClkSet(0, ulSampleRate * usBitsPerSample * 8);

    //
    // Convert the MCLK rate to sample rate.
    //
    g_ulSampleRate = g_ulSampleRate/(usBitsPerSample * 8);

    //
    // Configure the I2S TX DMA channel to use high priority burst transfer.
    //
    uDMAChannelAttributeEnable(UDMA_CHANNEL_I2S0TX,
                               (UDMA_ATTR_USEBURST |
                                UDMA_ATTR_HIGH_PRIORITY));

    //
    // Set the DMA channel configuration.
    //
    if(g_usChannels == 1)
    {
        //
        // Handle Mono formats.
        //
        if(g_usBitsPerSample == 8)
        {
            //
            // The transfer size is 8 bits from the TX buffer to the TX FIFO.
            //
            ulDMASetting = UDMA_SIZE_8 | UDMA_SRC_INC_8 |
                           UDMA_DST_INC_NONE | UDMA_ARB_2;
        }
        else
        {
            //
            // The transfer size is 16 bits from the TX buffer to the TX FIFO.
            //
            ulDMASetting = UDMA_SIZE_16 | UDMA_SRC_INC_16 |
                           UDMA_DST_INC_NONE | UDMA_ARB_2;
        }
    }
    else
    {
        //
        // Handle Stereo formats.
        //
        if(g_usBitsPerSample == 8)
        {
            //
            // The transfer size is 16 bits(stereo 8 bits) from the TX buffer
            // to the TX FIFO.
            //
            ulDMASetting = UDMA_SIZE_16 | UDMA_SRC_INC_16 |
                           UDMA_DST_INC_NONE | UDMA_ARB_2;
        }
        else
        {
            //
            // The transfer size is 32 bits(stereo 16 bits) from the TX buffer
            // to the TX FIFO.
            //
            ulDMASetting = UDMA_SIZE_32 | UDMA_SRC_INC_32 |
                           UDMA_DST_INC_NONE | UDMA_ARB_2;
        }
    }

    //
    // Configure the DMA settings for this channel.
    //
    uDMAChannelControlSet(UDMA_CHANNEL_I2S0TX | UDMA_PRI_SELECT, ulDMASetting);
    uDMAChannelControlSet(UDMA_CHANNEL_I2S0TX | UDMA_ALT_SELECT, ulDMASetting);
}

//*****************************************************************************
//
//! Returns the current sample rate.
//!
//! This function returns the sample rate that was set by a call to
//! SoundSetFormat().  This is needed to retrieve the exact sample rate that is

⌨️ 快捷键说明

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