☰
SiI9136 HDMI发送芯片手册与驱动源码拆解及点亮排查
2026/10/26 18:42:25 网站建设 项目流程

简介:面向嵌入式硬件设计与Linux驱动开发者的SiI9136芯片资料包,围绕USB转串行桥接芯片的硬件设计、寄存器配置与驱动移植展开,适合需要查阅数据手册、核对引脚与电气参数,或实现底层读写、中断处理的工程师与进阶学习者。压缩包共24个文件、约13.73MB,以PDF技术文档、C源码与头文件、Makefile及内核模块相关文件为主,并附带少量命令脚本、备份与测试素材,兼顾手册查阅和代码对照。已有571人学习。资料中既有芯片数据手册和编程参考,便于理解初始化流程、接口参数与操作模式;也提供可参考的驱动源码和构建文件,能帮助读者梳理寄存器访问、模块编译与上层调用之间的关系,减少从手册到代码落地的摸索成本,适合作为项目开发中的案头参考。

1. 一块点不亮的 HDMI 输出板:SiI9136 手册加驱动源码到底值不值得拆

SiI9136 是一颗带 HDCP 的 HDMI 发送芯片,输入端接收 24 位并行 RGB 或 YCbCr 视频,输出端输出 TMDS 差分信号,控制面全部通过 I2C 完成。手上这块板子的现象很典型:上电、复位、I2C 能扫到地址、寄存器也能读写,但显示器永远停在「无信号」,示波器测量 TMDS 差分对时波形是一条直线。这种现场通常并不缺少灵感,真正缺的是两样东西:一份把寄存器行为写清楚的参考手册,和一份能对着改的驱动源码。这个压缩包给的就是这两样,手册部分覆盖引脚定义、寄存器映射、上电与初始化流程,源码部分是一套分了层、留了移植接口的 C 实现。

它适合三类人:正在维护带这颗芯片的老设备、需要靠反推寄存器过日子的人;在自研板上第一次要把这颗芯片点亮的人;以及接手了别人代码、只能拿着手册逐位比对的人。不适合指望「接上就跑」的人:这颗芯片的寄存器按页组织,初始化有严格的先后顺序,任何一步顺序错了都不会报错,只会在屏幕上表现为黑屏。第 2 章从手册的分页机制开始,把「为什么先写这一笔」讲透,再往下走到源码移植和参数标定。

2. 先把手册读薄:SiI9136 的寄存器分页与上电初始化时序

参考手册通常是两份 PDF:一份偏硬件,讲引脚、封装、电气特性和上电时序;一份偏软件,讲寄存器映射和初始化流程。很多人拿到手直接从寄存器表第一页开始啃,啃到第四十页就放弃了。我的顺序是反过来的:先看框图确认数据通路,再看引脚表确认板子上的走线对不对,然后直奔初始化流程那一章,最后才回头查具体寄存器。框图决定你能不能理解「视频从哪进、从哪出、音频怎么嵌进去」,引脚表决定你的硬件是不是设计错了,初始化流程决定你今晚能不能出图。寄存器表是字典,不是教材,不需要通读。

2.1 页寄存器那一笔写错,后面全白干

SiI9136 的寄存器地址只有 8 位,最多 256 个位置,显然不够用。所以它采用分页机制:先往一个固定的「页选择寄存器」写页号,之后读写的 8 位地址就落在这一页里。这个设计本身不复杂,麻烦在于它是隐式状态:你写了一次页号,接下来所有读写都默认还是这一页,直到你显式改成别的页。一旦代码里有人在中间插了一笔切页,后面所有寄存器访问就全部落到错误的页上,读回来的值看起来「有点像」但不正确,这类问题最难查。

/* sii_reg.c —— 页寄存器访问封装 * 所有对 SiI9136 内部寄存器的访问都必须走这两个函数。 * 不要在业务代码里直接调 i2c_write,否则页号会被别的模块踩乱。 */ #include "sii_port.h" /* 移植层:i2c_read / i2c_write / delay_ms */ #define SII_I2C_ADDR 0x39 /* 7bit 地址,实际值看原理图 SA 引脚和手册 */ #define SII_REG_PAGE 0xBC /* 页选择寄存器,以你手上这版手册为准 */ static uint8_t g_cur_page = 0xFF; /* 0xFF = 未知,强制第一次一定写页号 */ int sii_write_reg(uint8_t page, uint8_t reg, uint8_t val) { int ret; if (page != g_cur_page) { /* 只在跨页时多发一次事务 */ ret = i2c_write(SII_I2C_ADDR, SII_REG_PAGE, &page, 1); if (ret) return ret; g_cur_page = page; } return i2c_write(SII_I2C_ADDR, reg, &val, 1); } int sii_read_reg(uint8_t page, uint8_t reg, uint8_t *buf, int len) { int ret; if (page != g_cur_page) { ret = i2c_write(SII_I2C_ADDR, SII_REG_PAGE, &page, 1); if (ret) return ret; g_cur_page = page; } return i2c_read(SII_I2C_ADDR, reg, buf, len); } /* 任何可能被中断打断、或者多线程共用的场景,改页前后必须成对调用 */ void sii_page_lock(void); void sii_page_unlock(void);

这段代码做了三件事,每一件都有代价。第一,用g_cur_page缓存当前页号,避免每次读写都多发一次 I2C 事务;1080p 初始化动辄几百次寄存器访问,省下来的时间很可观。第二,初始值故意设成0xFF,因为 0x00 是合法页号,用它做初值会让「第一次访问页 0」被误判成「页号没变」而跳过切页。第三,用page作为第一个参数强制调用方声明意图,比让业务代码自己记得先切页要可靠得多。

提示:SII_REG_PAGE这个地址在不同版本的手册里出现过调整,源码包的sii_regs.h里有一份和你手上 PDF 对应的定义。照抄网上的地址是这类项目最常见的出错原因:地址差一位,读回来的全是 0xFF,而你还在怀疑供电。

2.2 从 HPD 到 TMDS 使能:一条能出图的最小序列

最小可出图路径可以拆成六步:复位、存活检测、配置输入视频格式、配置输出模式、读取接收端能力(EDID)、使能 TMDS。顺序不能乱,尤其是最后一步:TMDS 必须在所有参数都写完之后才打开,否则接收端会抓到一个参数错误的信号,很多显示器抓到这种信号后会锁死,必须断电重插才恢复。

/* 最小初始化,能出图但不含 HDCP */ int sii_bringup(const sii_video_mode_t *mode) { uint8_t id[4]; sii_hw_reset(); /* 按手册时序拉低再拉高 RESET#,中间至少延时 10ms */ delay_ms(20); /* 等内部晶振稳定,时间以手册上电章节为准 */ if (sii_read_reg(0x00, 0x00, id, 4)) return -1; if (id[0] == 0x00 || id[0] == 0xFF) return -2; /* 全 0 或全 1:总线没通 */ /* 正常值逐字节对照手册的 Device ID 表,别只看第一个字节 */ if (sii_video_set_input(SII_IN_RGB24, SII_RANGE_LIMITED)) return -3; if (sii_video_set_mode(mode)) return -4; if (sii_audio_config(SII_AUDIO_I2S, 48000)) return -5; /* 先关再开,能让一部分已经锁死的 sink 重新握手 */ sii_output_enable(0); delay_ms(50); sii_output_enable(1); /* 最后一步才打开 TMDS */ return 0; }

六个步骤里,最容易省略也最容易出问题的是存活检测。很多人图省事,复位完直接往下写配置,结果 I2C 上根本没有器件应答,i2c_write返回错误也被忽略,最后表现为「代码跑完了但没图」,排查方向全错。全 0 和全 1 的判据也要留着:读到 0x00 通常是 SDA 被拉低或者器件没上电,读到 0xFF 通常是 SCL 被占住或者地址不对,两种现象指向的硬件问题完全不同。

2.3 手册里必须折角的四张表

一份几百页的手册,真正需要反复翻的只有四张表,建议直接打印出来贴在工位上。

表位置你要从里面拿到什么
引脚定义与复用表硬件章节D[23:0] 的位序、DE/HSYNC/VSYNC 极性、I2S 四线接法
寄存器映射总表软件章节开头每一页负责什么功能,避免在错误页里找寄存器
视频时序与像素时钟表视频配置章节每个分辨率对应的 HTotal/VTotal/PCLK,和你算出来的是否一致
ACR 的 N/CTS 表音频章节各采样率下的 N 值,CTS 与像素时钟的对应关系

第一张表用来核对硬件,板子点不亮时有相当一部分原因在原理图上,不在代码里。第二张表用来建立索引,看完之后你知道「HDCP 相关的寄存器在页 X」,以后查任何东西都有方向。第三张表用来校验,你自己按 CEA-861 算出来的时序如果和手册表里差一个数,以手册为准,因为芯片内部可能对某些模式做了特殊处理。第四张表是音频正常工作的前提,后面 4.3 会专门讲。

3. 驱动源码怎么移植:三个适配函数撑起整包

源码包拿到手,第一反应不应该是打开main.c跑一遍,而是先看清楚它的分层。一套合格的芯片驱动,业务逻辑(配置视频、配置音频、跑 HDCP)必须和平台相关代码(I2C 怎么发、延时怎么实现)彻底分离,中间只留一层薄薄的接口。判断标准很简单:如果换一块板子只需要改一个文件,那这套代码就是可移植的;如果改一个 I2C 地址要在五个文件里搜索替换,那还不如自己重写。

3.1 源码包的分层:先删再读

常见的分层是这样:sii_port.h声明平台接口,sii_reg.c做页寄存器封装,sii_video.c管视频通路,sii_audio.c管音频,sii_hdcp.c管加密认证,sii_edid.c管读取接收端能力,demo/下放一个能编译的示例。有些包还会带一份寄存器定义头文件,把手册里的每个寄存器都写成宏,这份文件是整包最有价值的部分,比代码本身还值钱。

读的顺序建议是:先看sii_port.h,确认要你实现哪些函数;再看demo/,确认调用顺序;最后才看具体模块实现。跳过前两步直接读实现,很容易陷进某个寄存器的位定义里出不来,而那个位很可能跟你当前的板子毫无关系。

拿到包之后可以先做一次精简:把示例里和你平台无关的代码删掉,把没被调用的模块从编译列表里去掉,让第一次编译能过。能编译、能链接、能跑起来一个空壳,比读完所有源码更有价值,因为它给了你一个可以反复试错的基线。

3.2 I2C 适配层三件套

移植层通常只需要三个函数,签名如下。

/* sii_port.h —— 移植层头文件,换平台只改这一个文件的实现 */ #ifndef SII_PORT_H #define SII_PORT_H #include <stdint.h> /* dev7: 7bit 从机地址;reg: 8bit 寄存器偏移;len: 单次最多 32 字节 */ int i2c_write(uint8_t dev7, uint8_t reg, const uint8_t *buf, int len); int i2c_read (uint8_t dev7, uint8_t reg, uint8_t *buf, int len); void delay_ms(uint32_t ms); #endif

签名里有两个设计取舍值得说。dev7用 7 位地址而不是 8 位,是因为 Linux 的 i2c-dev 接口吃的是 7 位地址,而很多芯片手册给的是 8 位写地址(7 位左移一位),两者差一位,混用会导致「地址明明对但就是不应答」。len限制在 32 字节以内,是因为多数 I2C 控制器的 FIFO 就是这个量级,超过之后要么拆包要么阻塞,不如在接口上直接把约束写死。

在带/dev/i2c-N的板子上,实现起来不到五十行。

/* sii_port_linux.c —— 最小可用实现 */ #include <fcntl.h> #include <unistd.h> #include <string.h> #include <sys/ioctl.h> #include <linux/i2c-dev.h> #include "sii_port.h" static int g_fd = -1; int sii_port_open(const char *dev) { g_fd = open(dev, O_RDWR); return g_fd < 0 ? -1 : 0; } static int select_slave(uint8_t dev7) { return ioctl(g_fd, I2C_SLAVE, dev7) < 0 ? -1 : 0; } int i2c_write(uint8_t dev7, uint8_t reg, const uint8_t *buf, int len) { uint8_t tmp[33]; if (len > 32) return -1; tmp[0] = reg; /* 寄存器偏移打头,这符合芯片的写时序 */ memcpy(&tmp[1], buf, len); if (select_slave(dev7)) return -1; return write(g_fd, tmp, len + 1) == len + 1 ? 0 : -1; } int i2c_read(uint8_t dev7, uint8_t reg, uint8_t *buf, int len) { if (select_slave(dev7)) return -1; if (write(g_fd, &reg, 1) != 1) return -1; /* 先写偏移,不发 STOP */ return read(g_fd, buf, len) == len ? 0 : -1; } void delay_ms(uint32_t ms) { usleep(ms * 1000); }

i2c_read这一段是整套移植最容易失败的地方。它依赖「写偏移之后不发 STOP、直接进入读」的复合时序,靠的是驱动内部的 repeated start。多数 USB 转 I2C 的小工具和部分 SoC 的 I2C 控制器不支持这种拆开的写法,表现是读回来的全是 0xFF。如果遇到这种情况,把i2c_read换成I2C_RDWR的合并消息方式,一次 ioctl 里带两段 msg,让控制器自己产生 repeated start。

注意:usleep的实际精度在非实时系统上可能差出几毫秒,而复位时序里有些等待是硬性下限。手册写「至少 10ms」,代码里就写 20ms,宁可多等。

3.3 初始化状态机的代码走读

拿到能编译的基线之后,重点读初始化那一段,因为它决定了后面所有调试的方向。一个写得比较规范的初始化会做成状态机而不是线性流水账,每个状态做一件事,失败时返回明确的错误码。

typedef enum { SII_ST_IDLE = 0, SII_ST_RESET, /* 拉复位、等稳定 */ SII_ST_PROBE, /* 读 Device ID,确认总线通 */ SII_ST_VIDEO, /* 输入格式 + 时序 + 色彩空间 */ SII_ST_AUDIO, /* I2S 格式 + 采样率 + N/CTS */ SII_ST_OUTPUT, /* 使能 TMDS */ SII_ST_READY, SII_ST_ERROR } sii_state_t; /* 每个状态只做一件事,失败就把错误码带回去,不要吞掉 */ sii_state_t sii_poll(sii_ctx_t *ctx) { switch (ctx->state) { case SII_ST_RESET: sii_hw_reset(); ctx->state = SII_ST_PROBE; break; case SII_ST_PROBE: if (sii_probe(ctx)) { ctx->err = -1; ctx->state = SII_ST_ERROR; } else ctx->state = SII_ST_VIDEO; break; /* ... 其余状态同构 ... */ default: break; } return ctx->state; }

状态机的好处是烫手山芋式的调试变成可观测的:屏幕不亮时先打印ctx->state和ctx->err,能立刻判断是卡在探测阶段还是卡在输出阶段。线性流水账做不到这一点,它只能告诉你「函数返回了 -1」。另外状态机天然支持重入,接收端热插拔之后把状态推回SII_ST_VIDEO重跑一遍就行,不用整机重启。

3.4 编译与最小闭环验证

先编示例,确认工具链和头文件路径没问题。

# 在源码包根目录执行 gcc -O2 -Wall -Wextra -I./include \ src/sii_port_linux.c src/sii_reg.c src/sii_video.c \ src/sii_audio.c src/sii_hdcp.c src/sii_edid.c \ demo/sii_demo.c -o sii_demo sudo ./sii_demo /dev/i2c-1 --mode 1080p60 --audio 48k

-Wall -Wextra不要省。这类驱动里有大量位操作和类型转换,编译器的隐式截断告警能提前抓掉一批「写进去的值和预期不一样」的问题,尤其是把 32 位像素时钟塞进 16 位变量这种。

编过之后先别急着接显示器,用命令行工具做一次最小闭环:确认器件在总线上、确认页寄存器可写可读、确认 Device ID 和手册对得上。

# 1. 扫描总线,确认目标地址有应答(0x39 只是示例,以原理图为准) i2cdetect -y 1 # 2. 读当前页号,再切到页 0,再读 Device ID 首字节 i2cget -y 1 0x39 0xbc i2cset -y 1 0x39 0xbc 0x00 i2cget -y 1 0x39 0x00 # 3. 写一个可读回的自定义寄存器,验证读写通路 i2cset -y 1 0x39 0x01 0x5a i2cget -y 1 0x39 0x01

第 3 步容易被忽略,但它区分了两种完全不同的故障:如果写进去读不回,问题在 I2C 时序或者硬件;如果写得进读得回但屏幕还是不亮,问题在视频配置。不做这一步,后面所有排查都是在两个方向上瞎猜。

4. 视频与音频通路:像素时钟、色彩空间和 N/CTS 值

视频通路调通只是走完一半,剩下的一半在音频和 InfoFrame 上。很多板子出图正常但声音断续,或者画面颜色整体偏绿,问题都不在 TMDS 链路,而在配置参数的某一位上。

4.1 输入引脚映射:D[23:0] 到底怎么接

芯片的视频输入是并行的 24 根数据线加若干同步信号线。24 位 RGB888 是最直观的接法,R[7:0] 接 D[23:16]、G[7:0] 接 D[15:8]、B[7:0] 接 D[7:0],这个顺序在手册引脚表里写得很清楚。麻烦的是两种非标准场景:一是板子为了省线只走 16 位 RGB565,这时候要确认芯片支持哪种打包方式,是高位对齐还是低位对齐;二是走 YCbCr 4:2:2,数据线数量减半,色彩分量交替传输,配置寄存器的输入格式位必须跟着改,否则画面会出现明显的色带或者整屏偏色。

/* 输入格式配置,几个字段必须和硬件实际走线严格一致 */ typedef struct { uint8_t in_format; /* 0=RGB888 1=RGB565 2=YCbCr444 3=YCbCr422 */ uint8_t range; /* 0=limited(16-235) 1=full(0-255) */ uint8_t sync_mode; /* 0=独立 HSYNC/VSYNC 1=嵌入 DE */ uint8_t edge; /* 0=上升沿采样 1=下降沿采样 */ } sii_input_cfg_t; int sii_video_set_input(const sii_input_cfg_t *cfg) { uint8_t v = 0; v |= (cfg->in_format & 0x03) << 0; v |= (cfg->range & 0x01) << 2; v |= (cfg->sync_mode & 0x01) << 3; v |= (cfg->edge & 0x01) << 4; return sii_write_reg(PAGE_VIDEO, REG_INPUT_CFG, v); }

四个字段里,range和edge是最容易配错的两个。range配反了,画面整体发灰或者黑位被压死,很多人第一反应是换线换屏,其实只是这一位的问题。edge配反了,画面会出现横向的细密噪点或者整屏抖动,因为它采样时刻落在数据跳变沿上。这两个参数没有「通用正确值」,只能对着原理图和上游时序源的输出时序确认。

4.2 时序参数与 AVI InfoFrame 的 VIC

时序参数不能自己拍脑袋算,直接用 CEA-861 的标准值,同时和手册里的表对一遍。下面这几个是工业现场最常见的档位。

模式像素时钟HTotalVTotalVIC
1080p60148.5 MHz2200112516
1080p50148.5 MHz2640112531
720p6074.25 MHz16507504
576p5027.0 MHz86462517
480p6027.0 MHz8585252

VIC 这个字段进的是 AVI InfoFrame,接收端靠它识别当前是什么模式。VIC 填错不会导致无信号,但会导致部分显示器把画面按错误比例拉伸,或者干脆拒收。实际踩过的坑是:有人把 1080p50 的 VIC 填成 16,显示器按 60Hz 处理,画面撕裂,查了半天以为是时钟不稳。所以模式表和 VIC 表必须成对维护,配置结构体里把两者绑在一起,别让调用方自己填。

4.3 I2S 音频与 ACR 的 N/CTS

音频走 I2S,四根线:位时钟、帧时钟、数据、主时钟。采样率决定帧时钟频率,位宽和通道数决定位时钟频率,这些由上游音频源提供,芯片这边要做的是配置好格式并且把 ACR(Audio Clock Regeneration)的 N/CTS 值写对。ACR 的作用是在接收端重建音频时钟,N/CTS 写错的结果是音频断续、爆音或者干脆没声,而画面完全正常,很容易被误判成音频硬件问题。

采样率NCTS(148.5 MHz 像素时钟下)
32 kHz4096148500
44.1 kHz6272165000
48 kHz6144148500

CTS 和像素时钟相关,换分辨率就要重算。这里有个细节:44.1kHz 的 CTS 按公式算出来是 164996.8 之类的非整数,手册表里给的是取整后的值,用的时候直接照抄手册,不要自己算完再四舍五入。差几十个数在接收端看来就是时钟重建的累积误差,短时间听不出来,跑两小时就开始偶发咔哒声。

/* 音频配置:采样率和 N/CTS 一起下发,避免中间态 */ int sii_audio_config(uint8_t fmt, uint32_t fs, uint16_t n, uint16_t cts) { uint8_t v = 0; v |= (fmt & 0x03) << 0; /* 0=I2S 1=SPDIF */ if (sii_write_reg(PAGE_AUDIO, REG_AUDIO_FMT, v)) return -1; if (sii_write_acr_n(n)) return -2; if (sii_write_acr_cts(cts)) return -3; return sii_write_reg(PAGE_AUDIO, REG_ACR_EN, 0x01); /* 最后才使能 ACR */ }

使能 ACR 放在最后一步,和 TMDS 使能的道理一样:参数没写完就打开,接收端会先锁到一个错误的时钟上,之后再改参数它不一定重新锁。

5. 避坑与排查:五个让 SiI9136 停在黑屏的现场

黑屏是这颗芯片最常见的失败表现,而黑屏的原因可以分布在从供电到 InfoFrame 的任何一个环节上。下面五条是实际项目中反复出现的,按「现象 → 原因 → 解决」组织,建议排查时从上往下走,别跳步。

5.1 I2C 扫不到地址

现象:i2cdetect在预期地址上显示--,或者整条总线全是--。

原因通常有三个层次。最外层是供电或者复位没到位,芯片压根没工作;中间层是地址不对,7 位和 8 位混用,或者原理图上地址选择引脚接的电平和你以为的不一样;最内层是总线本身的问题,上拉电阻阻值不对、走线太长、多个器件地址冲突。

解决顺序是先用万用表量芯片电源脚和复位脚,确认电压正确且复位已经释放;再用示波器看 SCL 上有没有时钟、SDA 有没有被谁拉住;最后才怀疑地址。地址这一步有个省事的办法:把i2cdetect的扫描范围放宽到整段 0x03–0x77 全扫,看有没有哪个陌生地址冒出来,那个很可能就是它。

5.2 读回全是 0x00 或 0xFF

现象:器件能扫到,但读任何寄存器都是同一个值,写进去也读不回来。

原因分两种,靠读回值区分。全 0x00 通常是 SDA 被拉低,可能是芯片处于复位状态、也可能是总线上有器件把线拽住了。全 0xFF 通常是 SCL 被占住或者时序不满足,芯片根本没来得及驱动数据线。

解决:先用第 3.4 节里的「写一个可读回的寄存器再读」验证读写通路。如果读写都不通,把 I2C 速率从 400kHz 降到 100kHz 再试,很多转接板和长排线在 400kHz 下就是这个表现。如果降速后通了,说明是信号完整性问题,去查上拉电阻和线长,不要用降速当长期方案。

5.3 有 TMDS 时钟但显示器不进画面

现象:示波器能测到 TMDS 时钟差分对在动,说明输出的物理层是对的,但显示器一直显示「无信号」或者反复重连。

原因:一是 HPD(热插拔检测)没有正确读到,芯片不知道下游接了什么,于是不输出有效数据;二是 EDID 读到了但没解析,配置的模式接收端根本不支持;三是 AVI InfoFrame 没使能,部分显示器要求必须收到 InfoFrame 才肯进画面。

解决:按顺序查。先读 HPD 状态位,确认接收端确实被识别到;再把读到的 EDID 前 128 字节打印出来,看里面有没有你正在用的分辨率;最后确认 InfoFrame 的使能位和 VIC 字段。三步里任何一步缺失都会表现为同样的黑屏,所以不要凭感觉猜。

5.4 出图但颜色整体偏移

现象:画面能出来,但整体发绿、发紫或者明显偏灰。

原因:一是输入格式配错,实际走的是 YCbCr 但代码按 RGB 配,或者反过来;二是色彩范围配反,limited 当成 full,黑位被抬起来,整体发灰;三是数据线的位序接错,高位和低位对调,颜色会呈现出规律的错乱。

解决:先换一张纯色测试图(全红、全绿、全蓝各一张),单色图能最快暴露位序问题——如果红色显示成蓝色,就是通道映射错了。再用灰阶渐变图看范围问题,limited 配成 full 时最黑和最白两端会被截断。最后才去查 YCbCr 和 RGB 的转换系数。

5.5 有画面没声音或者爆音

现象:图像完全正常,音频没有、断续或者每隔几秒咔哒一下。

原因:采样率配错、N/CTS 值和像素时钟不匹配、ACR 没有使能、I2S 的主从模式配反。前三个是配置问题,第四个是硬件问题。

解决:先确认 I2S 的四根线上有没有波形,没有波形就是上游没给或者主从配反;有波形但没声音,去查 ACR 使能位和 N/CTS 寄存器是否真的写进去了(读回来对一遍);有声音但爆音,把 CTS 换成手册表里的精确值再试,别用自己算的近似值。

6. 进阶:把 HDCP 认证和寄存器回读做成上线前的固定动作

HDCP 是这颗芯片上最容易被忽视的一块,因为它在实验室里几乎不出问题,一到客户现场就开始偶发。原因很朴素:实验室就一台显示器,现场可能是几十种不同的接收设备,每台的密钥列表、认证响应时间、重连行为都不一样。芯片内部已经集成了密钥和认证状态机,主机侧要做的事情其实只有三件:使能、轮询、失败重试。三件事里最容易被写坏的是重试——认证失败之后立刻重试,接收端还没准备好,会连续失败,最后被判定为不可恢复。

我现在的做法是给认证加一个退避:第一次失败等 200

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询