cancel
Showing results for 
Search instead for 
Did you mean: 

Audio noob question

Pavel A.
Evangelist III

Preparing for some audio related project....

If I understand correctly, I2S can transmit and receive simultaneously like SPI.

Is this mode used practically? Are there codecs that can simultaneously transmit via I2S (generate sound) and receive digitized data (from a mic)?

Or is this typically done using two separate I2S or SAI interfaces?

13 REPLIES 13

Yes and no.

I found it easier to use another I2S for the MCLK (@Community member​  wasn't that your great idea?), it's usually only setting 2 registers and the GPIO.

And you can also use the extra "I2S_CKIN" external clock as source which might not be available for the timer (unless in external clock mode, but then that's an extra input for routing).

/* SPI6 / I2S6 is in domain 3
 *	-> canNOT be used for DMA to non-D3 RAM
 *	BUT we can use it as independent
 *		MCLK source
 */
void I2S6_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = { 0 };
	uint32_t u32I2S6Div = 0;
#if( 0 )
	RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = { 0 };
 
	/* init peripheral clock */
	//PeriphClkInitStruct.Spi6ClockSelection = RCC_SPI6CLKSOURCE_PIN;
	PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SPI6;
	PeriphClkInitStruct.Spi6ClockSelection = RCC_SPI6CLKSOURCE_PLL2;
	if( HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK ) Error_Handler_FL(__FILE__, __LINE__);
#endif
 
	/* I2S6 clock enable */
	__HAL_RCC_SPI6_CLK_ENABLE();
 
	__HAL_RCC_GPIOA_CLK_ENABLE();
 
	/* I2S6 GPIO Configuration
		PA3		------> I2S6_MCK
	*/
	GPIO_InitStruct.Pin 		= I2S6_MCLK_Pin;
	GPIO_InitStruct.Mode 		= GPIO_MODE_AF_PP;
	GPIO_InitStruct.Pull 		= GPIO_NOPULL;
	GPIO_InitStruct.Speed 		= GPIO_SPEED_FREQ_HIGH;
	GPIO_InitStruct.Alternate 	= GPIO_AF5_SPI6;
	HAL_GPIO_Init(I2S6_MCLK_GPIO_Port, &GPIO_InitStruct);
 
/* I2S6 = SPI6 register settings
 *	to get MCLK output
 *	clock input is I2S_CKPIN, set with RCC
 */
	SPI6->CR1 = 0;			/* unused for I2S */
	SPI6->CR2 = 0;			/* unused for I2S */
 
/* I2SCFGR: configuration register
 *	most important settings here
 * 	DMA and I2S enable are set when started
 *	MCKOE		= 1		MCLK is ON, on/off is done with SPI_CR1_SPE
 * 	ODD			= 0 	unused, for divider I2SDIV
 * 	I2SDIV		= 1 	divider, start with 1 -> 25.6 MHz
 * 	DATFMT		= 0 	data alignment - don't care
 * 	WSINV		= 0 	LRCK hi/lo - don't care
 * 	FIXCH		= 0 	data length - don't care
 * 	CKPOL 		= 1 	clock polarity ?
 *	CHLEN 		= 1		data length - don't care ?
 * 	DATLEN 		= 10 	32-bit - don't care ?
 * 	PCMSYNC		= 0 	PCM short / long sync - don't care
 *	I2SSTD 		= 00	standard - don't care
 *	I2SCFG 		= 011	master RX - master is must to turn on MCLK
 *	I2SMOD 		= 1 	I2S instead of SPI
 */
 
/* I2SCFGR: configuration register */
	SPI6->I2SCFGR = I2S_CFGR_MCLK_OUT_ONLY;
 
/* get I2S6 MCLK frequency */
	if( 	 __HAL_RCC_GET_SPI6_SOURCE() == RCC_SPI6CLKSOURCE_PIN )  u32I2S6Mclk = RCC_VCO_CLOCK_AUDIO_200K;
	else if( __HAL_RCC_GET_SPI6_SOURCE() == RCC_SPI6CLKSOURCE_PLL2 ) u32I2S6Mclk = RCC_PLL2_CLOCK_AUDIO;
	else if( __HAL_RCC_GET_SPI6_SOURCE() == RCC_SPI6CLKSOURCE_PLL3 ) u32I2S6Mclk = RCC_PLL3_CLOCK_AUDIO;
	else u32I2S6Mclk = 0;
	u32I2S6Div = (SPI6->I2SCFGR & SPI_I2SCFGR_I2SDIV) >> SPI_I2SCFGR_I2SDIV_Pos;
	if( u32I2S6Div == 0 ) u32I2S6Div = 1;
	u32I2S6Mclk /= (2 * u32I2S6Div);
 
/* I2S6 MCLK enable - later with SAI DMA start */
#if( 1 )
/* DEBUG */
	MCLK_I2S6_ON;
#endif
}

Pavel A.
Evangelist III

Thank you a lot, guys. There's quite a bit of new info for me to digest.

Piranha
Chief II

Several ST boards (for example, STM32F769I-DISCO) use WM8994 codec. That is a relatively high-performance, complex and expensive codec.

Thanks. Though for a beginner like me, simpler is better.