• CTAG-ALSA
  • CTAG face support in Linux 5.x kernel

Compiled a 5.10.140 RT kernel with the patched CTAG-2-4 driver. Needed a minor adjustment to use asoc_rtd_to_cpu() and asoc_rtd_to_codec() in the snd_davinci_audiocard_init() and snd_davinci_audiocard_hw_params() functions in sound/soc/ctag/davinci-ctag-face-2-4.c

The modules load:

root@ctag-host:~# lsmod |egrep -i "ctag|ad193x|snd"

snd_soc_davinci_ctag_face_2_4 16384 0
snd_soc_ad193x_spi 16384 0
snd_soc_ad193x 20480 1 snd_soc_ad193x_spi
snd_soc_core 172032 2 snd_soc_davinci_ctag_face_2_4,snd_soc_ad193x
snd_pcm_dmaengine 16384 1 snd_soc_core
snd_pcm 90112 3 snd_soc_ad193x,snd_pcm_dmaengine,snd_soc_core
snd_timer 28672 1 snd_pcm
snd 61440 3 snd_timer,snd_soc_core,snd_pcm
soundcore 16384 1 snd

but there's nothing reported in ALSA:

root@ctag-KR:~# aplay -l
aplay: device_list:278: no soundcards found...

The uEnv.txt file I'm using is a little more complex than the one created in the work mentioned in the previous post. Not sure if that matters.

uname_r=5.10.140+
enable_uboot_overlays=1
disable_uboot_overlay_video=1
disable_uboot_overlay_audio=1
disable_uboot_overlay_wireless=1
disable_uboot_overlay_adc=1
uboot_overlay_pru=AM335X-PRU-UIO-00A0.dtbo
enable_uboot_cape_universal=1
console=ttyS0,115200n8
cmdline=coherent_pool=1M net.ifnames=0 lpj=1990656 rng_core.default_quality=100 ti_cpsw.descs_pool_size=4096 quiet

a month later

So, I'm giving up on 5.x kernels for CTAG ALSA. The instructions in the various projects are incomplete, or maybe just assume that one can fill in the gaps without detail.

For anyone finding this, I'd say that CTAG on ALSA just doesn't work beyond the image provided by @hendrix (https://github.com/ctag-fh-kiel/bela-ctag/releases) which is now very old (4.4 where Linux is about to move to 6.x series).

It's stated that CTAG support is built into kernel now, but that doesn't seem to be a complete statement, as whilst the driver may be available in the kernel in some form, there seems to be some mismatch between the kernel support and overlays which effectively make the use of the CTAG card limited to the 4.4 image above that is based on the the old cape manager method, now deprecated and not used.

Hope the above helps others trying to use the CTAG Face with ALSA.

issues with this is that it doesn't actually contain the driver and while the provided dockerfile may be capable of building an image with the driver, working values for the user_config variables is not provided, essentially making it useless. Btw, the "binary" comes with 5.10 , but the driver as provided won't build for 5.10 because of an API change in 5.7 , so I am wondering what this binary is about ...

@siraaris

I managed to build a 5.10.145+ kernel with the patch provided by anbraten, plus the fixups for the API changes. Then I did a new overlay that loads correctly on the bb org image you linked with this kernel (needs disabiing a few more overlays in uEnv, including cape_universal).

With the correct overlay - which removes any pin conflicts - the soundcard does show up.
IMPORTANT: the soundcard takes over 70 seconds after boot to show up. This I belive is an issue with the requisites of the soundcard target in systemd. I used aplay -D plughw:CARD=C8CH,DEV=0 ~/out.wav and out.wav is an 8-channel wave file with different frequencies per each channel.

Scoping the signals, I see data on all slots, but the DAC only plays on channels 0 and 1 the signals that are set to channels 0 and 4; other channels are muted and sound is not distorted. Upon inspection, I see that the codec is set to I2S mode, which kind of explains why channels 0 and 4 are mapped to 0 and 1.

This seems to be an inconsistency between the mcasp driver and the ad198x driver, so probably an inconsistency in davinci-ctag-face-2-4.c. Perhaps playing around with AUDIOCARD_AD193X_DAIFMT things get fixed. I tried to set it to

-#define AUDIOCARD_AD193X_DAIFMT ( SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_CBM_CFM )
+#define AUDIOCARD_AD193X_DAIFMT ( SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_CBM_CFM )

and this way every time I start the playback with aplay I get a different result. I hear sound on all channels; occasionally I hear undistorted sound, but most of the time it is distorted, possibly with the channels shifted with respect to how they should be. It could be that the codec and mcasp do not agree on who drives the clock, or its polarity.

Further work is needed, but I spent a full day on it and am taking a few days off.

I started from the bb Buster image you linked elsewhere, but any modern image should work the same.

You'll need this in /opt/source/dtb-5.10-ti https://github.com/BelaPlatform/BeagleBoard-DeviceTrees/tree/v5.10.x-ti . make && make install

This uEnv https://gist.github.com/giuliomoro/29885ee2321164e2fc9ba30ed43522a6

I used this kernel source https://github.com/giuliomoro/linux/tree/5.10
following the instructions to build it that are split across several files here https://github.com/anbraten/beagle-bone-builder/tree/master/scripts , where I used a user_config.sh as follows (only the first one is really relevant as I didn't manage to finish building the image. There is no docs as to what these values are supposed to be):

KERNEL_BRANCH=5.10
ROOTFS_NAME=debian-10.13-minimal-armhf-2022-10-06
UBOOT_VERSION=v2019.04

For relatively quick iteration - after a full build and install - I build with
(after sourcing scripts/config.sh) :

make ARCH=arm CROSS_COMPILE="${CACHED_CC}"  modules && \
sudo make ARCH=arm CROSS_COMPILE="${CACHED_CC}" modules_install INSTALL_MOD_PATH=/lfs/tmp/fs/rootfs`

and then scp the relevant files /lfs/tmp/fs/rootfs/lib/modules/5.10.145+/kernel/sound/soc/ctag/snd-soc-davinci-ctag-face-2-4.ko.xz and /lfs/tmp/fs/rootfs/lib/modules/5.10.145+/kernel/sound/soc/codecs/snd-soc-ad193x.ko.xz to the board and reboot. I have to reboot because modprobe -r doesn't want to remove the modules for me. If you have suggestions on how to iterate more quickly (I think I could manually zip the two relevant modules instead of relying on modules_install to do it for me), I am all ears.

The latest commit on the kernel repo includes some debugging printks (and also changing the data format). I print the registers of the codec and they can be compared against the ones used when running CTAG with Bela:

0 156
1 8
2 64
3 12
4 24
5 0
6 0
7 0
8 0
9 0
10 0
11 0
12 0
13 0
14 0
15 35
16 108

(note that they don't necessarily have to match because the McASP config could also be different).

Anyhow, that's what I have so far. @siraaris if you want to keep digging, check for consistency in the dai format as seen from the codec and from the mcasp.

further thought: as it seems that the format for the codec is hardcoded in AUDIOCARD_AD193X_DAIFMT , there may be two ways out: one is editing the driver until it works, the other is fixing it from the device tree overlay.

I've compiled up a kernel with above instructions and confirm that the driver loads:

[   24.785735] snd_davinci_audiocard_probe
[   24.785981] snd_ctag_face_2_4 sound: snd_soc_register_card failed (-517)
[   25.792533] ad193x_probe
[   25.792681] has_adc
[   26.005560] snd_davinci_audiocard_probe
[   26.006447] ad193x_component_probe
[   26.006461] ad193x_reset
[   26.008468] ad193x_reg_default_init
[   26.011822] 0 0x00
[   26.011838] 1 0x00
[   26.011845] 2 0x00
[   26.011851] 3 0x00
[   26.011858] 4 0x00
[   26.011864] 5 0x00
[   26.011870] 6 0x00
[   26.011876] 7 0x00
[   26.011883] 8 0x00
[   26.011889] 9 0x00
[   26.011895] 10 0x00
[   26.011902] 11 0x00
[   26.011908] 12 0x00
[   26.011914] 13 0x00
[   26.011920] 14 0x00
[   26.011927] 15 0x00
[   26.011933] 16 0x00
[   26.022437] has_adc
[   26.027926] has_adc
[   26.028170] snd_davinci_audiocard_init
[   26.028225] SET_TDM_SLOT for both to ff ff 8 32
[   26.028236] ad193x_set_tdm_slot ff ff 8 32
[   26.033355] has_adc
[   26.034470] ad193x_set_dai_fmt
[   26.034483] ad1938 DSP
[   26.034490] has_adc

I can remove modules:

rmmod snd_soc_davinci_ctag_face_2_4 snd_soc_ad193x_spi snd_soc_ad193x

and re-insert:

modprobe snd-soc-ad193x snd-soc-ad193x-spi snd-soc-davinci-ctag-face-2-4

When I enable debugging, here's the dmesg:

mclk not found may be of interest.

[ 3404.436826] snd_davinci_audiocard_remove
[ 3408.609296] ad193x_probe
[ 3408.611999] has_adc
[ 3442.848434] ad193x_probe
[ 3442.851404] has_adc
[ 3443.896054] snd_davinci_audiocard_probe
[ 3443.900744] ad193x_component_probe
[ 3443.906847] ad193x_reset
[ 3443.912941] ad193x_reg_default_init
[ 3443.918309] 0 0x00
[ 3443.920343] 1 0x08
[ 3443.924266] 2 0x00
[ 3443.927683] 3 0x00
[ 3443.931054] 4 0x00
[ 3443.934339] 5 0x00
[ 3443.936372] 6 0x00
[ 3443.940308] 7 0x00
[ 3443.943720] 8 0x00
[ 3443.947160] 9 0x00
[ 3443.950500] 10 0x00
[ 3443.952619] 11 0x00
[ 3443.956377] 12 0x00
[ 3443.959821] 13 0x00
[ 3443.963270] 14 0x00
[ 3443.966905] 15 0x00
[ 3443.970321] 16 0x00
[ 3443.975176] has_adc
[ 3443.977738] has_adc
[ 3443.980099] snd_davinci_audiocard_init
[ 3443.986467] SET_TDM_SLOT for both to ff ff 8 32
[ 3443.992464] ad193x_set_tdm_slot ff ff 8 32
[ 3443.998260] has_adc
[ 3444.000550] ad193x_set_dai_fmt
[ 3444.005590] ad1938 DSP
[ 3444.007975] has_adc
[ 3598.828548] snd_davinci_audiocard_remove
[ 3603.000851] ad193x_probe
[ 3603.003822] has_adc
[ 3604.050799] snd_davinci_audiocard_probe
[ 3604.055085] snd_ctag_face_2_4 sound: mclk not found.
[ 3604.065521] ad193x_component_probe
[ 3604.068960] ad193x_reset
[ 3604.075884] ad193x_reg_default_init
[ 3604.081360] 0 0x00
[ 3604.083394] 1 0x08
[ 3604.087203] 2 0x00
[ 3604.090549] 3 0x00
[ 3604.092581] 4 0x00
[ 3604.096393] 5 0x00
[ 3604.099816] 6 0x00
[ 3604.103174] 7 0x00
[ 3604.106510] 8 0x00
[ 3604.108543] 9 0x00
[ 3604.112390] 10 0x00
[ 3604.115763] 11 0x00
[ 3604.119186] 12 0x00
[ 3604.122606] 13 0x00
[ 3604.124724] 14 0x00
[ 3604.128588] 15 0x00
[ 3604.132094] 16 0x00
[ 3604.136604] has_adc
[ 3604.140253] has_adc
[ 3604.143987] snd_davinci_audiocard_init
[ 3604.149230] snd_ctag_face_2_4 sound: Using configuration from dt overlay.
[ 3604.159443] SET_TDM_SLOT for both to ff ff 8 32
[ 3604.165662] ad193x_set_tdm_slot ff ff 8 32
[ 3604.171533] has_adc
[ 3604.175225] ad193x_set_dai_fmt
[ 3604.179545] ad1938 DSP
[ 3604.183257] has_adc
5 days later

An update: it works-hacked. https://github.com/giuliomoro/linux/tree/5.10-ctag-hacks

Notes first:

Workflow

Quick reload of modules: you need to unload and reload them in this order:

sudo modprobe -r snd_soc_davinci_ctag_face_2_4
sudo modprobe -r snd_soc_ad193x_spi
sudo modprobe -r snd_soc_ad193x
sudo modprobe -r snd_soc_davinci_mcasp
sudo modprobe snd_soc_davinci_mcasp
sudo modprobe snd_soc_ad193x
sudo modprobe snd_soc_ad193x_spi
sudo modprobe snd_soc_davinci_ctag_face_2_4

My current fast iteration script is as follows:

on the build machine quick-build.sh in kernel/ is:

#!/bin/bash
. ../../scripts/config.sh && make ARCH=arm -j$(nproc) CROSS_COMPILE="${CACHED_CC}"  modules
set -x
rm -rf  sound/soc/{ctag,codecs,ti}/snd-*.xz
xz -k sound/soc/ti/snd-soc-davinci-mcasp.ko
xz -k sound/soc/ctag/snd-soc-davinci-ctag-face-2-4.ko
xz -k sound/soc/codecs/snd-soc-ad193x.ko

on the target I have

#!/bin/bash
set -ex
REMOTE=bui
REMOTE_PREFIX=/lfs/tmp/kernel/sound/soc/
LOCAL_PREFIX=/lib/modules/5.10.145+/kernel/sound/soc/
MOD_EXT=.ko.xz
MODULES_PATHS="ti/snd-soc-davinci-mcasp codecs/snd-soc-ad193x ctag/snd-soc-davinci-ctag-face-2-4"
#MODULES_PATHS="codecs/snd-soc-ad193x ctag/snd-soc-davinci-ctag-face-2-4"
MODULES=
for a in $MODULES_PATHS; do
	MODULES="$MODULES $(basename $a)"
done
MODULES="$MODULES snd_soc_ad193x_spi"
RSYNC_LIST=
for a in $MODULES_PATHS; do
	RSYNC_LIST="$RSYNC_LIST $REMOTE:$REMOTE_PREFIX/$a$MOD_EXT"
done

rsync -av $RSYNC_LIST ./
sudo modprobe -r snd_soc_davinci_ctag_face_2_4
sudo modprobe -r snd_soc_ad193x_spi
sudo modprobe -r snd_soc_ad193x
sudo modprobe -r snd_soc_davinci_mcasp

for a in $MODULES_PATHS; do
	sudo cp $(basename $a)$MOD_EXT $LOCAL_PREFIX/$a$MOD_EXT
done
for a in $MODULES; do
	sudo modprobe $a
done

Then from the target I can run:

ssh bui "cd /lfs/tmp/kernel/ && ./quick-build.sh" && ./deploy.sh  && sleep 0.5 && aplay -D plughw:CARD=C8CH,DEV=0 ~/out.wav

(the above is mostly for my future self).

Driver and codec issues

Most of the entries in the dtb are ignored. As far as I can tell from grep ing through sound/, mcasp-controller-bit-delay-tx and mcasp-controller-bit-delay-rx from the device tree are not handled anywhere.

The AD1938 seems to mostly ignore the values in SDATA delay (DAC Control Register0 bits 5:3, AD193X_DAC_CTRL0) when in TDM mode. I don't see this explicitly stated in the datasheet anywhere. However it seems to be affected - at least to a certain extent - by SDATA delay (ADC Control Register 1 bits 4:2, AD193X_ADC_CTRL1), which makes little sense to me.

I found out experimentally that, when the DAC is set to TDM mode (and it ignores the DAC SDATA delay in AD193X_DAC_CTRL0 and with the ADC SDATA delay in AD193X_ADC_CTRL1 set to the default value of 1), it expects a data format that corresponds to what the McASP would call "data_delay = 2" ( i.e.: the word starts not at the same time as the frame clock ("data_delay = 0"), not on the first bitclock after the frame clock ("data_delay = 1"), but on the second bitclock after the frame clock ("data_delay = 2"). The data_delay property in the McASP's XFMT register (DAVINCI_MCASP_TXFMT_REG), however, can only be set to 0 or 1 in davinci_mcasp_set_dai_fmt(), and it currently can only be set to 2 via a hack, or perhaps calling mcasp_set_bits() from the driver after davinci_mcasp_set_dai_fmt() has been called. I didn't investigate that part.
https://github.com/giuliomoro/linux/commit/dc06cf9e383d265ebb3c055ddd2ac87a8fe7e60f shows this solution (via hack), which would also break any other driver using McASP.

An alternative, which leverages the fact that somehow the DAC format is affected by the ADC format register is in https://github.com/giuliomoro/linux/commit/0bf82f6cf053d8d6bfa600e04f60d12db17dc92e. This doesn't break any core mcasp stuff, but it leverages a poorly understood undefined or undocumented behaviour. Good enough for a PoC.

Known issues

Probably a better approach is needed, but this codec behaves so weirdly that I am not sure it's worth the pain.

I noticed that with either version of the driver above, if you stop/restart the aplay enough times, you may get that the output's amplitude becomes smaller, almost half, as if it was shifted by one bit to the right, but I don't see any bit shifting on the McASP side. If you unload and reload the snd_soc_davinci_ctag_face_2_4 module at that point, the amplitude increases slightly. If you also unload and reload (in order) snd_soc_ad193x_spi, then it goes back to normal. It may well be some issue with how the codec is handled there .. for instance: is it being reset appropriately? I didn't look at it.

You can easily reproduce the issue letting this running:

while sleep 0.1; do aplay -D plughw:CARD=C8CH,DEV=0 ~/out.wav & sleep 0.5; killall -2 aplay; done

A workaround is to always run

sudo modprobe -r snd_soc_davinci_ctag_face_2_4
sudo modprobe -r snd_soc_ad193x_spi
sudo modprobe snd_soc_ad193x_spi
sudo modprobe snd_soc_davinci_ctag_face_2_4

after opening/closing the soundcard (via aplay or otherwise).

    giuliomoro looking at your overlay, is there a delay of 1 for the McASP controller and another 1 for the interface (making a total delay of 2?). It does seem that the overlay would be the way to make this work. Reviewing the driver kernel code in the BB and TI kernels there’s not much difference (I notice the _priv struct is slightly different).

    My approach is based (following in parallel what you’ve been doing) on using buildroot to create a very small firmware for my project, removing all the unessary items/modules etc as I only need Ethernet and CTAG and GSTreamer plus ALSA.

    Ideally I’d have the CTAG driver compiled in not as a module.

      siraaris ooking at your overlay, is there a delay of 1 for the McASP controller and another 1 for the interface (making a total delay of 2?).

      As mentioned, I think many of the entries in the dtb are ignored. I could not manage to generate any difference on the McASP side (i.e.: observable changes in the delay between frame clock and data) or on the codec side (i.e.: observable changes in the registers set by the driver (as printed or changes in the analog signal generated by the DAC) when changing any of ti,audio-codec-bit-delay-dac or ti,audio-codec-bit-delay-dac = <1>. Inspecting the driver's source I don't see where those would be read anyhow and - interestingly - inspecting the commit log (-p) of the relevant files doesn't show me these have ever been used anywhere (as far as I can tell).

      siraaris Ideally I’d have the CTAG driver compiled in not as a module.

      Even when it is, you should still be able to bind/unbind it if needed, i.e.::

      echo  "ocp:bone_sound" | sudo tee /sys/bus/platform/drivers/snd_ctag_face_2_4/unbind
      echo  "ocp:bone_sound" | sudo tee /sys/bus/platform/drivers/snd_ctag_face_2_4/bind

      (I think). But sure it would be best to just fix the driver so it doesn't require this step.

      17 days later

      Just a quick note, I spent some time getting a Yocto setup working with 5.10-ctag-hacks. Had to combine the CTAG overlay into the device tree am335x-boneblack.dts as I couldn't get loading of DTBO's working.

      Did a very quick test, and confirm driver loading, and aplay/arecord seem to behave as expected on initial inspection.

      I think that I'll be able to progress with the POC and get a better sense and actual listening of the project during the end of year break - thank you.

        siraaris I couldn't get loading of DTBO's working.

        That's normally done in uboot.

        a year later

        I've been trying to follow along. I've compiled new kernel modules for the BBB bullseye release 11.7 with the 5.10-ctag-hacks and the API changes.
        If I don't include the DTBO overlay in the eEnv.txt then the sound card shows up in ALSA but its not really working.
        If I actively enable the DTBO overlay the in uEnv.txt the sound card doesn't show up at all in ALSA.

        @siraaris It seems you got things working. I understand you integrated the CTAG overlay into the device tree am335x-boneblack.dts, correct? Is there any way you could share you merged device tree file?
        Did you have to make further changes to the driver/codes as proposed by giuliomoro ?

          amessner If I don't include the DTBO overlay in the eEnv.txt then the sound card shows up in ALSA but its not really working.
          If I actively enable the DTBO overlay the in uEnv.txt the sound card doesn't show up at all in ALSA.

          can you show the content of uEnv.txt in either cases?

            giuliomoro
            I've attached the uEnv.txt where I see a sound card in ALSA but it doesn't actually use the device tree overlay for the CTAG face -> uEnv_original.txt
            I can run "speaker-test -D hw:0 -c 2 -r 48000 -t sine -f 1000" (please note channel count 2). If I try any higher channel count it doesn't work. And even with 2 channels I don't hear anything on any of the CTAG outputs.

            I've tried multiple configurations, the last one I tried is actually taken from one of your earlier posts. With this uEnv.txt I don't see a sound card in ALSA at all -> uEnv.txt.

            I found that adding the device tree overlay for CTAG to the uEnv.txt OR disabling any of the overlays for video, audio, etc will cause the sound card to disappear

            uenv.txt
            2kB
            uenv-original.txt
            2kB

            .

            OK I managed to have a look at this. You need this branch in /opt/sources/dtb-5.10-ti and then do make && sudo make install to put the update base device tree and overlay in place. At that point those will be loaded OK, but no soundcard will appear because the driver is not there and so you need to build and install the driver, as you can tell because modprobe snd-soc-ad193x snd-soc-ad193x-spi snd-soc-davinci-ctag-face-2-4 fails. I have not repeated the build and install procedure because it should be the same as previously and also I don't have machine to build it on with me right now, but hopefully you can.

            Thank you @giuliomoro.

            @amessner based on the above activity I dug out my BBB/CTAG and am going to attempt to rekindle where I got to previously - might be a week or so.

            Ok I made some progress.

            I used the latest Bullseye Image for the BBB (kernel 5.10.168-ti-r72) as a base.
            Then patched (https://github.com/anbraten/beagle-bone-builder/tree/master/resources/ctag-2.4) and compiled the drivers for snd-soc-ad193x, snd-soc-ad193x-spi and snd-soc-davinci-ctag-face-2-4, copied them over and confirmed that they load.

            Then I updated the uEnv.txt (see uEnv.txt of my last post)

            Now I can play sounds on 2 channels, but not on the other 6.
            If I try recording something it also doesn't "really" work. Sometimes I get a very noisy file, sometimes nothing.

            Did anyone get as far as to record something successfully? Or did you just test by playing back a test wav file?

            @giuliomoro if I try to use your device tree branch then the image won't even boot anymore.

              I won't be able to have another look until some point next week.

              amessner if I try to use your device tree branch then the image won't even boot anymore

              to troubleshoot that you'd need to get a serial log from the UART0 port on the BBB.