注意

这是最新开发分支的文档,可能包含尚未在发布版本中提供的功能。如果您在寻找特定版本的文档,请使用左侧的下拉菜单选择。

音频使用说明#

概述#

K230 的音频子系统提供三条采集通路和一条播放通路:

通路

信号来源

涉及引脚

所属声卡

内置 codec 采集

板载模拟麦克风

芯片内部,不占用引脚

K230_I2S_INNO

外置 I2S 数字麦采集

I2S 从设备(数字麦克风)

IO32、IO33 + IO34 或 IO36

K230_I2S_INNO

PDM 数字麦采集

PDM 麦克风,最多 4 根数据线 8 声道

IO26 + IO27(或 IO37)、IO28(或 IO35)、IO36、IO34

K230_PDM

播放

内置 codec 或外置 I2S DAC

耳机座 / IO35

K230_I2S_INNO

默认镜像只使能内置 codec。外置 I2S 数字麦和 PDM 数字麦都需要修改板级设备树, 分别见下面两节。

查看系统中的声卡:

[root@canaan ~ ]#cat /proc/asound/cards
 0 [K230I2SINNO    ]: K230_I2S_INNO - K230_I2S_INNO
                      K230_I2S_INNO
 1 [K230PDM        ]: K230_PDM - K230_PDM
                      K230_PDM

声卡编号由驱动注册顺序决定,未配置 PDM 时只有 0 号一张卡。本文中的 hw:0,0hw:1,0amixer -c0 按上面这份实测编号书写,实际编号以 cat /proc/asound/cards 为准。

内置 codec#

板级设备树中的 sound 节点(各板卡默认已有,不需要修改):

sound {
    status                      = "okay";
    compatible                  = "canaan,k230-audio-inno";
    canaan,model                = "K230_I2S_INNO";
    canaan,k230-i2s-controller  = <&i2s>;
    canaan,k230-audio-codec     = <&inno_codec>;
};

录音和播放:

# 板载模拟麦录音
arecord -D hw:0,0 -f S16_LE -r 44100 -c 2 -d 10 test.wav

# 播放
aplay -D hw:0,0 test.wav

外置 I2S 数字麦#

外置数字麦克风作为 I2S 从设备接在 K230 上,K230 提供时钟。支持两种接法, 在设备树中选择。

引脚#

引脚

function

功能

用途

io32

alt2

IIS_CLK

位时钟,两种接法都要

io33

alt2

IIS_WS

帧时钟,两种接法都要

io34

alt2

IIS_D_IN0

接法 A 的数据输入,对应声道 0/1

io36

alt2

IIS_D_IN1

接法 B 的数据输入,对应声道 2/3

io35

alt2

IIS_D_OUT0

数据输出,接外置 I2S DAC 时才需要

设备树属性#

sound 节点里新增,两个属性都是可选的,都不写时行为与默认镜像一致:

属性

取值

缺省

作用

canaan,i2s-route

internal-codec / external-i2s

internal-codec

声道 0/1 的来源:内置 codec 或 IO34

canaan,rx1-source

none / external-i2s

none

是否启用 IO36 作为声道 2/3

canaan,i2s-route 只是开机默认值,运行时可以用 Codec Route 控件切换; canaan,rx1-source 决定采集声道数上限(2 或 4),只能开机确定

接法 A:IO34 外置数字麦,2 声道#

声道 0/1 来自 IO34,内置 codec 不参与采集。

/ {
    sound {
        status                      = "okay";
        compatible                  = "canaan,k230-audio-inno";
        canaan,model                = "K230_I2S_INNO";
        canaan,k230-i2s-controller  = <&i2s>;
        canaan,k230-audio-codec     = <&inno_codec>;

        canaan,i2s-route = "external-i2s";
    };
};

&iomux {
    i2s_pins: i2s_pins {
        pin_clk_ws {
            pins = "io32", "io33";  /* IIS_CLK、IIS_WS */
            function = "alt2";
            output-enable;
            input-disable;
            bias-disable;
            drive-strength = <7>;
        };
        pin_din0 {
            pins = "io34";
            function = "alt2";      /* IIS_D_IN0 */
            input-enable;
            output-disable;
            bias-disable;
        };
        pin_dout0 {
            pins = "io35";
            function = "alt2";      /* IIS_D_OUT0,只录音可省略 */
            output-enable;
            input-disable;
            bias-disable;
            drive-strength = <7>;
        };
    };
};

&i2s {
    pinctrl-names = "default";
    pinctrl-0 = <&i2s_pins>;
};

采集:

amixer -c0 cset name='Codec Route' 'External I2S'   # 切到 IO34
arecord -D hw:0,0 -f S16_LE -r 44100 -c 2 -d 10 test.wav

amixer -c0 cset name='Codec Route' 'Internal Codec' # 切回板载模拟麦

注意

Codec Route 是双向的:切到 External I2S 后,采集来自 IO34,播放数据从 IO35 输出,板载喇叭无声。要听声音需要在 IO35 接外置 I2S DAC,或者先切回 Internal Codecaplay

录音或播放进行中不能切换,此时 amixer 会返回 Device or resource busy

要让选择在重启后保留,推荐用设备树属性 canaan,i2s-route 设定开机默认值。 默认镜像开机不执行 alsactl restore,所以只跑 alsactl store 是不生效的, 要用它得自己补一个开机恢复脚本:

alsactl store                       # 存到 /var/lib/alsa/asound.state
cat > /etc/init.d/S60alsa <<'EOF'
#!/bin/sh
[ "$1" = start ] && alsactl restore
EOF
chmod +x /etc/init.d/S60alsa

接法 B:内置 codec + IO36 外置数字麦,4 声道#

声道 0/1 是板载模拟麦,声道 2/3 是 IO36 上的外置数字麦,两者同时采集。 sound 节点只加 canaan,rx1-source

/ {
    sound {
        status                      = "okay";
        compatible                  = "canaan,k230-audio-inno";
        canaan,model                = "K230_I2S_INNO";
        canaan,k230-i2s-controller  = <&i2s>;
        canaan,k230-audio-codec     = <&inno_codec>;

        canaan,rx1-source = "external-i2s";
    };
};

&iomux {
    i2s_pins: i2s_pins {
        pin_clk_ws {
            pins = "io32", "io33";  /* IIS_CLK、IIS_WS */
            function = "alt2";
            output-enable;
            input-disable;
            bias-disable;
            drive-strength = <7>;
        };
        pin_din1 {
            pins = "io36";
            function = "alt2";      /* IIS_D_IN1 → 声道 2/3 */
            input-enable;
            output-disable;
            bias-disable;
        };
    };
};

&i2s {
    pinctrl-names = "default";
    pinctrl-0 = <&i2s_pins>;
};

这种接法下 IO34 不参与采集,不需要配置,Codec Route 保持默认值 Internal Codec 即可,播放从板载喇叭正常出声。

采集并拆分成两个文件:

arecord -D hw:0,0 -f S16_LE -r 44100 -c 4 -d 10 test_4.wav

ffmpeg -i test_4.wav -af "pan=stereo|c0=c0|c1=c1" 内置.wav
ffmpeg -i test_4.wav -af "pan=stereo|c0=c2|c1=c3" 外置.wav

4 声道的交织顺序是 [内置L][内置R][外置L][外置R]

检查#

# 接法 B 应打印 external-i2s。设备树字符串带结尾 '\0',用 tr 去掉便于脚本比较
cat /proc/device-tree/sound/canaan,rx1-source | tr -d '\0'

arecord -D hw:0,0 --dump-hw-params              # 接法 B 应出现 CHANNELS: [2 4]
amixer -c0 cget name='Codec Route'              # 查看当前通路

没写这个属性时 /proc/device-tree/sound/canaan,rx1-source 不存在catNo such file or directory 是正常的,表示走缺省值 none

PDM 数字麦#

PDM 是一条独立的采集通路,不占用 I2S 控制器,注册为单独的声卡 K230_PDM只能采集,不能播放,可以和内置 codec 的录音、播放同时使用。

接线和引脚#

PDM 麦克风只需要时钟、数据、地和供电。一根数据线上可以挂两个麦克风, 两者的 L/R 引脚一个接 GND、一个接 VDD,各自占用时钟的一个边沿:

K230 IO26 ─── CLK ──┬──▶ MIC A   L/R 接 GND → 上升沿
                    └──▶ MIC B   L/R 接 VDD → 下降沿

K230 IO27 ◀── DATA ─┬─── MIC A
                    └─── MIC B   两个麦克风共用这一根数据线

芯片共有 4 根数据线,每根 2 个麦克风,最多 8 声道:

数据线

引脚

function

对应声道

PDM_IN0

io27(或 io37)

alt3(io37 为 alt2)

0、1

PDM_IN1

io28(或 io35)

alt3(io35 为 alt2)

2、3

PDM_IN2

io36

alt2

4、5

PDM_IN3

io34

alt2

6、7

时钟固定用 io26(alt3,PDM_CLK)。

设备树配置#

在板级设备树的根节点下新增 sound_pdm 节点,并配置引脚。下面是 一根数据线、2 声道的最小配置:

/ {
    sound_pdm: sound_pdm {
        status        = "okay";
        compatible    = "canaan,k230-audio-pdm";
        canaan,model  = "K230_PDM";
        clocks        = <&pdm_clk>;
        clock-names   = "pdm";
        dmas          = <&pdma 1 0xfff 0 0x21>;
        dma-names     = "rx";
        pinctrl-names = "default";
        pinctrl-0     = <&pdm_pins>;
    };
};

&iomux {
    pdm_pins: pdm_pins {
        pin_clk {
            pins = "io26";
            function = "alt3";      /* PDM_CLK */
            output-enable;
            input-disable;
            bias-disable;
            drive-strength = <7>;
            input-schmitt = <0>;
        };
        pin_data0 {
            pins = "io27";
            function = "alt3";      /* PDM_IN0 */
            input-enable;
            output-disable;
            bias-disable;
            drive-strength = <4>;
            input-schmitt = <0>;
        };
    };
};

clocksdmas 这几行是固定写法,照抄即可。

可选属性#

四个属性都可以不写,不写就是下表中的缺省值(一根数据线、双边沿、2 声道):

属性

取值

缺省

作用

canaan,pdm-data-lines

1 ~ 4

1

接了几根数据线,从 PDM_IN0 数起

canaan,pdm-edge

both / rising / falling

both

在哪个时钟边沿采样,both 表示一根线两个麦

canaan,pdm-oversample

32 / 64 / 128

64

过采样倍率,与采样率一起决定 PDM 时钟频率

canaan,pdm-io-group

io27-28 / io35-37

io27-28

前两根数据线接在哪组引脚上

声道数 = 数据线数 × (both ? 2 : 1),最多 8。

注意

canaan,pdm-io-group 必须和实际接线一致。前两根数据线接在 io35/io37 上的板卡 要写 canaan,pdm-io-group = "io35-37",配错的表现是全程静音。

选了 io35-37 之后,io35 和 io37 就不能再作 I2S 数据输出,也就是 io35(IIS_D_OUT0)上接不了外置 I2S DAC 播放;同时 io27、io28 无论 pinctrl 怎么配都收不到 PDM 数据了。第 3、4 根数据线(io36、io34)不受这个属性影响, 按 pinctrl 配置即可。

增加数据线#

canaan,pdm-data-linespdm_pins 里的引脚必须一起改,写几根线就在 pins 列表里列几个引脚。接满 4 根线(8 声道)时:

    sound_pdm: sound_pdm {
        /* 其余属性同上 */
        canaan,pdm-data-lines = <4>;    /* 4 根线 × 双边沿 = 8 声道 */
    };
&iomux {
    pdm_pins: pdm_pins {
        pin_clk {
            pins = "io26";
            function = "alt3";      /* PDM_CLK */
            output-enable;
            input-disable;
            bias-disable;
            drive-strength = <7>;
            input-schmitt = <0>;
        };

        pin_data01 {
            pins = "io27", "io28";  /* PDM_IN0、PDM_IN1 */
            function = "alt3";
            input-enable;
            output-disable;
            bias-disable;
            drive-strength = <4>;
            input-schmitt = <0>;
        };

        pin_data23 {
            pins = "io36", "io34";  /* PDM_IN2、PDM_IN3 */
            function = "alt2";
            input-enable;
            output-disable;
            bias-disable;
            drive-strength = <4>;
            input-schmitt = <0>;
        };
    };
};

一个子节点里的所有引脚共用同一条 function 和同一份配置,所以数据脚按档位分成 两个子节点:io27、io28 是 alt3,io36、io34 是 alt2,档位不同的引脚不能写在一起。

只要 6 声道就写 canaan,pdm-data-lines = <3>,并把 pin_data23pins 改成只有 "io36";只要 4 声道就写 <2>,整个 pin_data23 都不要。

注意

用到第 4 根线(io34)时,必须把 Codec Route 切到 External I2S, 否则声道 6、7 始终是一个恒定的满量程值:

amixer -c0 cset name='Codec Route' 'External I2S'

切过去之后内置 codec 的采集和播放都不可用(板载模拟麦、板载喇叭)。 只用 3 根线(io27 + io28 + io36,6 声道)没有这个限制。

采集#

# 先确认驱动认到的配置和实际接线一致
dmesg | grep -i pdm
# PDM capture: 1 data line(s) on IO27/IO28, both edge, 64x oversampling, up to 2 channels

# 录音
arecord -D hw:1,0 -f S16_LE -r 48000 -c 2 -d 10 pdm.wav

# 从板载喇叭放出来听
aplay -D hw:0,0 pdm.wav

硬件出的是 24bit,驱动支持三种格式:

-f

得到的数据

使用场景

S16_LE

24bit 的高 16 位

常规录音、语音识别,推荐

S24_LE

完整 24bit,装在 4 字节容器低位

需要满精度

S32_LE

24bit 左移 8 位

后续处理链要求 32bit 对齐

多声道采集,声道数只能从 1 到上限连续取,不能跳着指定:

arecord -D hw:1,0 --dump-hw-params 2>&1 | grep -i channels
# 根线时应为 CHANNELS: [1 8]

amixer -c0 cset name='Codec Route' 'External I2S'   # 需要声道 6、7 时才执行
arecord -D hw:1,0 -f S16_LE -r 48000 -c 8 -d 5 八声道.wav

# 拆成单声道文件
for i in 0 1 2 3 4 5 6 7; do
    ffmpeg -y -i 八声道.wav -af "pan=mono|c0=c$i" ch$i.wav
done

canaan,pdm-edge = "both" 时的声道对应关系:

声道

来源

声道

来源

0

io27,L/R 接 GND

4

io36,L/R 接 GND

1

io27,L/R 接 VDD

5

io36,L/R 接 VDD

2

io28,L/R 接 GND

6

io34,L/R 接 GND

3

io28,L/R 接 VDD

7

io34,L/R 接 VDD

PDM 和内置 codec 可以同时使用:

arecord -D hw:1,0 -f S16_LE -r 48000 -c 2 -d 20 pdm.wav &
arecord -D hw:0,0 -f S16_LE -r 48000 -c 2 -d 20 板载麦.wav &
aplay   -D hw:0,0 test.wav
wait

资源冲突#

io34 和 io36 同时是 I2S 数据输入和 PDM 数据输入,同一时刻只能给一条通路使用:

需求

PDM 数据线

可用的外置 I2S 数字麦

2 声道 PDM

io27

io34、io36 都可用

4 声道 PDM

io27 + io28

io34、io36 都可用

6 声道 PDM

+ io36

只剩 io34

8 声道 PDM

+ io36 + io34

都不可用,且需要切 Codec Route

板载模拟麦(内置 codec 采集)和喇叭播放在上述组合下都不受影响, 但 Codec Route 切到 External I2S 后不可用。

上表是前两根数据线接 io27、io28(缺省的 canaan,pdm-io-group = "io27-28")的情况。 改接 io35、io37(canaan,pdm-io-group = "io35-37")时还会多一条冲突:io35 是 IIS_D_OUT0,被 PDM 占走后外置 I2S DAC 播放不可用,板载喇叭播放不受影响。

评论列表
条评论
登录