本节主要讲述了一种对数据以行为单位的编码方法。该方法采用摄像头采集数据后经由 FPGA 的 RGMII 接口通过 UDP 协议实现以太网图像传输。以该方法进行 UDP 协议下的以太网图像传输,可以有效缓解 UDP 协议的差错控制缺陷带来的传输质量不佳问题。
提示:任何文章不要过度深思!万事万物都经不起审视,因为世上没有同样的成长环境,也没有同样的认知水平,更「没有适用于所有人的解决方案」 ;不要急着评判文章列出的观点,只需代入其中,适度审视一番自己即可,能「跳脱出来从外人的角度看看现在的自己处在什么样的阶段」才不为俗人 。怎么想、怎么做,全在乎自己「不断实践中寻找适合自己的大道」
我们通过以太网进行数据传输时,通常对于一些对数据正确性要求较低
(允许少量丢失)但是不能有较大时延的场景,都会使用 UDP 协议。UDP 协议是传输层的一种协议,该协议具有以下特点:
正因为 UDP 协议有如上种种优点,所以可以对 UDP 协议图像传输的策略进行改进,而降低干扰的影响后,UDP 协议仍然可以作为图像传输的一种优质
方案。
我们前面说过:以太网图像数据的传输通常采用 UDP 协议,图像数据在传输时一旦受到外界干扰发生数据丢失,而数据的丢失会导致图像发生断层,割裂,压缩等现象。
正因为如此,我们可以进行如下有针对性的改进后,仍保留使用 UDP 协议:如果我们对图像数据进行处理,将摄像头采集到的图像数据按照一定的编号方式例如以行为单位编号后,再通过 UDP 协议经由以太网传输到电脑,电脑接收FPGA 发送的图像数据解析后按照编号将相应的图像内容绘制到电脑显示屏的对应位置上,就能有效解决该问题。
经过该种编码方法改进,当数据在通过 UDP 协议传输的时候,理论上即使发生了少量数据丢失也不会出现断层割裂等效果。而对于图像传输显示这类场景,对于图像数据的准确性要求较低,即使一幅图像中有一两行数据的丢失,只要不是每幅图像都有该丢失情况,在每秒几十上百帧的刷新率下,其影响也极小。为了让上述理论能够更加加通俗易懂,我们结合图形,来对该理论进行讲解。
本次设计原理如图所示:
左边第一张为图像的写入过程,图像数据从左至右被依次写入。
第二张图为正常写入后所应展现出的画面,假设被标绿线的行在传输过程中丢失了,在未对行号进行编码的情况下,将会得到第三张图中被压缩的结果,而后续如果仍有图像传输过来,甚至可能出现两张图像重叠的情况,会影响后续图像数据的显示效果。
如果我们对每行图像数据进行编号,即使数据在传输过程中有部分行的数据丢失了,但因为序号的存在,它们仍会排列在自己所应处的位置。
举例来说:上图中,假设绿色行发生丢失,数据在显示屏上的显示画面如第四张图,被丢失的行由于没有数据,会显示黑色,即使数据丢失,图像也不会发生压缩等现象,只会在当前帧有影响,不会影响后续帧的图像。在每秒几十帧的刷新率下,一两行数据的丢失对人眼而言甚至无法识别到,或者只是看到黑线一闪而过。
在理解了本次设计最终目的的实现原理后,接下来可以开始进行工程的设
计。
我们可以结合前面开发的内容,作如下设计。本次本次板级验证我们将在开发板上结合前面章节学习过的以太网传图工程对设计模块进行验证。
结合板级验证的硬件搭建环境,本章节的原理作如下对应与深化讲解:
以上处顶层模块与Camera_ETH_Formator模块外其他模块均在相关文章中讲述,可以参考我的相关文章。
根据前面介绍的设计思想,本次模块设计的目的是实现对图像数据以行为单位进行编号。如果实现数据以行为单位编号,就需要知道当前输入的数据位
于每帧图像数据的哪一行。对此,我们可以通过计数行场同步信号实现。
模块 Camera_ETH_Formator 在整个系统内,可以起到防止在图像显示的过
程中由于某一行数据的丢失,导致的图像压缩断层现象发生的作用。在加入了该模块后,数据会按照其排列序号一行行进行排列,即使有一行或多行数据丢失,其余行数据也会排列在自己所应处的位置。
综合以上信息,设计模块 Camera_ETH_Formator 的结构如图 :
其中各个信号的含义如表所示:
当 HREF由低电平转为高电平时,DATA开始输入到图像数据编码模块,当
HREF 从高电平转为低电平时代表一行的数据输出完成,当模块中的数据处理完成后便会产生 wrreq 信号,并输出 8 位的 wrdata 数据。
我们以 1280*720 的显示屏为例,在摄像头将采集到的 RGB565 格式数据通过以太网发送给 PC 的显示屏显示的过程中,每一行有两倍 1280 个字节即 2560字节有效数据。依照前文我们介绍的设计思想:为了让部分数据即使在丢失的情况下其余行数据也能显示在自己应处的位置,我们可以在每一行的数据前加上 2 个字节的行号。也就是说,以太网每一帧,需要发送一行的数据外加两个字节的行号。
为了方便理解和设计,我们绘制了本次模块设计各个信号之间的时序图,如图图像编码模块时序图:
上图中:href_r1 和 href_r2 为对摄像头行同步 HREF 信号寄存后得到的信号,data_tmp 为 24 位的寄存器,用来完成对数据的移位转换。
如:时序图中 C0 时刻,当 HREF 出现上升沿时,代表数据开始输入。此时
我们可以用 HREF 与 href_r1 位拼接后的值表示,当{href_r1,HREF }的值为2’b01 时,HREF 的电平由低到高,数据开始输入;当{ href_r1,HREF }的值为2’b10 时,HREF 的电平由高到低,一行数据输入完毕,数据停止输入。
本次模块设计的目的是以行为单位,对数据进行编号,根据 HREF 的电平变化,我们可以利用计数器对行信号进行下降沿次数的累加生成行号,该部分代码实现如下:
//---------------------------------------
//VSYNC为高电平(有效)时,每当HREF1拉低时自加1,为记录行号
always@(posedge PCLK or negedge Rst_n)
if(!Rst_n)
Vcnt <= 0;
else if(!VSYNC)
Vcnt <= 0;
else if({
href_r1,HREF} == 2'b10)
Vcnt <= Vcnt + 1'd1;
//---------------------------------------
代码中:Vcnt 为行号计数器,每当 HREF 电平状态由高变低时,代表一行数据输出完毕,此时我们只需使计数器自加一即可,当VSYNC信号为低电平,即代表一幅图像数据输入完成,此时将计数器清零。完成了行号的产生,接下来就是将行号写入数据中。
如时序图中所示,C0 处检测到 HREF 信号的上升沿,由于该上升沿在时钟上升沿之后才到来,所以实质上该信号是在下一个时钟上升沿到来时才被采集到。该信号被采集后,随即将行号写入 data_tmp 寄存器中。当 2 字节的行号输出完成后,再开始输出图像数据,相应的代码如下:
//---------------------------------------
//对HREF进行计数,用于判断奇偶,对data_tmp进行数据拼接
reg [11:0]HREF_CNT;
always@(posedge PCLK or negedge Rst_n)
if(!Rst_n)
HREF_CNT <= 0;
else if({
href_r1,HREF} == 2'b01)
HREF_CNT <= HREF_CNT + 1;
else if(href_r1)
HREF_CNT <= HREF_CNT + 1;
else if(!href_r1)
HREF_CNT <= 0;
else
HREF_CNT <= HREF_CNT;
//---------------------------------------
//---------------------------------------
//HREF1上升沿时移位传输数据
always@(posedge PCLK or negedge Rst_n)
if(!Rst_n)
data_tmp <= 0;
else if({href_r1,HREF} == 2'b01)
data_tmp <= {
Vcnt[7:0],Vcnt[15:8],DATA};
else if(HREF_CNT[0] == 1)
data_tmp <= {
data_tmp[15:8],DATA,data_tmp[7:0]};
else if(HREF_CNT[0