2017-07-04 12:28 AM
Hello! Is it possible to use single I2S port to read from two external stereo audio ADC ICS?
I want to obtain 4-channel audio signal without any time offset.
My setup is:
1) STM32F407 x 1pcs
2) PCM1808 24bit ADC 2 channels x 2pcs
My idea is to configure
I2S2 as master full-duplex receiver with master clock generation.
Connect all clock signals from mater I2S2 to two slaves PCM1808 in parallel
Then configure
I2S2_EXT as I2S_MODE_SLAVE_RX
(by default STM32HAL firmware makes
I2S2_EXT =-
TX if I2S2 is set to RX)
Is there any problem with this approach?
Reference manual rm0090 and HAL i2s driver source code states that 'Both I2Sx and I2Sx_ext can be configured as transmitters or receivers.'
Another way is to use two I2S ports, but i am unsure if they will run synchronously. Maybe I can use I2S2 master with clock generation and I2S3 as slave. Then all I2S2 clock signals will be connected to pair of PCM1808 ICs and I2S3 input.
Please tell me which way is better. Currently I prefer first solution, although I did not tested it (using I2S2 receiver with one additional line I2S2_EXT as I2S_MODE_SLAVE_RX).
Thank for your attention.
2017-07-13 10:22 AM
I am still trying to solve this problem. I2S2 and I2S2ext must simultaneously receive data to two DMA buffers, without transmitting. Here is preliminary code copy/pasted altered from HAL library to accomplish this task:
hi2s2.Instance = SPI2;
hi2s2.Init.Mode = I2S_MODE_MASTER_RX; hi2s2.Init.Standard = I2S_STANDARD_PHILIPS; hi2s2.Init.DataFormat = I2S_DATAFORMAT_24B; hi2s2.Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE; hi2s2.Init.AudioFreq = I2S_AUDIOFREQ_8K; hi2s2.Init.CPOL = I2S_CPOL_LOW; hi2s2.Init.ClockSource = I2S_CLOCK_PLL; hi2s2.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_ENABLE;GPIO_InitTypeDef GPIO_InitStruct;
__HAL_RCC_SPI2_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_2; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Alternate = GPIO_AF6_I2S2ext; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Alternate = GPIO_AF5_SPI2; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Alternate = GPIO_AF5_SPI2; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); hdma_spi2_rx.Instance = DMA1_Stream3; hdma_spi2_rx.Init.Channel = DMA_CHANNEL_0; hdma_spi2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_spi2_rx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_spi2_rx.Init.MemInc = DMA_MINC_ENABLE; hdma_spi2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; hdma_spi2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; hdma_spi2_rx.Init.Mode = DMA_CIRCULAR; hdma_spi2_rx.Init.Priority = DMA_PRIORITY_LOW; hdma_spi2_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; if (HAL_DMA_Init(&hdma_spi2_rx) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); }__HAL_LINKDMA(&hi2s2,hdmarx,hdma_spi2_rx);
hdma_i2s2_ext_tx.Instance = DMA1_Stream4; hdma_i2s2_ext_tx.Init.Channel = DMA_CHANNEL_2; hdma_i2s2_ext_tx.Init.Direction =DMA_PERIPH_TO_MEMORY
;//DMA_MEMORY_TO_PERIPH; hdma_i2s2_ext_tx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_i2s2_ext_tx.Init.MemInc = DMA_MINC_ENABLE; hdma_i2s2_ext_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; hdma_i2s2_ext_tx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; hdma_i2s2_ext_tx.Init.Mode = DMA_CIRCULAR; hdma_i2s2_ext_tx.Init.Priority = DMA_PRIORITY_LOW; hdma_i2s2_ext_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; if (HAL_DMA_Init(&hdma_i2s2_ext_tx) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); }__HAL_LINKDMA(&hi2s2,hdmatx,hdma_i2s2_ext_tx);
i removed some HAL functions here and directly write to registers to ensure both channels are RX
uint32_t aa; aa=0x00000317; // prescaler WRITE_REG(hi2s2.Instance->I2SPR,aa); aa=0x00000B03; //master receive
WRITE_REG(hi2s2.Instance->I2SCFGR,aa); aa=0x00000002; WRITE_REG(I2SxEXT(hi2s2.Instance)->I2SPR,aa); aa=0x00000903; //slave receive
WRITE_REG(I2SxEXT(hi2s2.Instance)->I2SCFGR,aa);two buffers i2s_rx1/2
(10 32-bit elements each).
hi2s2.pTxBuffPtr = (uint16_t *)&i2s_rx2;
hi2s2.pRxBuffPtr = (uint16_t *)&i2s_rx1; hi2s2.TxXferSize = 20;(20 because receiving 24bit over 32bit)
hi2s2.TxXferCount = 20;ALTHOUGH it is called TXfer i use it for RX (HAL generated names)
hi2s2.RxXferSize = 20; hi2s2.RxXferCount = 20;hi2s2.ErrorCode = HAL_I2S_ERROR_NONE; // seems have no effect
hi2s2.State = HAL_I2S_STATE_BUSY_RX; __HAL_I2S_CLEAR_OVRFLAG(&hi2s2);HAL_DMA_Start_IT(hi2s2.hdmarx, (uint32_t)&hi2s2.Instance->DR, (uint32_t)&i2s_rx1, hi2s2.RxXferSize);
SET_BIT(hi2s2.Instance->CR2,SPI_CR2_RX
DMAEN); HAL_DMA_Start_IT(hi2s2.hdmatx, (uint32_t)&I2SxEXT(hi2s2.Instance)->DR,(uint32_t)&i2s_rx2, hi2s2.TxXferSize); SET_BIT(I2SxEXT(hi2s2.Instance)->CR2,SPI_CR2_RX
DMAEN); if((hi2s2.Instance->I2SCFGR &SPI_I2SCFGR_I2SE) != SPI_I2SCFGR_I2SE) {__HAL_I2SEXT_ENABLE(&hi2s2);__HAL_I2S_ENABLE(&hi2s2); }Unfortunately, only I2S2 RX buffer is filled. I2S2_EXT buffer remains intact.
Surprisingly if i set TX DMA ENABLE (
SPI_CR2_TX
DMAEN) for one of the channels, both DMA buffers are filled, but data is corrupted. Reference manual says that I2Sx_EXT can be used for tx/rx, so it seems there is no limitation to TX/RX mode or RX/TX mode. In my opinion TX/TX or RX/RX modes should be possible. Although i am unsure how to achieve that.
2017-07-13 11:23 PM
I found the problem.
SPI2_RX and I2S2_EXT_RX share single DMA Stream 3 and could not be used simultaneously.
2017-07-16 06:59 PM
Good catch. Still possible with two SPI/I2S units with bit and word clocks connected externally, or with I2S3/I2S3Ext.
JW
2017-07-16 09:26 PM
Important note: SPI2_RX and I2S2_EXT_RX share single DMA Stream 3 and could not be used simultaneously only in DMA mode.
Without DMA both channels could be configured as receivers! Up to 4 stereo ADCs/DACs could b e connected to 2 SPI ports, resulting in 8 audio channels. So relatively cheap audio DAC/ADCs could be used to make 3D audio recorder/player using 8 channels.
2017-07-17 04:27 AM
Yes, the I2SxExt units are are just a crippled-down version of the same SPI/I2S IP block, and they are entirely independent from their respective SPIx/I2Sx units as far as setup and operation goes; their only connection is that their WS and CK are connected at the GPIO level.
With I2S2/Ext in STM32F405/407/415/417 there's one more
https://community.st.com/0D50X00009XkaBPSAZ
, in the larger packages this clock connection is missing at the PI pins, see also in errata.JW
2017-08-13 12:10 PM
If someone interested I want to confirm it works. I have 4 channels of 24-bit audio using single I2S channel, PCM1808 connected in parallel as slaves,perfectly synchronized with excellent dynamic range. I think I can connect up to 4 PCMxxx stereo ADC/DAC chips, providing 8-channel 24-bit audio. Using STM32F407.