zephyrproject-rtos / zephyr

Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.
https://docs.zephyrproject.org
Apache License 2.0
10.68k stars 6.53k forks source link

why i2s3 is missing in stm32f412 dtsi? #78821

Closed fariouche closed 1 week ago

fariouche commented 3 weeks ago

Is your enhancement proposal related to a problem? Please describe. I'm using the stm32f412g-disco and woulike lkke to use the i2s. I know that the i2s is not written a supported in zephyr's doc of the board, but i was hopping that enabl8ng i2s3 would be enough. But i2s3 is not defined in the dtsi. i2s1, i2s2, i2s4 and i2s5, but no i2s3... strange.

Any reason? adding i2s3 (by copying it from a similar soc) will be enough? I'm not yet sure about the value to put inside (interrupts, dma etc)

Describe the solution you'd like enabling i2s3 and that's all

marwaiehm-st commented 3 weeks ago

HI @fariouche,

You can add this I2S3 to stm32f412.dtsi. It's similar to I2S3 stm32f401, but I added some configurations to ensure efficient and timely data transfer for the I2S peripheral:

        i2s3: i2s@40003c00 {
            compatible = "st,stm32-i2s";
            #address-cells = <1>;
            #size-cells = <0>;
            reg = <0x40003c00 0x400>;
            clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00008000>;
            interrupts = <51 5>;
            dmas = <&dma1 5 0 (STM32_DMA_PERIPH_TX  | STM32_DMA_16BITS | \
                    STM32_DMA_PRIORITY_HIGH) 0x3 
                        &dma1 0 0 (STM32_DMA_PERIPH_RX | STM32_DMA_16BITS | \
                    STM32_DMA_PRIORITY_HIGH) 0x3>;
            dma-names = "tx", "rx";
            status = "disabled";
        };

Note: To use I2S3, you must disable SPI3 to free up the shared resources for I2S3 to function correctly.

fariouche commented 3 weeks ago

great, thank! yes, it's true for all i2s/spi on stm32 right?

fariouche commented 3 weeks ago

Is it normal that the dmas here have 4 fields, while the one I used in f401 has 5 fields (&dma1 5 0 0x400 0x3)?

fariouche commented 3 weeks ago

I had to add STM32_DMA_FIFO_FULL at the end of the dmas and now it compiles

marwaiehm-st commented 3 weeks ago

Is it normal that the dmas here have 4 fields, while the one I used in f401 has 5 fields (&dma1 5 0 0x400 0x3)?

Yes, you are right. I forgot to add 0x3 at the end.

marwaiehm-st commented 3 weeks ago

great, thank! yes, it's true for all i2s/spi on stm32 right?

Yes, it is true for all I2S/SPI peripherals on STM32 microcontrollers that you need to disable the SPI functionality to use the I2S functionality. This is due to the shared hardware resources between these peripherals.

fariouche commented 3 weeks ago

I will be able to test it soon, after i figure out why mcuboot is returning an error now all of a sudden after a fresh write 9f rhe image

marwaiehm-st commented 3 weeks ago

I will be able to test it soon, after i figure out why mcuboot is returning an error now all of a sudden after a fresh write 9f rhe image

Maybe you are flashing a corrupted image. Have you tried reflashing your board with an image generated from a basic sample like HelloWorld ?

fariouche commented 3 weeks ago

I think my config got corrupted. I've reset the config and now it boots again. Almost there.... Now I have "The linear prescaler value is unsupported" when configuring the i2s. Seems like I'm missing a device tree setting somewhere (maybe, I do not understand yet what this error is exactly)

fariouche commented 3 weeks ago

ok, I'm missing a else in i2s_stm32_set_clock to handle case when pclk_len <= 1 commited last month. With that patch, I have no more errors in config

fariouche commented 3 weeks ago

I think I may need some more help... I'm feeding the i2s using i2s_write and trigger start... but after a few buffers, I get an error -11 EAGAIN. No other errors:

My traces : Write buffer0 i2s started Write buffer1 Write buffer2 Write buffer3 Write buffer4 Write buffer5 (E)i2s_zephyr: Could not write TX buffer - -11

It seems that the i2s never really started (the timeout is from the semaphore of the queue in the driver... and no sound so clearly not started)

Same behavior with the sample application. It's as if the dma never started

marwaiehm-st commented 3 weeks ago

Please try with these modification:

do_trigger_stop:
        if ((ll_func_i2s_dma_busy(cfg->i2s) &&
            (queue_is_empty(&stream->mem_block_queue) == false))
#if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s)
                    || (stream->state == I2S_STATE_RUNNING)
#endif
        if (dir == I2S_DIR_TX) {
            if ((queue_is_empty(&stream->mem_block_queue) == false) ||
                        (ll_func_i2s_dma_busy(cfg->i2s))
#if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s)
                        || (stream->state == I2S_STATE_RUNNING)
#endif
fariouche commented 3 weeks ago

Same.... in fact the only function I'm calling are configure, write, trigger_start, write write etc And already right after trigger_start, I do not see any call to dma_tx_callback() So something is probably not set properly I think (clocks? I've see an old issue talking about enabling PLLI2S clock, but this seems to be irrelevant now ,as this config was removed)

fariouche commented 3 weeks ago

I'm moving forward. I added this: &plli2s { div-m = <8>; mul-n = <192>; div-r = <3>; status = "okay"; };

(not sure about the value, taken from some other board) Now dma_tx_callback() is called. Getting new errors now, but I need to check what they mean (queue_get returned an error from inside the callback and my loop didn't even had the time to push a new buffer (maybe my plli2s settings are wrong)

marwaiehm-st commented 3 weeks ago

Yes the plli2s looks wrong, test wit these settings

&plli2s{
        #clock-cells = <0>;
    clocks = <&clk_hse>;
    div-m = <4>;
    mul-n = <72>;
    div-r = <2>;
    status = "okay";
};

On the CLOCKS of node i2s3 add this line of "STM32_SRC_PLLI2S_R" to inicate that the I2S peripheral will use the clock generated by the PLLI2S_R output

clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00008000>,
     <&rcc STM32_SRC_PLLI2S_R I2S_SEL(0)>;
fariouche commented 3 weeks ago

Thank you; I have no more errors now, and the audio loop seems to work. Still have no sound, but this is most probably because the stm32f412g-disco board uses a codec (WM8994ECS) that may need some i2c commands to set the volume (first time I deal with such codec)

Thanks for you help. To sumup the needed modifications:

&plli2s{
        #clock-cells = <0>;
    clocks = <&clk_hse>;
    div-m = <4>;
    mul-n = <72>;
    div-r = <2>;
    status = "okay";
};
soc {
        i2s3: i2s@40003c00 {
            compatible = "st,stm32-i2s";
            #address-cells = <1>;
            #size-cells = <0>;
            reg = <0x40003c00 0x400>;
            clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00008000
                      &rcc STM32_SRC_PLLI2S_R I2S_SEL(0)>;
            interrupts = <51 5>;
            dmas = <&dma1 5 0 (STM32_DMA_PERIPH_TX | STM32_DMA_16BITS | STM32_DMA_PRIORITY_HIGH) STM32_DMA_FIFO_FULL
                    &dma1 0 0 (STM32_DMA_PERIPH_RX | STM32_DMA_16BITS | STM32_DMA_PRIORITY_HIGH) STM32_DMA_FIFO_FULL>;
            dma-names = "tx", "rx";
            status = "disabled";
            label = "i2s3";
        };

    };

And of course, for the application:

&i2s3 {
    status = "okay";
    pinctrl-0 = <  &i2s3_ck_pb12   &i2s3_sd_pb5   &i2s3_ws_pa4   &i2s3_mck_pc7   >;
    pinctrl-names = "default";
   mck-enabled;
};

No other modifications for now are needed for me. I will post here again as soon as I've fixed the codec issue

fariouche commented 2 weeks ago

I got some news. So far, I still have no sound. Cannot say for sure if the audio codec is incorrectly configured or if the i2S output is incorrect. I used my logic analyzer, and checked the signals of mck (too high for my cheap logic analyzer, frequency seems to be around 2MHz) but a slower signal like ws shows a period of 32us (31250Hz, this is strange) I'm using the following config: i2s_cfg.word_size = 16; i2s_cfg.channels = 2; i2s_cfg.format = I2S_FMT_DATA_FORMAT_I2S; i2s_cfg.frame_clk_freq = 44100;

This may explain why I do not have sound. I'm still searching the root cause

fariouche commented 2 weeks ago

I confirm the clocks: mck is 8MHz, ck is 1MHz and ws is 31250 ws is 29410 Hz if mck is disabled, ck around 961500

All values are correct in ratio, but the values are not correct (the plli2s is 72MHz) I will check the datasheet to better understand what is happening

fariouche commented 2 weeks ago

Some progress: For some reason, the clock_control_get_rate function returns 72MHz while in fact it should be 48Mhz. I'm not sure why yet, but forcing freq_in value to 48MHz gives me correct clocks

marwaiehm-st commented 2 weeks ago

You are rigth because the 48 MHz clock frequency is often used because it is a common multiple of standard audio sample rates (e.g., 8 kHz, 16 kHz, 32 kHz, 48 kHz, 96 kHz). Using a 48 MHz clock ensures that the I2S peripheral can generate accurate and stable audio clocks, which is critical for high-quality audio applications.

So the PLLI2S should be modified to return 48 MHz

&plli2s {
        div-m = <8>;
    mul-n = <192>;
    div-r = <4>;
    status = "okay";
};
fariouche commented 2 weeks ago

Thanks, it's better indeed. Just for my understanding, why the previous settings haven't changed the output clock? (48MHz) I was expecting the plli2s to configure the clock correctly by using the dts settings but it seems to only use the dts to "read" the clock instead (ie, even if it's actually 48MHz, it will return 72MHz in my case)

marwaiehm-st commented 2 weeks ago

The previous settings, do you mean this ?

&plli2s{
        #clock-cells = <0>;
    clocks = <&clk_hse>;
    div-m = <4>;
    mul-n = <72>;
    div-r = <2>;
    status = "okay";
};

The clock settings for peripherals like PLLI2S is primarily driven by DTS file. It is possible to configure the clock Kconfig or direct firmware configuration are less common and not recommended for standard peripheral clock settings.

fariouche commented 1 week ago

Just to let you know that I sorted out my codec issue, and now I have sound from my stm32f412 discovery board. It would help to have sane defaults in the dts I think.

Thanks for your help!