基于MCP3313-10 ADC 的SPI接口驱动练习
作者:互联网
先了解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 endmoduleView Code
SignalTap II Logic Analyzer 抓取波形如下:
标签:10,begin,采集,sclk,SPI,adc,rst,reg,ADC 来源: https://www.cnblogs.com/wen2376/p/15958363.html