| **银杏科技有限公司旗下技术文档发布平台** ||||
|技术支持电话|**0379-69926675-801**|||
|技术支持邮件|Gingko@vip.163.com|||
^ 版本 ^ 日期 ^ 作者 ^ 修改内容 ^
| V1.0 | 2020-01-14 | gingko | 初次建立 |
===== 实验三十三: =====
===== 基于ARM+FPGA的高速AD采集传输实验(AD9226) =====
==== 一、实验目的与意义 ====
- 了解AD9226芯片工作原理和驱动方式。
- 掌握FPGA驱动AD9226芯片并采集转换数据的方法。
- 学习ARM和FPGA通过FSMC实现数据传输的思想。
==== 二、实验设备及平台 ====
- iCore3 双核心板( FPGA型号为EP4CE10F17,ARM型号为STM32F407IGT6)。[[https://item.taobao.com/item.htm?spm=a1z10.5-c.w4002-251734908.16.351d704dx6vdgW&id=524229438677|点击购买]]
- 高速AD转换模块ADM9226。[[https://item.taobao.com/item.htm?spm=a1z10.5-c.w4002-251734908.34.4113769ffqyiV5&id=555671202016|点击购买]]
- Blaster(或相同功能的)仿真器和USB线缆。[[https://item.taobao.com/item.htm?id=554869837940|点击购买]]
- QuartusII开发软件(本实验中使用的是13.1版本)和commix.exe。
{{ :icore3:icore3_fpga_33_1.png?direct&700 |图33-1 核心板和ADM9226模块连接图}}
**注意事项1:** 注意FPC转接板和核心板之间引脚要对齐(如图31-1中红圈中细节图所示,转接板和核心板排针连接处下边缘要对齐)。\\
**注意事项2:** 下载程序前请确认iCore3核心板引脚与PIN.tcl文件中绑定引脚相互对应。
==== 三、实验原理 ====
* 本实验基于ARM+FPGA的双核心系统。实验目的可以分为两个,一是FPGA将AD9226芯片转换后的数字信号采集并存储到内部RAM存储器。二是 ARM读取FPGA内部RAM中的数据,并上传至PC。
* ADM9226模块是一款双通道高速AD采样模块,采用了两片12位精度、65Msps的高速AD转换芯片AD9226。关于AD9226芯片的相关细节,建议大家仔细查阅芯片手册。阅读过手册可以看到如下的数据采样时序图。也就是只需为AD9226提供时钟信号,便可在芯片的数据输出引脚得到二进制的转换数据,驱动较为方便。
{{ :icore3:icore3_fpga_33_2.png?direct |图33-2 ADM9226 采样时序图}}
* iCore 3开发板是ARM+FPGA架构。FPGA采用的cyclone IV 系列,负责AD芯片的驱动和数据的存储。FPGA调用IP核在内部构建两个存储深度为1024的RAM作为数据缓存,且输出时钟信号驱动两路AD9226对模拟信号进行采样。在接收到STM32F407发送的“写”指令后将采样数据分别存储在两个RAM中。ARM采用的是STM32F407IGT6,一款基于Cortex-M4内核的高性能微控制器,具有丰富的外设。STM32F407芯片将FPGA内RAM作为外挂存储器,通过FSMC分别对两个RAM里的值进行读取和指令的传输,然后通过UART将从RAM中读取的数据上传至PC。
* 系统框图如下图所示:
{{ :icore3:icore3_fpga_33_3.png?direct |图33-3 高速AD采样系统框图}}
* STM32的FSMC以及和PC通信的UART可以通过STM32CubeMX进行配置,包括引脚、时钟、电压的配置。
* 这里主要讲一下FPGA部分。
* AD9226是由FPGA驱动的,其时钟引脚和数据输出引脚是连接到FPGA的。FPGA的外部时钟信号是25MHz。AD9226的采样时钟信号可高达65MHz。本实验中FPGA调用PLL核输出60MHz的时钟信号,ADM9226在此时钟信号的驱动下对输入的模拟信号进行采样,并将采样结果以12位二进制的形式,通过数据输出端口并行输出。
* FPGA在接收到STM32通过FSMC发送的“写”命令后,使能片内RAM写使能信号,此时FPGA将两路AD9226转换的数据同时分别写入对应的两个RAM中。当RAM存储满,FPGA会停止向RAM内写入数据,并发送一个信号给STM32芯片。当STM32芯片接收到FPGA发送的满标志位,通过FSMC向FPGA发送“读”命令,FPGA接收到“读”命令,则控制RAM1和RAM2的读使能信号先后有效,按顺序分别读取RAM1和RAM2内存储的数据。当RAM中数据全部读取完毕,则FPGA会等待下一次写信号的到来。
* 这里采用RAM可以很好的解决跨时钟域问题。即STM32读取RAM中数据的速率和AD9226转换数据的速率是不同的,采用RAM作为数据缓存,可以避免由于存取速率不同导致的数据存取冲突,又避免了复杂的时序控制。
* FPGA和STM32之间数据传输是通过FSMC实现的。那么,FPGA内部就要定义和FSMC对应的接口信号,并对接收信号进行解析。FPGA和ARM之间指令传输则是通过对寄存器内容的读写实现的。
==== 四、代码讲解 ====
* 本实验是基于ARM+FPGA系统的,因此在代码的实现上也包括ARM程序和FPGA程序,ARM程序主要是对串口接收数据的处理以及指令的传输。详细的代码讲解请参考对应的ARM例程,这里主要讲解一下FPGA的代码实现。
=== FPGA代码讲解 ===
{{ :icore3:icore3_fpga_33_4.png?direct |图33-4 FPGA代码RTL视图}}
* 首先看一下FPGA综合的RTL视图,从图中可以看到,主要功能模块有三个,分别是fsmc_ctrl模块和ad9226_store模块。其中fsmc_ctrl模块负责和ARM通信, ad9226_store则负责采样数据的存储。
* 这里主要讲解一下ad9226_store文件和fsmc_ctrl文件。先看一下fsmc_ctrl文件,这个文件中主要是对fsmc接口信号的处理以及对ARM发送的指令进行解析。因为ARM的fsmc外设是连接到FPGA内的RAM上的,所以这里FPGA将fsmc接口和RAM的相关信号建立连接。
* 首先是读写使能信号的提取,代码如下:
//wr和rd信号提取
wire rdn = fsmc_cs | fsmc_rd;
wire wrn = fsmc_cs | fsmc_wr;
* 这个读写操作是对包括对寄存器进行读写的,即fsmc对寄存器和ram的读写都是通过这两个信号控制的,所以在fsmc_cs有效,或者fsmc对ram的读写信号有效期间,相对于FPGA来说,都应该是有效信号,所以这里使用的是或操作。
//寄存器地址分配:0-50为通用控制寄存器;51——100为ad9226相关寄存器;
//接收地址56和57是两个
reg [23:0]address_reg;
always@(posedge fsmc_nadv or negedge rst_n)
begin
if(!rst_n)
begin
address_reg <= 24'd0;
end
else
begin
address_reg <= {fsmc_ab,fsmc_db};
end
end
* 接下来这段代码则是将fsmc传输进FPGA的数据和地址拼接在一起然后存储进相应的寄存器。因为本实验中是通过复用fsmc的方式传输数据和地址的,因此将fsmc_ab和fsmc_db拼接后存储到address_reg中,并根据address_reg的值判断指令。这段代码则是根据寄存器内的值,判断是否有采样开始信号。当寄存器值为1时,表示采样开始,FPGA拉高sample_start。
/****************************************************************/
//0——50为通用寄存器;
//0:命令复位寄存器;1:开始采样寄存器;
reg sample_start_r;
always@(posedge wrn or negedge rst_n)
begin
if(!rst_n)
begin
sample_start_r <= 1'b0;
end
else
begin
case(address_reg)
24'd0:begin
sample_start_r <= 1'b0;
end
24'd1:begin//开始采样信号
sample_start_r <= 1'b1;
end
default:begin
sample_start_r <= 1'b0;
end
endcase;
end
end
assign sample_start = sample_start_r;
* 这里可以发现,寄存器内读取值跟串口发送给ARM的值,是一一对应的。这段代码中的address_reg的值只要跟串口发送给ARM的值相对应,设置为任意数值都可以。
* 再来看一下ad9226_store文件的代码。这里调用了两个1024深度的ram IP核,用于存储AD9226的转换数据。下面这两段代码则通过提取采样开始信号的上升沿和读取开始信号的上升沿,分别控制RAM开始存储数据和开始从RAM读取数据。
/****************************************************************/
//提取开始采样信号的上升沿
reg sample_start_r1,sample_start_r2,sample_start_r3;
always@(posedge ad9226_clk or negedge rst_n)
begin
if(!rst_n)
begin
sample_start_r1 <= 1'd0;
sample_start_r2 <= 1'd0;
sample_start_r3 <= 1'd0;
end
else
begin
sample_start_r1 <= sample_start;
sample_start_r2 <= sample_start_r1;
sample_start_r3 <= sample_start_r2;
end
end
wire sample_up = (!sample_start_r3) & sample_start_r2;
/****************************************************************/
//提取读取开始信号的上升沿ad9226_read_start
reg read_start_r1,read_start_r2,read_start_r3;
always@(posedge ad9226_clk or negedge rst_n)
begin
if(!rst_n)
begin
read_start_r1 <= 1'd0;
read_start_r2 <= 1'd0;
read_start_r3 <= 1'd0;
end
else
begin
read_start_r1 <= ad9226_read_start;
read_start_r2 <= read_start_r1;
read_start_r3 <= read_start_r2;
end
end
wire read_up = (!read_start_r3) & read_start_r2;
* 在ad9226_store文件中,有两个细节需要注意。因为ADM9226模块是双通道的,FPGA驱动的时候,两个通道给的是同样的采样时钟,因此,这里只用了一个RAM写满标志位。而ARM从ram中读取数据的时候,则需要分别读取两个ram中的数据。所以读取ram中数据的时候,通过先后控制两个ram的读信号使能,分别读取两个ram中的数据。
* AD模块的代码部分还有个地方是需要注意的,即AD芯片的驱动时钟和AD数据的采样时钟。AD9226的驱动时钟在本实验中是FPGA输出的65MHz的时钟信号,用于驱动AD9226对模拟信号采样。而AD数据的采样时钟是控制ram写的时钟,即AD芯片将数据输入FPGA后,通过采样时钟,将数据有选择的输入ram内,并不是写使能期间所有的转换数据都存入RAM内。这里两者之间的区别要深刻理解。
==== 五、操作流程和实验结果 ====
- 连接iCore3核心板和ADM9226模块,确认连接正确后连接仿真器和USB线。
- 在ADM9226的输入通道接入模拟信号(正负5伏范围)。
- 打开PC端串口软件,并配置好串口参数,注意此处参数要跟STM32CubeMX设置UART时的参数相互对应上。
- 编译文件,无报错后给核心板上电,并下载程序到核心板的ARM芯片和FPGA芯片。
- 在串口软件发送区输入“set:1\CR\LF”字符,并点击发送,可以看到接收区返回的指令以及采样数据,如下图红框所示:
{{ :icore3:icore3_fpga_33_5.png?direct |图33-5 串口发送指令及数据接收效果图}}
==== 六、拓展实验 ====
- 改变ADM9226的采样率。
- 实现双通道的独立读写控制。