Skip to main content
Jan Slavot�nek
Associate III
December 6, 2016
Solved

stm32f4 discovery mems microphone over i2s cant get it running

  • December 6, 2016
  • 19 replies
  • 5533 views
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
This topic has been closed for replies.
Best answer by Jan Slavot�nek
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 ...

19 replies

Walid FTITI_O
Visitor II
December 6, 2016
Posted on December 06, 2016 at 18:04

Hi

slav3k

,

You should start your transfer by using the transmit and receive start functions in the driver either you use polling or DMA or interruption:

  • Polling mode:

HAL_I2S_Transmit()

HAL_I2S_Receive()

  • DMA mode:

HAL_I2S_Transmit_DMA()

HAL_I2S_

Receive

_DMA()

  • Interruption mode:

HAL_I2S_Transmit_IT()

HAL_I2S_Transmit_IT()

I recommend that you check the ready-to-use example 'I2S_Audio' in

http://www.st.com/en/embedded-software/stm32cubef4.html

at this path:STM32Cube_FW_F4_V1.0\Projects\STM324xG_EVAL\Examples\I2S\I2S_Audio

Note that in the example, the I2S transmit/receive start function are putted inside the BSP Audio driverstm324xg_eval_audio.c

-Walid FTITI-

Ifthe response is useful, you would mention that by clicking the correct botton. Thank you for the contribution

Jan Slavot�nek
Associate III
December 7, 2016
Posted on December 07, 2016 at 10:14

Hi Walid!

So i took a look at the example you are reffering to. 

First thing that supprised me is, that in that example, there is newer version of 'stm32f4xx_hal_i2s.c'. It is  V1.6.0 with date 04-November-2016. The one i am using (ono that was 'given' to me by CubeMX) is V1.5.2 from 22-September-2016. I am wondering, why my cube doesnt have updated libs. Do i have to force update or smthing ? 

The difference between those two seems to be considerable. The 

V1.6.0 has a lot mor functions in it then V1.5.2 . Never mind.

In example you are reffering to, i can find, that they are using DMA option for handeling I2S date. Therfore for starting the process, they use  HAL_I2S_Receive_DMA(&hAudioInI2s, pbuf, size);. Ok no problem, i can use IT equivalent HAL_I2S_Receive_IT();. There i suppose the first date this function return is dummy date right? Or does it return anything, when i will call that function out of the blue without previous interrupt event?

In the example, for stopping or pausing the process they use HAL_I2S_DMAStop(&hAudioInI2s); function, that is availible in V1.6.0 of library. Unfortunately, it is availible only for DMA. Not for IT. So what should use as equivalent for me, when i would like to stop/pause the proces using IT variant of I2S handling? 

Thank you very much

Have a nice day

Jan 

EDIT: My I2S interrupt when i call HAL_I2S_Receive_IT(); at start come once, but then it is not comming continuously. 
Walid FTITI_O
Visitor II
December 7, 2016
Posted on December 07, 2016 at 12:29

Hi

Slavot_nek.Jan

,

You shoudl always check for update in the CubeMx tool and update/ download the latest versions.

-Walid F-

Jan Slavot�nek
Associate III
December 9, 2016
Posted on December 09, 2016 at 09:05

 

My Further studies of example of audio application by STM shows, that i probably dont understand how I2S works. I dont understand, why they are using both HalfTransfer_CallBack and TransferComplete_CallBack. I mean, isnt it enough wait till transfer complete comes and take data to buffer? What am I supposed to do when HalfTransfer is done anywway? Why should i take half the data? Or is it the problem, that the buffer is small and cpu cant guarantee that it can take whole data word in time, so its safer to take data in two halves? 

Can anyone advice me on that matter? 

Thanks

Jan 
Walid FTITI_O
Visitor II
December 9, 2016
Posted on December 09, 2016 at 12:22

Hi JAn, 

There is a low livel driver packages which ST is delivering by device series to give user more easy and flexible user with HAL.

For STM32F4 is not yet delivred, other devices are already published like F0, L1, L4.

Meanwhile, you can disable the unwanted transfer interrupt like the half transfer by adding a defined macros located in DMA header file just after the transfer function like following :

/*Disable the HT interrupt */

__HAL_DMA_DISABLE_IT(DMA_IT_HT);

-Walid F-

Jan Slavot�nek
Associate III
December 9, 2016
Posted on December 09, 2016 at 10:57

I have made new observation. HAL_I2S_IRQHandler();  interrupt is actually occurring after i start process with

HAL_I2S_Receive_IT()

! Inside the handler i can see I2S_Receive_IT(hi2s); to be used, but i cant see that the handler would actually call the callbacks (

TransferComplete_CallBack AND/OR 

HalfTransfer_CallBack). Why is that? So am i supposed to write my code directly into HAL_I2S_IRQHandler()? This seems t obe really odd...

Another confusion for me is, that there are two 2 driver files: 'stm32f4xx_hal_i2s.c' and 'stm32f4xx_hal_i2s_ex.c'. Most of the functions are just duplicated in the 'ex' version. I have noticed when i was debugging that by default HAL_I2S_IRQHandler(); leads into 'ex' version ...
Walid FTITI_O
Visitor II
December 9, 2016
Posted on December 09, 2016 at 12:28

Hi Jan , 

With HAl architecture, User is allowed to add his code inside the call back function called inside the predefined IRQHandler. the state machine

implemented

make from IRQhandler a fixed driver function shouldn't modified which calls the relevant callback to do a specific ISR processing .

-WalidF-

Jan Slavot�nek
Associate III
December 9, 2016
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
Jan Slavot�nek
Associate III
December 9, 2016
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 

Walid FTITI_O
Visitor II
December 9, 2016
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-

Jan Slavot�nek
Associate III
December 9, 2016
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. 

Jan Slavot�nek
Associate III
December 9, 2016
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.

Jan Slavot�nek
Associate III
December 12, 2016
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  
Jan Slavot�nek
Associate III
December 13, 2016
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.

Jan Slavot�nek
Jan Slavot�nekAuthorBest answer
Associate III
December 13, 2016
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 ...