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

Does anyone have the CTAG face 8 working on a recent Linux 5.x kernel with ALSA, eg with 5.18?

Aris

Nod, am aware of that project. I failed to apply the 5.4 notes on 5.15 (maybe it was me), and the implementation is admittedly incomplete.

I was hoping that someone here might have made more progress.

When looking at the overlay code it didn’t seem very complicated. However I haven’t worked out what would be involved yet to get CTAG ALSA working on 5.x kernels, esp recent ones.

For example, is CTAG code in the 5.x kernels ok, and what’s left is to get the overlay working, noting that the overlay mechanisms seem to have changed over the 5.x timeline?

The project above also noted other kernel areas that needed work for CTAG / ALSA to work properly on 5.4 at the time, let alone what other work would be required for 5.19 or now 6.0 coming up.

Is there a maintainer for CTAG Linux ALSA support that I can refer to or is it just here on this forum?

4 days later

Just as FYI, on 4.19, I simply activated the overlay in uEnv and the CTAG ALSA interface was available on reboot without need to activate pins via a shell script on /proc etc.

Interestingly, only 48k sample rate works:

aplay -D hw:CARD=C8CH,DEV=0 48k-24b_LE_8CH.raw -t raw -c 8 -f S24_LE -r 48000

Playing raw data '48k-24b_LE_8CH.raw' : Signed 24 bit Little Endian, Rate 48000 Hz, Channels 8

Trying 96khz or 192khz returns errors:

aplay -D hw:CARD=C8CH,DEV=0 96k-24b_LE_8CH.raw -t raw -c 8 -f S24_LE -r 96000

Playing raw data '96k-24b_LE_8CH.raw' : Signed 24 bit Little Endian, Rate 96000 Hz, Channels 8
Warning: rate is not accurate (requested = 96000Hz, got = 48000Hz)
please, try the plug plugin

aplay -D hw:CARD=C8CH,DEV=0 192k-24b_LE_8CH.raw -t raw -c 8 -f S24_LE -r 192000

Playing raw data '192k-24b_LE_8CH.raw' : Signed 24 bit Little Endian, Rate 192000 Hz, Channels 8
Warning: rate is not accurate (requested = 192000Hz, got = 48000Hz)
please, try the plug plugin

The desired target is to have the CTAG (8 in my case) working on current Linux kernels, eg 5.19 at 48khz, 96khz and 192khz with S24_LE format. I believe that’s what the specs of the device are?

Hi, there is some work on Media IP streaming with the CTAG face:
https://www.creative-technologies.de/setup-and-evaluation-of-an-media-ip-real-time-system/

The student created a script to build a 5.10 kernel with patched driver for the CTAG face:
https://github.com/anbraten/beagle-bone-builder

It includes a patched driver:
https://github.com/anbraten/beagle-bone-builder/tree/master/resources/ctag-2.4

A binary is released here:
https://github.com/anbraten/beagle-bone-builder/releases/tag/0.0.9

Let me know if this was of any help.

    6 days later

    Thank you! I will give the above a try and report back on progress.

    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.