📄 hwctxt.cpp
字号:
//-----------------------------------------------------------------------------
//
// Function: BSPAudioInitSsi
//
// This function initializes the specified audio port for input/output.
//
// Parameters:
// bus - Audio SSI bus to use SSI1 / SSI2
// pSSI - Pointer to the SSI base.
//
// Returns:
// None.
//
//-----------------------------------------------------------------------------
void HardwareContext::BSPAudioInitSsi(AUDIO_BUS bus, PCSP_SSI_REG pSSI)
{
// These are the only SSI configuration parameters that are different
// between the network and I2S modes. We just default to setting up for
// network mode and then adjust the settings if I2S mode was actually
// selected.
UNREFERENCED_PARAMETER(bus);
UINT32 SSI_i2s_Mode = SSI_SCR_I2S_MODE_NORMAL;
UINT32 SSI_stcr_tsckp_Mode = SSI_STCR_TSCKP_RISING_EDGE;
UINT32 SSI_stcr_tfsi_Mode = SSI_STCR_TFSI_ACTIVE_HIGH;
UINT32 SSI_stccr_dc_Mode = 1;
UINT32 SSI_scr_net_Mode = SSI_SCR_NET_ENABLE;
UINT32 SSI_stcr_tfsl_Mode = SSI_STCR_TFSL_1BIT;
UINT32 SSI_stccr_wl = SSI_STCCR_WL_8BIT;
UINT8 size = sizeof(HWSAMPLE);
if (size == sizeof(INT16))
{
SSI_stccr_wl = SSI_STCCR_WL_16BIT;
}
else if (size == sizeof(INT32))
{
// The SSI only supports a maximum transfer size of 24 bits/word.
SSI_stccr_wl = SSI_STCCR_WL_24BIT;
}
// Reconfigure the SSI to use the I2S mode instead if that was what was
// selected.
//
// The required SSI configuration changes consist of the following:
//
// * Either I2S master/slave mode.
// * The transmit data clocked at the falling edge.
// * Transmit frame sync is active low.
// * Select 2 words/frame.
//
PMIC_AUDIO_BUS_PROTOCOL stereo = STEREO_DAC_BUS_MODE;
PMIC_AUDIO_BUS_PROTOCOL voice = VOICE_CODEC_BUS_MODE;
if (((stereo == I2S_MODE) && (pSSI == STEREO_DAC_SSI)) ||
((voice == I2S_MODE) && (pSSI == VOICE_CODEC_SSI)))
{
SSI_i2s_Mode = (((pSSI == m_pSSI1) && (BSP_SSI1_MASTER_BOOL)) ||
((pSSI == m_pSSI2) && (BSP_SSI2_MASTER_BOOL))) ?
SSI_SCR_I2S_MODE_MASTER : SSI_SCR_I2S_MODE_SLAVE;
SSI_stcr_tsckp_Mode = SSI_STCR_TSCKP_FALLING_EDGE;
SSI_stcr_tfsi_Mode = SSI_STCR_TFSI_ACTIVE_LOW;
SSI_stccr_dc_Mode = 1; // 2 words/frame
SSI_scr_net_Mode = SSI_SCR_NET_DISABLE; // disable NETWORK mode
SSI_stcr_tfsl_Mode = SSI_STCR_TFSL_1WORD; // 1-word long framesync
}
// Enable SSI clocks before we access the SSI registers.
DDKClockSetGatingMode((pSSI == m_pSSI1) ? DDK_CLOCK_GATE_INDEX_SSI1:
DDK_CLOCK_GATE_INDEX_SSI2,
DDK_CLOCK_GATE_MODE_ENABLE);
// Disable the SSI transmitter and receiver.
CLRREG32(&pSSI->SCR, CSP_BITFMASK(SSI_SCR_RE) | CSP_BITFMASK(SSI_SCR_TE));
// Also mask all transmitter and receiver timeslots until we are ready
// to begin a new audio I/O operation.
OUTREG32(&pSSI->STMSK, 0xffffffff);
OUTREG32(&pSSI->SRMSK, 0xffffffff);
// Next disable the SSI so that we can reconfigure the items that
// can only be changed when the SSI is disabled.
//
// We should do this as a separate write from disabling the SSI
// transmitter and receiver in order to give the SSI sufficient
// time to properly complete the previous operation.
CLRREG32(&pSSI->SCR, CSP_BITFMASK(SSI_SCR_SSIEN));
// Disable all SSI interrupts and DMA requests.
OUTREG32(&pSSI->SIER, 0);
// Also disable the transmit and receive FIFOs so that we can configure
// the DMA watermark levels later.
OUTREG32(&pSSI->STCR, 0);
OUTREG32(&pSSI->SRCR, 0);
// We can now begin reconfiguring the SSI for synchronous 4-wire mode.
// Since we are using synchronous mode, we only need to configure the
// SSI transmitter clock in the following stages and there is no need to
// separately set the SSI receiver clock configuration.
//
// The SSI is configured for I2S master/slave mode here or just "normal"
// mode if NETWORK_MODE was selected for the audio bus above. All clock
// configuration settings for the selected master/slave mode will be done
// later.
//
// The SSI SYS_CLK clock output is also disabled here since we do not need
// it (even if the SSI is operated in master mode since the slave device
// just needs to receive the framesync and bitclock signals).
//
// We never use 2-channel mode (where both FIFO0 and FIFO1 are active) so
// that is disabled here as well.
OUTREG32(&pSSI->SCR,
CSP_BITFVAL(SSI_SCR_CLK_IST, SSI_SCR_CLK_IST_HIGH) |
CSP_BITFVAL(SSI_SCR_TCH_EN, SSI_SCR_TCH_EN_2CHAN_OFF) |
CSP_BITFVAL(SSI_SCR_SYS_CLK_EN, SSI_SCR_SYS_CLK_EN_OFF) |
CSP_BITFVAL(SSI_SCR_I2S_MODE, SSI_i2s_Mode) |
CSP_BITFVAL(SSI_SCR_SYN, SSI_SCR_SYN_SYNC) |
CSP_BITFVAL(SSI_SCR_NET, SSI_scr_net_Mode));
// Next, continue with the configuration of the SSI transmitter for
// audio output/playback.
//
// To match the PMIC's capabilities, the SSI transmitter must transmit
// 16-bit words MSB-first. Only FIFO0 is needed for single channel
// operation but we leave it disabled until we are actually ready to
// start an audio I/O operation.
//
// Also, the SSI transmitter's clock and framesync signals are configured
// here for the slave mode of operation. We will change this later if it
// turns out that the SSI is to be operated in bus master mode.
//
// Note that we must configure the transmitter's clock settings even if we
// never use this SSI for audio playback because we are using synchronous
// mode where the receiver shares the same clock configuration as the
// transmitter.
OUTREG32(&pSSI->STCR,
CSP_BITFVAL(SSI_STCR_TXBIT0, SSI_STCR_TXBIT0_LSB_ALIGNED) |
CSP_BITFVAL(SSI_STCR_TFEN1, SSI_STCR_TFEN1_DISABLE) |
CSP_BITFVAL(SSI_STCR_TFEN0, SSI_STCR_TFEN0_DISABLE) |
CSP_BITFVAL(SSI_STCR_TFDIR, SSI_STCR_TFDIR_EXTERNAL) |
CSP_BITFVAL(SSI_STCR_TXDIR, SSI_STCR_TXDIR_EXTERNAL) |
CSP_BITFVAL(SSI_STCR_TSHFD, SSI_STCR_TSHFD_MSB_FIRST) |
CSP_BITFVAL(SSI_STCR_TSCKP, SSI_stcr_tsckp_Mode) |
CSP_BITFVAL(SSI_STCR_TFSI, SSI_stcr_tfsi_Mode) |
CSP_BITFVAL(SSI_STCR_TFSL, SSI_stcr_tfsl_Mode) |
CSP_BITFVAL(SSI_STCR_TEFS, SSI_STCR_TEFS_EARLY)
);
// Now configure the SSI receiver for audio input/recording.
//
// To match the PMIC's capabilities, the SSI receiver must receive
// 16-bit words MSB-first. Only FIFO0 is needed for single channel
// operation but we leave it disabled until we are actually ready to
// start an audio I/O operation.
//
// Also, we skip configuring the SSI receiver's clock settings here because
// we're using synchronous mode and we've already configured the SSI's
// transmitter clock configuration above. The receiver will simply share
// the same clock configuration as the transmitter.
//
// Note that it is harmless to also configure the SSI receiver even if we
// never use this SSI for audio recording.
OUTREG32(&pSSI->SRCR,
CSP_BITFVAL(SSI_SRCR_RXBIT0, SSI_SRCR_RXBIT0_LSB_ALIGNED) |
CSP_BITFVAL(SSI_SRCR_RFEN1, SSI_SRCR_RFEN1_DISABLE) |
CSP_BITFVAL(SSI_SRCR_RFEN0, SSI_SRCR_RFEN0_DISABLE) |
CSP_BITFVAL(SSI_SRCR_RSHFD, SSI_SRCR_RSHFD_MSB_FIRST)
);
// Set the Receive FIFO empty and Transmit FIFO full watermark levels.
//
// We set the watermark levels for both FIFO0 and FIFO1 here even though
// we will only use FIFO0 because all of the watermark levels must be set
// to a valid value (regardless of whether the FIFO is used or not) in
// order for the SSI to operate properly.
OUTREG32(&pSSI->SFCSR,
CSP_BITFVAL(SSI_SFCSR_RFWM0, SSI_SFCSR_RX_WATERMARK) |
CSP_BITFVAL(SSI_SFCSR_TFWM0, SSI_SFCSR_TX_WATERMARK) |
CSP_BITFVAL(SSI_SFCSR_RFWM1, SSI_SFCSR_RX_WATERMARK) |
CSP_BITFVAL(SSI_SFCSR_TFWM1, SSI_SFCSR_TX_WATERMARK));
BOOL bSSI1 = BSP_SSI1_MASTER_BOOL;
BOOL bSSI2 = BSP_SSI2_MASTER_BOOL;
if (((pSSI == m_pSSI1) && bSSI1) ||
((pSSI == m_pSSI2) && bSSI2))
{
// First configure the Clock Control Module to route the correct
// system clock signal to the SSI.
#ifdef AUDIO_RECORDING_ENABLED
if (pSSI == VOICE_CODEC_SSI)
{
// We want a 16 kHz sampling rate from the SSI for the Voice CODEC.
//
// The calculation of the appropriate SSI clock divider constants
// is as follows:
//
// Ideal Sampling Rate = 16 kHz
// Oversampling Rate = 384
// Ideal MCLK Frequency = 16 kHz * 384 = 6.144 MHz
// Serial PLL Frequency = 220.1472 MHz
//
// SSI Divider = 220.1472 / 6.144 = 35.83125
// = 36 (rounded up)
//
// So that means we can set the predivider to divide-by-one (by
// just writing 0) and the postdivider to divide-by-thirty-six
// (which actually means writing a 35 to the postdivider control
// register).
DDKClockConfigBaud((pSSI == m_pSSI1) ? DDK_CLOCK_SIGNAL_SSI1 :
DDK_CLOCK_SIGNAL_SSI2,
(pSSI == m_pSSI1) ? SSI1_MASTER_CLOCK_SOURCE :
SSI2_MASTER_CLOCK_SOURCE,
35);
// The associated SSI internal clock divider constants are:
//
// Ideal Sampling Rate = 16 kHz
// Bits/Word = 16
// Words/Frame = 4
// Ideal Bit Clock Frequency = 16 kHz * 16 * 4 = 1.024 MHz
// SSI Internal Clock Frequency = 6.144 MHz (from above)
// SSI Internal Divider = 6.144 / 1.024 = 6
//
// An internal divider value of 6 can be achieved by setting the
// following:
//
// DIV2 = 0
// PSR = 0
// PM = 2
//
// We also set the following to configure for bits/word and
// words/frame:
//
// DC = 3 (for network mode with 4 words/frame)
// = 1 (for I2S mode with 2 words/frame)
// WL = 3 (for 8 bits/word)
// = 7 (for 16 bits/word)
// = 11 (for 24 bits/word)
//
OUTREG32(&pSSI->STCCR,
CSP_BITFVAL(SSI_STCCR_DIV2, SSI_STCCR_DIV2_BYPASS) |
CSP_BITFVAL(SSI_STCCR_PSR, SSI_STCCR_PSR_DIV8_BYPASS) |
CSP_BITFVAL(SSI_STCCR_WL, SSI_stccr_wl) |
CSP_BITFVAL(SSI_STCCR_DC, SSI_stccr_dc_Mode) |
CSP_BITFVAL(SSI_STCCR_PM, 2));
}
else
#endif
if (pSSI == STEREO_DAC_SSI)
{
// We want a 44.1 kHz sampling rate from the SSI for the Stereo DAC.
//
// The calculation of the appropriate SSI clock divider constants
// is done as follows:
//
// Ideal Sampling Rate = 44.1 kHz
// Oversampling Rate = 384
// Ideal MCLK Frequency = 44.1 kHz * 384 = 16.9344 MHz
// Serial PLL Frequency = 220.1472 MHz
//
// SSI Divider = 220.1472 / 16.9344 = 13
//
// So that means we can set the predivider to divide-by-one (by
// just writing 0) and the postdivider to divide-by-thirteen
// (which actually means writing a 12 to the postdivider control
// register).
//
// This will produce the exact 16.9344 MHz clock that we need
// as the input to the SSI.
DDKClockConfigBaud((pSSI == m_pSSI1) ? DDK_CLOCK_SIGNAL_SSI1 :
DDK_CLOCK_SIGNAL_SSI2,
(pSSI == m_pSSI1) ? SSI1_MASTER_CLOCK_SOURCE :
SSI2_MASTER_CLOCK_SOURCE,
12);
// The associated SSI internal clock divider constants are
// calculated as follows:
//
// Ideal Sampling Rate = 44.1 kHz
//
// For NETWORK mode only:
// Bits/Word = 16
// Words/Frame = 4
// Ideal Bit Clock Frequency = 44.1 kHz * 16 * 4
// = 2.8224 MHz
// SSI Internal Clock Frequency = 16.9344 MHz (from above)
// SSI Internal Divider = 16.9344 / 2.8224 = 6
//
// For I2S mode only:
// Bits/Word = 32
// Words/Frame = 2
// Ideal Bit Clock Frequency = 44.1 kHz * 32 * 2
// = 2.8224 MHz
// SSI Internal Clock Frequency = 16.9344 MHz (from above)
// SSI Internal Divider = 16.9344 / 2.8224 = 6
//
// The corresponding SSI internal divider settings are as follows:
//
// For both NETWORK and I2S modes:
// DIV2 = 0
// PSR = 0
// PM = 2
//
// We also set the following to configure for bits/word and
// either 4 or 2 words/frame:
//
// DC = 3 (for network mode with 4 words/frame)
// = 1 (for I2S mode 2 words/frame)
// WL = 3 (for 8 bits/word)
// = 7 (for 16 bits/word)
// = 11 (for 24 bits/word)
//
// Note that for the I2S mode, the word length is fixed at 32
// bits/word and the WL value only serves to indicate how many
// out of the 32 bits/word are actually valid.
OUTREG32(&pSSI->STCCR,
CSP_BITFVAL(SSI_STCCR_DIV2, SSI_STCCR_DIV2_BYPASS) |
CSP_BITFVAL(SSI_STCCR_PSR, SSI_STCCR_PSR_DIV8_BYPASS) |
CSP_BITFVAL(SSI_STCCR_WL, SSI_stccr_wl) |
CSP_BITFVAL(SSI_STCCR_DC, SSI_stccr_dc_Mode) |
CSP_BITFVAL(SSI_STCCR_PM, 2));
}
// Also set the SSI transmitter to use it's internal clock source to
// generate the bit clock and framesync signals for master mode.
SETREG32(&pSSI->STCR, CSP_BITFMASK(SSI_STCR_TXDIR));
SETREG32(&pSSI->STCR, CSP_BITFMASK(SSI_STCR_TFDIR));
}
else
{
// Configure the SSI transmit clock for slave mode operation where
// the internal divider and prescaler parameters are irrelevant. The
// key settings are DC to select words/frame and WL for bits/word to
// match the PMIC's configuration.
OUTREG32(&pSSI->STCCR,
CSP_BITFVAL(SSI_STCCR_DIV2, SSI_STCCR_DIV2_BYPASS) |
CSP_BITFVAL(SSI_STCCR_PSR, SSI_STCCR_PSR_DIV8_BYPASS) |
CSP_BITFVAL(SSI_STCCR_WL, SSI_stccr_wl) |
CSP_BITFVAL(SSI_STCCR_DC, SSI_stccr_dc_Mode) |
CSP_BITFVAL(SSI_STCCR_PM, 0));
// We have already configured the SSI transmitter to use an external
// clock and framesync so nothing needs to be done here.
}
#ifdef SSI_DEBUG
OUTREG32(&pSSI->STR, 0x1111);
#endif
// Leave the SSI in a disabled state until we are actually ready to perform
// audio playback or recording.
//
// Also note that we leave all of the transmit and receive timeslots masked
// at this time and only unmask the required timeslots when we call either
// BSPAudioStartSsiOutput() or BSPAudioStartSsiInput().
// Disable SSI clocks to minimize power consumption.
BSPSSIConfigGPIO(CSP_BASE_REG_PA_SSI2, TRUE);
#ifdef AUDIO_RECORDING_ENABLED
BSPSSIConfigGPIO(CSP_BASE_REG_PA_SSI1, TRUE);
#endif
DDKClockSetGatingMode((pSSI == m_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -