📄 i2saudio.cpp
字号:
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
(
ULONG ulRightVolume,
ULONG ulLeftVolume,
ULONG ulChannel
)
{
UCHAR ucRightDacVolume, ucLeftDacVolume;
ULONG ulRightDacVolume, ulLeftDacVolume;
UCHAR ulRightDacReg, ulLeftDacReg;
//
// If We are not using i2s volume control just return.
//
if(!m_bUseI2SVolumeControl)
return(MMSYSERR_NOERROR);
if(m_ulCodec == 4228)
{
//
// Calculate the left and right volume for the 4228.
//
ulRightDacVolume = 181 - ( ( 181 * ( ulRightVolume>>16 )) / 0xFFFF );
ucRightDacVolume = (UCHAR) ulRightDacVolume;
ulLeftDacVolume = 181 - ( ( 181 * ( ulLeftVolume>>16 )) / 0xFFFF );
ucLeftDacVolume = (UCHAR) ulLeftDacVolume;
ulRightDacReg = CS4228_DAC1_VOL;
ulLeftDacReg = CS4228_DAC2_VOL;
}
else
{
//
// Calculate the left and right volume for the 4271.
//
ulRightDacVolume = 90 - ( ( 90 * ( ulRightVolume>>16 )) / 0xFFFF );
ucRightDacVolume = (UCHAR) ulRightDacVolume;
ulLeftDacVolume = 90 - ( ( 90 * ( ulLeftVolume>>16 )) / 0xFFFF );
ucLeftDacVolume = (UCHAR) ulLeftDacVolume;
ulRightDacReg = CS4271_DACA_VOL;
ulLeftDacReg = CS4271_DACB_VOL;
}
if(m_bTwoWire )
{
//
// Write the codec registers.
//
EnterCriticalSection( &m_CriticalSection);
WriteCodecReg(ulRightDacReg, ucRightDacVolume);
WriteCodecReg(ulLeftDacReg, ucLeftDacVolume);
LeaveCriticalSection( &m_CriticalSection);
}
else
{
//
// Write the codec registers.
//
EnterCriticalSection( &m_CriticalSection);
SetSPIToI2S(m_ulCodec);
WriteCodecRegSPI(ulRightDacReg, ucRightDacVolume);
WriteCodecRegSPI(ulLeftDacReg, ucLeftDacVolume);
SetSPIToPS2(m_ulCodec);
LeaveCriticalSection( &m_CriticalSection);
}
return (MMSYSERR_NOERROR);
}
//****************************************************************************
// I2SCodec::GetDmaPort
//****************************************************************************
// Returns the port type to the dma engine.
//
//
ULONG I2SCodec::GetDmaPort(void)
{
return PRALLOC_I2S1;
}
//****************************************************************************
// I2SCodec::WriteCodecReg
//****************************************************************************
// ucRegAddr - CS4228 Register Address.
// usRegValue - CS4228 Register Value.
//
MMRESULT I2SCodec::WriteCodecReg(UCHAR ucRegAddr, UCHAR ucRegValue)
{
ULONG uiVal, uiDDR;
unsigned char ucData, ucIdx, ucBit;
ULONG ulTimeout;
FUNC_I2S
(
(
L"WriteCodecReg: Reg = 0x%02x, Value = 0x%02x\n",
ucRegAddr,
ucRegValue
)
);
//
// Read the current value of the GPIO data and data direction registers.
//
uiVal = *GPIO_PGDR;
uiDDR = *GPIO_PGDDR;
//
// If the GPIO pins have not been configured since reset, the data
// and clock lines will be set as inputs and with data value of 0.
// External pullup resisters are pulling them high.
// Set them both high before configuring them as outputs.
//
uiVal |= (GPIOG_EEDAT | GPIOG_EECLK);
*GPIO_PGDR = uiVal;
//
// Delay to meet the EE Interface timing specification.
//
DelayuS( EE_DELAY_USEC );
//
// Configure the EE data and clock lines as outputs.
//
uiDDR |= (GPIOG_EEDAT | GPIOG_EECLK);
*GPIO_PGDDR = uiDDR;
//
// Delay to meet the EE Interface timing specification.
//
DelayuS( EE_DELAY_USEC );
//
// Drive the EE data line low. Since the EE clock line is currently
// high, this is the start condition.
//
uiVal &= ~GPIOG_EEDAT;
*GPIO_PGDR = uiVal;
//
// Delay to meet the EE Interface timing specification.
//
DelayuS( EE_DELAY_USEC );
//
// Drive the EE clock line low.
//
uiVal &= ~GPIOG_EECLK;
*GPIO_PGDR = uiVal;
//
// Delay to meet the EE Interface timing specification.
//
DelayuS( EE_DELAY_USEC );
//
// Loop through the three bytes which we will send.
//
for(ucIdx = 0; ucIdx < 3; ucIdx++)
{
//
// Get the appropriate byte based on the current loop iteration.
//
if(ucIdx == 0)
{
//
// Since this is a write operation, we set d0 of the address
// which is the r/w bit.
//
ucData = (UCHAR)CS4228_DEV_ADDRESS;
}
else if(ucIdx == 1)
{
ucData = ucRegAddr;
}
else
{
ucData = ucRegValue;
}
//
// Loop through the 8 bits in this byte.
//
for(ucBit = 0; ucBit < 8; ucBit++)
{
//
// Set the EE data line to correspond to the most significant bit
// of the data byte.
//
if(ucData & 0x80)
{
uiVal |= GPIOG_EEDAT;
}
else
{
uiVal &= ~GPIOG_EEDAT;
}
*GPIO_PGDR = uiVal;
//
// Delay to meet the EE Interface timing specification.
//
DelayuS( EE_DELAY_USEC );
//
// Drive the EE clock line high.
//
*GPIO_PGDR = uiVal | GPIOG_EECLK;
//
// Delay to meet the EE Interface timing specification.
//
DelayuS( EE_DELAY_USEC );
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -