基于Nios平台的光信号采集片上系统设计
同时,SOPC Builder自动产生一些必需的仲裁逻辑来协调系统中以上各个部件的工作,我们将系统的工作频率设为33MHz。定制完片上系统的硬件后,SOPC Builder还为编写操作这些片上硬件的软件代码提供了一个软件开发环境,这个软件环境包括语言头文件、外围接口的驱动以及实时操作系统的内核,极大地方便了软件的开发。
5 系统实现
以下分两部分来分析和介绍:①在ApexEP20K FPGA中,使用Verilog编写时钟和控制信号发生器用于驱动CCD和ADC,并且协调两者的工作;②使用C语言编写程序,通过SOPC Builder配置的SPI接口读取ADC输出的数据。
5.1 时钟和控制信号发生器
使用Verilog编写时钟和控制信号发生器,用于产生驱动CCD和ADC的时钟和控制信号。时钟发生器的工作原理是:使用频率为33MHz的系统时钟,作为时钟发生器的输入和同步售,用于产生所需的CCD和ADC驱动的时钟和控制信号。根据系统的要求和CCD以及ADC芯片特性,将产生的CCD时钟频率设为1MHz;同时把ADC的时钟频率设为33MHz。在时钟发生器中,还需对产生CCD和ADC两个高速设备的时钟和控制信号进行匹配,使得两者能够正常地工作。
现在详细地分析这两个高速设备如何完成时序的匹配。由于系统中的CCD和ADC都是依靠外加时钟同步的高速设备,因此,这两个设备之间的时序的匹配对于能否获取正确有效的数据来说至关重要。为了使两个设备协同工作,首先要分析每个设备所需的外加时钟和控制两个外加信号,分别是CCD_ROG和CCD_CLK。CCD_ROG信号使得CCD的输出数据有效,也就是每次从CCD读取数据时,都要先给CCD_ROG一个低电平,将CCD置光电转换后的数据一位位地输出。ADC进行模数转换也需要两个外加信号,分别是ADC_CONV和ADC_CLK。ADC_CONV信号使ADC芯片开始进行模数转换,每次进行转换前都要给ADC_CONV一个高电平;同时,转换过程和转换后的结果输出在ADC_CLK信号的同步完成。
由于需要先从CCD光电转换器读出模拟数据,所以,要通过CCD_ROG给CCD一个长度为t1(t1=4000ns)的低电平。在CCD_ROG重新变为高电平后,CCD就在CCD_CLK信号的同步下输出数据了,在每个CCD_CLK作用下输出一个模拟量数据。CCD每次输出的2087个模拟量分别由33个首部伪数据字段、2048个有效数据和6个尾部伪数据字段组成。其中的2048个有效数据和首部伪数据字段的后20个数据就是我们希望得到的,所以从第14个数据到第2081个数据中的每个模拟量,都通过ADC_CONV(ADC_CONV的高电平宽度为4ns),给出一个高电平启动ADC;同时,在ADC_CLK的作用下,完成模数转换过程和数字量输出。图4、图5是时钟和控制信号发生器的程序流程和仿真时序图。
javascript:window.open(this.src);" style="cursor:pointer;"/>
ADC将模拟信号转换成数字信号后,Nios通过SPI接口读入这些信号并进行相应的处理。我们通过Quartus II中的SOPC Builder为Nios核配置SPI接口。在我们的系统中,将SPI配置为从设备。软件通过访问存储器中映射的5个16位的寄存器来控制和读写SPI接口。读入的数据通过MOSI引脚逐位进入移位寄存器。通过移位寄存器的移位和缓冲后,一帧数据进入寄存器rxdata,同时将状态寄存器的rrdy位置1,通过访问rxdata就得到一帧数据。数据被读取后,rrdy位自动置回0。如果前一帧数据还未从rxdata读取,后一帧数据就会将原数据覆盖,造成错误,同时将状态寄存器的ROE(Read Overwrite Error)位置成1。SPI接口共有4个引脚,分别是MISO(Master Input Slave Output)、MOSI(Master Output Slave Input)、SCLK(同步时钟)和SS_n。当SS_n为低电平时,从设备可以在SCLK同步作用下读入数据。系统中的SPI接口是从设备,所以只使用MOSI、SCLK和SS_n三根引脚。图6是Nios中SPI与ADC的接口示意图。
从ADS的芯片特性可知,当ADC_CONV在一个高电平的作用下,ADC开始进行模数转换。ADC_CONV回复到电平后,因为SS_n和ADC_CONV连在一起,所以Nios中的SPI就处于可以读入数据的状态了;同时,在ADC_SCK的作用下ADC输出数据,而SPI也在相同的时钟SCLK的作用下,通过MOSI读入数据。为了能够准确得到数据,还要将SPI寄存器rxdata的位数设为13位。软件中,我们将通过等待SPI寄存器的rrdy位的置位,来读取rxdata中的数据,与此同时寄存器中roe的状态决定此帧数据的读取过程中是否存在数据溢出现象。以下是相关的读取数据的软件代码。
do{
//读一行CCD数据
for(i=0;i<2069;i++){
//等待,直到准备好
while(spi->np_spistatus&np_spistatus_rrdy_mask)==0)
;
//从SPI数据寄存器读数据
c=spi->np_spirxdata;
}
//读覆盖状态
b=spi->np_spistatus&np_spistatus_roe_mask;
}while(b==8);
结论
本系统经过仿真测试,其功能达到了设计要求,并用HP逻辑分析仪验证了系统功能。