手把手教你如何在HDL中调用并使用MAX10的ADC(双通道)

作者: fanyao-367090
上传时间为: 2015-12-10 09:04 AM
2015-12-10
阅读:

该ADC实验基于艾瑞的BeMicro Max10开发板:


板子上左上角,有一个光敏电阻Photo Resistor和一个温度传感器Thermistor,将这两个作为ADC的两个模拟通道的输入。

双通道和多通道转换是一样的,只要确切的明白了控制通道的时序,那更多通道的不在话下。

上一篇中,我为了方便,将很多ADC的输入信号都固定下来了,但这次为了通道切换,必须将固定的信号都加以利用

ADC的例化结果如下:

reg adc_com_vaild;
reg[4:0] adc_com_channel;
wire adc_com_ready;
wire adc_rep_vaild;
wire[4:0] adc_rep_channel;
wire[11:0] adc_rep_data;
MAX10_ADC ADC(
.adc_pll_clock_clk(adc_clk_10m), // ADC的PLL时钟,必须为PLL1或者3的C0输出
.adc_pll_locked_export(adc_clk_lock), // 上面这个时钟的PLL锁定信号
.clock_clk(clk_50m), // 用于ADC与外部用户逻辑的交互时钟,用户自定义

.command_valid(adc_com_vaild), //用户命令有效指示
.command_channel(adc_com_channel), //用户命令-ADC转换通道指示
.command_startofpacket(), //用户命令-总线打包开始指示,在only core模式下忽略
.command_endofpacket(), //用户命令-总线打包结束指示,在only core模式下忽略
.command_ready(adc_com_ready), // ADC对命令的反馈,置高就意味着ADC可以接受下一个命令

.reset_sink_reset_n(rst_n), // 复位信号
.response_valid(adc_rep_vaild), // 回馈数据有效指示
.response_channel(adc_rep_channel), // 回馈数据通道指示
.response_data(adc_rep_data), // ADC的转换数据
.response_startofpacket(), //回馈的总线打包开始指示,在only core模式下忽略
.response_endofpacket() //回馈的总线打包结束指示,在only core模式下忽略
);

这里可以看到,我将用户命令除了总线打包以外的信号都引出作为控制信号使用。

首先,我们要对adc_com_ready信号做出处理。首先我们知道这是一个反馈信号,当其为高时,说明ADC已经准备好接收下一个命令了。
我们要以这个信号作为触发条件去切换ADC的通道,也就是将通道号作为命令输入到ADC中。
但我们需要注意的是,altera并没有提供时序图,也就是说我们不知道这个ready信号将持续几个时钟,因此在这里我做了一个小技巧,抓ready信号的上升沿,具体程序如下:

reg f_adc_com_ready;//ADC命令准备好存寄存器
always @(posedge clk_50m) begin
if(rst_n == 1'b0)begin
f_adc_com_ready <= 1'b0;
end
else begin
f_adc_com_ready <= adc_com_ready;
end
end
其实做的很简单,就是多加了一级缓冲,也就是多打一拍。但通过判断f_adc_com_ready和adc_com_ready的状态,我们就可以判断ready信号是否出现了跳变。
((adc_com_ready == 1'b1)&(f_adc_com_ready == 1'b0))就是上升沿跳变,反之((adc_com_ready == 1'b0)&(f_adc_com_ready == 1'b1))就是下降沿跳变。

这样做,无论ready信号将持续多少个时钟,我都能确定的让每一次ready的置高触发有且只有一次的通道变换。

切换通道进程如下:
always @(posedge clk_50m) begin
if(rst_n == 1'b0)begin
adc_com_vaild <= 1'b0;
adc_com_channel <= 5'd4;
end
else begin
adc_com_vaild <= 1'b1;
if ((adc_com_ready == 1'b1)&(f_adc_com_ready == 1'b0)) begin //在ready的上升沿改变通道
if(adc_com_channel == 5'd4) begin //通道切换
adc_com_channel <= 5'd12;
end
else begin
adc_com_channel <= 5'd4;
end
end
else begin
adc_com_channel <= adc_com_channel;
end
end
end
有以下几点要点:
第一,我将vaild信号在复位过后就一直置高,实测证明这是可用的但不一定是正确的,如果以后有更详细的时序图,这里可能会有修正。

第二,在ready的上升沿切换通道,本例中是4通道和12通道。

第三,在ready未出现上升沿时,保持通道号。

对了,别忘记设置ADC的IP核,打开第十二通道并重新生成HDL文件:



最后,在ADC的输出分通道分别显示到LED的高四位和低四位
always @(posedge clk_50m) begin//计数输出
if(rst_n == 1'b0)begin
o_led <= 8'h0;
end
else if ((adc_rep_vaild == 1'b1)&(adc_rep_channel == 5'd4)) begin //高位给光敏传感器
o_led[7:4] <= ~(adc_rep_data[11:8]);
end
else if ((adc_rep_vaild == 1'b1)&(adc_rep_channel == 5'd12)) begin//低位给温度传感器
o_led[3:0] <= ~(adc_rep_data[7:4]);
end
end

这里和上一篇帖子不同,因为我发现LED的输出是高灭低亮,因此这里讲输出数据取反了。
温度传感器的输出值较小,所以用了7:4的范围,而光敏传感器用了11:8.

好了, 编译,下载,上结果:
首先,光敏传感器依然灵敏:



可以看到在遮挡情况下LED的7;4均发生了变化。接下来,用手指触碰温度传感器,LED的3:0也发生了变化


说明温度信号已经被ADC所采集并输出。

至此,双通道实验正式完成。

在此试验中,通过对ready信号的判断,实现对双通道的对半采样(每个通道都是500Ksps)。在此基础上加入更多通道的切换,即可实现多通道采样了。

这里要提醒一句,MAX10的ADC是一直工作在1Msps的采样率下的,因此多通道采样计算采样率的时候要以这个速度作为基准。

应该可以通过欺骗的方法让ADC速度降低。比如说在QSYS里设置ADC的PLL时钟为80M,但真正输入ADC的时钟为10M,那实际采样速度应为1M/8=125Ksps。

但这样后果未知,因为硬件上的采样保持电路应该是按照1M采样率去设计的。

好了,MAX10的ADC基本功能探索完成,希望大家能顺利用上MAX10所提供的便利功能~

全部评论 ()
条评论
写评论

创建讨论帖子

登录 后参与评论
系统提示