FPGA纯硬件驱动VGA显示:ROM存图与Verilog时序实现
简介这份资源面向FPGA初学者与数字电路课程实践者围绕“用ROM存储图片并通过VGA接口显示”这一典型项目展开帮助读者打通从图像数据生成到硬件显示的完整链路。压缩包共245个文件约1.12MB以Verilog源码.v、Quartus工程与综合报告.qpf、.rpt、.cdb、.hdb、仿真波形.vwf、引脚与配置文件.pin、.sof、.pof以及初始化文件.mif为主覆盖工程建立、综合、布局布线与下载各阶段。已有1056人学习下载说明该案例在入门群体中具有较高参考价值。资源内含ROM模块与VGA控制器的可运行代码、MATLAB生成的.mif图像数据、时序约束与仿真文件读者可据此理解像素数据如何映射为RGB信号、同步信号如何按VGA时序产生并借助现成工程快速复现64×64图片显示效果为后续扩展色彩深度与分辨率打下基础。1. 从一块 FPGA 开发板说起ROM 存图 VGA 显示到底能跑出什么效果手头有一块 FPGA 开发板想让它不依赖电脑、不接 HDMI 盒子直接往显示器上输出一张固定图片——这个需求听起来简单但真动手会发现两个绕不开的问题图片数据放哪以及怎么按 VGA 时序把像素一个不差地吐出去。这份资源给的就是一套 Verilog 实现的完整方案把图片转成 ROM 初始化文件综合进片内 Block RAM再用 VGA 时序控制器逐像素扫描输出。它解决的是「无 CPU、无操作系统、纯硬件逻辑驱动显示」这个场景适合正在学 FPGA 图像通路、需要一份能直接上板验证的工程参考的人。关键词 verilog 存储显示说的就是这条从存储到显示的硬连线。2. ROM 初始化与图片格式转换mif 文件怎么生成、参数怎么算2.1 为什么选 ROM 而不是 RAM 或外部 Flash先说选型。图片是静态的上电后内容不变ROM 是最自然的映射——综合工具会把$readmemh或 mif 初始化数据直接烧进 Block RAM不占逻辑资源也不需要写时序。用 RAM 的话你得额外写一套初始化状态机纯属给自己找事用外部 Flash 又要多一层 SPI 读取逻辑对「显示一张固定图」这个目标来说完全是过度设计。真正要算清楚的是容量。一张 640×480 的图片如果按 RGB565 每像素 16 bit 存总数据量是 640×480×16 4,915,200 bit也就是 600 KB。这个数字很关键——大多数入门级 FPGA 的片内 Block RAM 总量在几百 KB 到 1 MB 出头600 KB 已经吃掉相当比例。所以常见做法是降分辨率或降色深320×240 配 RGB565 只要 150 KB或者 640×480 配 8 位索引色调色板另存只要 300 KB。我一般会先查目标器件的 Block RAM 手册确认单块容量和总块数再倒推能接受的图片规格。提示ROM 深度必须是 2 的幂次附近地址位宽由深度决定。深度 76800320×240不是 2 的幂综合工具通常会自动补齐到 131072别被「浪费了一半」吓到这是正常行为。2.2 用脚本把图片转成 mifPython 转换代码手工生成 mif 不现实写个脚本最省事。下面这段把一张图片缩放到目标分辨率再按 RGB565 打包成 mif 格式from PIL import Image def img_to_mif(img_path, mif_path, width320, height240): img Image.open(img_path).convert(RGB) img img.resize((width, height)) # 强制缩放到 VGA 分辨率 pixels list(img.getdata()) with open(mif_path, w) as f: f.write(fWIDTH16;\nDEPTH{width * height};\n\n) f.write(ADDRESS_RADIXUNS;\nDATA_RADIXHEX;\n\nCONTENT BEGIN\n) for addr, (r, g, b) in enumerate(pixels): # RGB565: R 高 5 位, G 中 6 位, B 低 5 位 rgb565 ((r 3) 11) | ((g 2) 5) | (b 3) f.write(f{addr:06X} : {rgb565:04X};\n) f.write(END;\n) img_to_mif(input.png, rom_image.mif, 320, 240)逻辑说明resize保证像素数和 ROM 深度严格对应否则地址会越界或显示错位。RGB565 的位拼接顺序是 R 在高位、B 在低位这个顺序必须和后面 VGA 模块里拆分的顺序一致两边对不上就会出现「红蓝互换」的经典翻车。ADDRESS_RADIXUNS表示地址用无符号十进制DATA_RADIXHEX表示数据用十六进制这两个声明 Quartus 的 mif 解析器认Vivado 则更常用.coe格式转换思路一样只是文件头写法不同。参数方面width和height必须和 VGA 时序模块里的行、场参数完全一致改一个就要同步改另一个。色深如果从 16 位降到 8 位WIDTH改成 8打包逻辑也要换成调色板索引不能只改一个数字。2.3 在 Verilog 里例化 ROMIP 核配置与读时序mif 生成后用厂商 IP 核向导生成 ROM。以常见流程为例深度填 76800或工具自动补齐后的值位宽 16初始化文件指向刚才的 mif。生成后会得到一个带地址输入和数据输出的模块例化时注意读延迟// ROM 例化1 周期读延迟 rom_image u_rom ( .address (rom_addr), // 像素地址位宽由深度决定 .clock (pix_clk), // 像素时钟和 VGA 扫描同步 .q (rom_data) // 输出 16 位 RGB565 );关键点是address必须在pix_clk上升沿稳定q会在下一个周期才有效。这意味着 VGA 模块取像素时地址要提前一个时钟周期给出否则显示会整体偏移一列。这个「提前一拍」是新手最容易忽略的地方现象是画面左边多一条竖线或整体错位一格。3. VGA 时序控制器行场同步参数与像素时钟的配合3.1 640×48060Hz 的时序参数表VGA 显示的本质是「按固定节奏扫像素」。640×48060Hz 这个模式行业里有标准参数但不同资料给的数值略有出入下面这组是我实际跑通过的参数行水平场垂直有效像素640480同步脉冲962前肩1610后肩4833总周期800525像素时钟 800 × 525 × 60 ≈ 25.175 MHz实际取 25.2 MHz 或 25 MHz 都能点亮差别是刷新率微偏显示器一般能容忍。行计数从 0 数到 799场计数从 0 数到 524只有落在有效区间行 9616 到 9616640场 210 到 210480时才输出真实像素其余时间输出消隐通常给黑色。3.2 行场计数与同步信号生成代码// 行场计数与同步信号 always (posedge pix_clk or negedge rst_n) begin if (!rst_n) begin h_cnt 0; v_cnt 0; end else begin if (h_cnt H_TOTAL - 1) begin h_cnt 0; v_cnt (v_cnt V_TOTAL - 1) ? 0 : v_cnt 1; end else h_cnt h_cnt 1; end end assign hsync (h_cnt H_SYNC) ? 1b0 : 1b1; // 低有效 assign vsync (v_cnt V_SYNC) ? 1b0 : 1b1; // 有效显示区判断 assign display_on (h_cnt H_SYNC H_BACK h_cnt H_SYNC H_BACK 640) (v_cnt V_SYNC V_BACK v_cnt V_SYNC V_BACK 480);逻辑说明行计数到 799 归零并推动场计数这是「一行结束进下一行」的机制。同步信号在计数值小于同步脉冲宽度时拉低注意多数 VGA 同步是低有效写反了显示器直接黑屏无信号。display_on用组合逻辑判断当前是否在有效区只有它为高时才把 ROM 数据送到 RGB 输出否则给 0。参数修改时H_TOTAL、V_TOTAL要和上面的表对应H_BACK、V_BACK是后肩值。如果换分辨率比如 800×600整张表都要重算像素时钟也要跟着变不能只改有效像素数。3.3 把 ROM 输出接到 VGA地址生成与一拍延迟对齐地址生成要和display_on配合。有效区内像素坐标是(h_cnt - H_SYNC - H_BACK, v_cnt - V_SYNC - V_BACK)转成一维地址就是y * 640 x。但前面说过 ROM 有一拍读延迟所以地址要在display_on有效的前一拍就给出// 地址提前一拍生成补偿 ROM 读延迟 always (posedge pix_clk or negedge rst_n) begin if (!rst_n) rom_addr 0; else if (display_on_next) // 下一拍将进入有效区 rom_addr (v_cnt_next - V_SYNC - V_BACK) * 640 (h_cnt_next - H_SYNC - H_BACK); end assign vga_r display_on ? rom_data[15:11] : 5b0; assign vga_g display_on ? rom_data[10:5] : 6b0; assign vga_b display_on ? rom_data[4:0] : 5b0;这里的display_on_next、h_cnt_next、v_cnt_next是当前计数值的「下一拍预测」可以用组合逻辑提前算出来。如果懒得做预测另一个常见做法是把 ROM 地址直接用当前计数值算但输出时整体延后一拍判断display_on效果等价。两种方式选一种别混用混用会出现画面撕裂或偏移。RGB 拆分顺序[15:11]是红、[10:5]是绿、[4:0]是蓝必须和 mif 打包时的顺序严格对应。我见过有人打包时 R 放低位拆分时按高位取结果整张图颜色全反排查半天才发现是位序问题。4. 上板联调避坑黑屏、偏色、错位、闪烁的排查清单4.1 黑屏无信号先查时钟和同步极性现象显示器提示「无信号」或一直黑屏。原因通常是像素时钟没起来或者同步极性写反。解决先用示波器或逻辑分析仪量pix_clk有没有波形PLL 有没有锁定再确认hsync、vsync在非同步期是不是高电平。如果极性反了把判断条件从改成即可。还有一种情况是复位没释放计数器一直停在 0同步信号恒定显示器也认不到。4.2 画面偏色或红蓝互换位序和打包顺序不一致现象图片能显示但颜色明显不对蓝天变红、红字变蓝。原因就是 mif 打包和 Verilog 拆分的位序对不上。解决回到转换脚本确认rgb565的拼接是(r11)|(g5)|b再确认 Verilog 里[15:11]给红、[4:0]给蓝。两边对齐后颜色就正常。如果只是整体偏暗检查是不是把 5 位色值直接当 8 位用了需要左移补低位。4.3 图像整体偏移或左边多一条竖线ROM 读延迟没补偿现象画面整体右移或下移一格或者最左边有一条重复的竖线。原因就是第 3.3 节说的读延迟没对齐地址给晚了。解决把地址生成提前一拍或者把display_on判断延后一拍。判断方法很简单——如果偏移量恰好是一列像素基本就是这个问题。4.4 画面闪烁或滚动场同步参数或时钟频率偏差现象图像能显示但不停滚动或者轻微闪烁。原因可能是场同步脉冲宽度、前后肩和显示器不匹配或者像素时钟频率偏差太大导致刷新率超出显示器容忍范围。解决先核对时序表确认V_SYNC、V_BACK数值再用 PLL 把像素时钟调到 25.175 MHz 附近。如果显示器支持自动同步轻微偏差能自动纠正但偏差超过 1% 就可能滚屏。4.5 综合报 ROM 容量不足深度补齐与位宽取舍现象综合时报 Block RAM 不够或者布局失败。原因是图片数据量超过了器件可用 Block RAM。解决优先降分辨率320×240 比 640×480 省 75% 空间其次降色深RGB565 降到 RGB332 或 8 位索引色最后才考虑换更大容量的器件。别硬扛Block RAM 用满会导致布线困难时序也容易不收敛。5. 进阶技巧用参数化写法让同一套代码适配多种分辨率写到这儿工程基本能跑了。但如果你像我一样今天想显示 320×240明天想换 640×480每次都手改一堆常数很容易出错。我的习惯是把分辨率、时序参数全部做成parameter顶层只改几个数字就能切换。module vga_display #( parameter H_ACTIVE 640, parameter V_ACTIVE 480, parameter H_SYNC 96, parameter H_BACK 48, parameter V_SYNC 2, parameter V_BACK 33 )( input wire pix_clk, input wire rst_n, output wire [4:0] vga_r, output wire [5:0] vga_g, output wire [4:0] vga_b, output wire hsync, output wire vsync ); localparam H_TOTAL H_ACTIVE H_SYNC H_BACK 16; // 前肩固定 16 localparam V_TOTAL V_ACTIVE V_SYNC V_BACK 10; // 前肩固定 10 // ... 其余逻辑用 localparam 替代硬编码 endmodule这样改分辨率时只需在例化处覆盖H_ACTIVE、V_ACTIVE和对应的肩宽H_TOTAL、V_TOTAL自动算出来。但要注意ROM 的深度和 mif 文件必须同步改参数化解决不了数据文件的问题——这是两套东西别指望一个 parameter 全搞定。验证方法上我一般会先跑行为仿真用 testbench 把h_cnt、v_cnt打出来确认计数范围和有效区判断正确再上板。仿真能过、上板黑屏九成是时钟或引脚约束问题这时候查约束文件比改逻辑有用。还有一个实用技巧在 ROM 里存一张测试图比如四角不同颜色、中间画十字的图案。上板后一眼就能看出偏移、偏色、翻转这些问题比拿一张风景图排查快得多。从那以后我每次做 VGA 显示都强制先跑这张测试图确认时序和位序全对了再换正式图片。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

FPGA实现ROM图片VGA显示:Verilog时序与ROM初始化详解

FPGA实现ROM图片VGA显示:Verilog时序与ROM初始化详解

简介:这份资源面向FPGA初学者与数字电路课程实践者,围绕“用ROM存储图片并通过VGA接口显示”这一典型项目展开,帮助读者打通从图像数据生成到硬件显示的完整链路。压缩包共245个文件,约1.12MB,以Quartus工程文件为主&a…

2026/10/19 4:45:00 阅读更多 →
本地大模型部署工具实测对比:Ollama、LM Studio、LocalAI

本地大模型部署工具实测对比:Ollama、LM Studio、LocalAI

如果你最近想把大模型部署到自己电脑上,八成绕不开这三款软件:Ollama、LM Studio(标题里写的LMstdio应该是笔误,官网实际叫LM Studio)和LocalAI。我在同一台机器上把这三款都装上、跑通、拉模型、压测,前后…

2026/10/19 4:45:00 阅读更多 →
CNN-GRU-Attention负荷预测实战:混合神经网络原理与工程实现

CNN-GRU-Attention负荷预测实战:混合神经网络原理与工程实现

负荷预测是个老话题,尤其到了调度和交易环节,预测误差直接关系到要不要多备一组机组、少签一笔偏差考核。传统方法折腾过 ARIMA、指数平滑之后,我慢慢把重心移到了深度学习上。最近在做的这个项目,用的就是 CNN-GRU-Attention 混合…

2026/10/19 4:45:00 阅读更多 →

最新新闻

BERT微调实战:IMDB影评情感二分类源码全流程解析与避坑指南

BERT微调实战:IMDB影评情感二分类源码全流程解析与避坑指南

简介:基于BERT模型的情感分析项目,是一套面向自然语言处理初学者与算法工程师的Python源码包,聚焦IMDB影评正面/负面情感二分类,帮助理解BERT预训练模型微调、特征抽取及分类器设计等关键环节。资源共5个文件,其中4个P…

2026/10/19 6:08:40 阅读更多 →
用Matlab完成测风塔风能资源评估:从数据清洗到发电量估算

用Matlab完成测风塔风能资源评估:从数据清洗到发电量估算

气象塔(风电行业里叫测风塔)出来的历史风力数据,看起来就是一堆时间和风速的表格,但真正能把它变成风能资源评估结论的人,并不算多。我刚接触这个领域的时候也犯过“拿数据就求平均”的错,结果被前辈按在工…

2026/10/19 6:08:40 阅读更多 →
单矢量控制下的占空比计算:有效抑制电流纹波与噪声

单矢量控制下的占空比计算:有效抑制电流纹波与噪声

做数字电机控制的人应该都经历过这种尴尬:算法层面跑得好好的,DTC或者有限集模型预测控制(FCS-MPC)每个控制周期都选了那个“最优电压矢量”,上示波器一看,电流纹波比SVPWM大一块,高频噪声还特别…

2026/10/19 6:08:40 阅读更多 →
AUV滑模控制器设计与Simulink仿真:从动力学建模到参数整定全解析

AUV滑模控制器设计与Simulink仿真:从动力学建模到参数整定全解析

1. AUV运动控制的核心难点与滑模控制的切入点自主水下机器人(AUV)的控制一直是个让人又爱又恨的问题。先说结论:在水下环境里,模型不确定性大、海流干扰强、参数摄动严重,传统的PID想同时搞定“深度保持”“航向稳定”…

2026/10/19 6:08:40 阅读更多 →
macOS终端重构:iTerm2+zsh打造可编程工作台

macOS终端重构:iTerm2+zsh打造可编程工作台

简介:本资源是一套面向 macOS 用户的终端环境深度优化配置方案,专为希望提升开发效率、定制化体验的程序员与系统爱好者设计,解决原生 Terminal 功能单一、主题简陋、插件缺失等痛点。压缩包包含 4489 个文件,主体为 1050 个 zsh …

2026/10/19 6:08:40 阅读更多 →
论文查重与AI率检测全攻略:原理、工具与降重技巧

论文查重与AI率检测全攻略:原理、工具与降重技巧

每年到了毕业论文提交季,最让人焦虑的往往不是论文本身有多难写,而是“查重”那一关。更麻烦的是,近两年几乎所有高校都多了一条新指标:AI生成内容检测。也就是说,论文不仅要控制重复率,还要控制“AI率”。…

2026/10/19 6:07:40 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →