简介:一套基于FPGA XC6SLX16的双目OV5640图像采集与HDMI显示完整实现方案,面向FPGA初学者与嵌入式视觉开发者,重点解决双目摄像头数据同步、像素读取、时序控制、TMDS编码与实时显示等核心问题,覆盖FPGA基础、Verilog HDL编程、OV5640驱动、MIPI接口协议与FPGA设计流程等关键知识。压缩包共687个文件,大小10.07MB,源码以Verilog为主,包含大量.v与.vhd文件,同时提供.ucf/.xdc约束文件、Tcl/Bat辅助脚本及TXT/PDF说明文档,便于对照阅读和工程复现;其中源码模块涵盖摄像头初始化、FIFO跨时钟域处理、时钟生成与DVI/HDMI输出编码等部分。已有481人学习,适合希望理解OV5640驱动、掌握FPGA图像采集链路以及HDMI输出实现的读者。通过该资源可系统学习双摄像头初始化配置、FIFO缓存设计、RGB转TMDS编码等关键模块,并结合完整工程目录快速定位设计文件,帮助提升Verilog实战能力与数字系统设计水平。
1. 这个工程到底在做什么:一块老芯片、两颗摄像头和一条 HDMI 线的“图像搬运流水线”
用 XC6SLX16 驱动双目 OV5640 并最终通过 HDMI 显示,本质上不是在做“图像处理”,而是在做一条同步、缓存、编码的搬运流水线。XC6SLX16 是 Spartan-6 家族里逻辑资源很紧的一款,只有 14579 个逻辑单元、约 576Kb 分布式 RAM 和 32 个 DSP48A1 切片。很多人第一反应是“这么小的芯片能同时接两颗 500 万像素摄像头?”,答案是能,但你必须放弃“在 FPGA 里做复杂 ISP”的幻想,老老实实把每一帧都当成一串需要按像素时钟精确搬运的数据流。这颗芯片没有内置 HDMI PHY,也没有 MIPI CSI-2 硬核,所以 OV5640 的输出要用 DVP 并行接口接入,HDMI 则要用 TMDS 编码器自己搭,或者借助外部 PHY 芯片做电平转换。适合做这件事的人,是已经跑通过流水灯和串口收发、想往图像方向迈一步的初学者,以及需要在一个课程设计里同时展示“Verilog 状态机、DDR/DDR3 缓存或块 RAM 调度、时序约束”的在校生。看完这篇,你会知道从传感器配置到 HDMI 输出,哪一段最耗时、哪一段最容易翻车,以及为什么很多人最后卡在的不是代码而是时钟约束和上电时序。
2. OV5640 的 DVP 接口与寄存器配置:先把“图像源头”驯服,再谈显示
2.1 为什么不用 MIPI 而用 DVP:XC6SLX16 的引脚和逻辑资源决定了接口选型
OV5640 同时支持 MIPI CSI-2 和 DVP(Digital Video Port)两种输出。但 XC6SLX16 的普通 IO 不支持 MIPI 的差分信号接收所需的内部端接和高频切换特性,如果你硬要用 MIPI,要么外接电平转换芯片,要么换用带 MIPI 硬核的 Artix-7 或 Zynq 系列。所以在这个工程里,DVP 是唯一现实的选择。DVP 接口的信号组非常直白:8 位或 10 位并行数据(这里用 8 位)、像素时钟 PCLK、行同步 HREF(或 HSYNC)、帧同步 VSYNC,以及一个可选的 PWDN(掉电模式)。每个像素时钟上升沿,传感器在数据线上输出一个像素的 RGB888 或 YCbCr 值。OV5640 的 DVP 模式最大支持 1080p@30fps 输出,但实际在 XC6SLX16 上跑到 720p@30 就已经很吃紧了,因为像素时钟在 74.25MHz 左右,而 Spartan-6 的 IO 和内部布线在时序收敛上需要花不少功夫。另一个隐蔽问题是:OV5640 的 DVP 引脚和 MIPI 引脚部分复用,上电默认状态不一定是 DVP 模式,所以寄存器配置是第一道坎。
2.2 用 SCCB(类 I2C)协议初始化 OV5640:寄存器写入的完整 Verilog 实现
OV5640 的配置接口是 SCCB,兼容 I2C 协议,但时序要求略有不同。这里给出一个最常用的 SCCB 写寄存器模块,包含起始条件、停止条件、8 位设备地址和 16 位寄存器地址写入。注意:OV5640 的 SCCB 设备地址是 0x78(7 位地址 0x3C 左移一位),且寄存器地址是 16 位。
module sccb_wr( input clk, // 系统时钟,建议 50MHz input rst_n, input start, input [15:0] reg_addr, input [7:0] reg_data, output reg sccb_scl, output reg sccb_sda, output reg done ); localparam IDLE = 3'd0; localparam START = 3'd1; localparam ADDR_H = 3'd2; localparam ADDR_L = 3'd3; localparam DATA = 3'd4; localparam ACK = 3'd5; localparam STOP = 3'd6; reg [2:0] state; reg [3:0] bit_cnt; reg [7:0] shift_reg; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin state <= IDLE; done <= 1'b0; sccb_scl <= 1'b1; sccb_sda <= 1'b1; end else case (state) IDLE: begin done <= 1'b0; if (start) begin shift_reg <= {1'b0, reg_addr[15:8]}; // 设备地址 + 写标志 bit_cnt <= 4'd8; state <= START; end end START: begin sccb_sda <= 1'b0; // SCL 高电平时 SDA 拉低 = 起始 state <= ADDR_H; end ADDR_H: begin if (bit_cnt == 0) begin bit_cnt <= 4'd8; shift_reg <= reg_addr[7:0]; state <= ACK; // 等待从设备应答 end else begin sccb_scl <= 1'b0; sccb_sda <= shift_reg[7]; shift_reg <= {shift_reg[6:0], 1'b0}; bit_cnt <= bit_cnt - 1; state <= ADDR_H; end end // 其余状态类似:写低地址、写数据、读 ACK、发停止 endcase end endmodule这段代码的核心逻辑是状态机驱动 SCCB 时序,每个 bit 都在 SCL 为低电平时改变 SDA,确保满足建立时间要求。需要特别注意的是 ACK 检测:OV5640 在第九个时钟周期会拉低 SDA 表示应答,如果你的 FPGA 引脚没有开漏配置,需要将 sccb_sda 设为 inout 类型,并在 ACK 状态读引脚电平而不是驱动它。很多人在这一步翻车,是因为 SDA 没有正确设置为 inout 或上拉电阻值不对。SCCB 总线的上拉电阻建议用 2.2kΩ 至 4.7kΩ,如果上拉太弱,在 400kHz 速率下上升沿会变缓,导致 ACK 检测失败。初始化顺序也有讲究:必须先让 OV5640 退出待机模式(寄存器 0x0A 写 0x00),然后依次配置输出格式、分辨率、像素时钟分频和 DVP 模式开关,最后触发软复位。如果你用网上找的 1080p 寄存器序列,务必检查 0x3808 和 0x3809(输出宽度高/低字节)、0x380A 和 0x380B(输出高度)这几个关键寄存器是否和你打算用的分辨率一致。
2.3 寄存器配置序列的“长脚本”怎么管理:ROM 存储与状态机回放
OV5640 的完整初始化通常需要配置上百个寄存器,比如 1080p 模式需要写入约 180 组地址-数据对。直接写在 Verilog 的 always 块里会让代码非常臃肿,而且改一个参数就要重新综合。常见的做法是把寄存器序列放在一个只读存储器(ROM)里,用计数器逐条取出并执行。这个 ROM 可以用系统内存里的 .mem 或 .coe 文件初始化,也可以用$readmemh在仿真时加载。在 Xilinx 平台,你可以在 IP Catalog 里生成一个单端口 ROM,宽度 24 位(16 位地址 + 8 位数据),深度按寄存器组数设定。状态机每步发一条:先送地址,再送数据,等 ACK,然后地址指针加一,直到遇到结束标志(比如地址为 0xFFFF)。这里有一个工程技巧:在寄存器表的最后加一条延时指令,比如把地址设为 0x0000、数据设为 0x00,但配合一个专门的“等待 N ms”状态,因为 OV5640 有些寄存器写入后需要响应时间。你完全可以用delay_count寄存器控制等待时间,避免靠空转循环凑时序。
3. 双路图像同步采集:从传感器时序到 FPGA 内部缓存的第一次握手
3.1 双目同步的三种做法:同源时钟、主从模式、帧同步信号复用
两颗 OV5640 同时工作,最难的不是并行驱动,而是让两路的帧起始时刻对齐。如果两路各走各的时钟,画面会存在可感知的相位差,这在立体视觉应用里是致命的。最推荐的方案是让两颗传感器共用同一个输入时钟(XVCLK),由 FPGA 的同一个 PLL 输出同时驱动两路。OV5640 的内部 PLL 会把 XVCLK 倍频产生 PCLK,只要 XVCLK 完全同源,两路的 PCLK 频率就是一致的,但相位不一定同相,因为传感器内部的 PLL 锁定过程有不确定性。解决相位差的方法是使用 OV5640 的“主从模式”:一颗配为主模式,输出 VSYNC 和 PCLK 给另一颗的同步输入;另一颗配为从模式,跟踪主传感器的输出时序。不过 OV5640 的从模式实现比较麻烦,需要正确配置 0x3008 等寄存器,且并非所有版本都支持可靠的外同步。更实用的替代方案是:两路都独立工作,但 FPGA 检测到第一路 VSYNC 上升沿时,清除两路缓存模块的行计数器,并在第二路 VSYNC 到来后只缓存“与第一路同帧号”的数据,丢掉错帧。这样做的本质是软同步,精度大约在一行以内,对大多数双目测距实验足够。
3.2 PCLK 与系统时钟的跨时钟域处理:用 FIFO 还是用双口 RAM
OV5640 的 PCLK 由传感器内部 PLL 产生,频率在 720p 模式下约为 74.25MHz,而 FPGA 系统逻辑和 HDMI 编码通常工作在另一路时钟域。直接把 PCLK 作为全局时钟使用是可行的,但前提是你必须为它建立独立的时钟约束(create_clock),否则时序分析工具无法验证这个时钟域的路径。常见做法是为每路摄像头分配一个异步 FIFO 或双口 RAM 做跨时钟域 Buffering:写入侧用 PCLK,读取侧用显示端的像素时钟。Xilinx 的 FIFO IP 可以分别指定读写时钟,并且有独立的 nearly_full/nearly_empty 标志,方便你控制读写节奏。但这里要小心一个资源问题:XC6SLX16 的 Block RAM 总共只有 32 个(每个 18Kb),如果两路都使用 1080p 帧缓存,每帧需要约 1920x1080x3 字节 ≈ 6.2MB,这远远超出片内 RAM,所以必须用行缓存而非帧缓存。FIFO 深度只缓存几行数据就够了,真正的帧缓存要依赖外部 DDR——但 XC6SLX16 没有集成 DDR 控制器硬核,用 MIG 生成软核又会占用大量逻辑资源。所以这个工程最常见的设计是:两路都只缓存 2~4 行,然后以时分复用方式把两路数据送入同一个显示通道,画面左右分屏显示。这样做绕开了 DDR 的复杂性和时序风险,代价是只能做“并排同帧显示”,不能做任意帧的随机访问。
3.3 数据合并的仲裁逻辑:轮询调度如何保证两路都不丢行
两路摄像头同时产生像素数据,写入侧的速率是 2 x 74.25MHz 的字节流,而读出侧 HDMI 也只有一路像素时钟。如果直接让两路同时写入一个存储,必然冲突。仲裁逻辑的常见实现是一个简单的双路轮询:当行的 FIFO 不空且显示通道处于当前行的有效显示区间时,轮流读出一像素来自左路、下一像素来自右路。这样在 720p 分辨率下,每行 1280 个有效像素中,左路占 640 个,右路占 640 个,刚好把两路图像拼成左右格式。仲裁状态机只需要维护一个 1 位的 round-robin 标志,并用 FIFO 的 empty 信号做门控:
always @(posedge px_clk or negedge rst_n) begin if (!rst_n) begin left_valid <= 1'b0; right_valid <= 1'b0; sel_left <= 1'b1; end else begin if (h_active && v_active) begin if (sel_left) begin if (!left_fifo_empty) begin left_valid <= 1'b1; sel_left <= 1'b0; end else begin left_valid <= 1'b0; end end else begin if (!right_fifo_empty) begin right_valid <= 1'b1; sel_left <= 1'b1; end else begin right_valid <= 1'b0; end end end else begin left_valid <= 1'b0; right_valid <= 1'b0; sel_left <= 1'b1; end end end这段仲裁有一个关键点:当某一路 FIFO 暂时为空(因为 PCLK 抖动或行同步偏差),仲裁器会暂停输出该路像素,而不是插入空白数据,否则画面会出现水平撕裂。暂停的代价是当前行的显示时间会略有延长,但只要 HREF 消隐期足够长,不会影响下一行的对齐。你还需要注意 FIFO 的读使能信号:只有当仲裁器决定读某一路时,对应 FIFO 的 rd_en 才拉高,否则会丢掉数据。很多人在这里写错,导致某一路画面出现周期性缺行,看起来像闪烁,实际上是 FIFO 溢出丢行。为了避免丢行,FIFO 的写侧必须监控 nearly_full 信号:如果 FIFO 快满了,说明读侧带宽不足,此时宁可让传感器暂停输出(通过拉高 PWDN 或调整 PCLK 分频),也不能让 FPGA 内部的 FIFO 溢出。但实际操作中更简单的做法是提高 FIFO 深度——在 XC6SLX16 上,用两个 4KB 的 FIFO 分别缓存一行数据是可行的,因为 720p 一行 1280 像素,每个像素 16 位(RGB565)或 24 位(RGB888),1280 x 2 字节 = 2.5KB,深度 1024 的 18Kb FIFO 够存半行多一点,建议用 2048 深度。
4. 图像数据从 FIFO 到 HDMI 显示:像素时钟重建与 RGB 编码
4.1 HDMI 的 TMDS 编码到底是什么:从 8 位 RGB 到 10 位串行码流的映射
HDMI 的物理层是基于 TMDS(Transition Minimized Differential Signaling)的串行传输。每个像素的 8 位 RGB 分量(共 24 位)被并行的三个 TMDS 通道编码为 10 位数据,然后以 10 倍像素时钟的速率串行发送。编码的核心目的是减少传输过程中的电平跳变,降低电磁干扰,同时为接收端提供时钟恢复的参考。编码规则分两种:数据周期内使用 TMDS 编码算法,控制周期内(消隐期)使用固定的控制码。在 Verilog 实现层面,你不需要自己从零写 TMDS 编码器——Xilinx 的 Spartan-6 提供了OSERDES(输出并串转换器),每个通道可以用一个 OSERDES2 原语把 10 位并行数据转成串行比特流。但编码逻辑依然需要你自己完成,否则收到端无法正确还原数据。一个简洁的做法是使用查表法:将 256 种可能的 8 位值对应的 10 位编码结果预计算并存入 ROM,然后直接查表。这样做虽然浪费 ROM 资源,但逻辑简单、时序容易收敛。如果你不想预计算,也可以按 TMDS 算法用逻辑门实现 DC 平衡模块,但这部分很容易在时序分析中成为关键路径,建议直接用$fread读取一个包含了全部 256 个 10 位编码值的二进制文件。
4.2 像素时钟域和串行时钟域:PLL 配置与约束的注意点
在 XC6SLX16 上,HDMI 输出通常需要三个时钟:像素时钟(如 720p@60 为 74.25MHz)、10 倍像素时钟(742.5MHz)用于 OSERDES 的串行数据输出,以及一个 5 倍像素时钟(371.25MHz)用于 OSERDES 内部的上半/下半字节切换。Spartan-6 的 PLL 最高 VCO 频率在 540MHz 到 800MHz 之间(取决于速度等级),所以 742.5MHz 的串行时钟是可以生成的,但时序裕量会很小。你需要确保在 Xilinx 约束文件(UCF 或 XDC)中为这三个时钟分别创建约束,并把 OSERDES 的输出路径设为 false path(因为它不是同步逻辑,而是纯组合输出)。这里有一个最常见的坑:如果你在代码里直接用一个 742.5MHz 时钟复位逻辑,时序分析器会报告大量时序违例,因为这些高速时钟域的寄存器根本没有任何设计余量。正确做法是:只有 OSERDES 的数据输入寄存器使用这个高速时钟,而所有状态机和数据通路都用像素时钟(74.25MHz),并行数据准备好后,由 OSERDES 内部的 DDR 模式完成串行化。只要你遵守这个原则,742.5MHz 的时钟网络上几乎不会有普通逻辑,时序收敛就很轻松。
4.3 显示时序生成:VSYNC、HSYNC、DE 和 720p 参数表
HDMI 显示需要精确的同步时序,以 720p@60 为例:像素时钟 74.25MHz,一行总像素 1650(其中水平有效 1280),一帧总行数 750(其中垂直有效 720)。VSYNC 每帧一个脉冲,宽度 5 行;HSYNC 每行一个脉冲,宽度 40 像素;水平消隐包括前沿 110 像素、后沿 220 像素;垂直消隐包括前沿 5 行、后沿 20 行。在 Verilog 里,你需要一个行计数器和场计数器,当行计数等于 0 时输出 HSYNC,当行等于对应区间时输出 VSYNC。数据使能信号 DE 在水平有效区间和垂直有效区间同时为高时拉高,只有 DE 为高时,FIFO 读出的数据才被送进 TMDS 编码器。有一个实用技巧:把 DE 信号同时作为 FIFO 的读使能门控,可以避免读出去的数据落在消隐区,造成画面边缘出现噪点。如果你用 VGA 转 HDMI 的 DAC 芯片(如 ADV7513),那么 FPGA 只需要输出并行 RGB、HSYNC、VSYNC、DE 和像素时钟即可,编码和串行化全部由外部芯片完成,这对 XC6SLX16 来说更现实。这个工程标题里提到 HDMI 显示但没限定是否外接 PHY,我建议初学者先用 ADV7513 等外部方案跑通图像链路,再把 TMDS 编码移植到 FPGA 内部——分步推进能显著降低排错难度。
5. 避坑与常见问题排查:上电时序、花屏、闪烁和数据错位的实录
以下五条踩坑记录来自这类工程的常见失败点,按现象、原因、解决组织,都是我实际处理过的典型问题。
5.1 现象:摄像头初始化后无 VSYNC 输出,sccb_done 信号一直不拉高
原因:绝大多数情况是 SCCB 的第一个起始条件发不出去,因为 FPGA 引脚配置为推挽输出而不是开漏,导致 SDA 无法释放为高电平;另一种可能是 OV5640 的复位时序不对——PWDN 引脚需要上电后先拉高再拉低,且复位脉冲宽度必须大于 1ms。解决:将 sccb_sda 声明为inout,在输出模式使用时由 FPGA 驱动,在读取 ACK 时切换为高阻态并启用内部上拉(Spartan-6 的 IO 有可编程上拉,但外部 4.7k 电阻更可靠)。复位时序方面,写一个状态机:上电后拉高 PWDN 保持 10ms,拉低后等待 20ms,再开始 SCCB 配置。如果你用逻辑分析仪看 SDA 上电后一直为低,基本可以断定是开漏配置问题。
5.2 现象:单个摄像头显示正常,双路同时开启后画面出现整行错位或撕裂
原因:双路 FIFO 都正常,但两路摄像头的 PCLK 虽然有相同标称频率,实际相位差导致读侧对数据的采样点不同步——比如左路的行首像素比右路晚一个时钟周期。对比单路显示正常,问题不在编码,而在仲裁逻辑没有在 VSYNC 前沿做对齐。解决:在每个 VSYNC 上升沿,把两路的行计数器和写指针全部清零(即将 FIFO 的读指针归零),保证两路从同一帧的第一行第一列开始读。另外在写入侧加一个“首像素标记”:当左路检测到 HREF 上升沿时,把 FIFO 写入的第一笔数据打上标志,仲裁器读到该标志时对右路的 FIFO 做一次复位,从而在行的粒度上强制对齐。
5.3 现象:HDMI 画面整体偏红或偏绿,且只在某个分辨率下出现
原因:这是 RGB 通道映射错误或像素格式配置不一致。OV5640 默认输出格式可能是 RGB565 或 YCbCr422,而 HDMI 编码器期望的是 RGB888。如果传感器输出的是 16 位 RGB565,而你按 24 位 RGB888 打包,每个通道的高字节和低字节会错位,画面自然偏色。解决:检查 OV5640 的寄存器 0x4300(格式控制)和 0x501F(输出格式选择),确认设置为 RGB888。同时确认 HDMI 侧的通道映射:TMDS 通道 0 对应蓝、通道 1 对应绿、通道 2 对应红(按标准顺序)。在代码里写一个自测模式:输出纯红、纯绿、纯蓝各占一帧,观察画面是否符合预期,这是最直接的定位手段。
5.4 现象:画面有周期性条纹或水波纹,移动摄像头时条纹跟着变化
原因:电源噪声或地弹问题,通常不是逻辑错误。FPGA 和传感器共用一个电源,当两路摄像头同时启动时,瞬时电流可能达到 300mA 以上,电源跌落会导致传感器内部 PLL 抖动,表现为 PCLK 频率不稳,显示端出现水平条纹。解决:把数字电源和模拟电源分开走线,OV5640 的 AVDD 加磁珠和 10uF + 0.1uF 去耦电容;FPGA 的核心电压与 IO 电压分开供电。如果板子已经做好了无法改布线,尝试降低 XVCLK 频率——从 24MHz 降到 12MHz,PCLK 也随之减半(分辨率降低),电源负载会显著下降。
5.5 现象:Vivado 或 ISE 综合报错“Placer could not place two components on the same slice”,资源不足
原因:XC6SLX16 的查找表和触发器资源被双路图像缓存和仲裁逻辑耗尽。许多人把两路的 FIFO 都设置成 4096 深度,每个 FIFO 占用 2 个 18Kb BRAM,再加 HDMI 编码逻辑,布线和寄存器资源就爆了。解决:FIFO 深度压缩到 2048,并用单端口 ROM 替代双端口 RAM 的查表;同时把不是时序关键的组合逻辑合并,比如将 RGB 通道拼接操作放到寄存器输出级而不是组合逻辑层。如果仍不够,可以考虑把其中一路图像降为 640x480 分辨率,通过寄存器配置实现分辨率差异化。
6. 验证与进阶技巧:用 FPGA 生成测试彩条验证链路,再扩展到真正的双目画面
在接入 OV5640 之前,先用 FPGA 生成 RGB 彩条直接输出到 HDMI,是验证显示链路是否正常的黄金方法。我习惯在工程里保留一个test_pattern_gen模块,通过一个拨码开关切换“彩条模式”和“摄像头模式”。彩条模式的代码很简单:行计数和场计数在有效区域内,直接按像素位置生成八条垂直色带:白、黄、青、绿、品红、红、蓝、黑。每条色带宽度是 1280/8 = 160 像素。如果 HDMI 显示出正常的八条色带,就说明像素时钟、行场同步和 TMDS 编码没问题;如果色带顺序错乱或颜色不对,问题一定在 RGB 映射或编码器本身。这个步骤能帮你把故障隔离在“显示链路”还是“摄像头链路”,节省大量排查时间。等彩条验证通过后,再接入 OV5640 数据,此时如果画面有问题,基本可以锁定在传感器配置或跨时钟域缓存上。
进阶阶段,你可以尝试在 FPGA 内部实现一个简单的灰度化逻辑:把 RGB888 转为 YCbCr 并直接输出 Y 分量,这在 Verilog 里只需要一个乘加运算。由于 XC6SLX16 的 DSP48A1 可以级联,用 3 个乘法器即可实现标准公式,延迟约 3 个时钟周期,需要在数据通路中插入同样深度的流水寄存器以保证时序对齐。如果做双目视觉入门,下一步就是在灰度图基础上实现块匹配视差计算——但先提醒一句:XC6SLX16 的 32 个 DSP48A1 和 576Kb 分布式 RAM 不足以支撑全图块的实时匹配,你需要在行列方向做降采样(比如把分辨率降到 320x240),或者只计算感兴趣区域(ROI)内的视差。另一个更实用的进阶方向是把两路视频通过 UART 或千兆以太网发送到 PC,在 PC 端做立体校正,FPGA 只做采集和格式化,这样能绕开芯片资源限制。
关于整体的工程习惯,我最后想说的是:永远不要把 OV5640 的寄存器配置序列当成一次性工作。每次改动分辨率或帧率,我都建议先做一次“最小改动验证”——只改分频相关寄存器,不动输出格式,确认画面稳定后再动其他参数。另外,给每个模块加调试用的计数器和状态输出,通过 ChipScope(ISE 时代的逻辑分析仪核)或 VIO 观察内部信号,比盲猜时序问题高效得多。这个工程里的血泪经验就是:花了两天排查花屏,最后发现只是 SCCB 总线上拉电阻虚焊——所以拿到板子先量电源、量时钟、量上拉,再动代码。希望帮到你。
本文还有配套的精品资源,点击获取