cancel
Showing results for 
Search instead for 
Did you mean: 

STMF469I as I2S slave with external MEMS microphone

Posted on March 08, 2017 at 10:03

Hi.

I'm trying to understand the I2S configuration in STMF469I-Discovery. I've got external MEMS microphone that's outputting 16khz mono output. I can see with oscilloscope that the output is OK however I cannot seem to get the I2S configured correctly.

I've connected the mic like this and generated code with cubemx as I2S2 as slave with microphone outputting the clock signal (1Mhz), so no as SAI I2S input:

/**I2S2 GPIO Configuration

PB13 ------> I2S2_CK

PB12 ------> I2S2_WS

PC1 ------> I2S2_SD

I'm trying to read the output in task context like this:

 status = HAL_I2S_Receive(&hi2s2, buf, time * hi2s2.Init.AudioFreq, time*1000);

However the I2S_WaitFlagStateUntilTimeout expires as the while(__HAL_I2S_GET_FLAG(hi2s, Flag) == RESET) stays in RESET.

The HAL init is not the _weak definition stmf4xx_hal_i2s.c, but one _i2s_ex.c. Is this the problem or is this clock related?

I'm really having a hard time understanding the clock configuration and the audio pipelines as general. Is there any documentation about this? Below is the simple intialization generated by CubeMX and read function added by me.

/* I2S2 init function */

void MX_I2S2_Init(void)

{

hi2s2.Instance = SPI2;

hi2s2.Init.Mode = I2S_MODE_SLAVE_RX;

hi2s2.Init.Standard = I2S_STANDARD_LSB;

hi2s2.Init.DataFormat = I2S_DATAFORMAT_16B;

hi2s2.Init.MCLKOutput = I2S_MCLKOUTPUT_DISABLE;

//hi2s2.Init.AudioFreq = I2S_AUDIOFREQ_44K;

hi2s2.Init.AudioFreq = I2S_FREQ;

hi2s2.Init.CPOL = I2S_CPOL_LOW;

hi2s2.Init.ClockSource = I2S_CLOCK_PLL;

hi2s2.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_DISABLE;

if (HAL_I2S_Init(&hi2s2) != HAL_OK)

{

Error_Handler();

}

}

void HAL_I2S_MspInit(I2S_HandleTypeDef* i2sHandle)

{

GPIO_InitTypeDef GPIO_InitStruct;

if(i2sHandle->Instance==SPI2)

{

/* USER CODE BEGIN SPI2_MspInit 0 */

/* USER CODE END SPI2_MspInit 0 */

/* Peripheral clock enable */

__HAL_RCC_SPI2_CLK_ENABLE();

/**I2S2 GPIO Configuration

PB13 ------> I2S2_CK

PB12 ------> I2S2_WS

PC1 ------> I2S2_SD

*/

GPIO_InitStruct.Pin = GPIO_PIN_13|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);

GPIO_InitStruct.Pin = GPIO_PIN_1;

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);

/* Peripheral DMA init*/

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_BYTE;

hdma_spi2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;

hdma_spi2_rx.Init.Mode = DMA_NORMAL;

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();

}

__HAL_LINKDMA(i2sHandle,hdmarx,hdma_spi2_rx);

/* USER CODE BEGIN SPI2_MspInit 1 */

/* USER CODE END SPI2_MspInit 1 */

}

}

void HAL_I2S_MspDeInit(I2S_HandleTypeDef* i2sHandle)

{

if(i2sHandle->Instance==SPI2)

{

/* USER CODE BEGIN SPI2_MspDeInit 0 */

/* USER CODE END SPI2_MspDeInit 0 */

/* Peripheral clock disable */

__HAL_RCC_SPI2_CLK_DISABLE();

/**I2S2 GPIO Configuration

PB13 ------> I2S2_CK

PB12 ------> I2S2_WS

PC1 ------> I2S2_SD

*/

HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13|GPIO_PIN_12);

HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1);

/* Peripheral DMA DeInit*/

HAL_DMA_DeInit(i2sHandle->hdmarx);

}

/* USER CODE BEGIN SPI2_MspDeInit 1 */

/* USER CODE END SPI2_MspDeInit 1 */

}

/* USER CODE BEGIN 1 */

HAL_StatusTypeDef get_i2s_data(uint16_t *buf, uint16_t time) {

   HAL_StatusTypeDef status;

   HAL_I2S_MspDeInit(&hi2s2);

   MX_I2S2_Init();

   status = HAL_I2S_Receive(&hi2s2, buf, time * hi2s2.Init.AudioFreq, time*1000);

   return status;

}

/* USER CODE END 1 */
18 REPLIES 18
Posted on March 08, 2017 at 12:09

Then its clock in RCC is probably off.

I don't Cube (as you might have guessed).

JW

Posted on March 08, 2017 at 12:13

I would love not to either .

ST has wonderful HW with fantastic devboards, but the SW configuration & projects are a little bit a confusing. Way too complex interfaces and configurations with very hard to find documentation. Also simple makefile projects would be nice.

Posted on March 08, 2017 at 12:29

Way too complex interfaces and configurations with very hard to find documentation.

So you prefer to exchange them for way too complex interfaces to Cube and doxygen autovomited documentation?

Also simple makefile projects would be nice.

+1

Simplest ones on my website but I have bills to pay.

JW

Posted on March 08, 2017 at 13:32

Okay, so now STOP watching the variables, as reading SPI_DR clears the RXNE flag.

(TXE is okay - it IS empty).

JW

Posted on March 08, 2017 at 12:40

I didn't mean to insult anyone . Maybe I don't know where to look, but I'm having hard time finding fe firmware interface documentation. Not to mention reference manual to HW.

I just mean that having more easy to find configurations in easy to find locations would be nice. Fe clock definitions seem to be in several files, and it's not easy to see what functions are called and what not (thanks to _weak -defined functions and overrides to them). Seeing right away what pins are in use and what not would also be nice from configuration.
Posted on March 08, 2017 at 13:04

Not to mention reference manual to HW.

On the product page.

http://www.st.com/content/st_com/en/products/microcontrollers/stm32-32-bit-arm-cortex-mcus/stm32f4-series/stm32f469-479/stm32f469zi.html&sharpdesign-scroll

 

scroll down to 'Reference Manuals'

JW

PS. Switched on that clock yet? I2S working?

Posted on March 08, 2017 at 13:22

Whoa. Thanks!

Yes, the RCC is now on. However the I2S is not yet working. It still timeouts in that same condition. However now there's some content in the SPI config! Some progress!

SR Says 2 so it's TX empty. And this should be RX.

SPI2    SPI_TypeDef *    0x40003800    

    CR1    volatile uint32_t    0    

    CR2    volatile uint32_t    0    

    SR    volatile uint32_t    2    

    DR    volatile uint32_t    0    

    CRCPR    volatile uint32_t    7    

    RXCRCR    volatile uint32_t    0    

    TXCRCR    volatile uint32_t    0    

    I2SCFGR    volatile uint32_t    3360    

    I2SPR    volatile uint32_t    156    

Posted on March 09, 2017 at 11:27

Ok, now the I2S works. The remaining issue was rather embarassing.

I had connected the lines wrong. With other connectors the name is marked at the top. I didn't re-check that and just assumed that that's the chase here also. But no, here it was at the bottom :/. Damn I'm blind. The pin number is right next to that name...

Posted on March 09, 2017 at 12:21

But no, here it was at the bottom

Oh, all hw and sw designers I know of (including me of course) has been caught at least once by some variant of this '3D'/symmetry/etc. problem... We call this problem internally the 'left/right' problem, after a prominently painful incident with stereo audio... (with two such mistakes compensating each other in a particular prototype setup).

However, recall, what was my first question:

Do you see both SCK and WS on PB13/PB12 with an oscilloscope/LA?

I forgot to write this down precisely, but by 'on PB13/PB12' I *always* mean 'as measured DIRECTLY on the mcu pins'. I noted here and elsewhere that I am not the only one who takes this implication as granted...

JW