2022-09-22 12:33 AM
Hello, I am trying to learn I2S.
For SPI, it is pretty easy to understand, but for I2S, I have a few doubts and questions.
As I understand it, the WS pin will determine which channel will transmit. But when I pull high or low the Slave transmitter WS pin manually, it is not following that principle.
Questions:
1. In a continuous array of data passed to the HAL_I2S, which is the left or right channel (even or odd address number in the array)?
2. Why I2S does not stop after the DMA? It is still sending the last data to both left and right channels.
3. Why is the Master Receive still generate WS and CK after the DMA is finished? In this situation, the Slave Transmitter is also sending the last data.
4. If I pull low the WS of the Slave Transmitter, it sends the whole array of data (not the even/odd memory address in the array) but the Master Receiver is receiving only the even memory address in the array.
5. If I pull high the WS of the Slave Transmitter, it sends all zeros (low) of data (not the even/odd memory address in the array) and the Master Receiver also received all zeros as well.
My expectation is when WS is high or low, the data should be sent only the even or odd memory address part of the array.
My setup:
1. one STM32F4-discovery board both acting as Master RX and Slave TX
2. I2S2 = half duplex Master RX
3. I2S3 = half duplex Slave TX
4. SD, CK and WS are wired together like so:
Master RX > Slave TX
PB12 (WS) = PA15 (WS)
PB12 (CK) = PB3 (CK)
PB15 (SD) = PB5 (SD)
My Code:
1. fill 300 of data
#define numdata 300
uint16_t send_data1[numdata];
// fill data to be transmitted
for(uint16_t cntr = 0; cntr < numdata; cntr++)
send_data1[cntr] = cntr;
2. setup DMA transfer and receive
HAL_I2S_Transmit_DMA(&hi2s3, send_data1, numdata); // Slave TX
HAL_I2S_Receive_DMA(&hi2s2, receive_data1, numdata); // Master RX
3. Check results:
// check if transmitted data is equal to received data
for(uint16_t cntr = 0; cntr < numdata; cntr++)
{
if (send_data1[cntr] != receive_data1[cntr])
num_error++;
}
4. Print results:
printf("receive_data1 Buffer \n");
for(uint16_t cntr = 0; cntr < numdata; cntr++)
printf("%d = %d \n", cntr, receive_data1[cntr]);
printf("num_error = %d \n", num_error);
This is the printout when all connections are stated above.
0 = 0
1 = 1
.
.
.
298 = 298
299 = 299
If I connect the WS of the slave transmitter to LOW (GND)
I receive these data:
0 = 0
1 = 2
.
.
.
298 = 596
299 = 598
If I connect the WS of the slave transmitter to High (3V3)
I receive these data:
0 = 0
1 = 0
.
.
.
298 = 0
299 = 0
CubeMX Setup:
Master RX Parameter setting and DMA
Slave TX Parameter setting and DMA
Waveforms:
Similar to Q1 above. When connected normally all is ok. But when WS of Slave TX is connected to GND, still the same waveform, I expect only Left or Right to be transmitted.
The data shown is the beginning of the data, where SD pin is transmitting 0 - 6.
CH1 Yellow = CK
CH2 Blue = WS
CH3 Pink = SD
Similar to Q2-3 above. I2S is still sending data even after the last data (299), the data being transmitted is always 299 0x012B.
Before the last data is sent (299), the data is still incrementing to 299. The last 2 data are not 299 and same.
Similar to Q5 above. WS pin on the Slave TX is held high. The WS waveform below is from Master RX.
2022-09-22 02:58 AM
Which STM32? Read the errata, some devices have "In I2S Slave mode, WS level must be set by the
external master when enabling the I2S"
JW
2022-09-22 03:38 AM
Sorry for a little typo there, it should be STM32F4-discovery.
STM32F407 device.
2022-09-22 03:43 AM
I2S seems to work nicely and correctly if all pins are connected.
The question is when I connect the WS pin of the Slave TX "permanently" to either Low or High:
Should I receive the odd or even address number in the array?
How are the Left and Right channels arranged in the array?
2022-09-22 05:00 AM
> when I connect the WS pin of the Slave TX "permanently" to either Low or High
Due to the mentioned erratum, if the WS pin is at the inactive level (high for I2S) all the time from before the I2S was enabled, it will never start to transmit; on the other hand if it's active(low), it will start transmitting immediately when it sees the first clock.
> How are the Left and Right channels arranged in the array?
The I2S module itself is "left-right" agnostic. It transmits MSB first, so it depends on CHLEN and the particular way how you store data into SPI_DR, which data goes out first. And if you follow the erratum, the first data which goes out after WS high-to-low transition is in I2S word considered left channel.
JW
2022-09-22 08:32 AM
Thank you for the answers.
So far I have understood the answers to some of my inquiries, but there are still some I cannot understand:
2. Why I2S do not stop after the DMA? It is still sending the last data.
4. If I pull low the WS of the Slave Transmitter, the received data seems to be shifted, [0, 2, 4, 6, 8, ...... 596, 598] instead of [0, 1, 2, .... 288, 289]. But checking the waveform as shown below, the data within WS frame is correct. Does this mean that the Master RX is the one shifted?
CH1 Yellow = CK of both Master RX and Slave TX
CH2 Blue = WS of Master RX, while Slave TX is pulled low.
CH3 Pink = SD of both Master RX and Slave TX
2022-09-22 10:11 AM
> Why I2S do not stop after the DMA? It is still sending the last data.
What is "after the DMA"? Look into the Cube/HAL functions. Do they disable I2S? No? Then as long as there is clock, I2S wants to transmit something, and if you don't overwrite its data register, it keeps sending the same data over and over.
Cube/HAL - and any other "library" - inevitably supports only a limited subset of all possible combination of functionalities, what the authors deemed "usual", and what can be easily clicked in CubeMX. If you want the mcu to do something else, write your own code.
> 4. If I pull low the WS of the Slave Transmitter, the received data seems to be shifted
Then don't pull low the WS. The I2S module expects to see WS high at the moment when it's enabled, and then a falling edge. If you don't provide the expected waveform, it behaves unpredictibly.
JW