基于Zynq的VGA驱动
用ZYNQ做VGA显示确实有点大材小用,一般都是直接用VDMA、VTC等IP来驱动HDMI接口,输出图像视频。这里的VGA驱动仅用作练习。
VGA驱动电路
VGA驱动芯片用的是ADV7123,实际上是三路10bit的DAC。
VGA驱动
在写驱动之前需要确定具体的时序,可以通过这个网站查到,还可以参考知乎的这篇文章。
在PL的驱动中可以把一些具体的时序参数都提前准备好,然后把这个驱动封装成IP时,可以直接通过下拉菜单选择,就像下面这样。
实际的设计需求是,图像大小和实际的显示分辨率大小不一致,实际图像的分辨率小于等于屏幕的分辨率,而且屏幕的分辨率是实际图像分辨率的整数倍。一个简单的拉伸图像的方法就是对像素进行复制。比如我想将图像的长和宽都拉伸成原来的两倍,那么就只需要将单个像素在重复显示4次(行列各两次)即可。
具体实现采用行列两个方向的状态机进行控制,以下是行方向上的状态机:
以下是列方向上的状态机:
在代码中还实例化了一块BRAM,用作显存,因此只有在显存初始化完成后,状态机才能真正进入工作。
列方向的状态机就是单纯地按照时序进行切换。
行方向上的状态机,还控制了具体的工作模式。
- 正常模式 下,就是按比例缩放图像,并显示图像。每次HREAD状态从BRAM中读一次数据,一次是32bit,每个像素8bit,所以一次读数据至少能够用于显示4个像素点。再加上有时候图像要放大,一次读的数据可能需要被重复显示。所以后面一个HWTSCL状态等待的时钟周期数可能会更多,这个取决于实际图像和显示分辨率的比例。
- 测试模式 就是显示不同灰度级的条纹。
驱动中的模式控制位也是有处理器通过存储器读写特定的bit来实现的。我的做法是,在存储图像数据之后存放模式控制位。比如一幅图像是640×512个字节,在BRAM中的寻址空间就是0~640×512-1,而模式控制位就是地址为640×512处的第0位。处理器只要修改这一位就可以改变它的工作模式。
软件部分
软件部分比较简单,就是往显存对应的那块地址写事先准备好的图像数据,然后开启GPIO中断。用户在按下按键后可以切换工作模式。
1 | int main(){ |
实际效果
正常工作模式:
测试模式
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 小裘控制系统!