1 介绍
本文将介绍如何使用IP核控制DE0 nano上的ADC控制器。阅读本文的前提是假设读者熟悉C,verilog语言,Quartus ii,Qsys 软件。
*NIOS II 是用HDL实现的处理器
*Qsys 是一个系统集成工具,可以很智能的进行IP组件的互联的软件,相当于把不同的器件自动连接起来的软件。
/products/software/quartus-ii/subscription-edition/qsys/#Increase_Interconnect_Performance
内容
。背景知识
。ADC控制器
。用Qsys和NIOS ii 实现ADC控制器
。用HAL实现ADC 控制器
。Implementing the ADC Controller with MegaWizard Plug-In Manager
2 背景知识
板载ADC128S002 ,8通道,12位精度
2。1 ADC
2.2 ADC 时序
SCLK 频率为0.8 到 3.2 MHZ
2.3 相关电路
3 FPGA 实现的ADC控制器
ADC控制器,可以脱离软件独立运行,也可以通过软件控制,ADC控制器轮流采集每个通道。这个ADC控制器在实例化前还可以配置输入通道的个数,NUM_CH。还可以设置采样频率。
3.1 用Qsys Tool 实现ADC控制器
3.1.1 可以软件控制的ADC控制器核
实现一个ADC控制器可以通过内部的处理器访问的,就像对单片机内部外设的访问控制一样,自己设计的ADC控制器可以做位一个Qsys部件(就像一个器件)加入到库中,然后和Nios II 处理器内核连接使用。ADC控制器提供下面控制寄存器。
如果某个通道没有使用,那么读取时候返回0. 向update register 写入数据启动一次AD转换,当所有转换结束就可以读取转换结果了。如果试图读取一个正在转换的通道,那么ADC控制器会通过wait_request 信号上升沿停止处理器运行,直到AD转换结束。
向auto-update 写入1 使能自动转换,写0停止自动转换。这个时候用户需要自己判断数据是否是最新数据。
3.1.2 实现ADC核
为了演示怎么使用ADC核,我们将使用Qsys工具实现一个系统。这个系统包括处理器,通过软件控制ADC转换,并显示在LED0-LED7上。
a.使用Quartus II 建立一个工程名为 adc_demo ,顶层模块也叫adc_demo。选择器件 Cyclone iv EP4CE22F17C6 ,到此完成工程的建立。
b.打开Qsys tool。 系统主要包括4个组成部分,或者说4个主要元件或器件组成,反正就是这个意思。ADC控制器,NIOS ii 控制器,片上memory
LEDs。
c. 从元件表中找到Embedded processors列表,然后选择Nios II Processor。 选择Nios II/e 作为处理器类型,然后添加到系统中。从新命名这个模块为cpu,然后连接上时钟和复位信号。
d. 从Memory and Memory Controller > On-Chip componet 列表,然后选择On-Chip Memory(RAM or ROM) ,添加到系统中。连接时钟和复位信号,分别连接memory到NIOS II 的数据和指令总线上(_master sources )。从新命名为onchip_mem. 编辑处理器的复位和异常向量到指定的内存上。
e. 使用并口元件连接片外的LEDS. 选择 University Program > Generic IO 然后选择Parallel Port component。Select DE0-Nano as the board type and LEDs as the I/O device。从新命名为LEDs. 连接时钟和复位信号。the Nios II data_master, and export the conduit
as leds.
f. 最后加入ADC控制器,选择selecting University Program > DE0-Nano ADC Controller。设置2 作为通道数量,选择完成。命名为ADC.连接时钟,复位,adc_slave signals to the clock source, clock reset and data_master sources, and export the external_interface signal as adc.
g. 为系统内部的不同部分分配地址。System > Assign Base system should match the one presented in Figure 7. 记住系统为LEDs ADC分配的地址,后面会用, 保存系统为nios_system .
h. 生成系统后,需要产生一个顶层模块为系统(前面是只设计了一个简单的类似单片机的原理,并选择了在什么FPGA中实现,但是引脚怎么分配还没实现,是不是要在这个地方实现呢,顶层模块就相当与把上面设计的单片机封装到一个FPGA中,最后成为一个固定的产品呢?!,前面是抽象,这里是实例,前面是类,现在是类实现的对象?!),产生Verilog文件然后把下面的代码拷贝进来。
module adc_demo (CLOCK_50, KEY, LED, ADC_SCLK,
ADC_CS_N, ADC_SDAT, ADC_SADDR);
input CLOCK_50;
input [0:0] KEY;
output [7:0] LED;
input ADC_SDAT;
output ADC_SCLK, ADC_CS_N, ADC_SADDR;
nios_system NIOS (
.clk_clk (CLOCK_50),
.reset_reset_n (KEY[0]),
.leds_export (LED),
.adc_sclk (ADC_SCLK),
.adc_cs_n (ADC_CS_N),
.adc_dout (ADC_SDAT),
.adc_din (ADC_SADDR)
);
endmodule
保存文件为adc_system.v 添加这个顶层文件和synthesis/nios_system.qip文件到工程列表。导入DE0-Nano pin assignment表 编译工程。(估计这个是和上面的.v文件配合实现了实例化过程,引脚的分配)。然后产生了比特流,也就是在FPGA上实现的系统。
转换结果的高8位会显示在leds 上。
i. 使用Altera Monitor Program 下载系统(比特流)和c 程序到FPGA中。使用自定义系统(也就是上面的系统,估计会包含内存大小,外设地址等信息)新建工程,使用Qsys产生的.sopcinfo 和quartus产生的 .sof 文件。 然后选着c作为编程语言。包含相关头文件。其他默认,完成工程建立,然后编译程序,估计这里包含了硬件对应的比特流和C代码,不过c代码编译后是在内存中也编程比特流了吧。编译完成后,下载程序,Actions > Continue to run it。运行。代码如下
#define ADC_ADDR 0x00003000
#define LED_ADDR 0x00003020
int main (void){
volatile int * adc = (int*)(ADC_ADDR);
volatile int * led = (int*)(LED_ADDR);
unsigned int data;
int count;
int channel;
data = 0;
count = 0;
channel = 0;
while (1){
*(adc) = 0; //Start the ADC read
count += 1;
data = *(adc+channel); //Get the value of the selected channel
data = data/16; //Ignore the lowest 4 bits
*(led) = data; //Display the value on the LEDs
if (count==500000){
count = 0;
channel = !channel;
}
}
return 0;
}
3.2 通过HAL 使用ADC控制器
HAL 允许使用者通过调用函数来访问外设,而不是直接通过地址访问外设。HAL=hardware abstraction layer 硬件抽闲层。使用HAL需要包含下面的头文件,使用这种方法需要更多的内存,虽然方便,但是隐藏了太多内容,对于喜欢刨根问底的同学,还是使用3.1的方法吧。
#include "altera_up_avalon_de0_nano_adc.h"