Mark II audio in vanilla Raspbian

I’ve been toying with running vanilla Raspbian on the Mark II and quite a bit seems to work out of the box (networking works, video is fine, even the touch screen works) but so far I haven’t had any luck getting audio to work.

I poked around the mark-ii-sandbox repo and it appears that it disables bcm2835 audio in the config.txt, but I noticed the stock Neon images for the Mark II have it enabled (dtparam=audio=on is uncommented). On vanilla Raspbian if I enable it then the HDMI audio device shows up but doesn’t seem to actually work.

I guess my main issue is I don’t even know what audio interfaces are wired up in the Mark II enclosure. Does it use standard HDMI audio, or the headphone jack, or is it done through the I2C bus in some way that could be coerced into working with alsa on a vanilla Linux install?

Hey there, I’m not sure exactly how much the SJ-201 daughterboard hijacks the existing Pi audio, but here’s the recipe Neon uses to set up SJ-201 drivers: https://github.com/NeonGeckoCom/neon_debos/blob/dev/recipes/20-sj201.yml

That’s probably the best place to start. Best of luck, and do share your findings!

3 Likes

Hello. I’ve just finished repeated teardowns for upgrades and an unfinished photo guide. I can confirm that all the audio, or at least all the audio we hear, is routed through the SJ-201.

I’ve never worked on the driver side of OVOS, but the speakers are wired to the daughter board, not to the Pi, which pretty much settles the question :stuck_out_tongue:

The Pi is wearing the daughter board like a HAT. Apart from the camera and the screen, everything is via the SJ-201 via GPIO.

I should also note that, in our Matrix space, we have a channel where all the people who work directly on the images congregate to share their findings. It’s probably the Mark II expertise capital of the world, at this point.

The SJ-201 is build around the VocalFusion 3510 chip from XMOS.

I wrote a quick driver/overlay for it here;

(It also works on the newer 6.x kernels)

Building that repo creates the driver which is automatically loaded when you add;

dtoverlay=xvf3510

To your config.txt

However that is not enough as the chip does not have a SPI memory installed so it needs to be initiated into the right settings. This is done by flashing a binary firmware blob into the chip.

The firmware blob and flash script can be found here;

Secondly, the sound is also routed through a Texas Instruments amplifier which also needs to be initiated into the right settings. That script can be found here;

The soundcard talks over the I2C bus and the firmware flash talks over the SPI bus, so you need to have them both enabled and configured properly as well within confix.txt

dtparam=i2c_arm=on
dtparam=i2c_arm_baudrate=100000
dtoverlay=i2s-mmap
dtparam=i2s=on
dtparam=spi=on

The whole audio pipeline ONLY supports 48 kHz bitate so you need to configure your sound architecture to play at that bitrate and use a software resampling setup if you would like to play other bitrate files.

On the microphone side you will end up with a two channel PCM card. You need to setup to use the left channel as input.

For pulseaudio the below configuration snippet will split both channels the right way and uses the corrct one as default microphone;

# The Comms channel will attenuate all input audio if there is active output
# The ASR channel will subtract active output and isolate input voice audio
# https://github.com/xmos/vocalfusion-rpi-setup/blob/master/resources/asoundrc_vf_xvf3510_int
# https://www.xmos.ai/download/XVF3510-INT-Datasheet(4.1).pdf
load-module module-remap-source source_name=VF_ASR source_properties="device.description='VocalFusion ASR recording'" master=alsa_input.platform-asoc-simple-card.0.stereo-fallback remix=no master_channel_map=front-left channel_map=mono
load-module module-remap-source source_name=VF_Comms source_properties="device.description='VocalFusion Comms recording'" master=alsa_input.platform-asoc-simple-card.0.stereo-fallback remix=no master_channel_map=front-right channel_map=mono
set-default-source VF_ASR

The above works when you just use the alsa-pulse plugin to send everything towards pulseaudio.

If you want to use ALSA directly, the below asound configuration does the same for you;

#
# The I2S hardware device. Refer to it by name as it will not always
# be the same card number in every system.
#
pcm.i2s_48k {
    type hw
    card sndrpisimplecar
    device 0
    format S32_LE
    channels 2
    rate 48000
}

#
# VocalFusion playback device.
# plug - rate and format conversion
# softvol - control for alsamixer
# dmix - allow device to be shared
#
pcm.VocalFusion {
    type plug
    slave.pcm {
	type softvol
	slave.pcm {
	    type dmix
	    ipc_key 256
	    ipc_perm 0666
	    slave.pcm "i2s_48k"
	}
	control {
	    name "Playback"
	    card sndrpisimplecar
	}
    }
}

#
# VocalFusion Comms & ASR recording.
#
pcm.VF_ASR_Comms_(LR) {
    type plug
    slave.pcm {
	type softvol
	slave.pcm {
	    type dsnoop
	    ipc_key 512
	    ipc_perm 0666
	    slave.pcm "i2s_48k"
	}
	control {
	    name "Record"
	    card sndrpisimplecar
	}
    }
}


#
# VocalFusion ASR recording.
#
pcm.VF_ASR_(L) {
    type plug
    slave.pcm {
	type softvol
	slave.pcm {
	    type dsnoop
	    ipc_key 512
	    ipc_perm 0666
	    slave.pcm "i2s_48k"
	    bindings [0]
	}
	control {
	    name "Record"
	    card sndrpisimplecar
	}
    }
}

#
# VocalFusion Comms recording.
#
pcm.VF_Comms_(R) {
    type plug
    slave.pcm {
	type softvol
	slave.pcm {
	    type dsnoop
	    ipc_key 512
	    ipc_perm 0666
	    slave.pcm "i2s_48k"
	    bindings [1]
	}
	control {
	    name "Record"
	    card sndrpisimplecar
	}
    }
}

#
# Default devices.
#
pcm.!default {
    type asym
    capture.pcm "VF_ASR_(L)"
    playback.pcm "VocalFusion"
}

However you need to change teh cardname “sndrpisimplecar” with the one detected by alsa. Forgot its name. It is in the driver code but not sure anymore which name ALSA wanted.

6 Likes

Thank you so much for that detailed write up! I codified everything I did to get audio working into a script so I could easily repeat it without having to remember all the steps, it’s here for anyone interested (this works for me on a freshly flashed Raspbian, the latest version as of this post). It also installs the mark2-hal service and sets the fan speed to 50% at boot time:

#!/usr/bin/env bash

# enable i2c and spi
echo dtparam=i2c_arm=on | sudo tee -a /boot/config.txt
echo dtparam=i2c_arm_baudrate=100000 | sudo tee -a /boot/config.txt
echo dtparam=i2s=on | sudo tee -a /boot/config.txt
echo dtparam=spi=on | sudo tee -a /boot/config.txt

# install deps
sudo apt install -y build-essential git raspberrypi-kernel-headers
sudo pip install smbus2 ovos_utils

# install vocalfusion driver and overlay
git clone https://github.com/OpenVoiceOS/VocalFusionDriver.git
pushd VocalFusionDriver/driver || exit
make all
sudo cp vocalfusion-soundcard.ko "/lib/modules/$(uname -r)/kernel/sound/"
sudo depmod -a
sudo cp ../xvf3510.dtbo /boot/overlays/
sudo sed -i 's/^dtparam=audio=on/#dtparam=audio=on/g' /boot/config.txt
echo dtoverlay=xvf3510 | sudo tee -a /boot/config.txt
popd || exit

# set up vocalfusion initialization at boot
git clone https://github.com/OpenVoiceOS/ovos-buildroot.git
sudo cp ovos-buildroot/buildroot-external/package/vocalfusion/xvf3510-flash /usr/bin/
sudo chmod 755 /usr/bin/xvf3510-flash
sudo cp ovos-buildroot/buildroot-external/package/vocalfusion/app_xvf3510_int_spi_boot_v4_1_0.bin /usr/share/
sudo sed -i '$i \/usr/bin/xvf3510-flash --direct /usr/share/app_xvf3510_int_spi_boot_v4_1_0.bin\n' /etc/rc.local

# set up pulseaudio
echo default-sample-format = s32le | sudo tee -a /etc/pulse/daemon.conf
echo default-sample-rate = 48000 | sudo tee -a /etc/pulse/daemon.conf
echo default-sample-channels = 2 | sudo tee -a /etc/pulse/daemon.conf
echo deferred-volume-safety-margin-usec = 1 | sudo tee -a /etc/pulse/daemon.conf
echo load-module module-remap-source source_name=VF_ASR source_properties="\"device.description='VocalFusion ASR recording'\"" master=alsa_input.platform-asoc-simple-card.0.stereo-fallback remix=no master_channel_map=front-left channel_map=mono | sudo tee -a /etc/pulse/default.pa
echo load-module module-remap-source source_name=VF_Comms source_properties="\"device.description='VocalFusion Comms recording'\"" master=alsa_input.platform-asoc-simple-card.0.stereo-fallback remix=no master_channel_map=front-right channel_map=mono | sudo tee -a /etc/pulse/default.pa
echo set-default-source VF_ASR | sudo tee -a /etc/pulse/default.pa

# setup mark2 hal
git clone https://github.com/valorekhov/ovos-arch-linux.git
pushd ovos-arch-linux/PKGBUILDs/ovos-enclosure-sj201 || exit
dtc -@ -Hepapr -I dts -O dtb -o build/sj201-buttons.dtbo sj201-buttons-overlay.dts
dtc -@ -Hepapr -I dts -O dtb -o build/sj201-rev10-pwm-fan.dtbo sj201-rev10-pwm-fan-overlay.dts
sudo cp build/sj201-buttons.dtbo /boot/overlays/
sudo cp build/sj201-rev10-pwm-fan.dtbo /boot/overlays/
sudo cp sj201-init.service /etc/systemd/system/
sudo sed -i 's/\/opt\/ovos\/bin/\/usr\/bin/' /etc/systemd/system/sj201-init.service
sudo cp sj201-init.sh /usr/bin/
sudo sed -i 's/\/opt\/ovos\/bin/\/usr\/bin/g' /usr/bin/sj201-init.sh
sudo cp sj201-revisions.sh /usr/bin/
sudo cp sj201-tas5806 /usr/bin/
sudo cp sj201-rev6-fan.sh /usr/bin/
sudo chmod 755 /usr/bin/sj201-*
echo dtoverlay=sj201-buttons | sudo tee -a /boot/config.txt
echo dtoverlay=sj201-rev10-pwm-fan | sudo tee -a /boot/config.txt
sudo systemctl enable sj201-init
popd || exit
6 Likes

For the fan, led and button support another community member has writen the proper overlays and drivers.

I have it planned to merge his work into our OVOS image(s) however considering you obviously know your way around Linux, you might be able to connect the dots yourself already.

Here is his work;

4 Likes

Thanks, I edited my script above to incorporate those overlays instead of the mark2-hal stuff from the sandbox repo. I think it’s all working–audio works, I can hear the fan changing speeds depending on load, and the volume buttons are working now too. The mute switch is kinda working… when I flip it to the mute position it seems like it’s constantly toggling mute on and off, but then I can flip it into the un-mute position to catch one of the two states and make it stick.

2 Likes