Skip to main content
Graduate II
January 23, 2024
Question

STM32F429I I2S Rx/Tx simultaneously

  • January 23, 2024
  • 9 replies
  • 5120 views

Hello everyone, I'm asking for your advice. I use STM32F429I-DISCO1  board, I want to use I2S so that the reception and transmission occurred simultaneously, on different lines and only one frame on each <WS> signal, and I think in order to quickly implement it with DMA , how can I implement this.

thanks in advance.

    This topic has been closed for replies.

    9 replies

    Super User
    January 23, 2024

    Hi,

    Setup in Cube an I2S to: full duplex master ; (set Fs speed, format etc.)

    Then start in main : 

    HAL_I2SEx_TransmitReceive_DMA (...) ;

    I2S then running reception and transmission...

    gevmarAuthor
    Graduate II
    January 23, 2024

    I config it as a full duplex slave, the transmission mode as <mode slave receiver>.
    16 bit data per 32 bit frame. PCM short frame mode . DMA is < normal > without increment,
    all interrupts are <set> by default, <WS>= 8 kHz , in the my digital analyzer I see , regardless of the c signal,
    transmission is always carried out sequentially. And the impression is that this <WS> signal does not give anything
    to the interface, and if the interface wants to transmit data, regardless of the presence of <WS> the signal,
    it produces data ... I think this is not true . I'm from the outside, with each <WS> signal I enter one frame into the interface.


    HAL_I2SEx_TransmitReceive_DMA(&hi2s2, (uint16_t*) &my_tmp_I2S_2_Tx , (uint16_t*) &my_tmp_I2S_2_Rx , 1) ;

    Super User
    January 23, 2024

    >I config it as a full duplex slave

    ?? and who is master then ??

    gevmarAuthor
    Graduate II
    January 23, 2024

    any external PCM master device, for example, say SIM7600, or NAU8810 codec, or my own PCM master generator created in STM32F429i using TIMERs , PWMs..., where the input date and output date are physically on different pins (lines), clock = 2mHz, and with the arrival each <WS>. signal , my microcontroller simultaneously must read the data_IN and give data_OUT to the master, using different lines (Tx/Px),

    As I understand ,  the full duplex means that there must be two different lines ( I2Sx_SD
    , and I2Sx_extSD ), but the document says that

    < Note: I2S2_ext an I2S3_ext are used only in full-duplex mode>

    page 901/1751

    I2Sx can operate in master mode. As a result:
    • Only I2Sx can output SCK and WS in half duplex mode
    • Only I2Sx can deliver SCK and WS to I2S2_ext and I2S3_ext in full duplex mode.
    The extended I2Ss (I2Sx_ext) can be used only in full duplex mode. The I2Sx_ext operate
    always in slave mode.
    Both I2Sx and I2Sx_ext can be configured as transmitters or receivers

    >

    in master mode  ---> I2S2_ext and I2S3_ext in full duplex mode

    The I2Sx_ext operate always ---> in slave mode.

    here one contradicts the other ?

    or how configure I2Sx_ext as ---> transmitters

    or how configure I2Sx_ext as ---> receivers

     

    Is it possible in master mode to simultaneously (on different lines ---> I2Sx_SD
    , and I2Sx_extSD) transmit and receive data?

     

    Thanks in advance

     

     

    Super User
    January 23, 2024

    Sorry, i dont understand all your statements mixed assumptions .

    Just tell me: what you want ?  Which ADC or codec... and what you want to do.

    And yes, TransmitReceive as master  transmit and receive data , on one sync (ws + bcl) on two lines , rx + tx , if you accept my identifiers.

    gevmarAuthor
    Graduate II
    January 24, 2024

    1) Do I understand correctly?, if the slave, full duplex works in the transmission mode = <mod slave receive> mode,
    then I can transmit data only when there is data reception? . if so, why, as soon as I update the DMA,
    the data immediately goes out, regardless of whether there is reception at that moment or not. 

     

    2) Is it possible in master mode to launch full duplex mode with simultaneous operation of the SD and SD_ext lines
    (that is, receive data during transmission and vice versa, I have a board STM32F429I-DISCO1).

     

    3) I have an array of 10 elements uint16_t my_arr[10], I want to transmit these elements separately (only one element)
    in SLAVE and full duplex mode with each input short signal <WS -> period = 125 μsec (8 kHz), signal duration 500 nsec > .
    With each <WS> signal, only one 16-bit frame (duration 8 μsec) come to the STM32F429i,
    then the main interval between the two <ws> signals (125-8 μsec) remains simply empty.
    I need to pass one element from my array, simultaneously synchronous with the arrival of <WS> and the input 16-bit frame.
    how to implement this ?
    I have this settings

     

    Full Duplex SLAVE
    transmission mode = <mod slave receive>
    16 bit data on 32 bit Frame
    PCM with short synchro frame
    Audio Freq = 8 kHz

    NVIC = all interrupts is set default
    DMA -> I2S2_EXT_TX = mem to periph. ; normal ; half word ; not increment
    DMA -> SPI2_RX = periph. to mem ; normal ; half word ; not increment

     

    Thanks in advance

    Super User
    January 24, 2024

    Wait -- you still didnt say : Which ADC or codec... you have - and i don't want to have to guess. 

    gevmarAuthor
    Graduate II
    January 25, 2024

    I have a  NAU8810 codec

     

    Super User
    January 25, 2024

    Ok, now i see, why you try with slave mode on F429 . 

     

    >1) Do I understand correctly?, if the slave, full duplex works in the transmission mode = <mod slave receive> mode, then I can transmit data only when there is data reception?

    No. This "master - slave" thing is just : who is generating the clocks (wck , bck) = the master. And usually the master doing this permanently , with or without data ; if no data, its just "0000" data, send + receive , always.

    So now you understand, why also on the slave data is going out as soon as you put it to output register; as clocks are running , its always sending : 0-0-0-your data - 0-0-...

    2. If you have the NAU8810 in master mode, F429 has to be slave,  in full duplex mode; 

     

    3. Because the I2S stream is continuous, you should serve it in a matching mode : circular dma mode.

    + with some size of these send + receive buffers, to have some time to do something with the data.

    On the F429 you have > 100kB ram, so i would use (at first) maybe 4KB+4KB, 2K int16 as in-buf and 2K int16 as out-buf.

    Set in Cube circular dma, all on 16b (half-word) sizes, enable callbacks in Project Manager -> Advanced Settings.

    Now in your main.c , start I2S+DMA :

    HAL_DMA_Init(...

    HAL_I2SEx_TransmitReceive_DMA(...

    Now (if you set this correct) you have a running I2S system, permanently all received data coming to the in-buf and out-buf is sending out synchronous its data. 

    In the half and full buffer callbacks now you have about (1K samples * sample_rate) time, to use the incoming data and put new data to the 1K samples in out-buf. (or 00 data, if you want silence = "pause" )

    gevmarAuthor
    Graduate II
    January 25, 2024

    Thank you very much, you shed a lot of light on the overall picture.
    But I have a second question. when and how the <WS> signal coming from outside(I am slave) ,
    comes into play, in the I2S interface.

    We need to synchronize all this , with signal <WS>.
    for example, 16 bit data 32 bit frame, clk = 2 MHz, => one_frame = 32*500 nSec = 16 μs, and my array with 8 elements  => my_tx_buf[8]={payload_data , 0,0,0,0,0,0,0} it turns out cycle = 8*16=128 μs, and I have a <WS> signal coming from outside every 125 μs.
    That is, my full cycle has not yet ended, and the synchronizing signal <WS> comes from outside.

    1) At this time the I2S interface itself will reset the array elements counter ?, (I doubt that)
    2) or should I implement it myself, say with an external interrupt ?,
    3) if every time I call a function <HAL_I2SEx_TransmitReceive_DMA(...)> in the external interrupt function <EXTIn_IRQHandler()> ,
    will the counter of my array be reset to zero , at this moment.

    Super User
    January 25, 2024

    Sorry - but did you follow my suggestion >> 3. Because the I2S stream is continuous ... <<

    You can use your buffer with only 8 samples, if you like this so much. :)

    BUT start circular dma only once !!!!! Believe me, it will run then forever...

    gevmarAuthor
    Graduate II
    January 25, 2024

    I understood the concept of your proposal and I will definitely try it.
    I don’t understand whether it makes sense in the cubemx settings, in SLAVE mode, full-duplex, transmission mode = <mod slave receive> ? .

    As I understand , the arrival time of the signal <WS> will certainly be equal to ( integer_number * frame_length_time ).
    How do I properly use the arrived signal <WS> ?.

    I understand that along with this <WS> signal I receive useful 16-bit data.

    I understand that this data will be written to my <Rx_buf> buffer, but to which element number( Rx_buf [ ? ] ) specifically? .

    How can I implement this correctly?

    Super User
    January 25, 2024

    Seems, you dont understand it : audio is the sum of continuous data - not just one sample.

    One sample is just a number , one number - no audio signal.

    >How do I properly use the arrived signal <WS> ?

    Nope. On circular DMA , you get blocks of data; what you do with the data - i dont know, you didnt say.

    So do whatever you want to do.

    >How can I implement this correctly?

    What is "correctly" ? You dont want to tell, what you wanna do - so what ?

    Sorry, but its late , and i don't want to have to guess , what you want to do.

    I showed you, how to get and send a sound data-stream - what you want then ?

    gevmarAuthor
    Graduate II
    January 31, 2024

    Your help was really very valuable, and I tried both PCM-s (I2S2 and I2S3) on the STM32F429I-DISCO1 board
    in practice, a lot became clear in practice. But there are hardware nuances that are not fully understood.
    At first, PORTB PIN_13 (clk) did not work on I2S2; it turned out that it was connected to USB_OTG and capacitor C53
    and microcircuit U8 were interfering, after removing C53 and applying a HIGH level to PORTC_pin4 (or just the input - OTG_FS_PSO),
    everything started working.
    Separately, both I2S2 and I2S3 work normally, by the way, for normal operation of the DMA, we must definitely
    keep the NVIC I2S2 and I2S3 turned on.
    And when I set I2S2=SLAVE and full_duplex;
    I2S3=SLAVE and half_duplex and transmit mode;
    and from some source (pin) I apply PCM_CLOCK to both interfaces (I2S2 and I2S3), then I2S2 works normally,
    synchronously with the WS signal and each bit is correctly output, in its place and with the correct duration.
    And the I2S3 data output begins to go dull.

    ___ the wrong number of bits and their duration are output,
    and the wrong data, and it is synchronized (only on I2S3), and the data is output much more often.
    By the way, the green LED=ON on the USB_OTG port, which is not turned on for no reason.
    ---it is enough to remove the clock signal from I2S2, then the falsely output data on I2S3 disappears,
    but it does not work synchronously with the WS signal, and after RESET (button) the operation of I2S3 is normalized.
    How can this problem be solved?

    Super User
    January 31, 2024

    Why now on 2 x I2S same time ?  Two codecs connected ??

    1. Use only one I2S -> one codec .

    2. Dont use some pins, that already connected on your board - this wont work.

    Look in board schematic , if I2S3 pins are unused, so we try with this .

    https://www.st.com/en/evaluation-tools/32f429idiscovery.html#cad-resources

    3. Set the I2S to full-duplex-slave , connect bck, wck, miso, mosi to your codec NAU8810 .

    4. Set two DMA channels in circular mode, one receive and one transmit .

    Now we need to set the format: you have I2C connected , to program the NAU8810 ?

    I would recommend: set to I2S , 16 bit, both channel used (is anyway mono codec) .

    You can set this ? 

    gevmarAuthor
    Graduate II
    February 1, 2024

    Yes, I made these settings, it’s just that my system is like this, sim7600 and NAU8810 codec are connected to
    each other, I want to cut off the lines to fit with stm32 between them, make my own digital additional filtering,
    for this I must connect one stm32_I2S2 to the sim7600, and the other stm32_I2S3 to NAU8810 , so that everything
    works in parallel. Just because everything was parallel, I want to run both I2S in slave mode(for example Master is only sim7600) ,
    now I created a hardware PCM simulator in stm32 with Timers (PCM in master mode), and from some pin the physical clock signal was sent to clock_ I2S2 and clock_ I2S3, which was causing the problem .

     

    But right now I physically defined the same clock on two pins, and applied separate pins to clock_I2S2 and clock_I2S3, and the problem was solved.


    But this is a partial and incorrect solution method.

    Moreover, I think such a problem should not have arisen at all.
    I think the problem may be related to the pin settings (pull_up, pull_down, ...)?