今天给大侠带来基于FPGA的单目内窥镜定位系统设计,由于篇幅较长,分三篇。今天带来第二篇,中篇,话不多说,上货。
导读
随着现科技的发展和社会的进步,信息科技迅速发展,我们可从互联网、电台等媒体获取大量信息。现代信息的存储、处理和传输变得越来越数字化。在人们的日常生活中,常用的计算机、电视、音响系统、视频记录设备、远程通讯电子设备无一不采用电子系统、数字电路系统。因此,数字技术的应用越来越广泛。尤其在通信系统和视频系统中,数字系统尤为突出。而随着FPGA的出世,数字系统更加受到人们青睐,它为数字系统的设计提供更加便捷的通道,使得数字系统设计可以芯片小型化,电路规模大型化,庞大的逻辑资源,可满足各种数字系统设计。
随着社会的发展,科学技术已经应用于各个领域,尤其是医疗领域尤为突出。而在医疗领域中,心脏电信号模拟器手术辅助仪器发展迅速。为了训练经验少的医生熟悉心脏手术的操作过程,而专门开发心脏信号模拟仪器,让医生迅速掌握心脏手术操作过程,成为一个经验丰富心脏手术医生。
因此,本文将于FPGA平台,以图像处理结合信号采集原理,实现医生在做心脏模拟手术操作导管的过程中,不需要观察心脏内部情况,即可获取导管头在心脏内部信息的功能,采用内窥镜摄像头采集视频和并对导管头进行跟踪定位,信号采集技术可将采集到的导管头在心脏内部触碰区域的信号采集出来送到专业医用仪器,进行心脏3D建模。
本设计的实现对医院培养的经验少的医生尽快掌握心脏手术操作流程很有价值,未来将可以培养更多从事心脏手术工作的医学专业毕业的学生或刚刚从事这个行业的社会医生。
第二篇内容摘要:本篇还会介绍硬件设计,包括电源电路、FPGA外围电路、采集电路、缓冲电路、显示电路等相关内容,以及介绍软件设计,包括采集模块、缓冲模块、处理模块、解码模块、显示模块等相关内容。
四、硬件设计
硬件设计包括有电源电路、FPGA外围电路、采集电路、缓冲电路和显示电路。
4.1 电源电路
电路设计:使用接口连接电源并且附带串口输出,电源输出需要VCC(5V)、3.3V、2.8V、2.5V、1.2V。其中某些外设需要VCC、和3.3V供电,而3.3V、2.8V、2.5V、1.2V是FPGA芯片和其外围电路的供电以及摄像头电路和SDRAM电路。
设计如图4.1所示。
图4.1 电源电路原理图
4.2 FPGA外围电路
芯片选型:本设计电路使用Altera公司的clcone IV系列的EP4CE6F17C8型芯片。
电路设计:FPGA外围电路包括JTAG电路,EPCS电路和晶振电路等主要的电路。电路图如下,图4.2 JTAG电路,图4.3 EPCS电路,图4.4 晶振电路。
图4.2 JTAG电路原理图
图4.3 EPCS电路原理图
图4.4 晶振电路原理图
4.3 采集电路
电路设计:采集电路设计在设计时,将cmos_sclk和cmos_sdat上拉4.7k电阻即可,类似于I2C总线。设计如图4.5所示。
图4.5 摄像头采集电路原理图
4.4 缓冲电路
电路设计:按照官方设计存储器外围电路如图4.6所示。
图4.6 SDRAM电路原理图
4.5 显示电路
电路设计:VGA设计电路如图4.7所示。
图4.7 VGA电路原理图
五、软件设计
以下是对各个模块具体的设计和划分,整体设计如图5.1所示。
图5.1 软件模块设计
图5.1可分为5大块,采集模块(OV7670采集图像)、缓冲模块(SDRAM图像缓冲)、处理模块(乒乓输入、乒乓输出、帧差、二值图像投影并计算目标)、解码模块(YUV格式转RGB565格式)、显示模块(打印出坐标信息、驱动VGA)。详细设计在接下来的章节中一一讲解。
5.1 采集模块
5.1.1. 初始化SCCB(I2C)协议实现
SCCB 由OV公司生产,通过配置寄存器,来设置摄像头功能,从而达到采集数据的目的。通讯协议和I2C差不多,都是有一个时钟线和一个数据线,数据线是双向的,如图5.2所示为SCCB主机和从机电气连接图。SCCB协议的主机发出启动停止和数据信号,从机响应应答信号和非应答信号,主机在SCLK为高电平时,将SDAT从高拉低,这时触发启动信号,在SCLK为高电平时,将SDAT从低拉高,这时触发停止信号,至于发送数据信号,只有在启动信号和停止信号之间,SCLK为低电平时,SDAT才允许改变,但是在SCLK为高电平时,SDAT必须保持不变,换句话来说,SDAT只有在SCLK为低电平时才能改变。主机使用FPGA,从机为摄像头。每个从机都会有一个独一无二的地址,软件访问从机时,识别从机地址即可。根据厂家使用手册SCLK和SDAT需要接上拉电阻。
接下来,讲一下SCCB传输的基本格式,其传输格式与I2C基本上一样,如图5.3所示,总共写时序有三个部分。每一部分都传输特定的数据,第一部分由8bit组成,最低位是读写选择控制,高7bit由从唯一机地址组成,最后当从机接收到8bit数据后,会向主机反馈一个应答信号ACK。第二部分,由8bit数据组成,其为从机内部寄存器地址,最后当从机接收到8bit数据后,会向主机反馈一个应答信号ACK。第三部分,由8bit数据组成,其为从机内部寄存器数据,最后当从机接收到8bit数据后,会向主机反馈一个非应答信号NACK。
图5.2 SCCB电气连接
图5.3 SCCB时序图
通过ModelSim仿真可以得到相应的SCCB时序图,如图5.4所示。
图5.4 仿真时序图
结论:SCCB总线仿真时序图和厂家手册时序图一致,i2c_sdat为数据信号,ui2c_sclk为时钟信号。在时钟高电平时,数据从高拉低为起始信号,数据从低拉高为停止信号,在时钟低电平时,数据信号可以改变,而且可以收到应答信号,时钟为高电平时数据保持。
5.1.2. 像素数据捕获设计
在驱动摄像头时,摄像头输出时序是按照图5.5输出的,本设计按照摄像头产生的行有效信号HREF和捕获时钟PCLK对相应的数据进行捕获即可。
图5.5 摄像头输出时序图
5.2 缓冲模块
sdram控制器:动态随机访问存储器(Synchronous Dynamic Random Access Memory)价廉,容量大,但控制复杂。SDRAM以及随后的DDR2,DDR3成为当前数字系统主要的存储器器件,SDRAM器件电气接口如图5.6所示。
图5.6 SDRAM器件的端口图
然后介绍sdram控制器设计步骤以及相应时序图和仿真图。
5.2.1. 器件初始化:
1). 加载电源(VDD和VDDQ)
2). CKE设置为低(LVTTL逻辑低电平)
3). 加载稳定的时钟信号
4). 等待至少100us,此时的命令保持为INHIBIT或NOP
5). 在步骤4的100us中的某个时刻,将CKE设置为高,命令仍然保持为INHIBIT或NOP
6). 步骤4的100us结束后,即可发出一个全部Bank的预充电命令(PRECHARGE ALL)
7). 等待至少tRP(行预充电最小周期),此时命令保持为NOP或DESELECT
8). 发出一个自动刷新命令(AUTO REFRESH)
9). 等待至少tRFC(自动预充电周期),此时的命令仅允许是NOP或INHIBIT
10). 再发出一个自动刷新命令( AUTO REFRESH )
11). 再等待至少tRFC(自动预充电周期),此时的命令仅允许是NOP或INH
12). 使用LMR命令设置模式寄存器
13). 等待至少tMRD(LMR命令至激活或刷新命令的最小间隔),此时的命令仅允许是NOP或DESELECT
图5.7 sdram控制器初始化时序图
图5.8 sdram控制器初始化仿真时序图
结论:仿真如图5.8所示,达到厂家时序图5.7所示的指标,按照厂家时序步骤设计时序仿真图红色光标线标明。要注意的是在发出上电命令之前要发出NOP指令100us以上,设计100.0025us满足指标。
5.2.2. sdram刷新操作
SDRAM的刷新分为自动刷新(Auto Refresh)和自刷新(Self Refresh) ,前者由外部控制,必须定时给出刷新命令,后者在cke为低时SDRAM器件自己进行,无需外部干预。自动刷新(Auto Refresh)时,SDRAM内部的自动刷新计数器定时对所有Bank的行进行刷新。刷新期间所有操作要停止。自动刷新命令是由外部发出的(SDRAM控制器发出)。通常存储电容的充放电周期为64ms,8192行(13位行地址寻址范围)。以下是自动刷新步骤以及时序图如图5.9所示和仿真图如图5.10所示。
1). 所有Bank执行预充电(关闭所有Bank的行)
2). 等待至少tRP,期间的命令保持为INHIBIT或NOP
3). 执行Auto Refresh命令
4). 等待至少tRFC,期间不能有任何可执行命令,仅允许INHIBIT或NOP
5). 若要执行背靠背刷新,则执行下一个Auto Refresh
6). 若无背靠背(Back to back, 即A10=1执行预充电),则刷新结束,可以开始激活新的bank
7). 自动刷新周期保证每行(所有Bank)满足行刷新周期64ms,因此刷新周期=64ms/8192=7.813us
注意:对所有bank充电(如果使用突发中断指令,可以不用充电);第一次自动刷新(第一次刷新必须);第二次自动刷新(第二次刷新可选)。
图5.9 sdram控制器自动刷新时序图
图5.10 sdram控制器自动刷新仿真时序图
结论:按照厂家手册再刷新之前需要做充电操作,然后再做两次刷新操作,如果设置模式成页写突发中断模式,则不需要充电,只需要一次刷新即可。
5.2.3. sdram写操作
图5.12为写操作时序图,图5.13为写操作仿真图,以下是写操作步骤。
a. 发出激活指令,同时加载行地址,如图5.11所示;
b. 经过时间tRCD后,发出写指令,加载列地址和有效数据;
c. 数据突发。
图5.11 激活时序图
图5.12 写操作时序图
图5.13 写操作仿真图
结论:写操作之前一定要发出激活指令,同时加载行地址,才能发出写命令加载数据和行地址,延时参数和厂家手册指标一致。
5.2.4. sdram读操作
图5.14为读操作时序图,图5.15为读操作仿真图,以下是读操作步骤。
a. 发出激活指令,同时加载行地址,如图5.11所示;
b. 经过时间tRCD后,发出读指令,加载列地址;
c. 经过CL=3,3拍潜伏期之后可读出数据;
d. 数据突发。
图5.14 读操作时序图
图5.15 读操作仿真图
结论:读操作之前一定要发出激活指令,同时加载行地址,才能发出读命令加载行地址,最后得出数据,延时参数和厂家手册指标一致。
为了便于图像的实时缓冲,在sdram控制器两端专门设计了fifo端点,以适应不同时钟域数据的缓冲,详细设计如下。
二端点缓冲:sdram控制器两端接有两个异步fifo(一个写fifo和一个读fifo),用户可对一个写fifo和一个读fifo同时进行操作,而且sdram控制器是页写突发。
图5.16 二端点缓冲仿真图
四端点缓冲:sdram控制器两端接有两个异步fifo(两个写fifo和两个读fifo),用户可对两个写fifo和两个读fifo同时进行操作,而且sdram控制器是页写突发。
图5.17 四端点缓冲仿真图
结论:二端点缓冲要求在任意时刻一端口写入一帧数据,另一端口在任意时刻能无损的读出写入的图像,图5.18红色光标线标明设计满足要求;四端点缓冲要求在任意时刻写1端口写入一帧数据,读1端口在任意时刻能无损的读出写入的图像,在任意时刻写2端口写入一帧数据,读2端口在任意时刻能无损的读出写入的图像,图5.17红色光标线标明设计满足要求;根据本文设计要求写入一端乒乓写入一帧图像,另一端同时同步读出相邻两帧图像数据,则需要做3端口访问,四端点缓冲刚好满足需求。
5.3 处理模块
处理模块总共包括三个处理模块,乒乓输入、帧差且乒乓输出、投影直方图和目标定位模块。
乒乓操作:包括乒乓输入和乒乓输出,在关键问题解决方法中已经详细讲述其原理,在这里讲述设计实现方法及需要注意的问题。
1). 通过sdram缓冲模块输出的完成信号,在状态机的控制下完成乒乓输入切换和输出切换。
2). 注意切换标志信号不能使用输入模块(摄像头采集模块)或输出模块(VGA显示模块)的完成信号,否则会造成sdram缓冲模块数据未完全缓冲完毕,从而丢失数据。
帧差:在本设计中,通过乒乓操作使我采集到的相邻的两帧图像同时输出,两帧图像相减得到的值,到底是前一帧减去后一帧还是后一帧减去前一帧,理论上来说都可以,如果使用两帧相减的绝对值来输出,不管是谁减谁都无所谓了。
投影直方图和目标定位:二值投影分为水平方向的投影和垂直方向的投影,水平方向投影就是把x轴方向各个地址所对的数据加在一块,然后存储到内存里面,垂直方向投影就是把y轴方向各个地址所对的数据加在一块,然后存储到内存里面。最终存储起来就得到二值图像的投影。使用状态机检测输入数据是否为1来进行直方图计数并写入ram中。同关键问题解决方法一节中,通过硬件描述语言设计出来,得到相应目标坐标。
5.4 解码模块
摄像头配置模式为YUV(4:2:2)模式,通过摄像头采集到的YUV格式需要转换成RGB格式才能在VGA上输出。在格式转换中,需要把YUV422转成YUV444,再把YUV444转成RGB888,最后把RGB888转成RGB565,其中YUV444转成RGB888采用查找表的方式。下面详细说明一下转换方法。
5.4.1. YUV422转成YUV444,标准的视频的YCbCr信号,以Cb0 Y0 Cr0 Y1 Cb1 Y2 Cr1 Y3...,通过合并8bit到16bit(为了存储,16bit)后,数据变成了{Cb0 Y0}{Cr0 Y1}{Cb1 Y2}{Cr1 Y3}...,为了保持数据的同步,同时又不能丢失任何一个byte,重新组合出一幅完整的YCbCr图像,我们将所谓的YUV422转成YUV444,即每一个像素都有完整的亮度色差,但是这需要几级寄存来完成。如此,既保证了数据的同步,不至于色差错位,同时又有效的拼接了数据,有利于保存。以下是捕获步骤。
1). 捕获Cb0 Y0
2). 捕获Cr0 Y1
3). 捕获Cb1 Y2,输出Y0Cb0Cr0
4). 捕获Cr1 Y3,输出Y1Cb0Cr0
5.4.2. YUV444转成RGB888,关于这个转换有特定的公式,如下:
R=1.164(Y-16) 1.596(Cr-128)
G=1.164(Y-16)- 0.813(Cr-128)- 0.391(Cb-128)
B=1.164(Y-16) 2.018(Cb-128)
如果使用c语言方式设计,它支持浮点运算,非常易于实现。但是FPGA中仅仅只有逻辑低和逻辑高,那就需要另想办法设计了,好在上述的一些小数我们可以量化之后再通过一位就可以实现,这样就不需要涉及到小数运算和乘法运算问题了。具体设计如以下步骤。
1). 首先,分离变量,将公式化简
R=1.164Y 1.596Cr-222.912
G=1.164Y- 0.813Cr- 0.391Cb 135.488
B=1.164Y 2.018Cb-276.928
2). 然后进行放大,加上移位,去掉浮点
XOUT[19:0]=((Y*10’d596) (Cr*10’d817)-18’d114131)>>9
YOUT[19:0]=((Y*10’d596)- (Cb*10’d200)- (Cr*10’d416)-18’d69370)>>9
ZOUT[19:0]=((Y*10’d596) (Cb*10’d1033)-18’d141787)>>9
3). 乘法器出现溢出,我需要截断正负溢出部分,使得数据保持在0~255范围内。如下:
R=XOUT[10] ? 8’h0:(XOUT[8:0] > 9’d255) ? 8’hff:XOUT[7:0];
G=YOUT[10] ? 8’h0:(YOUT[8:0] > 9’d255) ? 8’hff:YOUT[7:0];
B=ZOUT[10] ? 8’h0:(ZOUT[8:0] > 9’d255) ? 8’hff:ZOUT[7:0];
4). 最后由于硬件原因,需要将RGB888转换成成RGB565,这一步仅仅只需要做截断操作即可。
5.5 显示模块
显示模块分为两大部分,第一部分为字符打印模块,在已有图像的基础上打印出要写的字符或图标;第二部分为VGA驱动模块,驱动硬件设备。下面具体设计如下。
字符打印模块:在VGA显示图像的基础上,在画面上打印出一串字符,并且可以控制其位置、内容任意改变。设计结构如图5.18所示。其原理是根据输入图像的地址矩阵构成字符或者图标,在对应的地址上将原始像素数据替换成特定的值,这个就可以在不影响原始图像的基础上打印出想要的字符或者图标。
图5.18 字符模块设计图
VGA驱动模块:标准的VGA接口有15个接口,但是真正用到的只有5个接口,分别是三个色彩信号,R,G,B,场同步信号VSYNC,行同步信号HSYNC,时序部分要通过控制行同步信号和场同步信号,色彩部分要控制RGB,先来看时序部分。对于一个分辨率为800*600的显示器,简单的说像素的刷新是从左到右,从上到下一行一行的刷新的,每一行要刷新的点成为行同步信号的帧长,有多少行称为场同步信号的帧长,从上到下刷新完一遍称为一帧,我们电脑上说的屏幕刷新频率就是说屏幕一秒钟能够刷新多少帧,当达到一定的帧数,我们的肉眼也就分辨不出来了,这样我们就看到我们的电脑屏幕,我们在操作的时候是连续的了。
5.5.1. 水平时序
水平同步信号HSYNC如图5.19所示,HSYNC使用一个负同步脉冲表示一行像素的开始时刻,到下一个负脉冲出现为一行像素的结束时刻。实际的一行有效图像数据是在25.422us的时间窗口内发送的,而水平同步信号之间的间隔是31.77us。没有图像数据发送的这段时间定义为消隐区,此时的图像为黑色。如果有25.422us的时间段来输出一行有效图像数据,做一些计算如下,640*480的VGA显示模式下,待填充的640个像素需要在25.422us内发送给显示器。即每个像素的时间为 25.422us/640 = 39.71875ns。可以算得最小时间单位是 25.175MHZ,这个即驱动VGA时FPGA所需要的时钟频率。
5.5.2. 垂直时序
垂直同步信号VSYNC如图20所示,VSYNC与水平同步信号相似,只不过其同步负脉冲表示整个一帧图像的开始和结束。一帧图像的有效图像数据是在15.25ms的时间窗口内发送的,而同步信号之间的间隔是16.68ms。同理,如果有15.25ms的时间段来输出一帧有效图像数据,做计算如下,640*480的VGA显示模式下15.25ms/480 = 0.031ms。可以算得完成填充一行640个有效像素数据的时间为0.031ms,即每一行的频率为31.46875Khz,显示像素数据或电子束退回到行首开始新的水平扫描时,RGB信号需要置为黑色,即全为零。
图5.19 VGA行数据时序
注:a (行消隐) , b(行消隐后沿),c(行显示),d(行消隐前沿),E(行时序总长度)
图5.20 VGA场数据时序
注:a (场消隐) , b(场消隐后沿),c(场显示),d(场消隐前沿),E(场时序总长度)
图5.21 VGA行数据仿真图
图5.22 VGA场数据仿真图
不同的分辨率下,行同步和场同步信号的周期是不同的,时序上的时间也不一样。附录2列出了VGA的常用分辨率参数。
结论:图5.21设计为行时序满足VGA设计行时序,图5.22设计为场时序满足VGA设计场时序。
本篇到此结束,下一篇带来基于FPGA的单目内窥镜定位系统设计(下),会介绍系统调试与测试以及结论,包括系统资源性能调试与分析、系统功能测试等相关内容,还会有VGA的常用分辨率参数表、整体电路图、主要程序分享等附录。
END
后续会持续更新,带来Vivado、 ISE、Quartus II 、candence等安装相关设计教程,学习资源、项目资源、好文推荐等,希望大侠持续关注。
大侠们,江湖偌大,继续闯荡,愿一切安好,有缘再见!