Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A question about using external I2S clocks with Bela codec and BB's McASP #532

Closed
martin-minovski opened this issue Jan 30, 2019 · 5 comments

Comments

@martin-minovski
Copy link

martin-minovski commented Jan 30, 2019

I am currently using an external 44kHz audio I2S bit clock on the SPI1_SCLK pin (BB #⁠31), by setting the Bela codec's 0x08 register to 0x40 in I2c_Codec.cpp (BLCK input, WCLK output) which works well, however setting WCLK as input on the SPI1_DO pin (BB #⁠29) results in terrible noise. I tried changing the bit stream format from DSP to I2S, as well as the needed 1 bit data offset both in the codec and McASP configurations - I2c_Codec.cpp and pru_rtaudio.p respectively. I am obviously missing something, but after hours of digging, still couldn't get acceptable audio. Any hints will be greatly appreciated.
Thanks!

@giuliomoro
Copy link
Contributor

Hmmm don't know what to say. Just be aware that the codec configuration in the mainline Bela code is actually slightly off (though it works fine). There is one commit here that makes it more compliant.

Maybe this could work as a starting point for fixing your thing.

Are you trying to use the Bela codec and this external codec together?

@martin-minovski
Copy link
Author

ACLKXCTL was the key! Setting that to falling edge produced crystal clear sound. Cheers for that!

Actually I am using the second PRU to read I2S from the GPIO pins and mix that with Bela's analog audio input, hence why I needed to use a single clock source - that of the raspberry pi which I used for testing.

The code is here, if you want to check it out. I'll also post it in the forum in case anyone might find it useful.

@giuliomoro
Copy link
Contributor

giuliomoro commented Jan 31, 2019

That looks very nice! One observation and one question:

  • you are reading GPIOs at 16x sample rate (if not more). This means lots of traffic on the bus, and potentially - if you decide to also write to them - you may (or will?) end up conflicting with the writes that the other PRU is doing (the value of the GPIO registers are flushed to the pins with a 100MHz clock: there is the chance that the two PRUs will write to them two different values within a single clock period). For these two reasons, why don't you move to using the PRU's own GPIOs? These can be accessed with a single read (from R30) or with a single write (to R31) operation. The pinmuxer need to be set properly in order to enable these pins. We currently are using P8_41 to P8_46 (PRU1 GPIOs) for the multiplexer capelet. If you are not using the muxer capelet, you could change the pinmuxer for 3 of those pins to be "input" (mode 5) intead of the current "output".

"Also note that if the I2S clocks stop running (that happens when you stop ALSA playback for instance), Bela will crash with message "PRU stopped responding". To prevent that, comment out the line that contains "exit(1)" in /root/Bela/core/PRU.cpp along with the fprintf messages surrounding it. Don't comment out the task_sleep_ns call."

not sure what you would expect to happen when the I2S clocks stop: I understand you have an external clock now? If that stops, how do you expect the mcasp cope with it?

@giuliomoro
Copy link
Contributor

giuliomoro commented Jan 31, 2019

Oh also something else: not sure how much flexibility you have on the other I2S device, but the McASP supports Time-division multiplexing, besides the regular I2S mode, so if the other device supports that as well, you could just have the two codecs doing TDM over the same McASP bus, without need for a PRU bitbanging it. That's what we do for the CTAG cards (check out pru/pru_rtaudio_irq.p)

@giuliomoro
Copy link
Contributor

giuliomoro commented Jan 31, 2019

Further to the above note: operations on the SOC's GPIOs take time: about 140/200ns to read, and about 30ns to write (but it takes longer than that for the results to be propagated to the output). (see timing comments in here , e.g.: lines 321, 366, 463 through 470). When using PRU GPIOs, you read and write in a single cycle (5ns). This means you can potentially achieve higher bandwidth. Right now you should have about 3 read operations for each bit: detect bitclock high, read data, detect bitclock low. Additionally, 2 read operations per frame (detect LR clock high, detect LR clock low). So, reading a total of 32 bits in a frame, you have (32*3 + 2) read operations per frame, which adds up to about 19.6us in the worst case scenario, where each read operation takes 200nS. That is still good, and you should be able to squeeze in some write operations there as well, for a total of ((32*3 +2)*0.2 + 32*0.03) = 20.56us, which still gives you some margin with a 44100kHz clock, where the frame rate is 22.7us. However, you are pretty tight!
Additionally, you have the time that it takes to write the acquired samples to RAM and read the output samples from RAM. Not sure what the timing is there, but I think you can expect it to be similar as above (i.e.: 30ns writes, 140-200ns reads, again once per frame). In other words: you will probably end up to have to use the PRU's GPIOs if you want to pull the whole thing out in R/W mode.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants