This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] TAC5111:当使用双通道 PDM 麦克风时、TAC5111 Linux 驱动程序会错误地启用 ADC、导致第一个 PDM 通道无法使用

Guru**** 2766605 points

Other Parts Discussed in Thread: TAC5111

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/audio-group/audio/f/audio-forum/1607993/tac5111-tac5111-linux-driver-wrongly-enables-adc-when-using-dual-channel-pdm-mics-rendering-first-pdm-channel-unusable

器件型号: TAC5111

您好、

我们将在 i.MX8M Plus 的新设计中使用 TAC5111。

为了进行播放、我们有 1 个模拟扬声器、其放大器连接到 OUT1P/OUT1M。

为了进行录音、我们在引脚 GPIO2(时钟)和 GPIO1(数据)上有 2 个 PDM 麦克风。
麦克风配置为交替时钟相位。 这通过连接双通道示波器并在每个相位期间看到脉冲来确认。

与 CPU 的接口是针对 I2S 配置的、对于本问题、我们在每个通道 16 位的速率下进行记录。  编解码器相应地通过 amixer 命令进行配置、对于 2 通道数字 PDM 输入:

amixer -c 0 sset 'IN1 Source Mux' 'PDM'
amixer -c 0 sset 'IN2 Source Mux' 'PDM'
amixer sset 'ASI_TX_CH1_EN' cap
amixer sset 'ASI_TX_CH2_EN' cap
amixer sset 'PDM1 Digital' 255
amixer sset 'PDM2 Digital' 255

# must record in S16_LE format to avoid driver bugs
amixer sset 'PDM Clk Divider' '1.4112 MHz or 1.536 MHz'
arecord -D hw:0,0 -c 2 -r 48000 -f S16_LE -d 15 rec.wav

相应地配置器件树:

/ {
	sound-tac5111 {
		/*
		 * TAC5111 Codec on i.MX8 SAI3 with 4-wire i2s interface.
		 *
		 * - SoC generates MCLK for Codec at 24.576
		 *   (avoids clock drift between SoC and Codec)
		 * - SoC is bitclock and frame master
		 * - I2S interface width max. S32_LE
		 * - Codec GPIO1 & GPIO2 with dual PDM microphone
		 * - Codec OUT1P/OUT1M differential mono output
		 *   routed to speaker through amplifier
		 *
		 */
		compatible = "simple-audio-card";
		simple-audio-card,format = "i2s";
		simple-audio-card,name = "Analog";
		simple-audio-card,bitclock-master = <&cpu_dai>;
		simple-audio-card,frame-master = <&cpu_dai>;

		simple-audio-card,widgets =
			"Line", "Line In",
			"Line", "Line Out";

		simple-audio-card,routing =
			"DIN1", "Line In",
			"DIN2", "Line In",
			"Line Out", "OUT1";

		cpu_dai: simple-audio-card,cpu {
			sound-dai = <&sai3>;
			/* TODO: clock rate? */
			/* ensure mclk is generated by SoC for Codec */
			//system-clock-direction-out;
			/* force 32-bit slots */
			//dai-tdm-slot-num = <2>;
			//dai-tdm-slot-width = <32>;
		};

		codec_dai: simple-audio-card,codec {
			sound-dai = <&codec>;
			/* this ensures codec set_sysclk call-back executes */
			system-clock-frequency = <24576000>;
			mclk-fs = <512>;
		};
	};
};

&i2c2 {
	codec: audio-codec@50 {
		compatible = "ti,tac5111";
		reg = <0x50>;
		#sound-dai-cells = <0>;
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_codec>;
		interrupts-extended = <&gpio4 21 IRQ_TYPE_EDGE_FALLING>;
		avdd-supply = <&v_3_3>;
		iovdd-supply = <&v_3_3>;
		/*
		 * configure gpio functionality on gpio pins:
		 * - GPIO1: pdm data input
		 * - GPIO2: pdm clock output
		 * - GPO1:  chip irq output
		 */
		ti,gpios-func = <1>, <4>, <3>;
		/*
		 * select pdm input pins for channels 1/2 & 3/4:
		 * - ch0/1: gpio1
		 * - ch2/3: not used
		 */
		ti,pdm-input-pins = <1>, <0>;
		/* configure gpi1 as cclk input */
		ti,gpi1-func = <2>;
		/*
		 * configure MICBIAS and VREF to fix driver probe error:
		 * [    8.570840] tac5x1x-codec 1-0050: Fail to get verf E:-22
		 *
		 * Yet bindings clearly state to that these are powered down if "node" (read property) omitted:
		 * - "If node is omitted then MicBias is powered down."
		 * - "If node is omitted then VREF is powered down."
		 * This board does not use them ...
		 */
		ti,vref = <0>;
		ti,micbias-vg = <3>;
		/* configure gpi(o) drive:
		 * - GPIO1: floating, i.e. output buffer disabled
		 * - GPIO2: push-pull, i.e. active low & active high (PDM clock)
		 * - GPO1:  open-drain, i.e. active low & high impedance
		 */
		ti,gpios-drive = <0>, <1>, <3>;
		ti,gpa-gpio = <0>;
		ti,gpa-threshold = <75>, <186>;
	};
};

使用的内核驱动程序: https://git.ti.com/cgit/lpaa-android-drivers/tac5x1x-linux-driver/log/?h=tac5x1x_driver_k5.15&id=7fc10d15919d3054b8155bcb1cbfd7ee5c855c83

据观察、在正确设置混频器控制并开始录制后、驱动器禁用了其中一个 PDM 通道:

amixer -c 0 sset 'IN1 Source Mux' 'PDM'
amixer -c 0 sset 'IN2 Source Mux' 'PDM'
amixer sset 'ASI_TX_CH1_EN' cap
amixer sset 'ASI_TX_CH2_EN' cap
amixer sset 'PDM1 Digital' 255
amixer sset 'PDM2 Digital' 255

arecord -D hw:0,0 -c 2 -r 48000 -f S16_LE -d 60 rec.wav &
i2cget -f -y 1 0x50 0x76
0x80

Expected value 0xC0, for both channels 1&2 active.

Ben 确认、当该寄存器用值 0xc0 更新后、编解码器会在 I2S 上将 2 通道音频传输到主 CPU。

跟踪 dapm 小工具事件、我们可以看到 Linux 驱动程序通过 CH1_ADC_EN 为该记录选择了错误的路由 — 这应该不会发生,因为我们使用 PDM 并相应地设置输入多路复用器混频器控制:

 # arecord -D hw:0,0 -c 2 -r 48000 -f S16_LE -d 60 rec.wav
[ 1186.960011] tac5x1x_adc_event CH1_ADC_EN (efault) 2
[ 1186.964920] tac5x1x_enable_channel_unlocked adc left
Recording WAVE 'rec.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo 

因此、在移除违规路由(禁用 ADC 路径)后、无需手动 i2cset 即可自动更正通道使能寄存器值:

diff --git a/src/tac5x1x-i2c.c b/src/tac5x1x-i2c.c
index da6300e..10a8465 100644
--- a/src/tac5x1x-i2c.c
+++ b/src/tac5x1x-i2c.c
@@ -1098,8 +1106,6 @@ static const struct snd_soc_dapm_route taa5x1x_dapm_routes[] = {
        /* ADC channel1 */
        {"IN1 Source Mux", "Analog", "AIN1"},
        {"IN2 Source Mux", "Analog", "IN1 Source Mux"},
-       {"CH1_ADC_EN", NULL, "IN2 Source Mux"},
-       {"ASI_TX_CH1_EN", "Capture Switch", "CH1_ADC_EN"},
        {"ADC1 Config", "Differential", "ASI_TX_CH1_EN"},
        {"ADC1 Config", "Single-ended", "ASI_TX_CH1_EN"},
        {"ADC1 Config", "Single-ended mux INxP",
# arecord -D hw:0,0 -c 2 -r 48000 -f S16_LE -d 60 rec.wav &
Recording WAVE 'rec.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo
# i2cget -f -y 1 0x50 0x76
0xc0


ADC 路由应由 IN1 和 IN2 多路复用器进行控制、这两个多路复用器已针对 PDM 进行了配置(请参阅上文)。

删除有问题的路由后、所有信道现在都处于静默状态。
这是因为与 CH1_ADC_EN 小工具不同、PDM 小工具没有 连接事件处理程序(比较 tac5x1x_adc_event)。

该事件处理程序启用了必要的寄存器值、但也启用了 ADC、这导致 I2S 上的第一个通道数据仅包含未连接模拟麦克风的电路板上的噪声:

static int tac5x1x_adc_event(struct snd_soc_dapm_widget *w,
			     struct snd_kcontrol *kcontrol, int event)
{
	u8 pwr_cfg;
	u32 right = w->shift;
	s32 ret = 0;
	struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
	struct tac5x1x_priv *tac5x1x = snd_soc_component_get_drvdata(c);

	printk("tac5x1x_adc_event %s %s %d\n", w->name, kcontrol->id.name, event);

	mutex_lock(&tac5x1x->ch_lock);
	switch (event) {
	case SND_SOC_DAPM_POST_PMU:
		ret = tac5x1x_enable_channel_unlocked(c, true, right);
		if (ret < 0) {
			dev_err(c->dev,
				"Failed to update enable ADC channels\n");
			break;
		}

		pwr_cfg = TAC5X1X_PWR_CFG_ADC_PDZ |
			TAC5X1X_PWR_CFG_MICBIAS | 
			TAC5X1X_PWR_CFG_DAC_PDZ;
		ret = snd_soc_component_write(c, TAC5X1X_PWR_CFG,
						pwr_cfg);
		if (ret) {
			dev_err(c->dev,
				"Failed to power up ADC\n");
			tac5x1x_disable_channel_unlocked(c, true, right);
		}

		print_regs();
		schedule_delayed_work(&tac5x1x->powerup_work,
				      msecs_to_jiffies(0));
		break;

	case SND_SOC_DAPM_PRE_PMD:
		tac5x1x_disable_channel_unlocked(c, true, right);
		if (IS_ADC_CH(tac5x1x->ch_enabled) == 0)
			snd_soc_component_update_bits(c, TAC5X1X_PWR_CFG,
						      TAC5X1X_PWR_CFG_ADC_PDZ |
						      TAC5X1X_PWR_CFG_MICBIAS,
						      0);
		print_regs()
		break;
	}
	mutex_unlock(&tac5x1x->ch_lock);

	return ret;
}

请修复驱动程序、以便在通道 1 和 2 上正确设置 PDM 2 通道录音。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Josua、

    今天是我们在美国的团队的假期、我们将在星期二上再次与您联系。

    感谢您的耐心、
    Garret

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我又更新了一个提交。

    git.ti.com/.../

    请注意、PDM 仍需要“为 ADC 加电路径“。 但不需要 Micbias。  

    https://www.ti.com/lit/ds/symlink/tac5111.pdf 的“四通道 PDM 麦克风录音“一节包含详细信息。