Skip to content

audio_i2sin module for espressif and raspberrypi#10990

Open
FoamyGuy wants to merge 4 commits into
adafruit:mainfrom
FoamyGuy:audio_i2sin
Open

audio_i2sin module for espressif and raspberrypi#10990
FoamyGuy wants to merge 4 commits into
adafruit:mainfrom
FoamyGuy:audio_i2sin

Conversation

@FoamyGuy
Copy link
Copy Markdown
Collaborator

@FoamyGuy FoamyGuy commented May 8, 2026

Adds audio_i2sin.I2SIn class. Only enabled/implemented for espressif and raspberrypi ports currently.

Two new manual test scripts are included in the PR that were used to verify the functionality of the module. Recording to an SDCard, and sound reactive neopixels.

Sparkle Motion board def is updated to include the pins that the I2S mic is connected to.

Testing:

  • Tested with mic built-in to sparkle motion and with https://www.adafruit.com/product/6049
  • Record to sdcard works successfully on espressif port. On raspberrypi it seems like it's taking too long to write data to the sdcard and it's causing the recording to take too long and be broken up. All testing was with SPI and sdcardio. Might be worth testing sdio?
  • Sound reactive neopixels work under espressif and raspberrypi. I tested with sparkle motion, ESP32 Huzzah feather, ESP32 S3 TFT feather, RP2040 feather, and RP2350 feather.

Copy link
Copy Markdown
Member

@tannewt tannewt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code seems fine. Do we want it to be audio_i2sin instead of audioi2sin? I think the latter is more Python-style and more what we've done in the core. Python reference: https://peps.python.org/pep-0008/#package-and-module-names

@relic-se
Copy link
Copy Markdown

relic-se commented May 12, 2026

Starting to play around with this module. I see there's no option to support signed samples. The audio codec I'm testing with only supports signed samples (or I haven't implemented it in the driver library). I think it'd be beneficial to add that option to the constructor rather than require the user to perform the conversion within Python (which I haven't figured out how best to do yet).

An example of a samples_signed property would be within audiomixer.Mixer (https://docs.circuitpython.org/en/latest/shared-bindings/audiomixer/index.html#audiomixer.Mixer).

Here's the code I'm working with right now with a Pimoroni Pico Plus 2, TLV320AIC3204 audio codec, and SPW2430 microphone.

import array
from audioi2sin import I2SIn
import board
import ulab.numpy as np

import relic_tlv320aic3204

# Initialize codec
codec = relic_tlv320aic3204.TLV320AIC3204(
    i2c=board.STEMMA_I2C(),
    mclk=board.GP17,
    rst=board.GP16,
)
codec.sample_rate = 44100
codec.bit_depth = 16

# Initialize I2S bus
i2sin = I2SIn(
    bit_clock=board.GP18,
    word_select=board.GP19,
    data=board.GP21,
    sample_rate=codec.sample_rate,
    bit_depth=codec.bit_depth,
    mono=True,
)

# Connect IN1L to Left MICPGA and IN1R to Right MICPGA
codec.connect_input(relic_tlv320aic3204.INPUT_1, relic_tlv320aic3204.IMPEDANCE_20K)
codec.input_gain = 6.0  # dB

# Setup ADC Input
codec.dac_enabled = True  # BUG: DAC must be enabled for ADC functionality
codec.adc_volume = 0.0  # dB
codec.adc_enabled = True
codec.adc_muted = False

# Setup buffer
buf = array.array("H", [0] * (codec.sample_rate // 16))

while True:
    
    # Record to buffer
    i2sin.record(buf, len(buf))
    
    # Determine maximum level
    print(np.max(np.array(buf, dtype=np.uint16)))

Right now, the level is all wonky because of the issue with signedness.

@FoamyGuy
Copy link
Copy Markdown
Collaborator Author

@relic-se The latest commit adds samples_signed argument that is modeled after audiomixer. It defaults to True which is the same as prior behavior and can now be set to False to change behavior. I tested the default case on esp32s3 and rp2350 successfully. I'm not sure I have the right kind of mic breakout to test the new behavior.

@FoamyGuy
Copy link
Copy Markdown
Collaborator Author

@tannewt this is refactored to audioi2sin with no underscore in the latest commits. I agree it follows the existing modules naming pattern better this way, only a few have underscores.

@relic-se
Copy link
Copy Markdown

I was beginning to do a deeper review of the recent samples_signed addition, but I didn't realize that I2S data is always signed. I think it might be best to omit that property and assume that all data will be signed going forward. Speaking of, is there any reason why unsigned data was the default from the beginning? Or is that a hold-over from PDMIn?

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

Successfully merging this pull request may close these issues.

3 participants