Luckfox
Luckfox

Привет, Хабр!

Глядя на то, как из-за кризиса производства оперативной памяти цены на одноплатные компьютеры улетают в космос, чувствуешь острую необходимость искать для своих проектов более бюджетные и порой нестандартные решения. Одним из таких решений, которое случайно попалось мне на глаза, стал вычислительный модуль от компании Luckfox. В данной статье мы посмотрим его характеристики, соберем операционную систему и запустим I2S-интерфейс для передачи цифрового аудио.

❯ Начало

Для своего проекта я искал решение со встроенной постоянной памятью EMMC, радио модулем Wi-Fi/BT, производительным SoC и в компактном форм-фактора а-ля вычислительный модуль. И кажется я его нашел, им стал вычислительный модуль Luckfox Core 1106 на базе SoC Rockchip RV1106G3.

❯ Технические характеристики модуля

Ниже в таблице представлены технические характеристики модулей:

Модель

Core11061408

CPU

RV1106G3

Processor

Cortex A7 @1.2GHz

NPU

1TOPS, supports int4, int8, int16

ISP

Supports input 5M@30fps

Аппаратное кодирование

Hardware encoding, supports MJPEG, H264, H265

Оперативная память

256MB DDR3L

Интерфейс дисплея

Parallel RGB 18-bit × 1

Интерфейс камеры

MIPI CSI 2-lane × 2 or MIPI CSI 4-lane × 1

Микрофон

Analog differential MIC interface × 2

Аналоговые аудио выходы

LINEOUT × 1

USB

USB 2.0 Host/Device

WIFI/Bluetooth

2.4 GHz WIFI 6 and Bluetooth 5.2/BLE

Ethernet порт

10/100M Ethernet controller and embedded PHY

Постоянная память

eMMC 5.1 (8GB)

Интерфейсы

I2S × 3, I2C × 5, SPI × 2, SDIO × 2, ADC × 2, UART × 6, PWM × 12

Размер

30 × 30 (mm)

Количество выводов

112 Pin

В моём случае используется модель модуля Core11061408. Особенностью используемого SoC является то, что оперативная память реализована на самом кристалле, а не отдельной микросхемой. Это значительно повышает скорость обмена с RAM и заметно уменьшает габариты платы. Габариты вычислительного модуля представлены на фото ниже.

Размеры вычислительного модуля
Размеры вычислительного модуля

Как вы могли заметить в техническом описании, используемый в модуле SoC также имеет на борту NPU-ускоритель на 1 TOPS и интерфейс для подключения камеры. Это намекает нам на то, что основной функционал модуля заточен под системы видеонаблюдения с локальной ИИ-обработкой видеопотока.

❯ Первый тестовый запуск

Так как данный модуль был куплен «как есть» — без платы разработчика, в которую его можно было бы вставить для прошивки, — мне пришлось самостоятельно разбираться со схемой подключения. Ниже представлен вариант распиновки, который получился в итоге.

Схема подключения модуля
Схема подключения модуля

Здесь стоит похвалить компанию Luckfox за подробную документацию. Они даже подготовили проект для KiCad с распиновкой модуля, что значительно упростило мне дальнейшую разработку.

А вот так выглядит моё тестовое подключение к модулю вживую:

Физическое подключение к модулю
Физическое подключение к модулю

Также будет нелишним привести нумерацию выводов самого модуля:

Распаковка модуля
Распаковка модуля

Теперь пришло время прошить модуль. Luckfox очень подробно описала этот процесс, поэтому я лишь продемонстрирую видео из их Wiki:

А если коротко, то прошивка модуля выполняется с помощью фирменного приложения SocToolKit flashing tool от компании Rockchip и скомпилированного образа. Удерживая кнопку BOOT, подключите плату к компьютеру. Отпустите кнопку BOOT, как только приложение для прошивки Rockchip отобразит устройство MaskRom. Далее в поле Search Path выбрать необходимый образ прошивки и нажать кнопку Download.

Для прошивки предлагается несколько готовых вариантов образов на базе Buildroot и Ubuntu:

Version

Description

Download

Buildroot

Standard models (A/B): Burn the Luckfox_Pico_Pi_EMMC_250313 firmware Wireless models (A/B W): Burn the Luckfox_Pico_Pi_W_EMMC_250313 firmware

Google Driver

Community-Supported Image Download

Version

Description

Download

Ubuntu22.04

Standard models (A/B): Burn the Ubuntu_Luckfox_Pico_Pi_EMMC_250313 firmware Wireless models (A/B W): Burn the Ubuntu_Luckfox_Pico_Pi_W_EMMC_250313 firmware

Google Driver

Для тестовой прошивки я выбрал образ на базе Ubuntu. Так как используется модуль со встроенной памятью и радиомодулем, необходимо выбирать версию с индексами W и EMMC. В моём случае корректно заработала прошивка с названием Ubuntu_Luckfox_Pico_Ultra_W_EMMC — на остальных вариантах радиомодуль не запускался.

После прошивки у нас по умолчанию нам доступны несколько вариантов подключения к модулю:

  • ADB;

  • SSH (+RNDIS);

  • USB-to-TTL.

Всё по классике: разработчикам и обычным пользователям, работающим с одноплатниками, эти аббревиатуры отзываются с теплотой в душе. Повторяться и описывать процесс подключения здесь, с вашего позволения, я не стану — всё уже подробно изложено здесь в официальном Wiki.

❯ Дайте мне звук!

А тут начинаются мои эксперименты! Данный модуль был выбран не просто так, а из-за хорошего набора интерфейсов (I2S × 3, I2C × 5, SPI × 2, SDIO × 2, ADC × 2, UART × 6, PWM × 12) при небольшой стоимости. А так как я планирую реализовать аудио приложение на данном модуле, то возникает задача запуска цифрового аудио интерфейса I2S.

Но, как всегда, все сладкие мечты разбиваются о жестокую действительность китайских SBC: ну не любят они интерфейс (I2S), и «из коробки» он не работает, хотя и отображается в списке звуковых устройств. Выполняя команду на модуле:

alsamixer

Мы видим следующее:

Конфигурация аудиоустройства. Взято из официального Wiki, свой забыл сделать :)
Конфигурация аудиоустройства. Взято из официального Wiki, свой забыл сделать :)

Есть упоминание об I2S-интерфейсе, но, к сожалению, потыкав осциллографом в шину при тестовом воспроизведении звука, понимаешь, что она мертва. Легкого пути, как всегда, не случилось, поэтому будем пересобирать систему с активированной шиной I2S.

❯ Пересобираем систему

И заодно избавляемся от лишнего. Для начала нам нужно разобраться с деревом устройств и посмотреть что там вообще происходит, активирован ли интерфейс I2S?

Кстати, процесс сборки образа прошивки детально описан здесь, поэтому в статье подробно раскрывать эту тему не стану. Вся компиляция образа выполняется на виртуальный машине с Ubuntu 22.04.

Для начала нам нужно скачать SDK с исходниками с помощью команды:

git clone -b 5.10.110 https://github.com/LuckfoxTECH/luckfox-pico.git

Пока я потренируюсь на кошках на старом ядре, а дальше посмотрим.

Для начала нам нужно отключить всё лишнее оборудование, что не будет использоваться в нашем проекте. По следующему пути лежат файлы конфигурации для плат:

cd /luckfox-pico/project/cfg/BoardConfig_IPC

Ранее я уже упоминал, что наиболее рабочая конфигурация прошивки это Ubuntu Luckfox Pico Ultra W, поэтому будем использовать эту конфигурацию при сборке. Откроем файл и уберем лишнее оборудование:

nano BoardConfig-EMMC-Ubuntu-RV1106_Luckfox_Pico_Ultra_W-IPC.mk

Приведем файл к следующему содержанию:

Содержание файла
#!/bin/bash

#################################################
# 	Board Config
#################################################

# Target CHIP
export RK_CHIP=rv1106

# app config
# export RK_APP_TYPE=RKIPC_RV1106

# Config CMA size in environment
export RK_BOOTARGS_CMA_SIZE="1M"

# Kernel dts
export RK_KERNEL_DTS=rv1106g-luckfox-pico-ultra-w.dts

#################################################
#	BOOT_MEDIUM
#################################################

# Target boot medium: emmc/spi_nor/spi_nand
export RK_BOOT_MEDIUM=emmc

# Uboot defconfig fragment
export RK_UBOOT_DEFCONFIG_FRAGMENT=rk-emmc.config

# specify post.sh for delete/overlay files
# export RK_PRE_BUILD_OEM_SCRIPT=rv1103-spi_nor-post.sh

# config partition in environment
# RK_PARTITION_CMD_IN_ENV format:
#     <partdef>[,<partdef>]
#       <partdef> := <size>[@<offset>](part-name)
# Note:
#   If the first partition offset is not 0x0, it must be added. Otherwise, it needn't adding.
export RK_PARTITION_CMD_IN_ENV="32K(env),512K@32K(idblock),256K(uboot),32M(boot),512M(oem),256M(userdata),6G(rootfs)"

# config partition's filesystem type (squashfs is readonly)
# emmc:    squashfs/ext4
# nand:    squashfs/ubifs
# spi nor: squashfs/jffs2
# RK_PARTITION_FS_TYPE_CFG format:
#     AAAA:/BBBB/CCCC@ext4
#         AAAA ----------> partition name
#         /BBBB/CCCC ----> partition mount point
#         ext4 ----------> partition filesystem type
export RK_PARTITION_FS_TYPE_CFG=rootfs@IGNORE@ext4,userdata@/userdata@ext4,oem@/oem@ext4

# config filesystem compress (Just for squashfs or ubifs)
# squashfs: lz4/lzo/lzma/xz/gzip, default xz
# ubifs:    lzo/zlib, default lzo
# export RK_SQUASHFS_COMP=xz
# export RK_UBIFS_COMP=lzo

#################################################
#	TARGET_ROOTFS
#################################################

# Target rootfs : ubuntu(only emmc)/buildroot/busybox
export LF_TARGET_ROOTFS=ubuntu

# SUBMODULES : github/gitee
export LF_SUBMODULES_BY=github

# Buildroot defconfig
export RK_BUILDROOT_DEFCONFIG=luckfox_pico_w_defconfig

#################################################
# 	Defconfig
#################################################

# Target arch
export RK_ARCH=arm

# Target Toolchain Cross Compile
export RK_TOOLCHAIN_CROSS=arm-rockchip830-linux-uclibcgnueabihf

#misc image
export RK_MISC=wipe_all-misc.img

# Uboot defconfig
export RK_UBOOT_DEFCONFIG=luckfox_rv1106_uboot_defconfig


# Kernel defconfig
export RK_KERNEL_DEFCONFIG=luckfox_rv1106_linux_defconfig

# Kernel defconfig fragment
export RK_KERNEL_DEFCONFIG_FRAGMENT=rv1106-bt.config

# Config sensor IQ files
# RK_CAMERA_SENSOR_IQFILES format:
#     "iqfile1 iqfile2 iqfile3 ..."
# ./build.sh media and copy <SDK root dir>/output/out/media_out/isp_iqfiles/$RK_CAMERA_SENSOR_IQFILES
#export RK_CAMERA_SENSOR_IQFILES="sc4336_OT01_40IRC_F16.json sc3336_CMK-OT2119-PC1_30IRC-F16.json"
#export RK_CAMERA_SENSOR_IQFILES="sc4336_OT01_40IRC_F16.json sc3336_CMK-OT2119-PC1_30IRC-F16.json sc530ai_CMK-OT2115-PC1_30IRC-F16.json"

# Config sensor lens CAC calibrattion bin files
#export RK_CAMERA_SENSOR_CAC_BIN="CAC_sc4336_OT01_40IRC_F16"
#export RK_CAMERA_SENSOR_CAC_BIN="CAC_sc4336_OT01_40IRC_F16 CAC_sc530ai_CMK-OT2115-PC1_30IRC-F16"

# build ipc web backend
# export RK_APP_IPCWEB_BACKEND=y

# enable install app to oem partition
export RK_BUILD_APP_TO_OEM_PARTITION=y

# enable rockchip test
#export RK_ENABLE_ROCKCHIP_TEST=y

# enable rockchip wifi
export RK_ENABLE_WIFI=y
export RK_ENABLE_WIFI_CHIP=AIC8800DC

# config wifi ssid and passwd
export LF_WIFI_SSID="Your wifi ssid"
export LF_WIFI_PSK="Your wifi password"

В строках 97 и 101 закомментируем использование камеры, а для экономии места в строке 111 отключим тест железа.

С основным файлом конфигурации разобрались, идем дальше по следу. В строке 17 у нас указана ссылка файл конфигурации дерева устройств:

export RK_KERNEL_DTS=rv1106g-luckfox-pico-ultra-w.dts

Давайте и займемся им. Всё это добро у нас лежит по пути:

cd luckfox-pico/sysdrv/source/kernel/arch/arm/boot/dts

А теперь посмотрим содержание этого файла, нам нужно обратить внимание на импорты в начале файла:

nano rv1106g-luckfox-pico-ultra-w.dts

В импортах мы видим следующее:

#include "rv1106.dtsi"
#include "rv1106-luckfox-pico-ultra-ipc.dtsi"
#include "rv1106-thunder-boot-emmc.dtsi"
#include <dt-bindings/input/input.h>
#include <dt-bindings/display/media-bus-format.h>

И здесь нам важны файлы с префиксом rv1106, чтобы разобраться, что здесь происходит.

Посмотрим на их содержание.

nano rv1106-luckfox-pico-ultra-ipc.dtsi
Содержание файла

// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
 * Copyright (c) 2022 Rockchip Electronics Co., Ltd.
 */
#include "rv1106-amp.dtsi"
#include "rv1106-evb.dtsi"
#include <dt-bindings/input/input.h>
#include <dt-bindings/display/media-bus-format.h>

/ {
	chosen {
		bootargs = "earlycon=uart8250,mmio32,0xff4c0000 console=ttyFIQ0 root=/dev/mmcblk0p7 rootwait snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_pool=0";
	};

	backlight: backlight {
		status = "okay";
		compatible = "pwm-backlight";
		pwms = <&pwm1 0 25000 12500>;
		brightness-levels = <
			  0   1   2   3   4   5   6   7
			  8   9  10  11  12  13  14  15
			 16  17  18  19  20  21  22  23
			 24  25  26  27  28  29  30  31
			 32  33  34  35  36  37  38  39
			 40  41  42  43  44  45  46  47
			 48  49  50  51  52  53  54  55
			 56  57  58  59  60  61  62  63
			 64  65  66  67  68  69  70  71
			 72  73  74  75  76  77  78  79
			 80  81  82  83  84  85  86  87
			 88  89  90  91  92  93  94  95
			 96  97  98  99 100 101 102 103
			104 105 106 107 108 109 110 111
			112 113 114 115 116 117 118 119
			120 121 122 123 124 125 126 127
			128 129 130 131 132 133 134 135
			136 137 138 139 140 141 142 143
			144 145 146 147 148 149 150 151
			152 153 154 155 156 157 158 159
			160 161 162 163 164 165 166 167
			168 169 170 171 172 173 174 175
			176 177 178 179 180 181 182 183
			184 185 186 187 188 189 190 191
			192 193 194 195 196 197 198 199
			200 201 202 203 204 205 206 207
			208 209 210 211 212 213 214 215
			216 217 218 219 220 221 222 223
			224 225 226 227 228 229 230 231
			232 233 234 235 236 237 238 239
			240 241 242 243 244 245 246 247
			248 249 250 251 252 253 254 255>;
		default-brightness-level = <255>;
	};

	panel: panel {
		compatible = "simple-panel";
		backlight = <&backlight>;

		reset-gpios = <&gpio0 RK_PA1 GPIO_ACTIVE_LOW>;
		reset-delay-ms = <200>;
		status = "okay";

		bus-format = <MEDIA_BUS_FMT_RGB666_1X18>;
		width-mm = <85>;
		height-mm = <85>;

		display-timings {
			native-mode = <&timing0>;

			timing0: timing0 {
				clock-frequency = <30000000>;
				hactive = <720>;
				vactive = <720>;
				hback-porch = <44>;
				hfront-porch = <46>;
				vback-porch = <18>;
				vfront-porch = <16>;
				hsync-len = <2>;
				vsync-len = <2>;
				hsync-active = <0>;
				vsync-active = <0>;
				de-active = <0>;
				pixelclk-active = <0>;
			};
		};

		port {
			panel_in_rgb: endpoint {
				remote-endpoint = <&rgb_out_panel>;
			};
		};
	};

	reserved_memory: reserved-memory {
		status = "okay";
		#address-cells = <1>;
		#size-cells = <1>;
		ranges;
		drm_logo: drm-logo@00000000 {
			compatible = "rockchip,drm-logo";
			reg = <0x0 0x0>;
		};
		linux,cma {
			status = "okay";
			compatible = "shared-dma-pool";
			inactive;
			reusable;
			size = <0xA00000>; //10M
			linux,cma-default;
		};
	};

	acodec_sound: acodec-sound {
		compatible = "simple-audio-card";
		simple-audio-card,name = "rv1106-acodec";
		simple-audio-card,format = "i2s";
		simple-audio-card,mclk-fs = <256>;
		simple-audio-card,cpu {
			sound-dai = <&i2s0_8ch>;
		};
		simple-audio-card,codec {
			sound-dai = <&acodec>;
		};
	};

	dsm_sound: dsm-sound {
		status = "disabled";
		compatible = "simple-audio-card";
		simple-audio-card,format = "i2s";
		simple-audio-card,mclk-fs = <256>;
		simple-audio-card,name = "rockchip,dsm-sound";
		simple-audio-card,bitclock-master = <&sndcodec>;
		simple-audio-card,frame-master = <&sndcodec>;
		sndcpu: simple-audio-card,cpu {
			sound-dai = <&i2s0_8ch>;
		};
		sndcodec: simple-audio-card,codec {
			sound-dai = <&dsm>;
		};
	};

	vcc_1v8: vcc-1v8 {
		compatible = "regulator-fixed";
		regulator-name = "vcc_1v8";
		regulator-always-on;
		regulator-boot-on;
		regulator-min-microvolt = <1800000>;
		regulator-max-microvolt = <1800000>;
	};

	vcc_3v3: vcc-3v3 {
		compatible = "regulator-fixed";
		regulator-name = "vcc_3v3";
		regulator-always-on;
		regulator-boot-on;
		regulator-min-microvolt = <3300000>;
		regulator-max-microvolt = <3300000>;
	};

	vdd_arm: vdd-arm {
		compatible = "regulator-fixed";
		regulator-name = "vdd_arm";
		regulator-min-microvolt = <900000>;
		regulator-max-microvolt = <900000>;
		regulator-always-on;

		regulator-boot-on;
	};

	leds: leds {
		compatible = "gpio-leds";
		work_led: work{
			gpios = <&gpio3 RK_PC6 GPIO_ACTIVE_HIGH>;
			linux,default-trigger = "activity";
			default-state = "on";
		};
	};
};

/***************************** audio ********************************/
&i2s0_8ch {
	#sound-dai-cells = <0>;
	status = "okay";
};

&acodec {
	#sound-dai-cells = <0>;
	pa-ctl-gpios = <&gpio3 RK_PD3 GPIO_ACTIVE_HIGH &pcfg_pull_up>;
	status = "okay";
};

/************************* FIQ_DUBUGGER ****************************/
&fiq_debugger {
	rockchip,irq-mode-enable = <1>;
	status = "okay";
};

/***************************** USB *********************************/
&u2phy {
	status = "okay";
};

&u2phy_otg {
	status = "okay";
};

&usbdrd {
	status = "okay";
};

&usbdrd_dwc3 {
	extcon = <&u2phy>;
	status = "okay";
};

/***************************** DSM *********************************/
&dsm {
	status = "disabled";
};

&cpu0 {
	cpu-supply = <&vdd_arm>;
};

/*************************** CSI *********************************/
&csi2_dphy_hw {
	status = "okay";
};

&csi2_dphy0 {
	status = "okay";

	ports {
		#address-cells = <1>;
		#size-cells = <0>;

		port@0 {
			reg = <0>;
			#address-cells = <1>;
			#size-cells = <0>;

			csi_dphy_input0: endpoint@0 {
				reg = <0>;
				remote-endpoint = <&sc3336_out>;
				data-lanes = <1 2>;
			};

			csi_dphy_input1: endpoint@1 {
				reg = <1>;
				remote-endpoint = <&sc4336_out>;
				data-lanes = <1 2>;
			};

			csi_dphy_input2: endpoint@2 {
				reg = <2>;
				remote-endpoint = <&sc530ai_out>;
				data-lanes = <1 2>;
			};
		};

		port@1 {
			reg = <1>;
			#address-cells = <1>;
			#size-cells = <0>;

			csi_dphy_output: endpoint@0 {
				reg = <0>;
				remote-endpoint = <&mipi_csi2_input>;
			};
		};
	};
};

&i2c4 {
	status = "okay";
	clock-frequency = <400000>;
	//pinctrl-names = "default";
	//pinctrl-0 = <&i2c4m2_xfer>;

	sc3336: sc3336@30 {
		compatible = "smartsens,sc3336";
		status = "okay";
		reg = <0x30>;
		clocks = <&cru MCLK_REF_MIPI0>;
		clock-names = "xvclk";
		pwdn-gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>;
		pinctrl-names = "default";
		pinctrl-0 = <&mipi_refclk_out0>;
		rockchip,camera-module-index = <0>;
		rockchip,camera-module-facing = "back";
		rockchip,camera-module-name = "CMK-OT2119-PC1";
		rockchip,camera-module-lens-name = "30IRC-F16";
		port {
			sc3336_out: endpoint {
				remote-endpoint = <&csi_dphy_input0>;
				data-lanes = <1 2>;
			};
		};
	};

	sc4336: sc4336@30 {
		compatible = "smartsens,sc4336";
		status = "okay";
		reg = <0x30>;
		clocks = <&cru MCLK_REF_MIPI0>;
		clock-names = "xvclk";
		pwdn-gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>;
		pinctrl-names = "default";
		pinctrl-0 = <&mipi_refclk_out0>;
		rockchip,camera-module-index = <0>;
		rockchip,camera-module-facing = "back";
		rockchip,camera-module-name = "OT01";
		rockchip,camera-module-lens-name = "40IRC_F16";
		port {
			sc4336_out: endpoint {
				remote-endpoint = <&csi_dphy_input1>;
				data-lanes = <1 2>;
			};
		};
	};

	sc530ai: sc530ai@30 {
		compatible = "smartsens,sc530ai";
		status = "okay";
		reg = <0x30>;
		clocks = <&cru MCLK_REF_MIPI0>;
		clock-names = "xvclk";
		pwdn-gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>;
		pinctrl-names = "default";
		pinctrl-0 = <&mipi_refclk_out0>;
		rockchip,camera-module-index = <0>;
		rockchip,camera-module-facing = "back";
		rockchip,camera-module-name = "CMK-OT2115-PC1";
		rockchip,camera-module-lens-name = "30IRC-F16";
		port {
			sc530ai_out: endpoint {
				remote-endpoint = <&csi_dphy_input2>;
				data-lanes = <1 2>;
			};
		};
	};
};

&mipi0_csi2 {
	status = "okay";

	ports {
		#address-cells = <1>;
		#size-cells = <0>;

		port@0 {
			reg = <0>;
			#address-cells = <1>;
			#size-cells = <0>;

			mipi_csi2_input: endpoint@1 {
				reg = <1>;
				remote-endpoint = <&csi_dphy_output>;
			};
		};

		port@1 {
			reg = <1>;
			#address-cells = <1>;
			#size-cells = <0>;

			mipi_csi2_output: endpoint@0 {
				reg = <0>;
				remote-endpoint = <&cif_mipi_in>;
			};
		};
	};
};

&rkcif {
	status = "okay";
};

&rkcif_mipi_lvds {
	status = "okay";

	pinctrl-names = "default";
	pinctrl-0 = <&mipi_pins>;
	port {
		/* MIPI CSI-2 endpoint */
		cif_mipi_in: endpoint {
			remote-endpoint = <&mipi_csi2_output>;
		};
	};
};

&rkcif_mipi_lvds_sditf {
	status = "okay";

	port {
		/* MIPI CSI-2 endpoint */
		mipi_lvds_sditf: endpoint {
			remote-endpoint = <&isp_in>;
		};
	};
};

&rkisp {
	status = "okay";
};

&rkisp_vir0 {
	status = "okay";

	port@0 {
		isp_in: endpoint {
			remote-endpoint = <&mipi_lvds_sditf>;
		};
	};
};

/***************************** ADC ********************************/
&saradc {
	status = "okay";
	vref-supply = <&vcc_1v8>;
};

&tsadc {
	status = "okay";
};

/**************************** LCD/TP ******************************/
&pwm1 {
	status = "okay";
	pinctrl-names = "active";
	pinctrl-0 = <&pwm1m2_pins>;
};

&display_subsystem {
	status = "okay";
	logo-memory-region = <&drm_logo>;
};

&rgb {
	status = "okay";
	pinctrl-names = "default";
	pinctrl-0 = <&lcd_pins>;

	ports {
		rgb_out: port@1 {
			reg = <1>;
			#address-cells = <1>;
			#size-cells = <0>;

			rgb_out_panel: endpoint@0 {
				reg = <0>;
				remote-endpoint = <&panel_in_rgb>;
			};
		};
	};
};

&rgb_in_vop {
	status = "okay";
};

&route_rgb {
	status = "disabled";
};

&vop {
	status = "okay";
};

&i2c3 {
    clock-frequency = <100000>;
    GT911:touchscreen {
      compatible = "goodix,gt911";
      reg = <0x14>;

      interrupt-parent = <&gpio0>;
      interrupts = <RK_PA3 IRQ_TYPE_EDGE_FALLING>;

      reset-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
      pinctrl-names = "default";
    };
};

/**************************** PINCTRL ******************************/
// SPI
&spi0 {
	pinctrl-0 = <&spi0m0_clk &spi0m0_miso &spi0m0_mosi &spi0m0_cs0>;
	#address-cells = <1>;
	#size-cells = <0>;
	spidev@0 {
		compatible = "rockchip,spidev";
		spi-max-frequency = <50000000>;
		reg = <0>;
	};
};

// I2C
&i2c1 {
	pinctrl-0 = <&i2c1m1_xfer>;
};
&i2c2 {
	pinctrl-0 = <&i2c2m0_xfer>;
};
&i2c3 {
	pinctrl-0 = <&i2c3m0_xfer &i2c3m1_xfer &i2c3m2_xfer &tp_rst &tp_irq>;
};
&i2c4 {
	pinctrl-0 = <&i2c4m0_xfer &i2c4m1_xfer &i2c4m2_xfer>;
};

// UART
&uart0 {
	pinctrl-0 = <&uart0m0_xfer &uart0m1_xfer>;
};
&uart1 {
	pinctrl-0 = <&uart1m1_xfer>;
};
&uart3 {
	pinctrl-0 = <&uart3m0_xfer &uart3m1_xfer>;
};
&uart4 {
	pinctrl-0 = <&uart4m0_xfer>;
};
&uart5 {
	pinctrl-0 = <&uart5m1_xfer>;
};

// PWM
&pwm0 {
	pinctrl-0 = <&pwm0m1_pins>;
};
&pwm2 {
	pinctrl-0 = <&pwm2m1_pins &pwm2m2_pins>;
};
&pwm3 {
	pinctrl-0 = <&pwm3m2_pins>;
};
&pwm4 {
	pinctrl-0 = <&pwm4m0_pins &pwm4m1_pins &pwm4m2_pins>;
};
&pwm5 {
	pinctrl-0 = <&pwm5m1_pins &pwm5m2_pins>;
};
&pwm6 {
	pinctrl-0 = <&pwm6m1_pins &pwm6m2_pins>;
};
&pwm7 {
	pinctrl-0 = <&pwm7m0_pins &pwm7m1_pins>;
};
&pwm8 {
	pinctrl-0 = <&pwm8m1_pins>;
};
&pwm9 {
	pinctrl-0 = <&pwm9m1_pins>;
};
&pwm10 {
	pinctrl-0 = <&pwm10m1_pins &pwm10m2_pins>;
};
&pwm11 {
	pinctrl-0 = <&pwm11m1_pins &pwm11m2_pins>;
};

&pinctrl {
	spi0 {
		spi0m0_clk: spi0m0-clk {
			rockchip,pins = <1 RK_PC1 4 &pcfg_pull_none>;
		};
		spi0m0_mosi: spi0m0-mosi {
			rockchip,pins = <1 RK_PC2 6 &pcfg_pull_none>;
		};
		spi0m0_miso: spi0m0-miso {
			rockchip,pins = <1 RK_PC3 6 &pcfg_pull_none>;
		};
		spi0m0_cs0: spi0m0-cs0 {
			rockchip,pins = <1 RK_PC0 4 &pcfg_pull_none>;
		};
	};

	touchscreen {
		tp_rst:tp-rst {
			rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>;
		};

		tp_irq:tp-irq {
			rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
		};
	};
};

И тут мы видим, что в секции dsm_sound параметр status = "disabled". Это намекает нам на то, что с данной конфигурацией I2S у нас запустить не получится:

	dsm_sound: dsm-sound {
		status = "disabled";
		compatible = "simple-audio-card";
		simple-audio-card,format = "i2s";
		simple-audio-card,mclk-fs = <256>;
		simple-audio-card,name = "rockchip,dsm-sound";
		simple-audio-card,bitclock-master = <&sndcodec>;
		simple-audio-card,frame-master = <&sndcodec>;
		sndcpu: simple-audio-card,cpu {
			sound-dai = <&i2s0_8ch>;
		};
		sndcodec: simple-audio-card,codec {
			sound-dai = <&dsm>;
		};
	};

Чтобы решить проблему и запустить I2S, нам необходимо подкорректировать файл rv1106-luckfox-pico-ultra-ipc.dtsi, и заодно удалить лишние секции:

  • backlight;

  • panel;

  • reserved_memory;

  • acodec_sound;

  • dsm_sound.

А ещё на всякий случай запретим acodec (аналоговый выход), изменив статус на disable:

&acodec {
	#sound-dai-cells = <0>;
	pa-ctl-gpios = <&gpio1 RK_PA1 GPIO_ACTIVE_HIGH>;
	status = "disable";
};

И так как я провожу эксперименты с ЦАП PCM5102, то добавим в файл конфигурации новое аудиоустройство с именем «PCM5102 Audio»:

    pcm5102_codec: pcm5102-codec {
        compatible = "linux,spdif-dit";
        #sound-dai-cells = <0>;
        status = "okay";
    };

    sound {
        compatible = "simple-audio-card";
        simple-audio-card,name = "PCM5102 Audio";
        simple-audio-card,format = "i2s";
        simple-audio-card,mclk-fs = <256>; // Для внешнего тактирования

        simple-audio-card,cpu {
            sound-dai = <&i2s0_8ch>;
            bitclock-master;
            frame-master;
        };

        simple-audio-card,codec {
            sound-dai = <&pcm5102_codec>;
        };
    };

И заодно скорректируем узел i2s0_8ch, где жёстко пропишем пины I2S-интерфейса:

&i2s0_8ch {
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&i2s0m0_sclk_tx>, <&i2s0m0_lrck_tx>, <&i2s0m0_sdo0>, <&i2s0m0_mclk_tx>;
    
    rockchip,clk-trcm = <1>; 
    #sound-dai-cells = <0>;
};

И после этого можно приступать к сборке прошивки модуля.

❯ Собираем прошивку

Данное действие, как я говорил ранее, выполняется на своей виртуальный машине с Ubuntu 22.04.

Настраиваем среду для компиляции с помощью скрипта, согласно Wiki:

cd tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/
source env_install_toolchain.sh

Для компиляции образа прошивки с Ubuntu в корневом каталоге luckfox-pico выполняем следующие команды:

sudo ./build.sh lunch

Далее будет предложено выбрать версию аппаратной конфигурации — необходимо выбрать [7] custom.

Выбор аппаратной конфигурации
Выбор аппаратной конфигурации

После ввода нам будет предложено выбрать кастомный файл конфигурации. В нашем случае это профиль под номером 3:

Список профилей
Список профилей

После выбора мы получим следующее сообщение:

[build.sh:info] Lunching for Default BoardConfig_IPC/BoardConfig-EMMC-Ubuntu-RV1106_Luckfox_Pico_Ultra_W-IPC.mk boards...
[build.sh:info] Running build_select_board succeeded.

Теперь можно запустить полный процесс компиляции прошивки для нашего модуля:

sudo ./build.sh

После успешного завершения сборки в папке output/images будут доступны файлы образов для загрузки. Получить удалённый доступ к этой папке можно по протоколу SMB.

❯ Тестируем результат

Для тестов я подключил к модулю ЦАП PCM5102 и усилитель PAM8406, которые были запитаны от пятивольтовой линии USB порта. И тестовый стенд у меня теперь выглядит так:

Паутина проводов
Паутина проводов

После загрузки модуля необходимо выполнить вход (логин по умолчанию: pico, пароль: Luckfox). Далее нам нужно убедиться в правильности назначения пинов. Для этого в режиме суперпользователя посмотрим содержание файла pinmux-pins:

sudo -i 
cat /sys/kernel/debug/pinctrl/pinctrl-rockchip-pinctrl/pinmux-pins

В моем случае вывод следующий:

Содержание файла pinmux-pins
Pinmux settings per pin
Format: pin (name): mux_owner gpio_owner hog?
pin 0 (gpio0-0): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 1 (gpio0-1): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 2 (gpio0-2): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 3 (gpio0-3): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 4 (gpio0-4): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 5 (gpio0-5): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 6 (gpio0-6): ff4b0000.serial (GPIO UNCLAIMED) function uart1 group uart1m0-ctsn
pin 7 (gpio0-7): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 8 (gpio0-8): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 9 (gpio0-9): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 10 (gpio0-10): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 11 (gpio0-11): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 12 (gpio0-12): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 13 (gpio0-13): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 14 (gpio0-14): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 15 (gpio0-15): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 16 (gpio0-16): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 17 (gpio0-17): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 18 (gpio0-18): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 19 (gpio0-19): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 20 (gpio0-20): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 21 (gpio0-21): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 22 (gpio0-22): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 23 (gpio0-23): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 24 (gpio0-24): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 25 (gpio0-25): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 26 (gpio0-26): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 27 (gpio0-27): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 28 (gpio0-28): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 29 (gpio0-29): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 30 (gpio0-30): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 31 (gpio0-31): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 32 (gpio1-0): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 33 (gpio1-1): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 34 (gpio1-2): (MUX UNCLAIMED) gpio1:34
pin 35 (gpio1-3): ff4b0000.serial (GPIO UNCLAIMED) function uart1 group uart1m0-xfer
pin 36 (gpio1-4): ff4b0000.serial (GPIO UNCLAIMED) function uart1 group uart1m0-xfer
pin 37 (gpio1-5): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 38 (gpio1-6): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 39 (gpio1-7): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 40 (gpio1-8): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 41 (gpio1-9): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 42 (gpio1-10): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 43 (gpio1-11): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 44 (gpio1-12): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 45 (gpio1-13): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 46 (gpio1-14): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 47 (gpio1-15): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 48 (gpio1-16): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 49 (gpio1-17): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 50 (gpio1-18): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 51 (gpio1-19): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 52 (gpio1-20): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 53 (gpio1-21): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 54 (gpio1-22): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 55 (gpio1-23): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 56 (gpio1-24): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 57 (gpio1-25): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 58 (gpio1-26): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 59 (gpio1-27): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 60 (gpio1-28): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 61 (gpio1-29): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 62 (gpio1-30): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 63 (gpio1-31): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 64 (gpio2-0): ffae0000.i2s (GPIO UNCLAIMED) function i2s0_8ch group i2s0m0-sclk-tx
pin 65 (gpio2-1): ffae0000.i2s (GPIO UNCLAIMED) function i2s0_8ch group i2s0m0-lrck-tx
pin 66 (gpio2-2): ffae0000.i2s (GPIO UNCLAIMED) function i2s0_8ch group i2s0m0-mclk-tx
pin 67 (gpio2-3): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 68 (gpio2-4): ffae0000.i2s (GPIO UNCLAIMED) function i2s0_8ch group i2s0m0-sdo0
pin 69 (gpio2-5): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 70 (gpio2-6): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 71 (gpio2-7): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 72 (gpio2-8): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 73 (gpio2-9): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 74 (gpio2-10): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 75 (gpio2-11): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 76 (gpio2-12): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 77 (gpio2-13): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 78 (gpio2-14): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 79 (gpio2-15): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 80 (gpio2-16): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 81 (gpio2-17): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 82 (gpio2-18): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 83 (gpio2-19): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 84 (gpio2-20): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 85 (gpio2-21): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 86 (gpio2-22): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 87 (gpio2-23): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 88 (gpio2-24): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 89 (gpio2-25): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 90 (gpio2-26): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 91 (gpio2-27): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 92 (gpio2-28): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 93 (gpio2-29): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 94 (gpio2-30): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 95 (gpio2-31): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 96 (gpio3-0): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 97 (gpio3-1): ffaa0000.mmc (GPIO UNCLAIMED) function sdmmc0 group sdmmc0-det
pin 98 (gpio3-2): ffaa0000.mmc (GPIO UNCLAIMED) function sdmmc0 group sdmmc0-bus4
pin 99 (gpio3-3): ffaa0000.mmc (GPIO UNCLAIMED) function sdmmc0 group sdmmc0-bus4
pin 100 (gpio3-4): ffaa0000.mmc (GPIO UNCLAIMED) function sdmmc0 group sdmmc0-clk
pin 101 (gpio3-5): ffaa0000.mmc (GPIO UNCLAIMED) function sdmmc0 group sdmmc0-cmd
pin 102 (gpio3-6): ffaa0000.mmc (GPIO UNCLAIMED) function sdmmc0 group sdmmc0-bus4
pin 103 (gpio3-7): ffaa0000.mmc (GPIO UNCLAIMED) function sdmmc0 group sdmmc0-bus4
pin 104 (gpio3-8): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 105 (gpio3-9): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 106 (gpio3-10): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 107 (gpio3-11): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 108 (gpio3-12): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 109 (gpio3-13): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 110 (gpio3-14): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 111 (gpio3-15): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 112 (gpio3-16): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 113 (gpio3-17): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 114 (gpio3-18): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 115 (gpio3-19): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 116 (gpio3-20): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 117 (gpio3-21): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 118 (gpio3-22): (MUX UNCLAIMED) gpio3:118
pin 119 (gpio3-23): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 120 (gpio3-24): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 121 (gpio3-25): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 122 (gpio3-26): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 123 (gpio3-27): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 124 (gpio3-28): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 125 (gpio3-29): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 126 (gpio3-30): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 127 (gpio3-31): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 128 (gpio4-0): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 129 (gpio4-1): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 130 (gpio4-2): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 131 (gpio4-3): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 132 (gpio4-4): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 133 (gpio4-5): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 134 (gpio4-6): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 135 (gpio4-7): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 136 (gpio4-8): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 137 (gpio4-9): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 138 (gpio4-10): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 139 (gpio4-11): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 140 (gpio4-12): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 141 (gpio4-13): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 142 (gpio4-14): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 143 (gpio4-15): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 144 (gpio4-16): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 145 (gpio4-17): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 146 (gpio4-18): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 147 (gpio4-19): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 148 (gpio4-20): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 149 (gpio4-21): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 150 (gpio4-22): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 151 (gpio4-23): (MUX UNCLAIMED) (GPIO UNCLAIMED)

Из вывода видно, что пины для I2S-интерфейса успешно задействованы:

pin 64 (gpio2-0): ffae0000.i2s (GPIO UNCLAIMED) function i2s0_8ch group i2s0m0-sclk-tx
pin 65 (gpio2-1): ffae0000.i2s (GPIO UNCLAIMED) function i2s0_8ch group i2s0m0-lrck-tx
pin 66 (gpio2-2): ffae0000.i2s (GPIO UNCLAIMED) function i2s0_8ch group i2s0m0-mclk-tx
pin 67 (gpio2-3): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 68 (gpio2-4): ffae0000.i2s (GPIO UNCLAIMED) function i2s0_8ch group i2s0m0-sdo0

В выводе мы видим номера пинов, а не их названия типа GPIO2_A4_d. Чтобы убедиться, что это именно те пины, которые мы хотим использовать, выполним расчет номера пина по следующей формуле:

pin = bank * 32 + (group * 8 + X)

где значения bankgroup и X берутся из названия пина GPIO{bank}_{group}{X}. Для примера рассчитаем номер пина для GPIO2_A4_d (I2S_SDO):

bank = 2
group = 0 [A=0, B=1, C=2, D=3]
X = 4
pin = 2 * 32 + (0 * 8 + 4) = 68

Всё совпадает, мы получили номер пина, соответствующий значению в файле. Теперь мы можем проверить наличие нашего аудиоустройства с помощью команды:

aplay -L

И если всё удачно сложилось, то мы должны получить следующий вывод в консоль:

hw:CARD=Audio,DEV=0
    PCM5102 Audio, ffae0000.i2s-dit-hifi dit-hifi-0
    Direct hardware device without any conversions
plughw:CARD=Audio,DEV=0
    PCM5102 Audio, ffae0000.i2s-dit-hifi dit-hifi-0
    Hardware device with all software conversions
sysdefault:CARD=Audio
    PCM5102 Audio, ffae0000.i2s-dit-hifi dit-hifi-0
    Default Audio Device
dmix:CARD=Audio,DEV=0
    PCM5102 Audio, ffae0000.i2s-dit-hifi dit-hifi-0
    Direct sample mixing device

Наша звуковая карта успешно определилась. Теперь можно немного «попищать» в динамики, для этого выполним следующую команду:

speaker-test -D hw:0,0 -t sine -f 440 -c 2

Во время выполнения команды в динамиках должен быть слышен плавающий звук с частотой 400 Гц. Если это произошло, значит, мы успешно запустили I2S-интерфейс на данном модуле.

Ну а чтобы было ещё интереснее, запустим немного кода из моего предыдущего проекта:

У кого нет доступа в YouTube

❯ Подведём итоги

Несмотря на моё желание, чтобы работало всё и сразу, мне понравилось работать с данным модулем — в частности, из-за полной и понятной документации, а также актуального SDK. Ещё один немаловажный момент — это форм-фактор модуля и экономическая составляющая, позволяющие с минимальными затратами интегрировать данную модель в свои проекты.

На этой позитивной ноте можно и закончить статью. Надеюсь, она будет кому-то полезна. Спасибо за уделенное время! Всем добра и успешных проектов! А если есть что добавить — добро пожаловать в комментарии.

Ссылки к статье:

Новости, обзоры продуктов и конкурсы от команды Timeweb.Cloud — в нашем Telegram-канале 

Перейти ↩
Может быть интересно: