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

📄 i2saudio.cpp

📁 EP9315开发板的Wince6.0的BSP包文件
💻 CPP
📖 第 1 页 / 共 5 页
字号:
    // Open the WaveDev driver key.
    //
    RegOpenKeyEx
    ( 
        HKEY_LOCAL_MACHINE,
        TEXT("\\Drivers\\BuiltIn\\WaveDev"),
        0,
        0,
        &hKey
    ); 
    //
    // Read our codec type.
    //
    m_ulCodec = ReadRegistryValue(hKey, TEXT("I2SCodec"), 4228);

	{ 
		volatile ULONG * pulTempDR[]={ GPIO_PADR,GPIO_PBDR,GPIO_PCDR,GPIO_PDDR,GPIO_PEDR,GPIO_PFDR, GPIO_PGDR, GPIO_PHDR};
		volatile ULONG * pulTempDDR[]={ GPIO_PADDR,GPIO_PBDDR,GPIO_PCDDR,GPIO_PDDDR,GPIO_PEDDR,GPIO_PFDDR,GPIO_PGDDR,GPIO_PHDDR};
		
		dwResetPin=ReadRegistryValue(hKey, TEXT("ResetPinUsed"), -1);

		if( dwResetPin != (DWORD)-1 && dwResetPin <64 )
		{
			m_pdwResetGPIO_DR= pulTempDR[ dwResetPin>>3 ];   //do /8
			m_pdwResetGPIO_DDR=pulTempDDR[ dwResetPin>>3 ];

			m_cResetBit=0x1<<(dwResetPin & 0x7);  //do %8,

			m_bWithMuteHW= ReadRegistryValue(hKey, TEXT("WithMute"), 0);

			RETAILMSG(1, (TEXT("Audio reset pin 0x%x bit 0x%x mute %d \r\n"),
				dwResetPin>>3, m_cResetBit, m_bWithMuteHW   ));

			if( (dwResetPin>>3) ==7 ) {//HGPIO is used by IDE by default.

				HalWriteCommonReg(CSC_DEVCFG, DEVCFG_HONIDE, DEVCFG_HONIDE);
			}
		}
	}
    //
    // Read the registry entry to see if volume control is enabled.
    //
    m_bUseI2SVolumeControl = ReadRegistryValue(hKey, TEXT("UseI2SVolumeControl"), 1);

    //
    // Close the registry key.
    //
    RegCloseKey( hKey);


    if((m_ulCodec != 4228) && (m_ulCodec != 4271))
    {
        // Use a default.
        //
        m_ulCodec = 4228;
    }

    RETAILMSG(1, (TEXT("Audio configuring for CS%d\r\n"),m_ulCodec));

    //
    // Set the sample rate at 441Khz.  Need to set the sample rate in order to
    // talk to the CS4228.
    //
    mmRet = SetSampleRate(44100, 0);
    //
    // Set up the I2S audio to use the AC97 port EGPIO for secondary I2S 
    // channels.
    //
    HalWriteCommonReg
    (
        CSC_DEVCFG, 
        DEVCFG_I2SONSSP | DEVCFG_I2SONAC97,
        DEVCFG_I2SONAC97
    );

    //
    // Disable all transmit audio channels.
    // Disable all recieve audio channels.
    // Set the global configuration register to Disable PCLK to it.
    //
    *SAI_TX0_EN = *SAI_TX1_EN =* SAI_TX2_EN   = 0;
    *SAI_RX0_EN = *SAI_RX1_EN =* SAI_RX2_EN   = 0;
    *SAI_GCR                                  = 0;

    //
    // Initialize the SAI interface. 
    //
    *SAI_TX_CLKCFG = CLKCFG_MST | CLKCFG_TREL ;
    *SAI_RX_CLKCFG = CLKCFG_MST | CLKCFG_TREL | CLKCFG_NBCG ;
    //
    // Left justified, MSB first, Repeat zero if underflow.
    // Outputing zero's will cause the dac to mute.
    //
    *SAI_TX_LCR     = 0;
  
    //
    // Generate a Interrupt on Halfempty
    // (Don't think this makes a difference for DMA.)
    //
    *SAI_TX_CR     = TX_CR_TXUFIE;

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

    //
    // Left justified, MSB first.
    //
    *SAI_RX_LCR     = 0;

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

    //
    // 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;

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

    //
    // Reconfigure the SPI so that we can setup our codec
    //
	if( !m_bTwoWire )
		SetSPIToI2S(m_ulCodec);

    if(m_ulCodec == 4228)
    {
        //
        // 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 I2S mode.
        //
        WriteCodecReg
        (
            CS4228_SERIAL_MODE, 
            SERIAL_MODE_DCK_H32 | SERIAL_MODE_DMS_SLAVE | SERIAL_MODE_DDF_I2S_24BIT
        );
    }
    else
    {
		if( m_pdwResetGPIO_DR )
		{
			// For the 4271 (on the 930x boards), if m_pdwResetGPIO_DR is not NULL, reset is neccessary.
			// so we can bring it out of standalone mode and configure it.
			//
			HalWriteCommonReg ( m_pdwResetGPIO_DR, m_cResetBit,0x00 );
			HalWriteCommonReg ( m_pdwResetGPIO_DDR, m_cResetBit, m_cResetBit );
			Sleep(2);
			HalWriteCommonReg ( m_pdwResetGPIO_DR, m_cResetBit, m_cResetBit );

			Sleep(1);
		}
        //
        // Write to the control port, setting the enable control port bit
        // and the PDN bit - so that we can write to the control port...
        //
        WriteCodecReg(CS4271_MODE_CNTL2,0x03);
        //
        // Select slave, 24Bit I2S
        //
        WriteCodecReg(CS4271_MODE_CNTL, 0x01);
        //
        // Select 24Bit I2S
        //
        WriteCodecReg(CS4271_ADC_CNTL,0x10);
		//
		// Ummute and set volumes to mid-range
		//
	    WriteCodecReg(CS4271_DACA_VOL,0x40);

        WriteCodecReg(CS4271_DACB_VOL,0x40);
        //
        // Clear the PDN bit and bring the codec up with our changes
        //
        WriteCodecReg(CS4271_MODE_CNTL2,0x02);
    }
    // Done with setup, configure SPI to handle PS2
    //
	if( !m_bTwoWire )
		SetSPIToPS2(m_ulCodec);

	if( m_bWithMuteHW && m_pdwResetGPIO_DR)
	{
		HalWriteCommonReg ( m_pdwResetGPIO_DDR, m_cResetBit,m_cResetBit );
		HalWriteCommonReg ( m_pdwResetGPIO_DR, m_cResetBit,m_cResetBit );
	}

    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++)
            // {

⌨️ 快捷键说明

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