cancel
Showing results for 
Search instead for 
Did you mean: 

stm32f4 discovery mems microphone over i2s cant get it running

Posted on December 06, 2016 at 14:00

Hi community! 

Jan Here, Cezch Republic. 

I am working on my project where i need to process audio for further uses. My first step is obviously get my data from mic. I have decided to use the MP45DT02 MEMS mic that is present on my stm32f4 discovery board. 

I have already successfully got working example (Audio_playback_and_record). I used that example to help me understand basics of .wav and also pdm lib. I have also observed settings necessary for setting up i2s2. I replicated those settings using CubeMX and created project. Now i am facing following problem:

I never receive interrupt when debugging ( SPI2_IRQHandler(); is never called). So what am I missing? I have thoroughlly read through comments at stm32f4xx_hal_i2s.c librarry. I believe most of the actions (settings) were actually made by CubeMX so i dont need to do anyting. I would expect i2c start generating clock for the MEMS mic and i would expect pdm stream to start flowing. But its not. So i said to my self, that it is necesarrry to call some kind of start function to get the peripherral running (like when using ADC's one need to call HAL_ADC_Start_IT(&hadcx)), but i cant find any 'i2s_start()' function at the library. 

Any help would be appreciated!

regards

Jan

The I2S HAL driver can be used as follow:

(♯) Declare a I2S_HandleTypeDef handle structure.

(♯) Initialize the I2S low level resources by implement the HAL_I2S_MspInit() API:

(♯♯) Enable the SPIx interface clock.

(♯♯) I2S pins configuration:

(+++) Enable the clock for the I2S GPIOs.

(+++) Configure these I2S pins as alternate function pull-up.

(♯♯) NVIC configuration if you need to use interrupt process (HAL_I2S_Transmit_IT()

and HAL_I2S_Receive_IT() APIs).

(+++) Configure the I2Sx interrupt priority.

(+++) Enable the NVIC I2S IRQ handle.

(♯♯) DMA Configuration if you need to use DMA process (HAL_I2S_Transmit_DMA()

and HAL_I2S_Receive_DMA() APIs:

(+++) Declare a DMA handle structure for the Tx/Rx stream.

(+++) Enable the DMAx interface clock.

(+++) Configure the declared DMA handle structure with the required Tx/Rx parameters.

(+++) Configure the DMA Tx/Rx Stream.

(+++) Associate the initialized DMA handle to the I2S DMA Tx/Rx handle.

(+++) Configure the priority and enable the NVIC for the transfer complete interrupt on the

DMA Tx/Rx Stream.

(♯) Program the Mode, Standard, Data Format, MCLK Output, Audio frequency and Polarity

using HAL_I2S_Init() function.

-@- The specific I2S interrupts (Transmission complete interrupt,

RXNE interrupt and Error Interrupts) will be managed using the macros

__I2S_ENABLE_IT() and __I2S_DISABLE_IT() inside the transmit and receive process.

-@- Make sure that either:

(+@) I2S PLL is configured or

(+@) External clock source is configured after setting correctly

the define constant EXTERNAL_CLOCK_VALUE in the stm32f4xx_hal_conf.h file.

#pdm #i2s #stm32f4-discovery #programming-i2s
19 REPLIES 19
Posted on December 09, 2016 at 12:42

Hi Walid,

I am well aware of that fact. But my problem is, that the callback function that should be called by IRQhandler are not called. So how i am supposed to get my data out of I2S buffer? I know i should do it in callback function, but it is not called. 

Am I missing something? Do i need to manually enable specific interrupt sources 1/2 RxCplt and so on? 

Thanks 

Jan
Posted on December 09, 2016 at 13:57

Another point i just found out on this issue is following:

In the HAL_I2S_Receive_DMA(); i have found something what i believe is callback function registration. 

/* Set the I2S Rx DMA Half transfer complete callback */

hi2s->hdmarx->XferHalfCpltCallback = I2S_DMARxHalfCplt;

/* Set the I2S Rx DMA transfer complete callback */

hi2s->hdmarx->XferCpltCallback = I2S_DMARxCplt;

/* Set the DMA error callback */

hi2s->hdmarx->XferErrorCallback = I2S_DMAError;

But when i look into HAL_I2S_Receive_IT(); i cant see the same thing there. So this is why my callbacks are not called? 

Please, is there any ST official who could give me answer on my issue? 

Thank you very much

Jan 

Posted on December 09, 2016 at 16:18

Hi

Slavot_nek.Jan

,

,

As indicated in the comments , these code lines are dedicated to enable the HT and TC of DMA .

In case of interrupt transfer, the call back is called inside the

HAL_I2S_IRQHandler().

If the handler is not reached means that is not configured in the NVIC registers. You should add the NVIC configuration of the SPI/I2S IRQ as example below:

HAL_NVIC_SetPriority(SPIx_IRQn, 0, 0);

HAL_NVIC_EnableIRQ(SPIx_IRQn); where x =1 or 2

Another thing should be doneas best practice : Before starting a new communication transfer, you need to check the current state of the peripheral; if it’s busy you need to wait for the end of current

transfer before starting a new one.

while (HAL_I2S_GetState(&I2sHandle) != HAL_I2s_STATE_READY)

{

}

Hope everything is clear now for you.

Note: ST engineer in this community as the ST badge near to their names.

-Walid F-

Posted on December 09, 2016 at 18:21

The thing is that i am using CubeMX to configure. So everything is actually done already. Even NVIC setup is done automatically, i have double checked the settings made by Cube NVIC, GPIOs, clock, everything seems to be configured. 

I might didnt mention that i was planning to use pure interrupt to get my PDM data. I thought that this interrupt style would be easier to implement. But now i am considering using DMA style to handle that, because it is done this way in the example from ST. But again here example is actually not so much helpful when i want to use CubeMX to configure. I have never used DMA before, so i am not so sure how link my memory buffer to DMA and how setup everything. 

Posted on December 09, 2016 at 22:19

So i have configure everything just the very same way as it is in audio example. But my DMA interrupt callback HAL_I2S_RxCpltCallback() jsut dont occure. 

#define DEFAULT_AUDIO_IN_FREQ 16000

#define DEFAULT_AUDIO_IN_CHANNEL_NBR 1

#define INTERNAL_BUFF_SIZE                    128 * DEFAULT_AUDIO_IN_FREQ / 16000 * DEFAULT_AUDIO_IN_CHANNEL_NBR

uint16_t InternalBuffer[INTERNAL_BUFF_SIZE];

I am calling HAL_I2S_Receive_DMA(&hi2s2, InternalBuffer, INTERNAL_BUFF_SIZE); to start the process.

Posted on December 12, 2016 at 09:44

Hello there,

I am again working on my project. And during todays debugging i have found very strange behavior. 

So in driver file

''stm32f4xx_hal_i2s.c''

there are two functions that are setting up DMA Rx Callbacks:

/* Set the I2S Rx DMA Half transfer complete callback */

hi2s->hdmarx->XferHalfCpltCallback = I2S_DMARxHalfCplt;

/* Set the I2S Rx DMA transfer complete callback */

hi2s->hdmarx->XferCpltCallback = I2S_DMARxCplt;

If i go to

I2S_DMARxHalfCplt()

it brings me to the same file 

''stm32f4xx_hal_i2s.c'' and this function is directly called 

HAL_I2S_RxHalfCpltCallback(hi2s);

that is declared in my own .c file (it is weak ...) . This really works, this halp cplt callback is called and when debugging i get into my .c file where i define my version of 

HAL_I2S_RxHalfCpltCallback(hi2s);

Problem is in case of 

I2S_DMARxCplt()

. If i go to definition of that, it brings me to file

''stm32f4xx_hal_i2s_ex.c''

. Here i can see some code lines (i guess it has something to do with handeling of buffer and so on) and at the end of function there is  

HAL_I2S_RxCpltCallback(hi2s);

. Great but when debugging, i get to this line  

HAL_I2S_RxCpltCallback(hi2s);

and then program doesnt goes to my definition of

HAL_I2S_RxCpltCallback(hi2s);

, but it says ''no source code availible for

HAL_I2S_RxCpltCallback(hi2s);

. When i look to disassembly, i can see that actually there is code for my implementation of that callback. So this is explenation why i never ''catch'' the code with breakpoint inserted to my 

RxCpltCallback

.

Its like compiler would remove my RxCpltCallback, but in disassembly i can see it. 

Any Ideas? 

Thanks Jan

0690X00000603UnQAI.jpg

0690X00000603UmQAI.jpg

0690X00000603TGQAY.jpg 

Posted on December 12, 2016 at 10:32

Ok so now both callbacks stops when breakpoint is inserted. I needed to make both callbacks different, so when i added ++Data_Status; to halfCplt now i can observe how both callbacks are comming alternately.

Posted on December 12, 2016 at 18:57

OK so now i got to the point, where i can record full buffer on RAM of PCM data and store on flash drive in .wav in one shot. 

I have made a discovery: When i have set up i2s 'audio frequency' = 16 KHz, that means i2s is gonna make 16 000 * 64 PDM stream, that will result in 16KHz PCM sampling rate that means actual audio frequency tha i must fill to .wav header is 16/2 = 8KHz right?  At leaset that is what i have observed. Can anyone confirm that?

Thanks

Jan  
Posted on December 13, 2016 at 18:06

Lets consider this thread to be solved. Original questions about not calling interrupt callbacks seems to be solved right now. But another serious problems occured when i want to simultaneously run i2s data aquisition process and storing data to my flesh drive:

https://community.st.com/0D50X00009XkYcxSAF

Thanks in advance for any answers on that topic.

Posted on December 13, 2016 at 18:09

Probably code didnt went into the callbacks because compiler removed them during optimalization as it seemed to be unnecessary code ...