-
Notifications
You must be signed in to change notification settings - Fork 443
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
Feature request: Add full-duplex mode for I2S peripheral #1055
Comments
There is already input and output I2S support. You can instantiate both (or up to 4 total I2S interfaces, in fact...limited by DMA channels) with the same or different params. I don't think there'd be any savings in terms of compute, RAM, etc. in somehow merging the 2 together (and you'd have 1/2 the PIO FIFO space which may be a problem). |
I think the benefit of processing the OSR and ISR (Input and output shift registers) of the PIO at once would be saving at least the PIO SMs. Also, in that case the CB could be used to process both the incoming audio and generating the audio output stream. I have at least a dozen of use cases (including Vult DSP), which would greatly benefit from this. |
From my experience, it's the PIO instruction memory that gets exhausted first, not the SMs (c.f. the cool PIO-USB stuff which uses all 32 insns on a single SM). :) Because there are no You would save a couple pins, though, which might be handy. Also, two DMAs would be required and so you'd have 2 separate IRQs to handle, anyway. There's no bidir DMA option. You might be able to just assume the other one will fire, too, but it's awkward and open-loop at that point which feels unstable. |
Another way to achieve a similar outcome would be to implement slave input - using the same BCKL/LRCLK GPIO pins as the output PIO program is setting. The PIO code would have a interrupts on each of these signals. |
Unfortunately it's not possible to drive a PIO off of an input pin, only the system clocks. So any kind of slave mode is troublesome. I think you've got to run several multiples the frequency of the signal (to ensure you sample at proper setup/hold time). The PIO serial ports have this architecture, but they run at a much lower frequency...at I2S bit frequencies I don't think it's possible. To get something like this you'd probably need a new I2S input PIO program and start it at exactly the same time as the I2S output clock. They would run in lockstep and you'd be operating in open loop mode, shifting in at the computed times. There are methods of triggering both starts off of an IRQ, too, but in the end your I2S input is really just an open loop shift-in program. |
Thanks Earle, You are absolutely correct for trying to synchronise to an external master clock for outputs. It would be very difficult to meet the I2S timing requirements if the PIO clock wasn't locked to some multiple of BCLK. Even then, just one PIO cycle delay may be too long to meet the BCLK edge to DOUT ready timing requirement (which is around 20nS for several CODECs I use regularly). However, I think slave inputs are still worth considering - if only to save two GPIO pins on a CODEC setup. I was assuming that I could trigger actions via interrupts off GPIO pins for LRCLK and BCLK. With a master-mode Pico output, the issue of clock drift is avoided.
Yes, the PIO clock does need to be greater than BCLK, but a factor of anything more than 4 (and possibly 2) should provide enough accuracy to meet the data setup time requirements, despite clock drift or complete lack of synchronisation. I think a possible issue would likely be that the number of registers available might be exhausted, if an extra counter was needed to position the read near the middle of the bit cycle. Or, maybe just waiting one PIO clock cycle after the BCLK interrupt would be good enough to get a clean bit read. |
Is there any update for the RP2350 on this or is the situation the same? I am planing to use a audio codec for DSP (2i / 2o) |
Nope, no change. If you'd like to submit a PR w/a combined version, happy to look at it! But it's a really niche application and not on my radar right now. |
Good to know someone else cares. I haven't taken the approach I described above any further at this stage, I've been distracted by other projects. I'll get back to it when I next have a call for a full I2S CODEC on a Pico project. Sorry for the indefinite delay at this stage. Someone else may well pick it up in the meantime. |
I was wondering if shifting out and shifting in at the same time would not work?
|
I don't have a spec in front of me, but many of these interfaces shift on the opposite edge of sampling to help with setup and hold. Do it wrong and it will occasionally work, but not reliably across different instances. |
Earl is correct, almost all interfaces have the data set-up (in and out) on one edge of BCLK and read on the other. Which edge differs between the standards and chip implementations (particularly on TDM). The Philips I2S standard is: set-up on the falling edge, sample on the rising edge. 1 bit delay after LRCLK (WCLK/WS) on the first channel. I2SBUS.pdf This works to our advantage in this case, as the write and read are on opposite BCLK polarities. I haven't examined your code in detail, but you seem to be on the right track, however you may need to reverse the order of your in and out instructions to set up the outputs first, leaving the side sets in the order you have them. |
Add full-duplex (in+out) mode for I2S using PIO.
The text was updated successfully, but these errors were encountered: