1. 今日摸鱼计划
今天来学习一下ADC的原理,然后把ADC给实现 ADC芯片:ADC128S102 |
视频: 18A_基于SPI接口的ADC芯片功能和接口时序介绍_哔哩哔哩_bilibili 18B_使用线性序列机思路分析SPI接口的ADC芯片接口时序_哔哩哔哩_bilibili 18C_基于线性序列机的SPI接口ADC控制逻辑设计_哔哩哔哩_bilibili |
2. ADC指标参数
3. ADC128S102
在 ACZ702 EDA 扩展板上使用的模数转换器为逐次逼近型的低功耗芯片ADC128S102,其具有 8 通道以及 12 位的分辨率。电源采用独立的模拟供电以及数字供电,其中模拟电源 VA输入范围为 2.7V~5.25V,数字电源 VD输入范围为 2.7V~VA。其与外部通信支持多种接口如:SPI、QSPI、MICROWIRE以及通用的 DSP 接口。转换速度在 500 kps~1 Mkps,典型情况下当 3V 供电时功耗为2.3mW,5V 供电时为 10.7mW,如下图为该 ADC 芯片的内部结构图。
芯片引脚功能如下:
ADC128S102通过 SPI接口与控制器进行通信的时序图如下图所示:
四线SPI分析:
CS | 片选信号(本摸鱼怪不会加横线) CS拉低,表示通信的开始,CS拉高表示通信结束 |
SCLK | CS 为高时 SCLK 默认高 一帧包含 16 个上升沿 SCLK |
DIN | SCLK的上升沿,DIN上的信号要保持稳定,此时ADC芯片会对DIN上的信号采样 |
DOUT | 当CS 为高时代表空闲状态,当为低时为传输状态 |
4. 线性序列机实现ADC
|
|
|
module adc128s102( input Clk, input Reset_n , input Conv_Go,//使能信号 input [2:0]Addr, output reg Conv_Done, output reg[11:0]Data, output reg ADC_SCLK, output reg ADC_CS_N, output reg ADC_DIN, input ADC_DOUT ); parameter CLOCK_FREQ = 50_000_000; parameter SCLK_FREQ = 12_500_000; parameter MCNT_DIV_CNT = CLOCK_FREQ/(SCLK_FREQ * 2) - 1; reg[7:0]DIV_CNT; reg [5:0]LSM_CNT; reg [11:0]Data_r; reg [2:0]r_Addr; always@(posedge Clk) if(Conv_Go) r_Addr <= Addr; else r_Addr <= r_Addr; reg Conv_En; //转换使能 always@(posedge Clk or negedge Reset_n ) if(!Reset_n ) Conv_En <= 1'd0; else if(Conv_Go) Conv_En <= 1'd1; else if((LSM_CNT == 6'd34) && (DIV_CNT == MCNT_DIV_CNT)) Conv_En <= 1'd0; else Conv_En <= Conv_En; always@(posedge Clk or negedge Reset_n) if(!Reset_n) DIV_CNT <= 0; else if(Conv_En)begin if(DIV_CNT == MCNT_DIV_CNT) DIV_CNT <= 0; else DIV_CNT <= DIV_CNT + 1'd1; end else DIV_CNT <= 0; always@(posedge Clk or negedge Reset_n) if(!Reset_n) LSM_CNT <= 6'd0; else if(DIV_CNT == MCNT_DIV_CNT)begin if(LSM_CNT == 6'd34) LSM_CNT <= 6'd0; else LSM_CNT <= LSM_CNT + 1'd1; end else LSM_CNT <= LSM_CNT; always@(posedge Clk or negedge Reset_n ) if(!Reset_n )begin Data_r <= 12'd0; ADC_SCLK <= 1'd1; ADC_DIN <= 1'd1; ADC_CS_N <= 1'd1; end else if(DIV_CNT == MCNT_DIV_CNT)begin case(LSM_CNT) 0 : begin ADC_CS_N <= 1'd1; ADC_SCLK <= 1'd1;end 1 : begin ADC_CS_N <= 1'd0;end 2 : begin ADC_SCLK <= 1'd0;end 3 : begin ADC_SCLK <= 1'd1;end 4 : begin ADC_SCLK <= 1'd0;end 5 : begin ADC_SCLK <= 1'd1;end 6 : begin ADC_SCLK <= 1'd0;ADC_DIN <= r_Addr[2]; end 7 : begin ADC_SCLK <= 1'd1;end 8 : begin ADC_SCLK <= 1'd0;ADC_DIN <= r_Addr[1]; end 9 : begin ADC_SCLK <= 1'd1;end 10 :begin ADC_SCLK <= 1'd0;ADC_DIN <= r_Addr[0]; end 11: begin ADC_SCLK <= 1'd1;Data_r[11] <= ADC_DOUT; end 12: begin ADC_SCLK <= 1'd0;end 13: begin ADC_SCLK <= 1'd1;Data_r[10] <= ADC_DOUT; end 14: begin ADC_SCLK <= 1'd0;end 15: begin ADC_SCLK <= 1'd1;Data_r[9] <= ADC_DOUT; end 16: begin ADC_SCLK <= 1'd0;end 17: begin ADC_SCLK <= 1'd1;Data_r[8] <= ADC_DOUT; end 18: begin ADC_SCLK <= 1'd0;end 19: begin ADC_SCLK <= 1'd1;Data_r[7] <= ADC_DOUT; end 20: begin ADC_SCLK <= 1'd0;end 21: begin ADC_SCLK <= 1'd1;Data_r[6] <= ADC_DOUT; end 22: begin ADC_SCLK <= 1'd0;end 23: begin ADC_SCLK <= 1'd1;Data_r[5] <= ADC_DOUT; end 24: begin ADC_SCLK <= 1'd0;end 25: begin ADC_SCLK <= 1'd1;Data_r[4] <= ADC_DOUT; end 26: begin ADC_SCLK <= 1'd0;end 27: begin ADC_SCLK <= 1'd1;Data_r[3] <= ADC_DOUT; end 28: begin ADC_SCLK <= 1'd0;end 29: begin ADC_SCLK <= 1'd1;Data_r[2] <= ADC_DOUT; end 30: begin ADC_SCLK <= 1'd0;end 31: begin ADC_SCLK <= 1'd1;Data_r[1] <= ADC_DOUT; end 32: begin ADC_SCLK <= 1'd0;end 33: begin ADC_SCLK <= 1'd1;Data_r[0] <= ADC_DOUT; end 34: begin ADC_SCLK <= 1'd1;ADC_CS_N <= 1'd1; end default: ADC_CS_N <= 1'd1; endcase end always@(posedge Clk or negedge Reset_n ) if(!Reset_n )begin Data <= 12'd0; Conv_Done <= 0; end else if((LSM_CNT == 34) && (DIV_CNT == MCNT_DIV_CNT))begin Conv_Done <= 1'd1; Data <= Data_r; end else begin Conv_Done <= 1'd0; Data <= Data; end endmodule |
5. adc128s102_tb
`timescale 1ns/1ns module adc128s102_tb; reg clk; reg reset_n; reg Conv_Go; reg [2:0]Addr; wire Conv_Done; wire[11:0]Data; wire ADC_SCLK; wire ADC_CS_N; wire ADC_DIN; reg ADC_DOUT; adc128s102 adc128s102( .Clk(clk), .Reset_n(reset_n), .Conv_Go(Conv_Go), .Addr(Addr), .Conv_Done(Conv_Done), .Data(Data), .ADC_SCLK(ADC_SCLK), .ADC_CS_N(ADC_CS_N), .ADC_DIN(ADC_DIN), .ADC_DOUT(ADC_DOUT) ); initial clk = 1; always #10 clk = ~clk; initial begin reset_n = 0; Conv_Go = 0; Addr = 0; #201; reset_n = 1; #200; Conv_Go = 1; Addr = 3; #20; Conv_Go = 0; wait(!ADC_CS_N); //16'h0A58 @(negedge ADC_SCLK); ADC_DOUT = 0; //DB15 @(negedge ADC_SCLK); ADC_DOUT = 0; //DB14 @(negedge ADC_SCLK); ADC_DOUT = 0; //DB13 @(negedge ADC_SCLK); ADC_DOUT = 0; //DB12 @(negedge ADC_SCLK); ADC_DOUT = 1; //DB11 @(negedge ADC_SCLK); ADC_DOUT = 0; //DB10 @(negedge ADC_SCLK); ADC_DOUT = 1; //DB9 @(negedge ADC_SCLK); ADC_DOUT = 0; //DB8 @(negedge ADC_SCLK); ADC_DOUT = 0; //DB7 @(negedge ADC_SCLK); ADC_DOUT = 1; //DB6 @(negedge ADC_SCLK); ADC_DOUT = 0; //DB5 @(negedge ADC_SCLK); ADC_DOUT = 1; //DB4 @(negedge ADC_SCLK); ADC_DOUT = 1; //DB3 @(negedge ADC_SCLK); ADC_DOUT = 0; //DB2 @(negedge ADC_SCLK); ADC_DOUT = 0; //DB1 @(negedge ADC_SCLK); ADC_DOUT = 0; //DB0 wait(ADC_CS_N); #2000; Conv_Go = 1; Addr = 7; #20; Conv_Go = 0; wait(!ADC_CS_N); //16'h0893 @(negedge ADC_SCLK); ADC_DOUT = 0; @(negedge ADC_SCLK); ADC_DOUT = 0; @(negedge ADC_SCLK); ADC_DOUT = 0; @(negedge ADC_SCLK); ADC_DOUT = 0; @(negedge ADC_SCLK); ADC_DOUT = 1; @(negedge ADC_SCLK); ADC_DOUT = 0; @(negedge ADC_SCLK); ADC_DOUT = 0; @(negedge ADC_SCLK); ADC_DOUT = 0; @(negedge ADC_SCLK); ADC_DOUT = 1; @(negedge ADC_SCLK); ADC_DOUT = 0; @(negedge ADC_SCLK); ADC_DOUT = 0; @(negedge ADC_SCLK); ADC_DOUT = 1; @(negedge ADC_SCLK); ADC_DOUT = 0; @(negedge ADC_SCLK); ADC_DOUT = 0; @(negedge ADC_SCLK); ADC_DOUT = 1; @(negedge ADC_SCLK); ADC_DOUT = 1; wait(ADC_CS_N); #200; #2000; $stop; end endmodule |