earlephilhower / arduino-pico

Raspberry Pi Pico Arduino core, for all RP2040 and RP2350 boards
GNU Lesser General Public License v2.1
2.04k stars 425 forks source link

I2S Master clock WM8782 #647

Closed LouisCARRIOU closed 2 years ago

LouisCARRIOU commented 2 years ago

Hi, I'm looking to use the WM8782 with a pico board to make an USB dual guitar recorder. How to get the I2S master clock signal from the I2S pico lib ?

earlephilhower commented 2 years ago

Sorry, no MCLK is generated. Only BCLK/LRCLK/DATA. Without special hardware it's difficult to generate that high a frequency (on the PIO you'd probably run out of instruction space since).

LouisCARRIOU commented 2 years ago

I tried to change the pio clock speed and pio has no problem with higher frequency, I tried 12.288MHZ for the BCLK and it's working. So now I'm looking to change the pio code to get another pinout for MCLK signal , MCLK is arround 4 times faster than the BCLK. Do you have an idea to adjust the pio code to get a new pinout with 4 times faster or slower ?

earlephilhower commented 2 years ago

Sorry, it's not possible due to the PIO insn limits (32 insns total per instrance).

Basically you need to turn each insn in the PIO code https://github.com/earlephilhower/arduino-pico/blob/master/libraries/I2S/src/pio_i2s.pio here into 8 insns nd run it at 2x MCLK (one insn to set MCLK high, one to set MCLK low). It's already at 8 insns, so you'd need 64 insns total to do it.

However, if there are no restrictions on MCLK vs. BCLK, you could make another PIO state machine generate a clock at whatever frequency w/2 instructions. You might even be able to put one of the PLL generated clocks out to a pin, in fact. But in those cases you can't guarantee any phase relationship between the MCLK/BCLK, of course.

LouisCARRIOU commented 2 years ago

Yes I though also to this way, using the second PIO, but I don't find the way to do It, pio is a bit new for me. I also tried with the rp2040 clock, timer and pwn , but none worked well, there is a 'clack' noise distortion in the best time. Another way could be to use the WM8782 in master mode with an external clock and the rp2040 in slave mode, only receive the BCLK, RLCK and DATA but I also didn't find the way to use the lib in slave mode. Do you have an idea to change the lib to be in slave mode ?

earlephilhower commented 2 years ago

You'd need to basically start from scratch to be a I2S slave. It would be simpler, though, since basically you're just a shift-in register with a 1 cycle-delayed push-to-FIFO. The Pico DMA code/etc. shouldn't need to be touched.

LouisCARRIOU commented 2 years ago

Yes I would to make it but I don't realy know how to do. It's the first time for me to use the pio. But I think it's the best way to use it, and make an I2S slave mode lib.

earlephilhower commented 2 years ago

It looks like you can synchronize the start of two PIO state machines. So you could make a state machine running MCLK of 4x BCLK and start it with the proper phase relationship.

See https://raspberrypi.github.io/pico-sdk-doxygen/group__hardware__pio.html#gac3797a9f7e80606152eb44af9ca96398

LouisCARRIOU commented 2 years ago

I tried to use a second i2s machine 4xBCLK, it's quite good , but there is some noise sometimes. I think it's because the MCLK isn't exactly 12.288MHZ so there is a moment some datas are lost . So I'm looking to make an I2S slave input mode . I've seen the example : https://github.com/raspberrypi/pico-examples/tree/master/pio/clocked_input So I think I can use it to get the datas, but I don't know how to make the ring buffer as the actual i2s lib. is it possible for you to help me on this ?

earlephilhower commented 2 years ago

If you make a slave I2S, the existing DMA coffee should just work without any modifications. The DMA doesn't care how the data gets in to the FIFO.

jfrey-xx commented 1 year ago

Hi! For future reference I implemented a MCLK with a PIO (which by itself cannot be simpler than that, especially since I modeled my code on the I2S class). I am myself trying to control a SGTL5000, connecting the Pico with a Teensy Audio board. The SGTL5000 does need MCLK, and it works flawlessly as far as I can tel, at least once you set the CPU frequency to a multiple of MCLK -- otherwise I would here small "pops" here and now, more or less often depending on the selected sampling rate, similar I guess to what @LouisCARRIOU reported.

From the documentation of the various chips I consulted, it seems that MCLK does not need to be in phase with the other clocks; hence a completely separate PIO might suffice in most (all?) the cases, avoiding to setup something more complicated with pio_enable_sm_mask_in_sync() as @earlephilhower suggested.

Now, if phase locking between MCLK and BCLK is not required by the standard I2S protocol, maybe generating MCLK could be integrated to the I2S class? That way any I2S slave device could be used. I could try to propose a patch if it makes sense, on the user side one method to set the pin (and enable MCLK), another one to set the speed (with 256 x sampling rate being the default).

Maybe I should comment on https://github.com/earlephilhower/arduino-pico/discussions/430 or open a new issue ^^

earlephilhower commented 1 year ago

I'd suggest opening a bug or a discussion, because closed issues are hard to find. If you've got a PR to add in MCLK generation, please do submit it and we can see how it can be integrated!

LouisCARRIOU commented 1 year ago

Thank you @jfrey-xx , I found the same way , using a second pio to do the MCLK, but I have always the small missing audio buffer filling on the usb microphone :( and I don't find the reason why... Anyway, now I'm trying to make a new I2S class with an output MCLK using an external clock (it's more precise than the pio clock), but Pio code is not so easy for me, I don't usually use it. So it's long to understand and make it. If you can send me a repo of your working solution I could compare with mine and see if my problem is always here or not :-D Perhups I made a mistake in my previous code .

jfrey-xx commented 1 year ago

Here is a quick gist with (hopefully) all the required files to setup the MCLK with PIO: https://gist.github.com/jfrey-xx/37c645b0fa87d86375f8a356104951d9

If you have a chance to test that @LouisCARRIOU and if it somehow works for you it'll be one more reason to make a PR. . Note the chosen sample rate and CPU freq to avoid audio artifacts -- you can try other combinations, there are probably more standard sample rates that can be achieved, ideally one that is documented with the WM8782 and your other components.