📄 i2saudio.cpp
字号:
// 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 + -