查看: 1463|回复: 0

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

[复制链接]

该用户从未签到

发表于 2015-12-10 09:04:32 | 显示全部楼层 |阅读模式
分享到:
该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所提供的便利功能~
回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /2 下一条

手机版|小黑屋|与非网

GMT+8, 2024-4-25 17:29 , Processed in 0.123951 second(s), 17 queries , MemCache On.

ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

苏公网安备 32059002001037号

Powered by Discuz! X3.4

Copyright © 2001-2024, Tencent Cloud.