一.HDMI硬件原理
HDMI,全称为(High Definition Multimedia Interface)高清多媒体接口,主要用于传输高清音视频信号。
HDMI有A,B,C,D,E五种引脚类型,目前市面中比较常见的就是Type A:
其中
- 1-9 都是TMDS数据传输实际上用到的引脚,分为0,1,2三组
- 10-12 为TMDS时钟信号,如当前Video Timing为480p@60Hz(Htotal:800,Vtotal:525),则TMDS clock = 800x525x60 = 25.2MHz。TMDS clock就像是对像素的打包,一个clock分别在三个Channel传输一个像素的R、G、B(8bit)信号。
- 13 为CEC(consumer electronic control)类似一种扩展的HDMI功能,供厂家自己定制HDMI消息,(比如说你有一台sony的DVD与TV,两者用HDMI线接上,如果你用TV的遥控器可以控制DVD,另DVD执行某种功能,那么该功能的命令信号就是通过TV与DVD间的CEC引脚传输的)
- 14 为保留引脚,未使用(或者也可以为CEC提供多一个引脚)
- 15-16 为I2C引脚,用于DDC(Display Data Channel,主要用于EDID(EDID,Extended display identification data,中文名称扩展显示器识别数据,里面包含显示器也就是HDMI从机设备的像素显示制式一些信息,详细见百度百科)与HDCP(high bandwidth digital content protection高带宽数字内容保护技术)的传输)传输。在HDMI的流程中,DDC通信几乎是最先做的(前有Hotplug),因为HDMI的主从两个设备需要通过DDC来获得他们对方设备的EDID,从而得到各种信息,并且通过比较timming以确定以后送出来的timming为最合适的
- 17 为接地引脚
- 18 为5v的AC引脚
- 19 为Hotplug(热拔插)引脚(用于监测HDMI设备有没有存在,如果存在(Hotplug为high)那么可以通过DDC去读EDID),HDMI有规定在HDMI 5vAC断电时source device可以读reciever device的EDID,也就是需要Hotplug为High。其中有两种Hotplug相关的情况会导致HDMI被识别为DVI:
- Hotplug为High,不过EDID并没有准备好,那么信号源设备会由于无法读到EDID而认为接收设备为DVI,这样会导致HDMI有图像无声的问题。
- Hotplug为Low,也会导致信号源无法读到EDID而认为接收设备为DVI,从而导致HDMI有图无声
- 在TV这种有多个HDMI通道的情况下,有时会在多个HDMI通道进行切换,切换后HDMI通道应当先初始化,即先把Hotplug拉低,通知HDMI source device之前所用的EDID已经改变,需要重新读取,那么source device在Hotplug被拉高的时候会去读取新的EDID,但是拉低这个过程至少需要100ms,否则source device有可能不会去读取新的EDID,从而输出DVI信号
HDMI TMDS传输的数据类型有三种(加上Hsync与Vsync就算4种):
- Preamble(控制信息),主要用于控制接下来传输的数据是Data Island或者Video Data
- Data Island(数据包),各种类型的包信息,包括音频数据包,图像信息包等
- Video Data (视频信息),视频像素数据,HDMI可以传输RGB与YUV两种格式的像素数据
- 还有Hsync与Vsync。
二.HDMI音频设备树DTS配置
hdmiin音频DTS配置:
it6616_codec: it6616-codec {
compatible = "rockchip,dummy-codec";
#sound-dai-cells = <0>;
};
hdmiin-sound {
compatible = "simple-audio-card";
simple-audio-card,format = "i2s";
simple-audio-card,name = "rockchip,hdmi2csi";
simple-audio-card,mclk-fs = <128>;
simple-audio-card,bitclock-master = <&dailink0_master>;
simple-audio-card,frame-master = <&dailink0_master>;
status = "okay";
simple-audio-card,cpu {
sound-dai = <&i2s0_8ch>;
};
dailink0_master: simple-audio-card,codec {
sound-dai = <&it6616_codec>;
};
};
&i2s0_8ch {
status = "okay";
pinctrl-0 = <&i2s0_lrck
&i2s0_sclk
&i2s0_sdi0>;
};
刚注册的声卡为rockchiphdmi2cs。
HAL填写HDMIIN声卡信息:
struct dev_proc_info HDMI_IN_NAME[] =
{
{"realtekrt5651co", "tc358749x-audio"},
+ {"rockchiphdmi2cs", NULL},
{NULL, NULL},
/* Note! Must end with NULL, else will cause crash */
};
hdmiout音频dts:
hdmi1_sound: hdmi1-sound {
status = "okay";
compatible = "rockchip,hdmi";
rockchip,format = "i2s";
rockchip,mclk-fs = <128>;
rockchip,card-name = "rockchip,hdmi1";
rockchip,cpu = <&i2s6_8ch>;
rockchip,codec = <&hdmi1>;
rockchip,jack-det;
};
compatible:指定设备驱动程序的兼容性,即告诉内核该设备可以被哪些驱动程序所使用;
rockchip,format:指定数字音频接口格式为“I2S”,即使用I2S接口传输音频数据;
此外还支持的数字音频接口格式有:right_j、left_j、dsp_a、dsp_b、ac97、pdm、msb、lsb。
rockchip,mclk-fs:指定主时钟频率MCLK与采样频率之前的比值,例如256表示主时钟频率为系统频率的256倍;
rockchip,card-name:指定声卡的名称为“hdmi-sound”;
status:指定设备状态为“禁止”,表示该设备状态为禁止运行;
rockchip,cpu:指定cpu接入音频编解码的dai;这里配置为&i2s2,即i2s2设备节点的句柄;
rockchip,codec:指定编解码音频接入cpu的dai;这里配置为&hdmi,即hdmi设备节点的句柄;
i2s:
i2s6_8ch: i2s@fddf4000 {
compatible = "rockchip,rk3588-i2s-tdm";
reg = <0x0 0xfddf4000 0x0 0x1000>;
interrupts = <0 186 4>;
clocks = <&cru 588>, <&cru 588>, <&cru 594>;
clock-names = "mclk_tx", "mclk_rx", "hclk";
assigned-clocks = <&cru 585>;
assigned-clock-parents = <&cru 5>;
dmas = <&dmac2 4>;
dma-names = "tx";
power-domains = <&power 26>;
resets = <&cru 1007>;
reset-names = "tx-m";
rockchip,always-on;
rockchip,hdmi-path;
rockchip,playback-only;
#sound-dai-cells = <0>;
status = "disabled";
};
compatible:指定设备驱动程序的兼容性,即告诉内核该设备可以被哪些驱动程序所使用;
reg:指定I2S0控制器的基地址和地址空间大小,从0xff8a0000到0xff8a1000共有0x1000个字节的寄存器空间,其中0xff8a0000为I2S2寄存器基地址;
interrupts:指定I2S控制器的中断号为GIC_SPI 41,并且取值方式为IRQ_TYPE_LEVEL_HIGH,意味着中断信号为高电平触发;
dmas:指定数据传输时使用的DMA控制器,第一个表示tx数据使用的DMA控制器,第二个表示rx数据使用的DMA控制器;
dma-names:分别对应"tx"和"rx"的DMA名称;
clock-names:指定时钟名称,"i2s_clk"表示I2S0控制器时钟,"i2s_hclk" 表示I2S总线时钟;
power-domains:指定设备隶属于的电源域.
#sound-dai-cells:表示定义这个节点的sound DAI数据单元格的数量,这里为0表示没有单元格;
status:表示设备状态,这里 "disabled" 表示该设备当前是禁用状态;
三.音频调试
查看音频设备节点:
console:/ # ls dev/snd
controlC0 controlC3 controlC6 pcmC1D0p pcmC4D0p pcmC6D0p
controlC1 controlC4 pcmC0D0c pcmC2D0p pcmC5D0c timer
controlC2 controlC5 pcmC0D0p pcmC3D0p pcmC6D0c
controlCx:用于声卡的控制,例如通道选择,混音,麦克控制,音量加减,开关等;
pcmCxD0c:用于录音的pcm设备;
pcmCxD0p:用于播放的pcm设备;
seq:音序器;
timer:定时器;
C0D0代表的是声卡0中的设备0,pcmC0D0c最后一个c代表capture,pcmC0D0p最后一个p代表playback,这些都是alsa-driver中的命名规则。
查看所有声卡:
console:/ # cat /proc/asound/cards
0 [rockchipspdiftx]: rockchip_spdift - rockchip,spdiftx
rockchip,spdiftx
1 [rockchipdp0 ]: rockchip_dp0 - rockchip,dp0
rockchip,dp0
2 [rockchiphdmi2cs]: rockchip_hdmi2c - rockchip,hdmi2csi
rockchip,hdmi2csi
3 [rockchiphdmi1 ]: rockchip_hdmi1 - rockchip,hdmi1
rockchip,hdmi1
4 [it6621 ]: it6621 - it6621
it6621
5 [rockchiphdmiin ]: rockchip_hdmiin - rockchip,hdmiin
rockchip,hdmiin
6 [rockchipad82584]: rockchip_ad8258 - rockchip,ad82584f-codec
rockchip,ad82584f-codec
第一个数字为声卡编号,第二个数字为声卡唯一标识,最长16个字符。
声卡分两种通道,一种是Capture、一种是Playback。Capture是输入通道,Playback是输出通道;
console:/ # ls /proc/asound/card0 -l
total 0
-r--r--r-- 1 root root 0 2024-06-18 14:47 id
dr-xr-xr-x 4 root root 0 2024-06-18 14:51 pcm0p
```
```
130|console:/ # ls /proc/asound/card1 -l
total 0
-r--r--r-- 1 root root 0 2024-06-18 14:47 id
dr-xr-xr-x 4 root root 0 2024-06-18 14:53 pcm0p
```
```
console:/ # ls /proc/asound/card2 -l
total 0
-r--r--r-- 1 root root 0 2024-06-18 14:47 id
dr-xr-xr-x 4 root root 0 2024-06-18 14:53 pcm0c
dr-xr-xr-x 4 root root 0 2024-06-18 14:53 pcm0p
pcm0p属于声卡0输出通道,pcm0c属于声卡0输入通道,说明声卡0 1只有播放功能,声卡2有播放也有录制功能。
四.hdmi音频测试步骤
一.准备两台机器,一台hdmiin,一台hdmiout。
二.给两台机器都插上喇叭。
三.将一台机器的hdmiout输出,用hdmi线插在另一台的hdmiin上。
四.在hdmiout输出的机器上播放音乐,音乐会在两台机器的喇叭上播放。