ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

基于MCP3313-10 ADC 的SPI接口驱动练习

2022-03-03 10:02:36  阅读:240  来源: 互联网

标签:10 begin 采集 sclk SPI adc rst reg ADC


先了解MCP3313-10的操作步骤:

 

看上图可以了解,上电之后先经过tACQ(输入采集,但这个时候并不能对数据进行采集)一段时间,设定为状态0;再进入tCNV(数据转换期间,不能采集数据),设定为状态1;最后在进入tACQ(可以进行数据采集),设定位状态2。状态1-2-1-2之间进行轮回。

然后查看具体时序:

 

 

 CNVST 初始值为低,经过tACQ在上升沿到来时,adc进入数据转换,转换时间需要tCNV,然后进入数据采集,采集时间tACQ,所以需要知道这几个具体时间

tACQ 有一个最小值290ns,没标最大值,说明这个时间可以更长点

tCNV有标最大值,没标最小时值,说明这个时间可以短点

 

 

OK 确认之后,可以对计数器进行设计了。一共需要两个计数器,一个计数器产生sclk,另外一个计数器需对数据采集个数进行计数。由于转换期间和数据采集期间的时间不一样,不会同时计数,所以可以重复利用一个计数器,引入一个变量x.

上电时的tACQ ,和数据转换后的tACQ 时间是一样,计数器也可以共用一个。代码如下:

 1 always @(posedge clk or negedge rst_n)begin
 2     if(!rst_n)begin
 3         cnt0 <= 0;
 4     end
 5     else if(add_cnt0)begin
 6         if(end_cnt0)begin
 7             cnt0 <= 0;
 8         end
 9         else begin
10             cnt0 <= cnt0 + 1;
11         end
12     end
13 end
14 
15 assign add_cnt0 = flag_add;
16 assign end_cnt0 = add_cnt0 && cnt0 == 4 - 1; //输入时钟50M,4分屏,sclk = 50/4 = 12.5M
17 
18 always @(posedge clk or negedge rst_n)begin
19     if(!rst_n)begin
20         cnt1 <= 0;
21     end
22     else if(add_cnt1)begin
23         if(end_cnt1)begin
24             cnt1 <= 0;
25         end
26         else begin
27             cnt1 <= cnt1 + 1;
28         end
29     end
30 end
31 
32 assign add_cnt1 = end_cnt0;
33 assign end_cnt1 = add_cnt1 && cnt1 == x - 1;
34 
35 always @(*)begin
36     if(state == 0)begin
37         x = 16;     //tACQ:等待16 * 80 = 1280 ns
38     end
39     else if(state == 1)begin
40         x = 8;        //tCNV:等待8 * 80 = 640 ns ,
41     end
42     else begin
43         x = 16;        //tACQ:等待16 * 80 = 1280 ns
44     end
45 end

引入了一个状态机,上电时进入state =0 状态,数据转换进入state =1 状态,数据采集进入state =2 状态

 1 always @(posedge clk or negedge rst_n)begin
 2     if(!rst_n)begin
 3         state <= 0;
 4         flag_add <= 0;
 5         adc_cs <= 0;
 6         flag_sel <= 0;
 7         dout_vld <= 0;
 8     end
 9     else case(state)
10 
11         0:    begin
12             flag_add <= 1;
13             adc_cs <= 0;
14             flag_sel <= 0;
15             dout_vld <= 0;
16             if(end_cnt1)begin //等待16 * 80 = 1280 ns
17                 state <= 1;
18                 adc_cs <= 1;
19                 flag_sel <= 0;
20                 dout_vld <= 0;
21             end
22         end
23         
24         1:    begin    //adc数据在转换中
25             adc_cs <= 1;
26             flag_sel <= 0;
27             dout_vld <= 0;
28             if(end_cnt1)begin //等待8*80 = 640 ns
29                 state <= 2;
30                 adc_cs <= 0;
31                 flag_sel <= 1;
32                 dout_vld <= 0;
33             end
34         end
35         
36         2:    begin    // 数据采集期间
37             adc_cs <= 0;
38             flag_sel <= 1;
39             dout_vld <= 0;
40             if(end_cnt1)begin //等待16 * 80 = 1280 ns,数据采集完进入下一轮转换
41                 state <= 1;
42                 adc_cs <= 1;
43                 flag_sel <= 0;
44                 dout_vld <= 1;
45             end
46         end
47         
48         default: state <= 0;
49     endcase
50 end

引入了几个信号:

flag_add: 计数器启动条件,这里设置为1,计数器一直计数

 

flag_sel:将数据采集那段时间进行标注,用于区分哪段时间需要进行采数据

dout_vld:数据采集完产生一个有效标志,然后对一个完整数据进行锁存

 1 always @(posedge clk or negedge rst_n)begin
 2     if(!rst_n)begin
 3         adc_data_temp <= 0;
 4     end
 5     else if(flag_sel == 1 && add_cnt0 && cnt0 == 2-1 && cnt1 >= 0 && cnt1 < 16)begin //在sclk的下降沿采数据,同时在flag_sel有效期间
 6             adc_data_temp[15-cnt1] <= adc_sdo;
 7     end
 8 end
 9 
10 always @(posedge clk or negedge rst_n)begin
11     if(!rst_n)begin
12         adc_data <= 0;
13     end
14     else if(dout_vld)begin //一个完整的16bit数据采集完
15         adc_data <= adc_data_temp;
16     end
17 end

然后产生sclk时钟:

 1 always @(posedge clk or negedge rst_n)begin
 2     if(!rst_n)begin
 3         adc_sclk <= 1;
 4     end
 5     else if(add_cnt0 && cnt0 == 2-1)begin
 6         adc_sclk <= 0;
 7     end
 8     else if(end_cnt0)begin
 9         adc_sclk <= 1;
10     end
11 end

完整代码:

  1 module mcp3313_10_test(
  2                     clk,
  3                     rst_n,
  4                     adc_sdo,
  5                     
  6                     adc_cs,
  7                     adc_sclk,
  8                     adc_data        
  9 );
 10 
 11 input     clk;
 12 input     rst_n;
 13 input     adc_sdo;
 14 
 15 output                 adc_cs;
 16 output                 adc_sclk;
 17 output     [16-1 : 0]    adc_data;
 18 
 19 reg     [16-1 : 0]     adc_data_temp;
 20 reg     [16-1 : 0]    adc_data;
 21 reg     [3 -1 : 0]     cnt0/* synthesis keep*/;
 22 reg     [6 -1 : 0]     cnt1/* synthesis keep*/;
 23 reg     [6 -1 : 0]     x/* synthesis keep*/;
 24 reg     [2 -1 : 0]     state/* synthesis keep*/;
 25 reg                    flag_add;
 26 reg                    flag_sel;
 27 reg                 dout_vld;
 28 reg                 adc_cs;
 29 reg                 adc_sclk;
 30 
 31 
 32 wire                 add_cnt0;
 33 wire                 end_cnt0;
 34 wire                 add_cnt1;
 35 wire                 end_cnt1;
 36 
 37 always @(posedge clk or negedge rst_n)begin
 38     if(!rst_n)begin
 39         cnt0 <= 0;
 40     end
 41     else if(add_cnt0)begin
 42         if(end_cnt0)begin
 43             cnt0 <= 0;
 44         end
 45         else begin
 46             cnt0 <= cnt0 + 1;
 47         end
 48     end
 49 end
 50 
 51 assign add_cnt0 = flag_add;
 52 assign end_cnt0 = add_cnt0 && cnt0 == 4 - 1; //输入时钟50M,4分屏,sclk = 50/4 = 12.5M
 53 
 54 always @(posedge clk or negedge rst_n)begin
 55     if(!rst_n)begin
 56         cnt1 <= 0;
 57     end
 58     else if(add_cnt1)begin
 59         if(end_cnt1)begin
 60             cnt1 <= 0;
 61         end
 62         else begin
 63             cnt1 <= cnt1 + 1;
 64         end
 65     end
 66 end
 67 
 68 assign add_cnt1 = end_cnt0;
 69 assign end_cnt1 = add_cnt1 && cnt1 == x - 1;
 70 
 71 always @(*)begin
 72     if(state == 0)begin
 73         x = 16;     //tACQ:等待16 * 80 = 1280 ns
 74     end
 75     else if(state == 1)begin
 76         x = 8;        //tCNV:等待8 * 80 = 640 ns ,
 77     end
 78     else begin
 79         x = 16;        //tACQ:等待16 * 80 = 1280 ns
 80     end
 81 end
 82 
 83 always @(posedge clk or negedge rst_n)begin
 84     if(!rst_n)begin
 85         state <= 0;
 86         flag_add <= 0;
 87         adc_cs <= 0;
 88         flag_sel <= 0;
 89         dout_vld <= 0;
 90     end
 91     else case(state)
 92 
 93         0:    begin
 94             flag_add <= 1;
 95             adc_cs <= 0;
 96             flag_sel <= 0;
 97             dout_vld <= 0;
 98             if(end_cnt1)begin //等待16 * 80 = 1280 ns
 99                 state <= 1;
100                 adc_cs <= 1;
101                 flag_sel <= 0;
102                 dout_vld <= 0;
103             end
104         end
105         
106         1:    begin    //adc数据在转换中
107             adc_cs <= 1;
108             flag_sel <= 0;
109             dout_vld <= 0;
110             if(end_cnt1)begin //等待8*80 = 640 ns
111                 state <= 2;
112                 adc_cs <= 0;
113                 flag_sel <= 1;
114                 dout_vld <= 0;
115             end
116         end
117         
118         2:    begin    // 数据采集期间
119             adc_cs <= 0;
120             flag_sel <= 1;
121             dout_vld <= 0;
122             if(end_cnt1)begin //等待16 * 80 = 1280 ns,数据采集完进入下一轮转换
123                 state <= 1;
124                 adc_cs <= 1;
125                 flag_sel <= 0;
126                 dout_vld <= 1;
127             end
128         end
129         
130         default: state <= 0;
131     endcase
132 end
133 
134 always @(posedge clk or negedge rst_n)begin
135     if(!rst_n)begin
136         adc_data_temp <= 0;
137     end
138     else if(flag_sel == 1 && add_cnt0 && cnt0 == 2-1 && cnt1 >= 0 && cnt1 < 16)begin //在sclk的下降沿采数据,同时在flag_sel有效期间
139             adc_data_temp[15-cnt1] <= adc_sdo;
140     end
141 end
142 
143 always @(posedge clk or negedge rst_n)begin
144     if(!rst_n)begin
145         adc_data <= 0;
146     end
147     else if(dout_vld)begin //一个完整的16bit数据采集完
148         adc_data <= adc_data_temp;
149     end
150 end
151 
152 always @(posedge clk or negedge rst_n)begin
153     if(!rst_n)begin
154         adc_sclk <= 1;
155     end
156     else if(add_cnt0 && cnt0 == 2-1)begin
157         adc_sclk <= 0;
158     end
159     else if(end_cnt0)begin
160         adc_sclk <= 1;
161     end
162 end
163 
164 endmodule
View Code

SignalTap II Logic Analyzer 抓取波形如下:

 

标签:10,begin,采集,sclk,SPI,adc,rst,reg,ADC
来源: https://www.cnblogs.com/wen2376/p/15958363.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有