这一章在干嘛?

前五章是「钻进每个模块看细节」,这一章是「站到山顶看全貌」——一张架构图把五个模块的职责、三个时钟域、四条跨域握手连成整体;然后落到地面,告诉你板子到手后从装驱动、准备 SD 卡到下载上板、按图排错的完整动作。学到这里,你对这套官方例程的理解就不再是零散的知识点,而是一张能随时调用的地图。

一张图看懂整个系统

三个时钟域与跨域三板斧

一个像素的完整旅程

板子到手后的实操清单

准备一张能被识别的图

排错地图:黑屏 / 花屏 / 色错

一张图看懂整个系统

先看图。这是整套系统的数据流全景,每个模块下方都标了对应章节,你可以随时跳回去复习:

HDMI 多媒体播放系统数据流全景图(写路径蓝色、读路径橙色) HDMI 多媒体播放系统数据流全景图(写路径蓝色、读路径橙色)

从图里能读出三件事:

  1. 数据从左流到右:TF 卡读图 → BMP 解析 → 索引控制 → 双缓冲仲裁 → 帧缓存 → 时序对齐 → HDMI 上屏;
  2. 写读两条路径:左边半段是「写路径」(事件驱动,有新图才动),右边半段是「读路径」(时钟驱动,每帧必刷);
  3. SDRAM 是交汇点:写路径把像素「存进去」,读路径把像素「取出来」,中间用双缓冲 BUF0/BUF1 隔离,读写永不打架。

三个时钟域与跨域三板斧

五个模块分布在三个时钟域里,域与域之间不能直接连线,全靠一套「三板斧」衔接:

时钟域频率属于哪些模块跨域手段
sd_card_clk100 MHzbmp_readsd_card_bmp写 FIFO / 握手 / toggle
ext_mem_clk100 MHzframe_read_write 状态机、SDRAM写 FIFO + 读 FIFO
video_clk25.175 MHzvideo_timing_datavideo_delay、HDMI读 FIFO / 握手

所谓「三板斧」,就是前面几章反复出现的三个套路:

  1. 异步 FIFO——不同频率之间传数据,用格雷码指针 + 双口 RAM 隔离;
  2. 三级同步——单比特跨域信号先过 d0 → d1 → d2 三级寄存器,消除亚稳态;
  3. 跳变握手——跨域传「完成」这种脉冲,不用电平用 toggle 翻转,接收端异或取边沿。

这三招贯穿了 frame_read_write 的写/读状态机、sd_card_bmpwrite_finish_pulsebmp_readvideo_timing_data 的请求-应答。把它们记牢,你就能独立设计任何多时钟域的 FPGA 系统。

一个检验标准

现在如果让你随手画出这套系统的跨域信号有哪些,你应该能数出:写数据(写 FIFO)、读数据(读 FIFO)、 write_req / write_req_ackread_req / read_req_ackwrite_finish_toggle 。能数全,说明五章没白学。

一个像素的完整旅程

把视角缩到最小——跟踪一个像素从诞生到上屏,五章的知识就串成了一条线:

  1. bmp_read 从 SD 卡读出一串字节,跳过 54 字节文件头,每 3 个字节(BGR)拼成一个 24bit 像素(第四章);
  2. sd_card_bmp 把这 24bit 扩成 32bit,按 next_buf_lut 决定写进哪块缓冲,发出 write_req(第三、四章);
  3. frame_read_write 的写状态机应答握手,把像素经写 FIFO 跨到 mem_clk 域,突发写进 SDRAM 的 BUF0 或 BUF1,写完翻转 write_finish_toggle(第二章);
  4. sd_card_bmp 同步到 toggle、异或取边沿,配合「源送完」双确认,翻转 disp_buf_idx 把这块缓冲切给显示(第三章);
  5. video_timing_data 在场同步边沿发起 read_req,读状态机把整帧从 SDRAM 吸进读 FIFO,经 video_delay 对齐时序,像素终于赶上 hs/vs/de 的节拍,被推上 HDMI(第五章)。

一个像素走过五关,跨了三个时钟域,握了三次手。这才是「理解官方例程」该有的颗粒度。

板子到手后的实操清单

理论归理论,板子到手后按这个顺序做,能少走很多弯路:

  1. 装驱动:USB-JTAG 下载器驱动(TD 安装目录 driver\dl-cable 或板卡资料包 下载器驱动\win8_10_64)+ CH340 串口驱动;
  2. 连线:下载器接 JTAG 口、板子上电、HDMI 线接显示器、TF 卡插卡座;
  3. 备卡:TF 卡格式化成 FAT32,放入 640×480 的 24bit BMP 图片(最多前 4 张,见下一节);
  4. 开工程:用 TD 打开 lab_ex4_tf 工程,确认器件选的是 EG4S20BG256
  5. 生成位流:跑综合 → 布局布线 → 生成 bitstream,注意看时序报告有没有违例;
  6. 下载:选对下载器型号,下载后按复位,观察现象。

器件千万别选错

EG4S20 赛道用的是 EG4S20BG256 。器件型号选错,管脚约束、时钟资源全都对不上,综合能过下载必失败。打开工程第一件事就是核对器件。

准备一张能被识别的图

官方例程对 BMP 的校验很严格(第四章的 header_match),图不符合就永远显示不出来。准备图片时盯住这四条:

要求为什么
分辨率640 × 480bmp_width/bmp_height 写死 640/480,不符直接跳过
位深24bitbit_count == 24,8bit/16bit 都不行
压缩compression == 0,RLE 压缩的 BMP 解析不了
格式标准 BMP54 字节头,魔数 "BM"

生成方法任选其一:

  • Windows 画图「另存为 → 24 位位图」;
  • Photoshop「存储为 BMP,24 位,Windows」;
  • ImageMagick 一行命令:magick input.png -resize 640x480 -type TrueColor BMP3:out.bmp

图片放在 TF 卡根目录即可,文件名无所谓(扫描是按扇区找、不靠文件名),最多认前 4 张(SCAN_TARGET_COUNT = 4)。

多图轮播

放 2~4 张合格 BMP,上电后 key1 (下一张)/ key2 (自动播放)就能切换。只有一张图时 key2 无效——代码里自动播放要求 img_found_count > 1

排错地图:黑屏 / 花屏 / 色错

上板遇到问题,按现象对号入座:

现象最可能的原因先查这里
完全黑屏首图没加载成功,display_valid 一直为 0TF 卡识别(sd_init_done)、BMP 格式、卡是否 FAT32
花屏 / 撕裂双缓冲没生效,读写冲突write_buf_idx/disp_buf_idx 是否真的错开、write_finish_toggle 是否同步
红蓝互换(蓝脸)BGR/RGB 顺序搞反第四章的 bmp_byte_idx 拼像素顺序
上下颠倒垂直翻转配置错WRITE_V_FLIP 参数(第二章的地址重映射)
不识别卡SPI 初始化失败卡容量、FAT32 格式、SD_nCS 管脚电平
只显示第一张、切不动按键消抖/扫描没跑完scan_doneimg_found_count、按键管脚

排查时善用模块里现成的 state_codesd_card_bmp 输出到数码管的那个 4bit 信号)——它把当前状态机状态暴露出来,上板一读就知道卡在哪个状态。

黑屏先别慌

黑屏 ≠ 程序挂了。按第五章讲的,首图提交前 display_valid = 0 ,屏幕本来就是黑的。先确认 TF 卡里有合格 BMP、 sd_init_done 拉高了,再往下查。