AXI协议(六) Axi-Stream接入实例及小总结

19 篇文章 35 订阅
18 篇文章 6 订阅
本文深入解析了如何将普通摄像头的数据流通过AXI-Stream协议接入系统,涉及时钟域转换、像素格式调整、异步FIFO的应用以及AXI4协议的关键要点。通过实例讲解,帮助读者理解AXI-Stream在硬件接口设计中的实际操作和协议细节。
摘要由CSDN通过智能技术生成

AXI协议(六) AXI-Stream接入实例及小总结

在这节中,你将可能看到:

  • 一个普通的摄像头接口介绍
  • 摄像头数据转AXI-Stream的接入实例
  • 关于AXI4协议暂时性的总结

文前声明

  • 本文所举例来自黑金的ov5640摄像头驱动代码,开发板是zynq系列的,本文仅用于学习交流,知识分享,如有侵权通知后会下架(到时我再自己写一个吧)核心转换ip、流程如下:

本文也不会放硬件的原理图和PCB,会自己画图取而代之

普通摄像头的硬件模块

这里的"普通"是除mipi或者其他专用设计以外的摄像头。以ov5640为例,一般会包含两个部分:

  • 通过IIC进行摄像头的各种参数配置
  • 像素流+行同步和列同步信号

如图所示,iic配置接口在ZYNQ的PS端,即ARM端做配置,数据流在PL端,即FPGA做接收。由于本文主要讲PL端的AXI-Stream转换,所以我们默认IIC部分是已经实现好了,使用行扫描模式。

这个摄像头在配置的时候有很多参数可以设置,在这里我们就不做介绍了,主力于把Axi-Stream搞出来。

需要注意的是,在硬件上,ov5640是10位的,但是在本模块中只用了高8位做数据传输。

基本思路和问题

在接着往下做的时候,我们先厘清一下问题:

  1. 摄像头传进的数据的时钟域与AXI总线的时钟域不同
  2. 像素格式和硬件上的“data”线往往是不匹配的,比如我们可能接收的是RGB888,假设数据线位宽为8,这需要三个时钟才能传完一个像素,此时的行列同步信号时序需要提前规定好,不然容易空行。

实现思路

而对于实现方式来说,对一个行扫描的摄像头,我们可以以行为axi-stream的last信号,列同步也就是帧同步信号因后级的VDMA需要放在tuser[0]中,可见于手册:

但是需要注意,这里的行列同步信号是需要通过处理的,正如上面的问题2而言,若我们直接将行列同步信号往外送,就会出现空行和空帧情况。

问题解决思路

  1. 对于时钟域问题解决不当会有“亚稳态问题”,主流解决方法有两种:

    • “打两拍”
    • 异步fifo、ram

    这里刚好和我们上一篇中讨论的“Default value signaling”有关系,由于各家定义的不同,我们可以省略很多axis的信号线,其中对于tready信号则讨论了反压的问题,所以这里我们选择异步fifo,让流水线出现反压时,fifo可以先局部地缓存一下数据

  2. 像素格式和硬件上的“data”线不匹配问题可以根据手册按照自己想要的像素格式和硬件数据线做一个转换,比如在本设计中像素格式是RGB565,而接收数据线只有8bit,所以就需要做一个8转16的模块,同时处理边界指示信号问题。

所以具体解决思路为:

代码解析

这里大家从代码上就知道,问题的关键点在于怎么拿fifo的数据位,empty和full跟AXI-Stream协议握手做映射

完整代码建议大家支持黑金的zynq开发板后获取,或者去他们的官方论坛获取,此处不放出链接

我们假设同步信号按下面的格式进来:

见手册6.1.2

所以整体的代码实现上有这三点:

  • 摄像头像素格式的对齐cmos8->16
  • 将同步位和像素数据转成axis的"初步格式"
  • 加入异步fifo,完成异步时钟域处理

像素格式对齐

这里主要对应cmos_8_16bit模块

这里主要是将两个pdata_i合并在一起就完事了,de_i是有效位,所以我们可以根据de_i做一个二分频就可以得到输出的像素时钟。所以像素输出和有效位de_o控制如下(为简便展示,对源代码有修改):

// 输出
always@(posedge pclk or posedge rst)
begin
	if(rst) begin
		de_o <= 1'b0;
		pdata_o <= 16'd0;
	end
	else if(de_i && x_cnt[0])begin
		de_o <= 1'b1;
		pdata_o <= {pdata_i_d0,pdata_i};
	end
	else begin
		de_o <= 1'b0;
		pdata_o <= 16'd0;
	end
end

其中,x_cnt[0]为de_i的2分频:

always@(posedge pclk or posedge rst)
begin
	if(rst)
		x_cnt <= 12'd0;
	else if(de_i)
		x_cnt <= x_cnt + 12'd1;
	else
		x_cnt <= 12'd0;
end

但是像素的有效位做二分频后,就不能再用有效位的下降沿做axis_tlast了,所以我们需要拿原来的有效位给个延迟做行同步信号:

always@(posedge pclk or posedge rst)
begin
	if(rst)
		hblank <= 1'b0;
	else
		hblank <= de_i;
end

至此,像素处理结束,因为代码上逻辑层次比较清晰,这里给出例化代码,不然下面代码比较难讲:

cmos_8_16bit cmos_8_16bit_m0(
	.rst(~cmos_aresetn),
	.pclk(cmos_pclk),
	.pdata_i(cmos_d_d0),
	.de_i(cmos_href_d0),
	.pdata_o(cmos_d_16bit),
	.hblank(cmos_hblank),
	.de_o(cmos_href_16bit)
);

将同步位和像素数据转成axis的"初步格式"

这里主要处理的是同步位,因为像素数据是直接接fifo的,逻辑上比较直接。

这里不解释各个信号的延时,因为后面要检测hblank的下降沿和16bit的数据要等一拍才能出来,导致几乎所有的信号都要delay,这个具体时序大家自己仿真对一下吧🦾。

我们直接看代码中的对应关系(slave端,逻辑关系见上图):

assign s_axis_tready = ~full;	// fifo的满信号
wire   s_axis_tvalid = cmos_href_16bit_d1 & cmos_hblank_d1 & s_axis_tready;
wire[15:0]    s_axis_tdata = cmos_d_16bit_d1;

// 时序逻辑部分 axis_tlast
always@(posedge cmos_pclk)
begin
    if(cmos_aresetn == 1'b0)
      s_axis_tlast <= 1'b0;
	else
      s_axis_tlast <= cmos_hblank_d0 & ~cmos_hblank;
end

// 时序逻辑部分 axis_tuser
always@(posedge cmos_pclk)
begin
    if(cmos_aresetn == 1'b0)
        s_axis_tuser <= 1'b0;
	else if(cmos_vsync_d1 == 1'b1 && cmos_vsync_d0 == 1'b0)
		s_axis_tuser <= 1'b1;
	else if(s_axis_tuser == 1'b1 && s_axis_tvalid == 1'b1)
		s_axis_tuser <= 1'b0;
end

可以看出:

  1. ready和valid信号主要在判断fifo的状态和**'像素数据’的有效**,和AXI协议上握手过程是一样的,唯一有疑惑的就在于在AXI协议中,说明valid信号不能根据ready而置位,否则可能会引起互锁。不过与后级fifo连接中可以得知,这里的与s_axis_tready可以看作是axi握手成功的标志。
  2. 同步信号基本就是原传进来的cmos_hblank和cmos_vsync,通过检测他们的下降沿得到同步信号。

加入异步fifo

再看一次框图,所以在具体的fifo连线中,是这样的:

  • 在从端(输入端):
.wr_clk           (cmos_pclk),
.wr_en            (s_axis_tvalid & fifo_ready),
.din              ({s_axis_tdata,s_axis_tlast,s_axis_tuser}),
.full             (full),

其中,fifo_ready是fifo这个ip核所需要的复位时间,这里不展开。所以可以看见wr_en是只受s_axis_tvalid影响的,所以我们可以将这一部分重构成:

// 旧版
assign s_axis_tready = ~full;	// fifo的满信号
wire   s_axis_tvalid = cmos_href_16bit_d1 & cmos_hblank_d1 & s_axis_tready;
.wr_en            (s_axis_tvalid & fifo_ready),
// 新版
assign s_axis_tready = ~full;	// fifo的满信号
assign s_axis_tvalid = cmos_href_16bit_d1 & cmos_hblank_d1;
.wr_en            (s_axis_tvalid & s_axis_tready & fifo_ready),

这样大家可能就能理解我上面说的"这里的与s_axis_tready可以看作是axi握手成功的标志"。

  • 在主端(输出):
.rd_clk           (m_axis_video_aclk),
.rd_en            (m_axis_video_tready & ~empty & fifo_ready_maxis),
.dout             ({m_axis_video_tdata,m_axis_video_tlast,m_axis_video_tuser}),
.empty            (empty),

其中,fifo_ready_maxis是在axi时钟下fifo的复位完成标志位,这里异步时钟处理用的是打拍,也不展开。

此时我们只需要加上主端数据输出的握手设计,整个ip就做完了:

assign        m_axis_video_tkeep = 2'b11;
assign m_axis_video_tvalid = ~empty & m_axis_video_tready;

可以看到,他这里的valid又跟ready沾一起了,我们这里就不管了,毕竟不知道外部的ready信号怎么来。

  • 观察可知,tlast和tuser走的是数据通路。

加点魔法

对这个我们自己做出来的AXIS,这个时候看回框图:

实际上我们可以用xilinx的AXI4-Stream Subset Converter转换成"更为标准和完整的流数据"

我们看看黑金的实例工程的设计:

可以看到,这里我们再把我们之前接出来得到RGB565改成了RGB888,输出的位宽也变成了24。这里可以回想在AXI协议中,做这种非标准位宽传输就会涉及到非对齐传输(Unaligned Transfer)问题。所以后级在VDMA中,也需要打开这个选项,因为我们后级存进ddr的是64位的。

AXI4简要总结

这个协议写到这里其实要迎来一个“小结束“了,因为再介绍下去就是:

  1. 缓存结构的设计
  2. 和内存之间的交互
  3. 互联机制的设计
  4. ……

这些都需要对别的领域先进行一定的介绍,而前几篇下来我们已经可以利用AXI做好一个endpoint IP的设计了,这个系列就暂且放放了。

总的来说,我们主要介绍了AXI4的这么几个东西:

  1. AXI协议的通道和握手机制,并以此讲了AXI-Lite和代码解析:

  1. 介绍了AXI的burst机制和窄传输问题,并以此讲了AXI-FULL和代码解析:

  1. 介绍了用于高速数据流的AXI-Stream,在此基础上整了摄像头接入代码解析:

主线上的介绍其实就上面这些东西,希望大家能有较好的"入门"体验。

小结

大家好,鸽了许久,甚是想念!

《让我们来猜猜下一个系列会是什么》


如果你觉得有丶收获的话

也欢迎关注我的个人公众号,小何的芯像石头:

实现将AXI4协议数据转换为AXI-Stream协议数据的过程可以通过以下步骤进行: 1. AXI4协议数据格式(如地址、数据、控制信号等)与AXI-Stream协议数据格式(仅有数据信号)存在差异,在转换过程中需要对数据进行重新组织和调整。 2. 首先,从AXI4总线上接收到的数据包括地址信号、数据信号和控制信号。其中,地址信号指示要访问的AXI4设备的具体位置,数据信号包含要传输的实际数据,而控制信号则指示操作类型和传输方向。 3. 在数据转换模块中,需要将接收到的AXI4数据进行解析和分离。根据AXI4协议规范,地址信号和数据信号以及控制信号之间存在对应关系。通过解析控制信号,可以确定要进行的操作类型,如读取或写入。 4. 根据控制信号的类型(读取或写入),确定在AXI-Stream数据中要设置的有效位(Valid)标志。对于写入操作,需要将有效位设置为高电平,以指示有新的数据要传输。对于读取操作,有效位设置为低电平,以指示无新的数据传输。 5. 组织被选中的数据(根据控制信号的读取或写入操作类型),并以AXI-Stream协议的格式进行处理和编码。AXI-Stream协议仅包含数据信号,没有地址信号和控制信号。 6. 在AXI-Stream数据中,根据AXI4数据的信息,包含数据位(data)以及标志位(valid)。有效位标志(valid)在数据有效时设置为高电平,以表明数据位(data)是有效的。 7. 最后,将转换后的AXI-Stream数据发送到AXI-Stream总线上,以供其他支持该协议的设备使用。 通过以上步骤,可以将AXI4协议数据转换为AXI-Stream协议数据,实现不同协议之间的数据交互和传输。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小何的芯像石头

谢谢你嘞,建议用用我的链接

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值