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