2018-08-22 05:13 AM
Hi, I'm new to the ST microcontroller, and I'm learning how to use it. I am working with the 32F746GDISCOVERY board and want to operate an S2S interface via the Arduino-IOs on the board.
From the data sheets I can see that I should be able to use the I2S2 resource for this:
I also found an example (STM32Cube_FW_FW7_V1.12.0) that configures an I2S interface:
File: I2S/I2S_DataExchangeInterrupt/Src/main.c ->This example describes how to configure I2S using the STM32F7xx HAL API.
If I do this now analogous to this example, it does not work.
My first question: Where can I find more detailed documentation on the HAL drivers?
My second question: As I have understood this, the I2S2 resource can be assigned to different IOs. How is this configured?
2018-08-24 02:18 AM
Thank you JW for your time! I think i got it with the IOs now.
The I2S is still not working, but i think the reason is not the IOs. The HAL-API is very complex and in my eyes not well documented. I tried it again with the CubeMx-Software with more success. Now the I2S sends the clock and the WS- Signals. But how to get the data-stream in array, so that i can use it, is still not clear for me. I will search now for more example code or a tutorial for this HAL-API.
2018-08-24 03:02 AM
> But how to get the data-stream in array
Is it Tx or Rx?
What is connected to I2S?
It's little different from SPI - you can even operate it in polled mode, if you want, and that might be a good exercise for beginning too.
JW
2018-08-28 04:04 AM
I've been trying to make the connection work for the last couple of days. The MXCube helped me a little bit to get ahead. However, I still have problems. The goal is the continuous streaming of data from a SPH0645LM4H-B microphone.
Now I try to save the data into an array via DMA. I have configured everything to 32-bit. The microphone should give 18 bits of information. The way I look on the oscilloscope doesn't look bad. But I can't get the data properly into an array.
The most successful one was the following configuration:
hdma_i2sRx.Instance = DMA1_Stream3;
hdma_i2sRx.Init.Channel = DMA_CHANNEL_0;
hdma_i2sRx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_i2sRx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_i2sRx.Init.MemInc = DMA_MINC_ENABLE;
hdma_i2sRx.Init.PeriphDataAlignment = DMA_MDATAALIGN_WORD;
hdma_i2sRx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_i2sRx.Init.Mode = DMA_CIRCULAR;
hdma_i2sRx.Init.Priority = DMA_PRIORITY_HIGH;
hdma_i2sRx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
hdma_i2sRx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_i2sRx.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_i2sRx.Init.PeriphBurst = DMA_MBURST_SINGLE;
hAudioInI2s.Init.Mode = I2S_MODE_MASTER_RX;
hAudioInI2s.Init.Standard = I2S_STANDARD_MSB;
hAudioInI2s.Init.DataFormat = I2S_DATAFORMAT_24B;
hAudioInI2s.Init.MCLKOutput = I2S_MCLKOUTPUT_DISABLE;
hAudioInI2s.Init.AudioFreq = AudioFreq;
hAudioInI2s.Init.CPOL = I2S_CPOL_HIGH;
hAudioInI2s.Init.ClockSource = I2S_CLOCK_PLL;
However, I only get 8Bit information from the microphone (from 18):
Data from the Array: '9E9E0000' '9A9A0000' '8C8C0000' '8F8F0000' '95950000'
When I change:
hdma_i2sRx.Init.PeriphDataAlignment = DMA_MDATAALIGN_WORD;
to
hdma_i2sRx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
My code end in the HardFault_Handler() function. How do I have to configure the DMA and I2S to get the Full Information?
2018-08-30 01:06 AM
how do I get on? Which documentation could help me? I'm stuck with the problem. Alternatively I thought to use another chip as a bridge to transmit the data correctly to the ST chip.
2018-08-30 02:52 AM
Hi @MMett ,
A simple, but may be helpful proposal: have a look to the example: STM32Cube_FW_F7_V1.12.0\Projects\STM32F746ZG-Nucleo\Examples\I2S.
It is not the same HW used in this example, but it should be easy to port to your discovery as it is the same device (STM32F746).
All related documentation to STM32CubeF7 is available in https://www.st.com/content/st_com/en/products/embedded-software/mcus-embedded-software/stm32-embedded-software/stm32cube-mcu-packages/stm32cubef7.html.
Don't forget to update us on the status of your project :)
-Amel
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
2018-08-30 04:08 AM
> hdma_i2sRx.Init.PeriphDataAlignment = DMA_MDATAALIGN_WORD;
Cube just ORs together all the init-struct's fields before storing them to DMA_SxCR, so this together with the same constant being assigned to .MemDataAlignment simply gets ignored, and DMA_SxCR.PSIZE remains to be 0 i.e. byte. I don't have good explanation for the "doubling" but wouldn't be surprised if it's the result of the newer FIFO-containing SPI/I2S module being confused by the bytewise reads.
The hardfault is probably result of incorrectly assigned number of transfers (I guess it's sizeof(array) instead of the sizeof(array)/peripheral_transfer_size_as_given_by_DMA_SxCR.PSIZE) subsequently DMA writes beyond the array, possibly corrupting other variables or stack (or hitting some MPU-given boundary, if MPU is used in such way).
The I2S/SPI.DR is 16-bit wide and that's what you are supposed to use as peripheral transfer size (PeriphDataAlignment).
I don't Cube.
JW
2018-09-06 07:15 AM
Thanks for your support! I could actually get on with the problem. The hardfault problem was correctly suspected.
It was also helpful to know that the I2S/SPI data registers are aligned in 16-bit.
With this configuration I was now successful:
hdma_i2sRx.Instance = DMA1_Stream3;
hdma_i2sRx.Init.Channel = DMA_CHANNEL_0;
hdma_i2sRx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_i2sRx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_i2sRx.Init.MemInc = DMA_MINC_ENABLE;
hdma_i2sRx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_i2sRx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_i2sRx.Init.Mode = DMA_CIRCULAR;
hdma_i2sRx.Init.Priority = DMA_PRIORITY_HIGH;
hdma_i2sRx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_i2sRx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_i2sRx.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_i2sRx.Init.PeriphBurst = DMA_PBURST_SINGLE;
Another decisive factor was that I don't store the data in a 32-bit array, but in a 16-bit one. The DMA stores the high-16Bit and the low-16Bit in the array in the wrong direction.
Also the function HAL_I2S_Receive_DMA(I2S_HandleTypeDef *hi2s, uint16_t *pData, uint16_t Size) is a bit tricky. Size can be a maximum of 2^14. At a sample rate of 48000 this is just enough for 0.3 seconds. I was able to solve the problem in such a way that the triggered interrupts
HAL_I2S_RxHalfCpltCallback and HAL_I2S_RxCpltCallback, one half each of the DMA array can be written to a larger (32Bit) array. There I can also reverse the high-16Bit and low-16Bit. The DMA is operated in circular mode.
Now this works so far and I can fill the RAM to the limit with data from the microphone. Only the solution is a bit improvised. Is it possible to configure the DMA so that the 32Bit value is directly correct? E.g. by writing in the memory in the other direction?
Screenshot of the microphone-data with a 2.6kHz sinus-signal:
2018-09-06 08:26 AM
> Only the solution is a bit improvised.
I understand your sentiment, but in many if not most audio applications the data need to be manipulated somehow anyway.
> Is it possible to configure the DMA so that the 32Bit value is directly correct?
No, i.e. 32-bit I2S in the SPI/I2S module with its 16-bit data register inevitably results in the data swap (and the more usual 24-bit I2S feels maybe even more weird in this regard). There's no way to "reverse" the DMA's address register increment direction, and the DMA does not support reordering even in the FIFO mode. If this is a priority for you, use the SAI module instead of SPI/I2S.
JW