Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion .github/workflows/build-all.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,25 @@ jobs:
compression-level: 6
custom-hostname: picompose

# 2MICHAT-v2
build-2michat-v2:
uses: ./.github/workflows/build-image-template.yml
with:
image-name: PiCompose-2MicHat-v2
stage-list: stage0 stage1 stage2 ./01-stage-picompose ./02-stage-audiodriver-2michat-v2 ./04-stage-finish
compression: xz
compression-level: 6
custom-hostname: picompose

build-2michat-v2-lva:
uses: ./.github/workflows/build-image-template.yml
with:
image-name: PiCompose_2MicHat-v2_Linux-Voice-Assistant
stage-list: stage0 stage1 stage2 ./01-stage-picompose ./02-stage-audiodriver-2michat-v2 ./03-stage-linux-voice-assistant ./04-stage-finish
compression: xz
compression-level: 6
custom-hostname: picompose

# RESPEAKER-LITE
build-respeaker_lite:
uses: ./.github/workflows/build-image-template.yml
Expand All @@ -62,5 +81,5 @@ jobs:

# RPI IMAGER JSON
generate-rpi-imager-json:
needs: [build, build-2michat, build-respeaker_lite, build-2michat-lva, build-respeaker_lite-lva]
needs: [build, build-2michat, build-2michat-v2, build-respeaker_lite, build-2michat-lva, build-2michat-v2-lva, build-respeaker_lite-lva]
uses: ./.github/workflows/create-rpi-image-json.yml
4 changes: 4 additions & 0 deletions 02-stage-audiodriver-2michat-v2/01-driver/01-packages
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
git
build-essential
device-tree-compiler
alsa-utils
44 changes: 44 additions & 0 deletions 02-stage-audiodriver-2michat-v2/01-driver/03-run-chroot.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/bin/bash -e

# ReSpeaker 2-Mics Pi HAT **V2.0** uses a TLV320AIC3104 codec on I2C 0x18 —
# NOT the WM8960 codec (0x1a) used on V1. No out-of-tree DKMS module is
# needed: the mainline `snd-soc-tlv320aic3x` driver already ships in the
# kernel. We just need the device-tree overlay that wires it up to the Pi's
# I2S pins. The overlay source is maintained by Seeed in their
# seeed-linux-dtoverlays repo.

echo "Building ReSpeaker 2-Mic HAT V2.0 device-tree overlay..."

SRC=/tmp/seeed-linux-dtoverlays
rm -rf "$SRC"
git clone --depth 1 https://github.com/Seeed-Studio/seeed-linux-dtoverlays.git "$SRC"

cd "$SRC"
make overlays/rpi/respeaker-2mic-v2_0-overlay.dtbo

# detect boot config + overlays location
OVERLAYS_DIR=/boot/overlays
CONFIG=/boot/config.txt
if [ -d /boot/firmware/overlays ]; then
OVERLAYS_DIR=/boot/firmware/overlays
fi
if [ -f /boot/firmware/config.txt ]; then
CONFIG=/boot/firmware/config.txt
fi
if [ -f /boot/firmware/usercfg.txt ]; then
CONFIG=/boot/firmware/usercfg.txt
fi

install -v -m 644 overlays/rpi/respeaker-2mic-v2_0-overlay.dtbo \
"${OVERLAYS_DIR}/respeaker-2mic-v2_0.dtbo"

# set boot params: enable I2C and load the v2 overlay
sed -i -e 's:#dtparam=i2c_arm=on:dtparam=i2c_arm=on:g' "$CONFIG" || true
grep -q "^dtparam=i2c_arm=on$" "$CONFIG" || echo "dtparam=i2c_arm=on" >> "$CONFIG"
grep -q "^dtoverlay=respeaker-2mic-v2_0$" "$CONFIG" || \
echo "dtoverlay=respeaker-2mic-v2_0" >> "$CONFIG"

cd /
rm -rf "$SRC"

echo "Done. After boot the card appears as 'seeed2micvoicec' (bcm2835-i2s-tlv320aic3x-hifi)."
10 changes: 10 additions & 0 deletions 02-stage-audiodriver-2michat-v2/02-set-audio-volume/01-run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash -e

install -v -m 755 files/configure_audio.sh "${ROOTFS_DIR}/usr/bin/configure_audio.sh"
install -v -m 644 files/configure_audio.service "${ROOTFS_DIR}/etc/systemd/system/configure_audio.service"

on_chroot << EOF
echo "Enable audio services"
systemctl daemon-reload
systemctl enable configure_audio.service
EOF
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[Unit]
Description=PiCompose - Configure Audio volume setting (ReSpeaker 2-Mic HAT V2.0)
After=user@1000.service sound.target alsa-restore.service
Wants=user@1000.service sound.target alsa-restore.service

[Service]
Type=oneshot
Environment=XDG_RUNTIME_DIR=/run/user/1000
ExecStart=/usr/bin/configure_audio.sh
RemainAfterExit=yes
Restart=on-failure
RestartSec=30s

[Install]
WantedBy=multi-user.target
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#!/bin/bash
set -u

# TLV320AIC3104 on V2.0 ships quiet on both ends: HP DAC at -23.5 dB,
# HP/Line amps at ~89% and muted on some units, and the capture PGA at 27%
# (16 dB) — too low for microWakeWord detection. PCM is driven by wpctl as
# hardware-volume passthrough, so only the downstream stages need tuning.
# Runs every boot because WirePlumber can reset ALSA state between sessions.

wait_for_card_and_control() {
local card="$1"
local control="$2"
local max_tries=30
local count=0

while [ "$count" -lt "$max_tries" ]; do
count=$((count + 1))

if amixer -c "$card" info >/dev/null 2>&1; then
if amixer -c "$card" scontrols | grep -Fq "'$control'"; then
echo "Card $card with control '$control' is ready ($count/$max_tries)"
return 0
fi
echo "Card $card found, but control '$control' not ready yet ($count/$max_tries)"
else
echo "Card $card not ready yet ($count/$max_tries)"
fi

sleep 1
done

echo "Card $card with control '$control' did not become ready"
return 1
}

# Returns 0 on set-success or missing control; 1 on set-failure.
# Non-zero exit triggers the systemd retry.
set_control_if_exists() {
local card="$1"
local control="$2"
shift 2

if amixer -c "$card" scontrols | grep -Fq "'$control'"; then
echo "Setting $control on $card to $*"
if amixer -c "$card" set "$control" "$@"; then
return 0
fi
echo "amixer set failed for '$control' on $card" >&2
return 1
fi

echo "Control '$control' not found on $card, skipping"
return 0
}

# Same kernel alias as V1 (`seeed2micvoicec`); the PCM control distinguishes
# V2's tlv320aic3x from V1's wm8960.
if ! wait_for_card_and_control seeed2micvoicec PCM; then
echo "No TLV320AIC3104-based card became ready; is the V2.0 overlay loaded?"
exit 1
fi
CARD="seeed2micvoicec"

FAIL=0
set_control_if_exists "$CARD" "HP DAC" 100% || FAIL=1
set_control_if_exists "$CARD" "Line DAC" 100% || FAIL=1
set_control_if_exists "$CARD" "HP" 100% unmute || FAIL=1
set_control_if_exists "$CARD" "Line" 100% unmute || FAIL=1
set_control_if_exists "$CARD" "PGA" 80% cap || FAIL=1

if [ "$FAIL" -ne 0 ]; then
echo "One or more amixer set calls failed; not storing state." >&2
exit 1
fi

# Keep PipeWire sink at unity so HA/LVA volume reaches the ALSA stages
# above. Matches the 2michat-v1 pattern from #42.
wpctl set-volume @DEFAULT_AUDIO_SINK@ 1.0

alsactl store
5 changes: 5 additions & 0 deletions 02-stage-audiodriver-2michat-v2/prerun.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash -e

if [ ! -d "${ROOTFS_DIR}" ]; then
copy_previous
fi
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ Here is a Overview for the specific images of each hardware:
| **[Sattelite1](docs/hardware_sattelite1.md)**<br>**+Linux-Voice-Assistant**<br>**+Snapcast** | <img src="docs/sattelite1-hat.jpg" alt="ReSpeaker Lite Board" style="width: 200px; height: auto;"> | • Satellite1 Hat Image<br>• Linux-Voice-Assistant (OpenHomeFoundation)<br>• Snapcast MultiRoom Audio Client<br>• Pre-configured for Home Assistant<br><br><span style="color: red;">Image is currently work in progress!</span> |
| **[ReSpeaker 2-Mic HAT v1](docs/hardware_2mic_v1.md)** | <img src="docs/respeaker_2michats.webp" alt="ReSpeaker 2-Mics Pi HAT" style="width: 200px; height: auto;"> | • Base Image<br>• Seeed Voicecard Driver |
| **[ReSpeaker 2-Mic HAT v1](docs/hardware_2mic_v1.md)**<br>**+Linux-Voice-Assistant**<br>**+Snapcast** | <img src="docs/respeaker_2michats.webp" alt="ReSpeaker 2-Mics Pi HAT" style="width: 200px; height: auto;"> | • 2-Mic HAT Image<br>• Linux-Voice-Assistant (OpenHomeFoundation)<br>• 2-Mic HAT GPIO LED Control<br>• Snapcast MultiRoom Audio Client<br>• Pre-configured for Home Assistant |
| **[ReSpeaker 2-Mic HAT v2.0](docs/hardware_2mic_v2.md)** | <img src="docs/respeaker_2michats.webp" alt="ReSpeaker 2-Mics Pi HAT" style="width: 200px; height: auto;"> | • Base Image<br>• TLV320AIC3104 device-tree overlay<br>• Per-boot codec mixer tuning for the V2.0 |
| **[ReSpeaker 2-Mic HAT v2.0](docs/hardware_2mic_v2.md)**<br>**+Linux-Voice-Assistant**<br>**+Snapcast** | <img src="docs/respeaker_2michats.webp" alt="ReSpeaker 2-Mics Pi HAT" style="width: 200px; height: auto;"> | • 2-Mic HAT v2.0 Image<br>• Linux-Voice-Assistant (OpenHomeFoundation)<br>• Snapcast MultiRoom Audio Client<br>• Pre-configured for Home Assistant |
| **[ReSpeaker Lite](docs/hardware_respeaker_lite.md)** | <img src="docs/respeaker_lite.jpg" alt="ReSpeaker Lite Board" style="width: 200px; height: auto;"> | • Base Image<br>• Audio keep-alive service<br>• Workaround for connectivity issues in combination with the Pi Zero 2W.<br><br><span style="color: red;">There is a USB connectivity issue with the Pi Zero 2W. I cannot recommend this board if you want to use it with that. Use Pi3 or higher.</span> |
| **[ReSpeaker Lite](docs/hardware_respeaker_lite.md)**<br>**+Linux-Voice-Assistant**<br>**+Snapcast** | <img src="docs/respeaker_lite.jpg" alt="ReSpeaker Lite Board" style="width: 200px; height: auto;"> | • ReSpeaker Lite Image<br>• Linux-Voice-Assistant (OpenHomeFoundation)<br>• Snapcast MultiRoom Audio Client<br>• Pre-configured for Home Assistant<br>• Workaround for connectivity issues in combination with the Pi Zero 2W.<br><br><span style="color: red;">There is a USB connectivity issue with the Pi Zero 2W. If you want to use it with that, you need to use Pi3 or higher.</span> |

Expand Down
41 changes: 41 additions & 0 deletions docs/hardware_2mic_v2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Hardware - ReSpeaker 2-Mics Pi HAT v2.0

<img src="respeaker_2michats.webp" alt="ReSpeaker 2-Mics Pi HAT" style="width: 300px; height: auto;"></img>

The V2.0 is a silent hardware revision of the 2-Mics Pi HAT. Visually identical, electrically different: the WM8960 codec used on v1 (I2C `0x1a`) is replaced with a **TLV320AIC3104** codec (I2C `0x18`). This matters because the v1 driver stage does not produce a working sound card on v2 hardware, and because the mixer defaults differ.

Features (same as v1):
- Support the Raspberry Pi 3B / 4B / Zero 2 W
- Two microphones (Mic L and Mic R)
- Two Grove connectors
- One User-defined button
- 3.5 mm audio interface
- XH2.54-2P audio output interface

## Order

### Base:

- [Raspberry Pi Zero 2 W](https://amzn.to/3M0G4hC)
- [SD-Card](https://amzn.to/4qfx06l)
- [US MicroUSB Power Supply](https://amzn.to/4c52mt3)
- [Cable for Speaker](https://amzn.to/3ZvU0Dz)

### ReSpeaker 2-Mics Pi HAT v2.0

- [Seeed Studio ReSpeaker 2-Mics Pi HAT V2.0](https://wiki.seeedstudio.com/respeaker_2_mics_pi_hat_v2/)

## Technical notes

Unlike v1 — which needs an out-of-tree DKMS kernel module — v2 uses the mainline `snd-soc-tlv320aic3x` driver that already ships with the Raspberry Pi OS kernel. The image only needs:

1. The device-tree overlay `respeaker-2mic-v2_0.dtbo` (built from [Seeed-Studio/seeed-linux-dtoverlays](https://github.com/Seeed-Studio/seeed-linux-dtoverlays)), enabled via `dtoverlay=respeaker-2mic-v2_0` in `/boot/firmware/config.txt`.
2. `dtparam=i2c_arm=on` in `/boot/firmware/config.txt`.
3. Per-boot mixer tuning — the TLV320 ships with several attenuators well below 100 % (`HP DAC` at -23.5 dB in particular), producing a card that appears to work but is inaudible at typical application volumes.

The PiCompose `02-stage-audiodriver-2michat-v2` stage performs all three steps automatically. The mixer tuning is applied by `configure_audio.service` on every boot, the same pattern other audiodriver stages follow after #42: amixer on the codec-specific controls, then `wpctl set-volume @DEFAULT_AUDIO_SINK@ 1.0` to keep the PipeWire sink at unity. PipeWire / WirePlumber manage ALSA state per session and can reset the mixer between reboots, so a first-boot-only guard would let users end up stuck at 0%. Customization via `amixer` is still possible at runtime — it just won't survive a reboot.

## Additional information

- [Seeed Studio Wiki — ReSpeaker 2-Mics Pi HAT v2.0](https://wiki.seeedstudio.com/respeaker_2_mics_pi_hat_v2/)
- [seeed-linux-dtoverlays (overlay source)](https://github.com/Seeed-Studio/seeed-linux-dtoverlays)