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

📄 i2saudio.cpp

📁 EP931X系列的WinCE声卡驱动源代码
💻 CPP
📖 第 1 页 / 共 4 页
字号:
    *SAI_RX_LCR     = 0;

    //
    // Generate a Interrupt on Half full
    // (Don't think this makes a difference for DMA.)
    //
    *SAI_RX_CR     = RX_CR_RXHALFFULL;

    //
    // Receive word length. I don't think this matters in Left Justified
    // mode.
    //
    *SAI_RX_WL      = WL_24BIT;

    //
    // Set the global configuration register to enable PCLK to it.
    //
    *SAI_GCR        = GCR_PCLK;


    //
    // Configure EGPIO7 as an output and set it.  This selects
    // I2S codec as the device on the SSP output instead of 
    // the serial flash.
    // 
    if(!m_bTwoWire)
    {
        ulTemp = *GPIO_PADDR;
        *GPIO_PADDR = ulTemp | 0x80;

        ulTemp = *GPIO_PADR;
        *GPIO_PADR = ulTemp & ~0x80;
    }

    //
    // Enable the SAI.
    //
    //*SAI_TX0_EN     = 1;

    //
    // Get the Performance counter.
    //
    bRet = QueryPerformanceFrequency(&m_PerfFreq);    
    ASSERT(bRet);


    //
    // Sleep for a couple milliseconds to wait for the codec to power up.
    //
    Sleep(4);    

    if(m_bTwoWire)
    {


        //
        // Unmute the three DACs. Perform auto mute if the samples are zero.
        //
        WriteCodecReg(CS4228_DAC_MUTE2, MUTE2_MUTEZ);

        //
        // Set up clock ratios. MCLK = 4 * SCLK
        //                      MCLK = 4 * 64 *LRCLK = 128
        //
        WriteCodecReg(CS4228_CLOCK_MODE, CLOCK_MODE_BASERATE_256);

        //
        // Power up the chip - all dacs and the adc powered up.
        //
        WriteCodecReg(CS4228_CHIP_CNTL, CHIP_CNTL_NDIGPN);

        //
        // Unmute the three DACs
        //
        WriteCodecReg(CS4228_DAC_MUTE1, 0);
    
        //
        // Set ADC serial mode.
        //
        // SCLK = 64 * LRCLK 
        // Put the EP9312 as the master.
        // Put in 24 bit left justified mode.
        //
        WriteCodecReg
        (
            CS4228_SERIAL_MODE, 
            SERIAL_MODE_DCK_B64 | SERIAL_MODE_DMS_SLAVE | SERIAL_MODE_DDF_LEFT_24BIT
        );


        ReadAllCodecReg();
    }
    else
    {
        ulTemp      =   *GPIO_PADR;
        *GPIO_PADR = ulTemp | 0x80;

        SetSPIToI2S();

        //
        // Unmute the three DACs. Perform auto mute if the samples are zero.
        //
        WriteCodecRegSPI(CS4228_DAC_MUTE2, MUTE2_MUTEZ);

        //
        // Set up clock ratios. MCLK = 4 * SCLK
        //                      MCLK = 4 * 64 *LRCLK = 128
        //
        WriteCodecRegSPI(CS4228_CLOCK_MODE, CLOCK_MODE_BASERATE_256);

        //
        // Power up the chip - all dacs and the adc powered up.
        //
        WriteCodecRegSPI(CS4228_CHIP_CNTL, CHIP_CNTL_NDIGPN);

        //
        // Unmute the three DACs
        //
        WriteCodecRegSPI(CS4228_DAC_MUTE1, 0);
    
        //
        // Set ADC serial mode.
        //
        // SCLK = 64 * LRCLK 
        // Put the EP9312 as the master.
        // Put in 24 bit left justified mode.
        //
        WriteCodecRegSPI
        (
            CS4228_SERIAL_MODE, 
            SERIAL_MODE_DCK_B64 | SERIAL_MODE_DMS_SLAVE | SERIAL_MODE_DDF_LEFT_24BIT
        );

        SetSPIToPS2();
    }

    FUNC_I2S((L"-I2SCodec::Initialize\r\n"));
    return (MMSYSERR_NOERROR);
}


//****************************************************************************
// I2SCodec::SetRecordSampleRate
//****************************************************************************
// Sets the Record Sample Rate.
//
// ulFreq       - Sample Rate
// ulChannel    - Setting the Sample Rate for a specific channel.
//

MMRESULT  I2SCodec::SetRecordSampleRate(ULONG ulFrequency, ULONG ulChannel)
{
    //
    // Check to see if we are playing audio.
    //
    if( m_ulCurrentFreq != ulFrequency)
    {
        return MMSYSERR_ALLOCATED;
    }

    return (MMSYSERR_NOERROR);
}

//****************************************************************************
// I2SCodec::SetPlaybackSampleRate
//****************************************************************************
// Sets the Sample Rate.
//
// ulFreq       - Sample Rate
// ulChannel    - Setting the Sample Rate for a specific channel.
//
MMRESULT  I2SCodec::SetPlaybackSampleRate(ULONG ulFrequency, ULONG ulChannel) 
{
    //
    // Check to see if we are playing audio.
    //
    if( m_ulCurrentFreq != ulFrequency)
    {
        return MMSYSERR_ALLOCATED;
    }

    return (MMSYSERR_NOERROR);
}




//****************************************************************************
// I2SCodec::SetSampleRate
//****************************************************************************
// Sets the Sample Rate.
//
// ulFreq       - Sample Rate
// ulChannel    - Setting the Sample Rate for a specific channel.
//
MMRESULT I2SCodec::SetSampleRate(ULONG ulFrequency, ULONG ulChannel)
{
    ULONG ulRequestedMClkFreq;
    ULONG ulMClkFreq1, ulMClkFreq2;
    ULONG ulI2SDiv, ulI2SDiv1, ulI2SDiv2;

    FUNC_I2S((L"+I2SCodec::SetSampleRate\r\n"));
    
    ulRequestedMClkFreq = ( ulFrequency * m_ulM2SClock * m_ulS2LRClock);


    CalculateClosestFreq
    (
        PLL1_CLOCK, 
        ulRequestedMClkFreq,
        &ulMClkFreq1,
        &ulI2SDiv1
    );
    CalculateClosestFreq
    (
        PLL2_CLOCK, 
        ulRequestedMClkFreq,
        &ulMClkFreq2,
        &ulI2SDiv2
    );

    //
    // See which is closer, MClk rate 1 or MClk rate 2.
    //
    if(abs(ulMClkFreq1 - ulRequestedMClkFreq) < abs(ulMClkFreq2 -ulRequestedMClkFreq))
    {
        ulI2SDiv       = ulI2SDiv1;
        m_ulActualFreq = ulMClkFreq1/ (m_ulM2SClock * m_ulS2LRClock);
    }
    else
    {
        ulI2SDiv = ulI2SDiv2 | I2SDIV_PSEL;;
        m_ulActualFreq = ulMClkFreq1 / (m_ulM2SClock * m_ulS2LRClock);
    }

    //
    // Calculate the new I2S rate.
    //
    HalWriteCommonReg
    (
        CSC_I2SDIV, 
        0xFFFFFFFF,
        ulI2SDiv |I2SDIV_SENA |  I2SDIV_ORIDE | I2SDIV_SPOL| 
        I2SDIV_LRDIV_64 | I2SDIV_SDIV |  I2SDIV_MENA | I2SDIV_ESEL
    );

    //
    // Save off the requested frequency.
    //
    m_ulCurrentFreq = ulFrequency;

    FUNC_I2S((L"-I2SCodec::SetSampleRate\r\n"));
    return (MMSYSERR_NOERROR);
}



//****************************************************************************
// CalculateClosestFreq
//****************************************************************************
// CalculateClosestFreq
// 
//   ulPLLFreq           -  PLL output Frequency (Mhz)
//   ulRequestedMClkFreq -  Requested Video Clock Frequency.
//   pulActualMClkFreq   -  Returned Actual Video Rate.
//   pulI2SDiv           -  Video Divider register.
//
//   Return            0 - Failure
//                     1 - Success
//
static int CalculateClosestFreq
(
    ULONG   ulPLLFreq, 
    ULONG   ulRequestedMClkFreq,
    PULONG  pulActualMClkFreq,
    PULONG  pulI2SDiv
)
{
    
    ULONG   ulLower;
    ULONG   ulUpper;
    ULONG   ulDiv;
    int     x;

    //
    // Calculate the closest divisor.
    //
    ulDiv =  (ulPLLFreq * 2)/ ulRequestedMClkFreq;

    for(x = 1; x < sizeof(I2SDivTable)/sizeof(DIV_TABLE); x++)
    {

        //
        // Calculate the next greater and lower value.
        //
        ulLower = I2SDivTable[x - 1].ulTotalDiv;     
        ulUpper = I2SDivTable[x].ulTotalDiv;     

        //
        // Check to see if it is in between the two values.
        //
        if(ulLower <= ulDiv && ulDiv < ulUpper)
        {
            break;
        }
    }

    //
    // Return if we did not find a divisor.
    //
    if(x == sizeof(I2SDivTable)/sizeof(DIV_TABLE))
    {
        *pulActualMClkFreq  = 0;
        *pulI2SDiv          = 0;
        return 0;
    }

    //
    // See which is closer, the upper or the lower case.
    //
    if(ulUpper * ulRequestedMClkFreq - ulPLLFreq * 2 >  
      ulPLLFreq * 2 - ulLower * ulRequestedMClkFreq)
    {
        x-=1;
    }
    *pulActualMClkFreq  = (ulPLLFreq * 2)/ I2SDivTable[x].ulTotalDiv;
    *pulI2SDiv          = I2SDivTable[x].ulI2SDiv;
    return(1);
}


//****************************************************************************
// I2SCodec::StartPlayBack
//****************************************************************************
// Starts the Playback
//
// 
//
MMRESULT  I2SCodec::StartPlayback(ULONG ulChannel)
{
    //int i;
    //if(!m_bRecordOpened)
    //{
    //    *SAI_GCR        = GCR_PCLK;
    //}

    switch(ulChannel)
    {
        case 0:
            // for(i = 0; i<8 ;i++)
            // {
            //    *SAI_TX0_LEFT   = 0;
            //    *SAI_TX0_RIGHT  = 0; 
            // }
            // DelayuS(160);
            *SAI_TX0_EN     = 1;
            break;
        case 1:
            // for(i = 0; i<8 ;i++)
            // {
            //    *SAI_TX1_LEFT   = 0;
            //    *SAI_TX1_RIGHT  = 0; 
            //    *SAI_TX1_EN     = 1;
            // }
            // DelayuS(160);
            *SAI_TX1_EN     = 1;
            break;
        case 2:
            // for(i = 0; i<8 ;i++)
            // {
            //    *SAI_TX2_LEFT   = 0;
            //    *SAI_TX2_RIGHT  = 0; 
            //     *SAI_TX2_EN     = 1;
            // }
            // DelayuS(160);
            *SAI_TX2_EN     = 1;
            break;
    }

    return (MMSYSERR_NOERROR);
}

//****************************************************************************
// I2SCodec::StartRecord
//****************************************************************************
// 
// 
//
MMRESULT  I2SCodec::StartRecord(ULONG ulChannel)
{
    //if(!m_bPlaybackOpened)
    //{
    //    *SAI_GCR        = GCR_PCLK;
    //}
    switch(ulChannel)
    {
        case 0:
            *SAI_RX0_EN     = 1;
            break;
        case 1:
            *SAI_RX1_EN     = 1;
            break;
        case 2:
            *SAI_RX2_EN     = 1;
            break;
    }

    return (MMSYSERR_NOERROR);
}

//****************************************************************************
// I2SCodec::StopPlayBack
//****************************************************************************
// 
// 
//
MMRESULT  I2SCodec::StopPlayback(ULONG ulChannel)
{
    switch(ulChannel)
    {
        case 0:
            *SAI_TX0_EN     = 0;
            break;
        case 1:
            *SAI_TX1_EN     = 0;
            break;
        case 2:
            *SAI_TX2_EN     = 0;
            break;
    }

    // DelayuS(160);
    // if(!m_bRecordOpened)
    // {
    //    *SAI_GCR        = 0;
    // }
    return (MMSYSERR_NOERROR);
}

//****************************************************************************
// I2SCodec::StopRecord
//****************************************************************************
// 
// 
//
MMRESULT  I2SCodec::StopRecord(ULONG ulChannel)
{
    switch(ulChannel)
    {
        case 0:
            *SAI_RX0_EN     = 0;
            break;
        case 1:
            *SAI_RX1_EN     = 0;
            break;
        case 2:
            *SAI_RX2_EN     = 0;
            break;
    }

    // if(!m_bPlaybackOpened)
    // {
    //     *SAI_GCR        = 0;
    // }
    return (MMSYSERR_NOERROR);
}


//****************************************************************************
// I2SCodec::SetVolume
//****************************************************************************
// 
// 
//
MMRESULT   I2SCodec::SetVolume
(

⌨️ 快捷键说明

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