Skip to content

P4 panel: playback and capture cannot run together — both directions open I2S(0) #23

Description

@bdbarnett

Reported by the camera session while verifying an unrelated I2C change, and passed to me to judge whether it is a bug or intended arbitration. It is a real limitation, and it is not the audio session contract refusing.

Symptom

On the Waveshare P4 panel board: open the microphone, then call play(), and it raises. Play first and then open the microphone and it sometimes succeeds and sometimes does not.

Not the session contract

AudioSession arbitrates owners of one shared codec, and this board correctly gives each direction its own session, since it has two codecs:

_SESSION       = AudioSession(codec_factory=lambda: _codec(),       duplex=False)   # ES8311, playback
_INPUT_SESSION = AudioSession(codec_factory=lambda: _input_codec(), duplex=False)   # ES7210, capture

Two separate sessions, so acquire() never sees a second owner and never raises. The contract permits simultaneous play and record.

What actually blocks it

Both directions construct the same I2S peripheral, board_peripherals.py around lines 91 and 108:

return I2S(0, sck=Pin(_SCLK), ws=Pin(_LRCK), sd=Pin(_DSDIN),  mode=I2S.TX, ...)   # audio_out
return I2S(0, sck=Pin(_SCLK), ws=Pin(_LRCK), sd=Pin(_ASDOUT), mode=I2S.RX, ...)   # audio_in

machine.I2S takes a direction at construction and one id cannot be both, so the second open fails. The order-dependence and the intermittency are about whether the first instance has been released, not about arbitration.

The wiring is genuinely full duplex: the two codecs share the bit and word clocks and have separate data lines (_DSDIN into the codec, _ASDOUT out of it). So this is one peripheral that should be running duplex, not two peripherals.

Why it matters

Under design principle 1, a pairing the hardware permits that the design does not deliver is a defect in the design rather than a feature request. The board has a speaker and a microphone on one bus, the API exposes both, and the two cannot be used together. Anything wanting monitoring, a loopback, an effects path, or a voice interface hits this.

It also cost real time this week: an attempt to prove speaker output by acoustic loopback was inconclusive, and could not be run at all in the obvious way for this reason.

Options, none free

  • Duplex machine.I2S. Correct, and a port-level change: the ESP32 port would need to expose one id in both directions. Upstream question.
  • A native duplex path in audiodev's I2S backend, bypassing machine.I2S for boards whose codecs share a bus.
  • Document the exclusion on the board and in audiodev, so it fails with a clear message naming the cause instead of an OSError from the second open. This is the cheap half and should happen regardless of which of the above is chosen.

Third option first, in any case: today the failure names neither the peripheral nor the reason.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions