VDMA指定帧传输

VDMA参数介绍

在这里插入图片描述

关键参数:
Frame Buffers:帧缓存数,提供缓存区存放像素数据

Memory Map Data Width:VDMA与AXI4 Memory-Mapped总线之间的数据位宽,比如这里设置成64,那就代表传输时数据位为64位,这时候如果stream上的数据是32bit,那vdma内部会有一个带宽转换模块,把数据拼成64bit。

Burst Size : AXI总线上突发传输的长度,指定VDMA在单次读/写操作中可以连续传输的最大数据量,假设 Burst Size = 16,Memory Map Data Width = 64 位。在一次突发传输中,传输的数据量为:BurstData = 16 * 8 = 128 bytes

Stream Data Width:VDMA与AXI4-Stream总线之间的数据位宽,对应每个像素的数据位宽,对于RGB图像,这里设置为24位,对于单通道图像,这里设置为8位

在这里插入图片描述
Fsync Options:
none: 在自由运行模式下,VDMA会尽可能快地传输视频数据,不需要外部触发信号来开始每一帧的传输,也就是只要vdma准备好就开始传输
mm2s_fsync:VDMA在检测到该信号的下降沿时开始传输数据,每次只传输一帧数据就停止

GenLock Mode:

有四种模式,这里不做介绍

VDMA使用

我打算在ps端利用相机采集图像,并将图像通过VDMA传送到pl端进行处理,要能实现单张指定图片传输,也就是要能控制每次只传递一张图片,而非连续传输
要求:1.要能控制vdma每次只传输一张图片
2.要能指定每次传输哪一张图片

方案一:函数控制vdma传输

开启vdma中断,配置帧完成中断,然后在中断中关闭vdma传输,指定下一张图片后再开启vdma传输

BD设计:Fsync Options选择none,GenLock Mode选择Master(四种模式都可以,因为只有一个vdma,没有主从关系也不需要同步)

程序设计:参考官方提供的函数,结合vdma.api.c和intr.c

在这里插入图片描述

关键参数:
在这里插入图片描述

FrameCfgPtr.ReadDelayTimerCount:中断延迟计数值(这个不知道该如何使用,按照官方文档介绍,在外部帧同步模式(external fsync mode)下,计时器从接收到外部帧同步信号(fsync)开始计数,达到设定值时产生中断,但是我不清楚单位,是时钟周期吗,但是最大也就256,有知道的麻烦告诉我一声),这里设置为0
FrameCfgPtr.ReadFrameCount:帧完成中断计数值,每完成多少帧就产生一个中断,我们要实现单帧切换这里就设置为1
SetupReadIntrSystem:参照intr.c设置的中断初始化函数
XAxiVdma_IntrEnable:将XAXIVDMA_IXR_FRMCNT_MASK帧计数中断打开

readsetup函数
在这里插入图片描述

FrameDelay:与之前的ReadDelayTimerCount不同,FrameDelay用于指定在连续的帧之间应当插入的延迟,这里不用就置0
EnableCircularBuf:循环缓冲区模式,为1时,vdma会循环传输所有帧缓存区中的数据,为0时,只传输固定帧的数据,可以通过XAxiVdma_StartParking指定传输帧,所以这里置0
EnableSync:帧同步的同步传输,就是是否开启vdma那四种模式,但这只对除了Genlock Master之外的三种模式有效,官方文档中有介绍,这里不需要同步模式就置0
PointNum:对应CR寄存器中的RdPntrNum,没了解,这里置0
EnableFrameCounter:帧计数的自动停止功能,也就是vdma完成ReadFrameCount个帧传输后关闭vdma传输,后面使用vdma还需要使用XAxiVdma_DmaStart手动开启,注意这不是开启计数中断!这里置0
FixedFrameStoreAddr:用于指定VDMA在停放模式下传输固定帧,也就是与XAxiVdma_StartParking作用相同,都是设置PARK_PTR_REG中的 RdFrmPtrRef,这里置0

程序逻辑比较简单,设置一个标志位,在帧完成中断中将该位置1,主函数中轮询检测该标志位,检测到后调用XAxiVdma_DmaStop关闭VDMA传输,然后调用XAxiVdma_StartParking切换帧缓存区,再XAxiVdma_DmaStart打开VDMA传输,当然还要将标志位置0
但是结果在屏幕上只能显示第一个帧缓存区内容,调整XAxiVdma_StartParking到XAxiVdma_DmaStart后也不行,最后ila查看波形发现

在这里插入图片描述

总结:

1.帧完成中断不是在当前帧传输结束时进入,而是在第二帧传输开启时进入(这个机制很坑,等会儿还会说到)
2.Dmastop后使用XAxiVdma_StartParking不能指定下一次开启DMA的帧缓存区,(通过查看PARK_PTR_REG寄存器,发现有被修改),但是下一次传输开启后始终会从第一帧开始传输,传输完一帧后才进行指定帧的传输
3.Dmastart后使用XAxiVdma_StartParking需要等待当前帧完成后再传输指定帧
所以该方案行不通

方案二:使用fsync信号控制vdma的传输

vdma传输只在每个Fsync信号下降沿开启

BD设计:vdma中Fsync Options选择mm2s fysnc,该信号与ps的emio相连接,使用emio输出脉冲信号模拟fsync信号
程序设计:vdma的配置跟方案一相同,
程序逻辑也类似,同样是利用标志位,检测到标志位后emio生成脉冲信号

   XGpioPs_WritePin(&Gpios,EMIO_FSYNC,1);
   usleep(1);
   XGpioPs_WritePin(&Gpios,EMIO_FSYNC,0);

并且开始要手动给一个脉冲信号来开启传输,这样设置后发现没有持续运行,并且没有进入中断,这就联想到了刚刚所说坑人的中断机制了,帧完成中断是在第二帧传输开启时进入,但是我又需要进入中断才能开启第二帧传输(开始套娃了)

没办法只能手动连续给两个脉冲信号了(注意两个信号之间要有延时,我设置的sleep 1),这下能够进入中断了,但是会进入错误中断,通过检查状态寄存器,出现SOFEarlyErr、VDMAIntErr,导致vdma停止,下面通过ila波形解释

在这里插入图片描述

关键就在于进入中断时第二帧已经开始传输了,并且此时标志位又置一,主程序中检测到标志位后立即生成fynsc信号,也就是第二帧传输未完成又开启了下一帧传输

解决方案:

1.这可以通过检测到标志位后引入延时来解决,这个延时就与每帧的大小有关了,我使用usleep(200)就能实现连续传输了,不过这样我的屏幕上却不显示图片,但是通过ila观察是vdma的M_AXIS_MM2S接口是有数据传输的(我估计是要去调节VTC,但是我调不来就放弃了);如果不需要显示那这样还是可行的

2.后面就考虑能不能检测当前vdma是否在传输数据,当标志位置1时且vdma空闲时再开启下一次传输;
在xaxivdma.h中发现XAxiVdma_IsBusy函数,按照它的介绍就是查看读写通道是否在传输,使用后发现其始终返回1,也就是读通道繁忙,查看该函数发现查看了状态寄存器的XAXIVDMA_SR_IDLE_MASK位

#define XAXIVDMA_SR_IDLE_MASK         0x00000002  /**< DMA channel idle */
Bits = XAxiVdma_ReadReg(Channel->ChanBase, XAXIVDMA_SR_OFFSET) &
	          XAXIVDMA_SR_IDLE_MASK;

然后查看数据手册PG020(6.3版本)

在这里插入图片描述

这就给我整懵了,为什么没有IDLE位,当时想到为什么3-2和1都是reserved为什么没有合到一起,是不是版本更新的问题,然后看了5.04版本,果然在这里插入图片描述
然后就查看6.3版本的寄存器有没有相似功能,硬是没找到,都想去找技术支持了
后面查看文档时发现在这里插入图片描述

原来vdma还有些隐藏端口,其中就包含一个能查看当前传输是否完成的端口
在这里插入图片描述

在vivado TCL中输入

set_property -dict [list CONFIG.C_ENABLE_MM2S_BUF_EMPTY {1}] [get_bd_cells axi_vdma_0]

VDMA IP核就多了两个接口

在这里插入图片描述

其中mm2s_buffer_empty在每帧传输完成后就会拉高,将其通过axi gpio连接到ps,在主程序中轮询检测标志位和mm2s_buffer_empty是否为1,同时为1时才开启下一帧传输,最后终于正常运行了

if (triggerFSync) {
	u32 data = XGpio_DiscreteRead(&axi_vdma_empty,1);
	if(data == 1){
    XGpioPs_WritePin(&Gpios,EMIO_FSYNC,1);
    usleep(1);
    XGpioPs_WritePin(&Gpios,EMIO_FSYNC,0);
        // 重置标志
    triggerFSync = false;
	}
}

总结:
1.vdma(6.3版本)状态寄存器没有IDLE位,不能使用XAxiVdma_IsBusy查看当前vdma是否在传输
2.可以在TCL中输入指令开启vdma的隐藏端口

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值