zynq例程学习总结 - minichao9901/TangNano-20k-Zynq-7020 GitHub Wiki
rgb_lcd
- 可以用pll的locked信号取反后作为rst_n信号
- 可以构造一个移动的方块,在屏幕中移动。每帧改变一次方块的坐标。
- 引脚定义
############## clock define##################
create_clock -period 20.000 [get_ports clk]
set_property PACKAGE_PIN N18 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
#############################################################
# LCD connect to GPIO2
#############################################################
set_property -dict {PACKAGE_PIN F16 IOSTANDARD LVCMOS33} [get_ports rgb[16]]
set_property -dict {PACKAGE_PIN F17 IOSTANDARD LVCMOS33} [get_ports rgb[17]]
set_property -dict {PACKAGE_PIN E17 IOSTANDARD LVCMOS33} [get_ports rgb[18]]
set_property -dict {PACKAGE_PIN D18 IOSTANDARD LVCMOS33} [get_ports rgb[19]]
set_property -dict {PACKAGE_PIN E18 IOSTANDARD LVCMOS33} [get_ports rgb[20]]
set_property -dict {PACKAGE_PIN E19 IOSTANDARD LVCMOS33} [get_ports rgb[21]]
set_property -dict {PACKAGE_PIN G17 IOSTANDARD LVCMOS33} [get_ports rgb[22]]
set_property -dict {PACKAGE_PIN G18 IOSTANDARD LVCMOS33} [get_ports rgb[23]]
set_property -dict {PACKAGE_PIN H17 IOSTANDARD LVCMOS33} [get_ports rgb[8]]
set_property -dict {PACKAGE_PIN B19 IOSTANDARD LVCMOS33} [get_ports rgb[9]]
set_property -dict {PACKAGE_PIN A20 IOSTANDARD LVCMOS33} [get_ports rgb[10]]
set_property -dict {PACKAGE_PIN C20 IOSTANDARD LVCMOS33} [get_ports rgb[11]]
set_property -dict {PACKAGE_PIN B20 IOSTANDARD LVCMOS33} [get_ports rgb[12]]
set_property -dict {PACKAGE_PIN D19 IOSTANDARD LVCMOS33} [get_ports rgb[13]]
set_property -dict {PACKAGE_PIN D20 IOSTANDARD LVCMOS33} [get_ports rgb[14]]
set_property -dict {PACKAGE_PIN J18 IOSTANDARD LVCMOS33} [get_ports rgb[15]]
set_property -dict {PACKAGE_PIN F19 IOSTANDARD LVCMOS33} [get_ports rgb[0]]
set_property -dict {PACKAGE_PIN F20 IOSTANDARD LVCMOS33} [get_ports rgb[1]]
set_property -dict {PACKAGE_PIN G19 IOSTANDARD LVCMOS33} [get_ports rgb[2]]
set_property -dict {PACKAGE_PIN G20 IOSTANDARD LVCMOS33} [get_ports rgb[3]]
set_property -dict {PACKAGE_PIN J20 IOSTANDARD LVCMOS33} [get_ports rgb[4]]
set_property -dict {PACKAGE_PIN H20 IOSTANDARD LVCMOS33} [get_ports rgb[5]]
set_property -dict {PACKAGE_PIN K16 IOSTANDARD LVCMOS33} [get_ports rgb[6]]
set_property -dict {PACKAGE_PIN J16 IOSTANDARD LVCMOS33} [get_ports rgb[7]]
set_property -dict {PACKAGE_PIN J19 IOSTANDARD LVCMOS33} [get_ports vpg_pclk]
set_property -dict {PACKAGE_PIN L16 IOSTANDARD LVCMOS33} [get_ports vpg_hs]
set_property -dict {PACKAGE_PIN L17 IOSTANDARD LVCMOS33} [get_ports vpg_vs]
set_property -dict {PACKAGE_PIN M19 IOSTANDARD LVCMOS33} [get_ports vpg_de]
set_property -dict {PACKAGE_PIN M20 IOSTANDARD LVCMOS33} [get_ports vpg_disp]
sdk-gpio
- 通过emio使用pl端的gpio与通过AXI接口使用pl端的gpio有什么区别? 区别在于:gpio控制器在哪边。通过emio,gpio控制器在ps端,只是一根线连到pl。通过AXI接口,则gpio控制器在pl端。
- 可以只生成HDL Wrapper。Generate Block Design在后面生成bitstream的时候,它会自动的跑这个流程。
- 经过测试,ps端的gpio翻转最大速度是6MHz
for(int i=0; i<1000; i++){
XGpioPs_WritePin(&gpiops, MIO_LED1, 0);
XGpioPs_WritePin(&gpiops, MIO_LED1, 1);
}
- 对于ps+pl的工程,如果调试的时候不勾选下面的2个, 也是可以运行printf的,但是pl的逻辑不工作。也就是说,pl侧是否烧录不影响ps侧的工作。
ps端以太网实验
- LwIP 实只需十几 KB 的 RAM 和 40K 左右的 ROM 就可以运行,这使 LwIP 协议栈适合在低端的嵌入式系统中使用。
- 注意bank1电压要选1.8V,否则编译报错。因为lwip/sd卡用的是1.8v。
将程序烧录到qspi-flash或sd卡的方法
生成fsbl和boot.bin
- 首先要配置zynq,开启qspi和sd卡。注意修改bank1电压为1.8V,并修改qspi管脚约束为Fast。(可以基于hello world实验)
- export hardware
- 打开sdk后,先确认hello_world工程可以运行。
- 然后创建fsbl工程,并修改其中如下内容,开启宏
- 右键单击hello_world工程(也可以是fsbl工程,不过要手动添加hello_world.elf文件。如果选择hello_world工程,则hello_world.elf已经自动选择了。),选择create boot image。
烧录到qspi-flash的方法一
- 选择菜单:xilinx->program flash, 填入如下内容,开始program flash,要花一点时间
- 烧录flash完成后。将拨码开关置于qspi,然后重新复位运行。结果如下,正确!
Xilinx First Stage Boot Loader
Release 2018.3 Jan 15 2024-21:00:53
Devcfg driver initialized
Silicon Version 3.1
Boot mode is QSPI
Single Flash Information
FlashID=0xEF 0x40 0x18
WINBOND 128M Bits
QSPI is in single flash connection
QSPI is in 4-bit mode
QSPI Init Done
Flash Base Address: 0xFC000000
Reboot status register: 0x60400000
Multiboot Register: 0x0000C000
Image Start Address: 0x00000000
Partition Header Offset:0x00000C80
Partition Count: 2
Partition Number: 1
Header Dump
Image Word Len: 0x00002002
Data Word Len: 0x00002002
Partition Word Len:0x00002002
Load Addr: 0x00100000
Exec Addr: 0x00100000
Partition Start: 0x000065D0
Partition Attr: 0x00000010
Partition Checksum Offset: 0x00000000
Section Count: 0x00000001
Checksum: 0xFFDF37C8
Application
PCAP:StatusReg = 0x40000A30
PCAP:device ready
PCAP:Clear done
PCAP register dump:
PCAP CTRL 0xF8007000: 0x4C00E07F
PCAP LOCK 0xF8007004: 0x0000001A
PCAP CONFIG 0xF8007008: 0x00000508
PCAP ISR 0xF800700C: 0x00033000
PCAP IMR 0xF8007010: 0xFFFFFFFF
PCAP STATUS 0xF8007014: 0x50000A30
PCAP DMA SRC ADDR 0xF8007018: 0xFC019741
PCAP DMA DEST ADDR 0xF800701C: 0x00100001
PCAP DMA SRC LEN 0xF8007020: 0x00002002
PCAP DMA DEST LEN 0xF8007024: 0x00002002
PCAP ROM SHADOW CTRL 0xF8007028: 0xFFFFFFFF
PCAP MBOOT 0xF800702C: 0x0000C000
PCAP SW ID 0xF8007030: 0x00000000
PCAP UNLOCK 0xF8007034: 0x757BDF0D
PCAP MCTRL 0xF8007080: 0x30800110
DMA Done !
Handoff Address: 0x00100000
In FsblHookBeforeHandoff function
SUCCESSFUL_HANDOFF
FSBL Status = 0x1
Hello World
烧录到qspi-flash的方法二:用vivado
- open Hardware manager,并连接device
- 添加存储器件
- 找到这个器件,此时跳线帽为jtag模式,然后点击开始编程。
- 烧录完成后,设置跳线帽为qspi模式,然后按复位重启。输出结果与前面一样。
烧录到sd卡运行的方法
- 将boot.bin放到sd卡中,然后插到板子上
- 跳线帽到sd卡模式,复位。结果如下:
Xilinx First Stage Boot Loader
Release 2018.3 Jan 15 2024-21:00:53
Devcfg driver initialized
Silicon Version 3.1
Boot mode is SD
SD: rc= 0
SD Init Done
Flash Base Address: 0xE0100000
Reboot status register: 0x60400000
Multiboot Register: 0x0000C000
Image Start Address: 0x00000000
Partition Header Offset:0x00000C80
Partition Count: 2
Partition Number: 1
Header Dump
Image Word Len: 0x00002002
Data Word Len: 0x00002002
Partition Word Len:0x00002002
Load Addr: 0x00100000
Exec Addr: 0x00100000
Partition Start: 0x000065D0
Partition Attr: 0x00000010
Partition Checksum Offset: 0x00000000
Section Count: 0x00000001
Checksum: 0xFFDF37C8
Application
Handoff Address: 0x00100000
In FsblHookBeforeHandoff function
SUCCESSFUL_HANDOFF
FSBL Status = 0x1
Hello World
双核AMP实验
- 创建cpu0工程,注意选择Processor为ps7_cortexa9_0
- 创建cpu1工程,注意选择Processor为ps7_cortexa9_1
- 修改cpu0和cpu1的ld文件中的ddr地址,两者不要重叠。如果重叠,运行异常。
- 打开cpu1_bsp的Board Support Package Setting,修改extra_compiler_flags,增加-DUSE_AMP=1,开启双核使能
- 创建cpu0.c和cpu1.c的main程序
- 运行,注意勾选2个cpu核
PL读写PS DDR
在这里,GPIO的用途是产生中断信号,用作中断控制器
BRAM读写实验
- 信号流如下。用的是双端口BRAM,每个端口均可独立的读写。
- CPU是通过M_AXI_GP0接口进行读写,中间需要用AXI SmartConnect总线矩阵。
DMA环路实验
- DDR进行读DMA和写DMA,因此有2个DMA通路,通过AXI SmartConnect合并到CPU的S_AXI_HP0接口(这是ddr的接口)
- DMA另一路还与AXI4 Stream Fifo连接,也是有Master/Slave接口。
- AXI4 InterConnect用于CPU配DMA的寄存器。
HDMI显示
- Framebuffer帧缓存
- 单帧缓存适用于输入速率小于读取速率的应用场景。对于摄像头图像显示或视频播放就需要用到多帧缓存。
- 为解决图像输入端和输出端的数据速率不匹配导致的潜在错误通常使用多帧缓存来保存数据。图像输入端在写入其中一个帧缓存时,输出端读取其它的帧缓存。这就涉及到帧缓存的读写策略,即同步锁相模式。xilinx的VDMA一共支持4种同步锁相模式。
- 在实际应用中,如果避开读通道和写通道同时访问同一帧缓存,那么 VMDA必须配置成动态同步锁相的模式,且帧缓存数量要大于等于3。(我实际没有测出差别来)
- VDMA的作用:实现AXI4-stream接口到AXI4/AXI4-Lite接口(memory mapped)的转换。
- AXI4/AXI4-Lite/AXI4-Stream。其中AXI4-Lite不支持burst模式,AXI4-Stream无地址。
- AXI4/AXI4-Lite有5组信号(读2组,写3组),AXI4-Stream只有1组信号。AXI4-Stream的数据分3种类型:有效数据,position数据,null数据,通过控制位区分。
- S2MM: Stream-to-Memory-Mapped(视频流写入内存),MM2S:Memory-Mapped-to-Stream(从内存读出到视频流)
- 信号流
- 已经试过了:zynq的axi接口不能与外设的axi接口直接连接,必须要加axi interconnect或者axi smartconnect。原因是zynq的axi是axi3,不能直接与axi4接。
- 引脚约束如下
set_property IOSTANDARD LVCMOS33 [get_ports {HDMI_HPD_tri_i[0]}]
set_property PACKAGE_PIN P19 [get_ports {HDMI_HPD_tri_i[0]}]
set_property PACKAGE_PIN U18 [get_ports TMDS_0_clk_p]
set_property PACKAGE_PIN V20 [get_ports {TMDS_0_data_p[0]}]
set_property PACKAGE_PIN T20 [get_ports {TMDS_0_data_p[1]}]
set_property PACKAGE_PIN N20 [get_ports {TMDS_0_data_p[2]}]
读取SD卡BMP图片到LCD显示的实验
- 这个例程折腾了很久: copy Z7-nano提供的官方例程,只是修改引脚以适应我的扩展板,始终不对,体现为修改了引脚,但烧进去调试发现波形仍然是原来的引脚出来的。折腾了很久也不知道原因。后来是这样解决的:删除原有.sdk,重新创建sdk,重新复制src下文件,重新编译后运行就ok了。
- 官方例程提供的porch参数,不用修改即可运行在原子的屏上,很方便。
- 引脚约束如下:
set_property -dict {PACKAGE_PIN F16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_o[16]}]
set_property -dict {PACKAGE_PIN F17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_o[17]}]
set_property -dict {PACKAGE_PIN E17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_o[18]}]
set_property -dict {PACKAGE_PIN D18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_o[19]}]
set_property -dict {PACKAGE_PIN E18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_o[20]}]
set_property -dict {PACKAGE_PIN E19 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_o[21]}]
set_property -dict {PACKAGE_PIN G17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_o[22]}]
set_property -dict {PACKAGE_PIN G18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_o[23]}]
set_property -dict {PACKAGE_PIN H17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_o[8]}]
set_property -dict {PACKAGE_PIN B19 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_o[9]}]
set_property -dict {PACKAGE_PIN A20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_o[10]}]
set_property -dict {PACKAGE_PIN C20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_o[11]}]
set_property -dict {PACKAGE_PIN B20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_o[12]}]
set_property -dict {PACKAGE_PIN D19 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_o[13]}]
set_property -dict {PACKAGE_PIN D20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_o[14]}]
set_property -dict {PACKAGE_PIN J18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_o[15]}]
set_property -dict {PACKAGE_PIN F19 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_o[0]}]
set_property -dict {PACKAGE_PIN F20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_o[1]}]
set_property -dict {PACKAGE_PIN G19 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_o[2]}]
set_property -dict {PACKAGE_PIN G20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_o[3]}]
set_property -dict {PACKAGE_PIN J20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_o[4]}]
set_property -dict {PACKAGE_PIN H20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_o[5]}]
set_property -dict {PACKAGE_PIN K16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_o[6]}]
set_property -dict {PACKAGE_PIN J16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_o[7]}]
set_property -dict {PACKAGE_PIN J19 IOSTANDARD LVCMOS33} [get_ports lcd_lcd_pclk]
set_property -dict {PACKAGE_PIN L16 IOSTANDARD LVCMOS33} [get_ports lcd_lcd_hs]
set_property -dict {PACKAGE_PIN L17 IOSTANDARD LVCMOS33} [get_ports lcd_lcd_vs]
set_property -dict {PACKAGE_PIN M19 IOSTANDARD LVCMOS33} [get_ports lcd_lcd_de]
set_property -dict {PACKAGE_PIN M20 IOSTANDARD LVCMOS33} [get_ports lcd_bl0]
- 信号流总结
- zynq的M_AXI_GP0是CPU的软件配置接口,通过AXI InterConnect给各个外设模块配置寄存器。
- 图像信号流是从ddr->S_AXI_HP0->AXI SmartConnect->VDMA->AX4 Stream to Video out->rgb to lcd
- 附录:用win11裁剪适合分辨率的bmp图片的方法:
- 打开图片,如果安装了wps,默认是用wps图片浏览器打开
- 点击编辑->裁剪旋转
- 输入分辨率,并拖动选择框到想要的位置,点击对勾确认。
- 输入名字,保存为bmp格式
- 将产生的bmp图片复制到sd卡中,即ok。
SD_HDMI_OUT实验
- 分辨率设置为1920x1080,但从sd卡读取800x480和480x800的图片,也都是可以正常显示的,只是会显示在屏幕的左上角一块。
- 修改block的模块后,例如zynq使能了sd卡或qspi等等。系统会自动更新verilog hdl wrapper,不需要手动重新生成。
- 注意sd开要设置bank1 vccio=1.8V(实际板子的bank电压接死为1.8V,不可调)。
- FATS默认支持shatan.bmp这样的名字,如果要读取shatan_1920x1080.bmp这样的名字,需要设置FATS,开启use_lfn=true,这样可以支持长文件名。
- 已经试过了:zynq的axi接口不能与外设的axi接口直接连接,必须要加axi interconnect或者axi smartconnect。原因是zynq的axi是axi3,不能直接与axi4接。
lcd_sd_out:
- 这个case没有使用axi4-stream subset converter,通过设置vdma的stream data width=24。
- 这个case的综合非常慢。原因不清楚。
- 拓展:只输出vs/hs/pclk/de这几个信号,去点屏也是可以亮的,符合预期。不过颜色是随机的,取决于引脚的当前电压。通过手动将引脚拉高/拉低,分别可以让屏幕输出red, green, blue等颜色。从这个角度看,点rgb屏,只输出一个颜色,其实是很容易的。
- 有时候,编译会报错,提示缺少文件(刚才都是好的,现在不行了)。这个时候,有时重新产生bsp包可以解决。
ov5640_to_hdmi:
- QSXGA,这里指:分辨率为 25921944 的输出格式,类似的还有:QXGA(20481536)、UXGA(16001200)、 SXGA(12801024)、WXGA(1440900)、WXGA(1280800)、XGA(1024768)、SVGA(800600)、 VGA(640480)、QVGA(320240)和 QQVGA(160*120)等。
- 采用原子的ov5640例程,修改编译后。烧不进去,有出错,提示AP transaction error, DAP status f0000021。后来发现是因为zynq的ddr内存型号没有换配置。 后来发现,是忘记了修改zynq的ddr的型号和位宽。修改好了后,马上结果就出来了。
- 原子例程的引脚约束
#----------------------摄像头接口的时钟---------------------------
#72M
create_clock -period 13.888 -name cam_pclk [get_ports cam_pclk]
set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets cam_pclk_IBUF]
#HDMI
set_property -dict {PACKAGE_PIN N20 IOSTANDARD TMDS_33 } [get_ports {TMDS_tmds_data_p[2]}]
set_property -dict {PACKAGE_PIN T20 IOSTANDARD TMDS_33 } [get_ports {TMDS_tmds_data_p[1]}]
set_property -dict {PACKAGE_PIN V20 IOSTANDARD TMDS_33 } [get_ports {TMDS_tmds_data_p[0]}]
set_property -dict {PACKAGE_PIN U18 IOSTANDARD TMDS_33 } [get_ports TMDS_tmds_clk_p]
#----------------------摄像头接口---------------------------
set_property -dict {PACKAGE_PIN E18 IOSTANDARD LVCMOS33} [get_ports cam_rst_n]
set_property -dict {PACKAGE_PIN D20 IOSTANDARD LVCMOS33} [get_ports cam_pwdn]
set_property -dict {PACKAGE_PIN E19 IOSTANDARD LVCMOS33} [get_ports {cam_data[0]}]
set_property -dict {PACKAGE_PIN G17 IOSTANDARD LVCMOS33} [get_ports {cam_data[1]}]
set_property -dict {PACKAGE_PIN G18 IOSTANDARD LVCMOS33} [get_ports {cam_data[2]}]
set_property -dict {PACKAGE_PIN H16 IOSTANDARD LVCMOS33} [get_ports {cam_data[3]}]
set_property -dict {PACKAGE_PIN H17 IOSTANDARD LVCMOS33} [get_ports {cam_data[4]}]
set_property -dict {PACKAGE_PIN B19 IOSTANDARD LVCMOS33} [get_ports {cam_data[5]}]
set_property -dict {PACKAGE_PIN A20 IOSTANDARD LVCMOS33} [get_ports {cam_data[6]}]
set_property -dict {PACKAGE_PIN C20 IOSTANDARD LVCMOS33} [get_ports {cam_data[7]}]
set_property -dict {PACKAGE_PIN E17 IOSTANDARD LVCMOS33} [get_ports cam_href]
set_property -dict {PACKAGE_PIN B20 IOSTANDARD LVCMOS33} [get_ports cam_pclk]
set_property -dict {PACKAGE_PIN F16 IOSTANDARD LVCMOS33} [get_ports cam_vsync]
#cam_scl:
set_property -dict {PACKAGE_PIN F17 IOSTANDARD LVCMOS33} [get_ports {emio_sccb_tri_io[0]}]
#cam_sda:
set_property -dict {PACKAGE_PIN D18 IOSTANDARD LVCMOS33} [get_ports {emio_sccb_tri_io[1]}]
set_property PULLUP true [get_ports {emio_sccb_tri_io[1]}]
Z7的ov5640摄像头例程修改
- 基本思想,使用原子的xdc引脚约束,并将Z7的引脚修改的与原子的引脚约束名字一样,这样最便捷。
- 输入端修改名字。并用constant+concat模块,将cam_data[7:0]转成cmos_data[9:0]
- 输出名字修改,并用concat将单根线的名字合并为总线
- 摄像头能work,但是结果不对,应该是显示分辨率或者时序没有设置好。后面没有去细查。ov5640的例程是基于原子的例程学习的,没有使用微相的。
DMA与VDMA
- PS的DMAC是通过AXI_GP接口,32bits, 速度只能到600MB/s,比较有限。性能不如AXI_HP接口(1200MB/s)+AXI DMA。
- AXI4 Stream Master(MM2S), AXI4 Stream Slave(S2MM)。如何区分Master/Slave,请根据数据的流向来看。 Memory->AXI_MM2S->DMA->AXIS_MM2S Memory<-AXI_S2MM<-DMA<-AXIS_S2MM。
- AXI4 Lite用于配置寄存器,AXI4 Memory Map用于读写寄存器,AXI4 Stream用于读写外设
- AXI DMA 提供 3 种模式,分别是 Direct Register 模式、Scatter/Gather 模式和 Cyclic DMA 模式
- 和 DMA 相比,VDMA 增加了帧缓存的缓冲机制和同步锁相(GenLock)等功能, 是为了针对视频图像应用而做的升级版的 DMA
- 为了解决单帧缓存区域带来的图像叠加问题,通过分配多个帧缓存区域保存数据,图像输入端在写入其中一个帧缓存时,输出端读取其它的帧缓存。
- 在Gen Master/Slave模式下,写通道在循环访问帧缓存 0,1,2;而由于读通道的帧速率比写通道慢,读通道会紧跟写通道,在操作 0 之后,跳过 1,而去处理 2。
- 在Dynamic Gen Master/Slave模式下,Master 会跳过 Slave 当前操作的帧缓存,Slave 工作在 Master 上一次操作过的帧缓存
- 如果想要避开读通道和写通道同时访问同一帧缓存,那么 VMDA 必须配置成动态同步锁相的模式,且帧缓存数量要大于等于 3。由于分配过多的帧缓存区域对效率的提升已经微乎其微,且会占用更多的存储空间和消耗 CPU 的时间,因此在摄像头图像显示的应用中,帧缓存空间一般设置为 3,并采用动态同步锁相的模式。
原子的sd_hdmi例程
- 参考原子教程上的,由于只使用了1个100MHz时钟,因此最大只能支持1280x800分辨率。注意例程中是1920x1080,这样屏幕是点不亮的,折腾了很久,将分辨率降下来就可以了。
- 原子的例程,是没有使用subset converter的,一样可以正常工作。也没有看出什么特别的不同。
原子的hdmi, lcd, ov5640例程
- ov5640例程中,注意vdma的设置,write/read burst size=8。在lcd/hdmi例程中,vdma的read burst size=64(这个好像没有什么影响)。
- video in/video out to AXI4S的fifo=1024, 而vdma的fifo=512或2048(这个可能要根据实验结果来调整,实际测试也没有什么影响)。
- 实验结果,我把vdma的framebuffer数量设置为1,ov5640_hdmi的显示效果仍然很稳定,一点都不抖动。
- 在使用ov5640/hdmi/lcd的例程中,这个video timing control模块的设置最容易出错! 以下4个信号都容易出错! 注意: clk要来自pll_clk_o, s_axi_aclk要来自zynq, gen_clkgen要来自AXI4-Stream to Video out模块的vtg_gen,resetn要悬空。把这4个注意了,基本上自己手动搭建没有问题,不会出错。
原子ov5640_lcd例子的引脚约束,其中lcd用GPIO1,ov5640用GPIO2
# lcd
set_property -dict {PACKAGE_PIN F16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_tri_io[16]}]
set_property -dict {PACKAGE_PIN F17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_tri_io[17]}]
set_property -dict {PACKAGE_PIN E17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_tri_io[18]}]
set_property -dict {PACKAGE_PIN D18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_tri_io[19]}]
set_property -dict {PACKAGE_PIN E18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_tri_io[20]}]
set_property -dict {PACKAGE_PIN E19 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_tri_io[21]}]
set_property -dict {PACKAGE_PIN G17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_tri_io[22]}]
set_property -dict {PACKAGE_PIN G18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_tri_io[23]}]
set_property -dict {PACKAGE_PIN H17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_tri_io[8]}]
set_property -dict {PACKAGE_PIN B19 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_tri_io[9]}]
set_property -dict {PACKAGE_PIN A20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_tri_io[10]}]
set_property -dict {PACKAGE_PIN C20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_tri_io[11]}]
set_property -dict {PACKAGE_PIN B20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_tri_io[12]}]
set_property -dict {PACKAGE_PIN D19 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_tri_io[13]}]
set_property -dict {PACKAGE_PIN D20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_tri_io[14]}]
set_property -dict {PACKAGE_PIN J18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_tri_io[15]}]
set_property -dict {PACKAGE_PIN F19 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_tri_io[0]}]
set_property -dict {PACKAGE_PIN F20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_tri_io[1]}]
set_property -dict {PACKAGE_PIN G19 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_tri_io[2]}]
set_property -dict {PACKAGE_PIN G20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_tri_io[3]}]
set_property -dict {PACKAGE_PIN J20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_tri_io[4]}]
set_property -dict {PACKAGE_PIN H20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_tri_io[5]}]
set_property -dict {PACKAGE_PIN K16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_tri_io[6]}]
set_property -dict {PACKAGE_PIN J16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_tri_io[7]}]
set_property -dict {PACKAGE_PIN J19 IOSTANDARD LVCMOS33} [get_ports lcd_clk]
set_property -dict {PACKAGE_PIN L16 IOSTANDARD LVCMOS33} [get_ports lcd_hs]
set_property -dict {PACKAGE_PIN L17 IOSTANDARD LVCMOS33} [get_ports lcd_vs]
set_property -dict {PACKAGE_PIN M19 IOSTANDARD LVCMOS33} [get_ports lcd_de]
set_property -dict {PACKAGE_PIN M20 IOSTANDARD LVCMOS33} [get_ports lcd_bl]
#----------------------摄像头接口的时钟---------------------------
#72M
create_clock -period 13.888 -name cam_pclk [get_ports cam_pclk]
set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets cam_pclk_IBUF]
#HDMI
#set_property -dict {PACKAGE_PIN N20 IOSTANDARD TMDS_33 } [get_ports {TMDS_tmds_data_p[2]}]
#set_property -dict {PACKAGE_PIN T20 IOSTANDARD TMDS_33 } [get_ports {TMDS_tmds_data_p[1]}]
#set_property -dict {PACKAGE_PIN V20 IOSTANDARD TMDS_33 } [get_ports {TMDS_tmds_data_p[0]}]
#set_property -dict {PACKAGE_PIN U18 IOSTANDARD TMDS_33 } [get_ports TMDS_tmds_clk_p]
#GPIO2
#物理PIN 电路PIN 电路PIN 物理PIN
#1 H15 3V3 2 G15 GND
#3 F16 cam_vsync 4 F17 emio_sccb_tri_io[0]
#5 E17 cam_href 6 D18 emio_sccb_tri_io[1]
#7 E18 cam_rst_n 8 E19 cam_data[0]
#9 G17 cam_data[1] 10 G18 cam_data[2]
#11 H16 cam_data[3] 12 H17 cam_data[4]
#13 B19 cam_data[5] 14 A20 cam_data[6]
#15 C20 cam_data[7] 16 B20 cam_pclk
#17 D19 cam_flash 18 D20 cam_pwdn
##----------------------摄像头接口---------------------------
#set_property -dict {PACKAGE_PIN E18 IOSTANDARD LVCMOS33} [get_ports cam_rst_n]
#set_property -dict {PACKAGE_PIN D20 IOSTANDARD LVCMOS33} [get_ports cam_pwdn]
#set_property -dict {PACKAGE_PIN E19 IOSTANDARD LVCMOS33} [get_ports {cam_data[0]}]
#set_property -dict {PACKAGE_PIN G17 IOSTANDARD LVCMOS33} [get_ports {cam_data[1]}]
#set_property -dict {PACKAGE_PIN G18 IOSTANDARD LVCMOS33} [get_ports {cam_data[2]}]
#set_property -dict {PACKAGE_PIN H16 IOSTANDARD LVCMOS33} [get_ports {cam_data[3]}]
#set_property -dict {PACKAGE_PIN H17 IOSTANDARD LVCMOS33} [get_ports {cam_data[4]}]
#set_property -dict {PACKAGE_PIN B19 IOSTANDARD LVCMOS33} [get_ports {cam_data[5]}]
#set_property -dict {PACKAGE_PIN A20 IOSTANDARD LVCMOS33} [get_ports {cam_data[6]}]
#set_property -dict {PACKAGE_PIN C20 IOSTANDARD LVCMOS33} [get_ports {cam_data[7]}]
#set_property -dict {PACKAGE_PIN E17 IOSTANDARD LVCMOS33} [get_ports cam_href]
#set_property -dict {PACKAGE_PIN B20 IOSTANDARD LVCMOS33} [get_ports cam_pclk]
#set_property -dict {PACKAGE_PIN F16 IOSTANDARD LVCMOS33} [get_ports cam_vsync]
##cam_scl:
#set_property -dict {PACKAGE_PIN F17 IOSTANDARD LVCMOS33} [get_ports {emio_sccb_tri_io[0]}]
##cam_sda:
#set_property -dict {PACKAGE_PIN D18 IOSTANDARD LVCMOS33} [get_ports {emio_sccb_tri_io[1]}]
#set_property PULLUP true [get_ports {emio_sccb_tri_io[1]}]
#GPIO1
#物理PIN 电路PIN 电路PIN 物理PIN
#1 N17 3V3 2 P18 GND
#3 R16 cam_vsync 4 R17 emio_sccb_tri_io[0]
#5 T17 cam_href 6 R18 emio_sccb_tri_io[1]
#7 T16 cam_rst_n 8 U17 cam_data[0]
#9 W18 cam_data[1] 10 W19 cam_data[2]
#11 Y18 cam_data[3] 12 Y19 cam_data[4]
#13 Y16 cam_data[5] 14 Y17 cam_data[6]
#15 V17 cam_data[7] 16 V18 cam_pclk
#17 V16 cam_flash 18 W16 cam_pwdn
#----------------------摄像头接口---------------------------
set_property -dict {PACKAGE_PIN T16 IOSTANDARD LVCMOS33} [get_ports cam_rst_n]
set_property -dict {PACKAGE_PIN W16 IOSTANDARD LVCMOS33} [get_ports cam_pwdn]
set_property -dict {PACKAGE_PIN U17 IOSTANDARD LVCMOS33} [get_ports {cam_data[0]}]
set_property -dict {PACKAGE_PIN W18 IOSTANDARD LVCMOS33} [get_ports {cam_data[1]}]
set_property -dict {PACKAGE_PIN W19 IOSTANDARD LVCMOS33} [get_ports {cam_data[2]}]
set_property -dict {PACKAGE_PIN Y18 IOSTANDARD LVCMOS33} [get_ports {cam_data[3]}]
set_property -dict {PACKAGE_PIN Y19 IOSTANDARD LVCMOS33} [get_ports {cam_data[4]}]
set_property -dict {PACKAGE_PIN Y16 IOSTANDARD LVCMOS33} [get_ports {cam_data[5]}]
set_property -dict {PACKAGE_PIN Y17 IOSTANDARD LVCMOS33} [get_ports {cam_data[6]}]
set_property -dict {PACKAGE_PIN V17 IOSTANDARD LVCMOS33} [get_ports {cam_data[7]}]
set_property -dict {PACKAGE_PIN T17 IOSTANDARD LVCMOS33} [get_ports cam_href]
set_property -dict {PACKAGE_PIN V18 IOSTANDARD LVCMOS33} [get_ports cam_pclk]
set_property -dict {PACKAGE_PIN R16 IOSTANDARD LVCMOS33} [get_ports cam_vsync]
#cam_scl:
set_property -dict {PACKAGE_PIN R17 IOSTANDARD LVCMOS33} [get_ports {emio_sccb_tri_io[0]}]
#cam_sda:
set_property -dict {PACKAGE_PIN R18 IOSTANDARD LVCMOS33} [get_ports {emio_sccb_tri_io[1]}]
set_property PULLUP true [get_ports {emio_sccb_tri_io[1]}]
#cam_flash(其实不需要):
set_property -dict {PACKAGE_PIN V16 IOSTANDARD LVCMOS33} [get_ports cam_flash_tri_o]
set_property PULLUP true [get_ports cam_flash_tri_o]
总结微相与原子的hdmi/lcd例程的差异
- 原子的hdmi例程,不能使用axi4 stream subset converter模块,否则显示异常。
- 微相的hdmi例程,必须使用axi4 stream subset converter模块,否则无显示。
- 以上2个的原因,并不是硬件的问题,是软件的问题。2个例程的软件不一样,模块设置和初始化不一样(具体哪里不同,没有去细查)。以上结果与图片是否从sd卡读取,或者是从rom读取,没有关系。
- 微相的hdmi例程,使用axi4 stream subset converter模块,如果使用微相提供的DVI接口,显示颜色失真;如果使用原子提供的DVI接口,显示颜色正常。原因是这2家的rgb2dvi的接口,颜色定义顺序是不一样的。如果使用微相科技的DVI接口和程序,必须使用axi4 stream subset converter模块,并且还要配置这个模块的颜色排序
- 微相的hdmi例程,如果不对axi4 stream subset converter模块做颜色排序,另一种方法是在程序中对颜色进行修改排序
如果将图形顺序换成如下,微相的例程也可以颜色正常:
// 1280 x 720
frame[linesStart + xcoi + 1] = Pixel_1280_720[pixelIdx++];
frame[linesStart + xcoi + 0] = Pixel_1280_720[pixelIdx++];
frame[linesStart + xcoi + 2] = Pixel_1280_720[pixelIdx++];
- 一个Video OUT模块可以接2个DVI模块,但是不能以总线的方式接。需要把总线展开后,一根一根的接。已经验证过,是ok的。