2020-02-10 11:51 PM
Hi.
The HAL_I2S_Receive_DMA() has defect around its size parameter.
The UM1905 explain the size parameter as following :
when a 24-bit data frame or a 32-bit data
frame is selected the Size parameter means the number of
16-bit data length
That mean, regardless of the data size, the buffer size to the DMA have to be measured by the count of the int16_t. On the other word, the length by int32_t have to be multiplied by 2.
I saw several example on the internet which follows this specification.
But, this description is incorrect. The HAL_I2S_Receive_DMA() interprets its size parameter as number of the int32_t type in the buffer, when the data type of I2S is 32 or 24bit.
This behavior can be confirmed by reading stm32f7xx_hal_i2s.c. As you can see the attached screenshot, this APi is compensating size parameter when the data is 24 or 32bit. So, the behavior and documentation doesn't match.
I have two request.
As I checked, this problem was observed on Nucleo F722, F446 and G431.
The firmware of the F722 is the STM32Cube FW_F7 V1.15.0
2023-11-28 08:42 PM - edited 2023-11-28 09:03 PM
I recommend using pre-filled buffer in such cases. E.g., we can initialize buffer filled with 1 2 3 4 5... and output it back using UART to see what values are actually being overwritten. To set right length for I2S DMA transfers, we need to know several parameters:
1. Data Width of DMA configuration (Byte, Half Word or Word)
2. I2S data configuration (16 or 24/32-bit data)
3. Array type (uint8_t, uint16_t or uint32_t)
E.g.,
assume that DMA data width is set to Word, I2S data type is set to 24/32-bit, and array type is uint32_t:
#define ARRAY_SIZE 10
uint32_t i2sBuffer[ARRAY_SIZE]={0x11111111, 0x22222222, 0x33333333, 0x44444444,
0x55555555, 0x66666666, 0x77777777, 0x88888888,
0x99999999,0xAAAAAAAA};
// let's test it:
HAL_I2S_Receive_DMA(&hi2s1, (uint16_t *)&i2sBuffer[0], 4);
// this will fill 8 elements of i2sBuffer array (all except 0x99999999 and 0xAAAAAAAA)
// thus, we can't pass ARRAY_SIZE (10), because it will write 20 elements
HAL_I2S_Receive_DMA(&hi2s1, (uint16_t *)&i2sBuffer[0], ARRAY_SIZE/2);
// because dma data width is Word (32-bit), but this function assumes 16-bit data.
HAL_I2S_Receive_DMA will multiply ARRAY_SIZE by 2, and will receive 10 32-bit elements
now, if DMA Data Width is set to Half Word, this will be correct:
HAL_I2S_Receive_DMA(&hi2s1, (uint16_t *)&i2sBuffer[0], ARRAY_SIZE);
Source: I2S data size (thundertronics.com)
Note that SPI/I2S data register (SPI_DR) is 16-bit. I've checked my I2S projects and I always configured I2S DMA as half word/half word (16-bit/16-bit) despite using 32-bit I2S ADC and 32-bit arrays. From my understanding, I2S provides data in 16-bit halves, thus we should use 16-bit data width regardless of connected chip format for correct operation.