0. 引言
在第 4 节中,我们实现了 UART 发送模块,它可以传输数据给电脑。有了这样的模块之后,如果我们想挂载各种各样的传感器,可以很方便地借助电脑来接收与观察它们的数据。
再次看看 YADAN Board,你可能会注意到上边有一个写着 CAMERA
的接口,它可以连接 DVP 接口的图像传感器,例如 OV2640。随着我们后期深入学习,可以尝试用 HDL 编写专用的图像处理或识别等模块,作为片内外设通过总线连接至 YADAN Core,以实现适用于特定领域的、能够快速处理图像的定制版 “YADAN SoC”。
不过,在开发上述那样令人激动的项目之前,我们暂时还没学到那一步,可以先尝试来做一个更迷你的项目,即连接摄像头后通过 UART 把画面传输给电脑,作为《在 YADAN Board 上入门 Verilog》主线章节的最后一个实验。
目录
1. 设计思路
在同样使用 EG4S20 系列 FPGA 的 SparkRoad-V 开发板的 例程 中,14_New_Cam
例程是从 OV2640 读取图像,然后通过 VGA 接口传输给显示器显示出来,它的大致结构如下图:

FPGA 内执行的功能可分为两大模块:
- 摄像头控制模块:与 OV2640 通过 SCCB 协议通信,设置一些参数完成初始化,然后反复地接收图像数据并写入 BRAM
- 图像传输模块:反复地从 BRAM 里读出图像数据,处理格式后传输给 VGA DAC 芯片
我们可以基于这个例程,只需要把图像传输模块改为通过 UART 发出图像,就能实现预期的功能了,即,大致结构如下图:

2. 从 BRAM 中读出图像数据
在 IP Generator
中可以将 BRAM 配置为如下图所示的双端口存储器,支持两个端口同时访问。

摄像头控制模块从摄像头读取到图像数据之后,可通过上半侧的 a 端口写入 BRAM,与此同时,图像传输模块可以从下半侧的 b 端口读出数据。
当 ceb
端口电平为高时,表示 b 端口允许访问,每当 clkb
端口检测到一次上升沿,BRAM 就会将 addrb[15 :0]
端口指定的地址所存储的数据输出在 dob[15: 0]
端口。
阅读摄像头控制模块的相关代码可知,假设图像的宽度为 w,高度为 h,坐标为 (x, y) 的像素的颜色数据会以 RGB565 格式写入 BRAM 中地址为 y \times w + x + 1 的存储单元。我们从对应的地址读出各个像素的颜色数据,打包成某种特定格式后即可发送给电脑了。
3. 传输与显示
因为图像数据稍微有点复杂,所以我们需要设计一种数据格式,以便让软件高效地知道哪些像素是同一行、同一帧的,这样才能更容易显示出来。
为了让实验有友好的展示效果,考虑到分辨率、颜色深度、传输速度的平衡,我的示例代码中传输的每帧图像的分辨率为 100 \times 82,色深为 4 位,我设计了一种用每 2 个字节来传输 1 个像素的数据格式,这 2 字节中每位的定义如下表:
15 | 14 | 13 | 12: 9 | 8 | 7 | 6: 4 | 3: 0 |
固定值 1 | 帧头标记 | 行头标记 | R[3: 0] | G[3] | 固定值 0 | G[2: 0] | B[3: 0] |
第 15 位和第 7 位分别是固定值 1 和 0,这样软件可以很容易地知道哪两字节属于同一像素。第 14 位和第 13 位分别是帧头标记和行头标记,表示该像素是一帧或一行的起始像素,以便让软件能知道何时换行、换帧,以显示出正确的图像。其余位的数据是 R、G、B 各颜色的分量。
显示软件的显示效果大致如下图所示,请查看 HDL 与显示软件的 完整代码 了解详细信息。

4. 结语
完成了这个迷你项目后,你已经完成了《在 YADAN Board 上入门 Verilog》主线章节的所有 5 个实验,这表明你已经基本了解 Verilog 的语法,成功入门 Verilog 了。在后续,你可以尝试稍微复杂一些的项目来提高熟练程度,我们也将不定期在论坛中分享各种各样的新示例。
当你认为你的 Verilog 水平已较为熟练,且已经准备好一定的计算机组成原理与体系结构的相关知识,就可以开启 YADAN 系列教程的第三阶段了:参照 YADAN Core 与 SoC,开始学习设计 RISC-V Core 与 SoC。