I use AD7606 to catch 8 ch sigals.
`timescale 1ns / 1ps
module ad7606(
input clk , //clock input
input rst_n , //reset input, low active
input ad_busy , //ad7606 convert busy
input first_data , //ad7606 first data
input sign , //1:module active 0:module fail
input [15:0] ad_data , //ad7606 data input
output ad_data_valid , //ad7606 data finish convert sign
output [2:0] ad_os , //oversampling mode select
output reg module_init , //module init finish
output reg ad_cs , //ad7606 AD cs
output reg ad_rd , //ad7606 AD rd
output reg ad_reset , //ad7606 AD reset
output reg ad_convstab , //ad7606 AD convert start
output reg [15:0] ad_ch1 , //ad7606 convert data ch1
output reg [15:0] ad_ch2 , //ad7606 convert data ch2
output reg [15:0] ad_ch3 , //ad7606 convert data ch3
output reg [15:0] ad_ch4 , //ad7606 convert data ch4
output reg [15:0] ad_ch5 , //ad7606 convert data ch5
output reg [15:0] ad_ch6 , //ad7606 convert data ch6
output reg [15:0] ad_ch7 , //ad7606 convert data ch7
output reg [15:0] ad_ch8 //ad7606 convert data ch8
);
//macro definition parameters
parameter cycle_time = 2500 ; //a convert cycle set
//state machine code
localparam IDLE = 4'd0 ; //init and wait state
localparam AD_CONV = 4'd1 ; //posedge edge start convert
localparam Wait_1 = 4'd2 ; //wait finish convert
localparam Wait_busy = 4'd3 ; //check convert finish sign
localparam READ_CH1 = 4'd4 ; //data ch1 read
localparam READ_CH2 = 4'd5 ; //data ch2 read
localparam READ_CH3 = 4'd6 ; //data ch3 read
localparam READ_CH4 = 4'd7 ; //data ch4 read
localparam READ_CH5 = 4'd8 ; //data ch5 read
localparam READ_CH6 = 4'd9 ; //data ch6 read
localparam READ_CH7 = 4'd10 ; //data ch7 read
localparam READ_CH8 = 4'd11 ; //data ch8 read
localparam READ_DONE = 4'd12 ; //data deliver
//reg define
reg [3:0] state ; //current state reg
reg [5:0] i ; //state change count
reg [15:0] cycle_cnt ; //convert data count
reg [7:0] rst_cnt ; //ad_reset time count
//assign define
assign ad_os = 3'b000; //oversampling mode select
//in the state of READ_DONE then set ad_data_valid high level
assign ad_data_valid = (state == READ_DONE) ? 1'b1 : 1'b0;
//when the system reset then also reset the AD7606
//module_init means this module wether finish init
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
ad_reset <= 1'b0;
rst_cnt <= 8'd0;
module_init <= 1'b0;
end
else if(rst_cnt < 8'hff) begin
rst_cnt <= rst_cnt + 1'b1;
ad_reset <= 1'b1;
end
else begin
ad_reset <= 1'b0;
module_init <= 1'b1;
end
end
//AD7606 convert process
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
state <= IDLE;
ad_cs <= 1'b1;
ad_rd <= 1'b1;
ad_convstab <= 1'b1;
i <= 6'd0;
ad_ch1 <= 16'd0;
ad_ch2 <= 16'd0;
ad_ch3 <= 16'd0;
ad_ch4 <= 16'd0;
ad_ch5 <= 16'd0;
ad_ch6 <= 16'd0;
ad_ch7 <= 16'd0;
ad_ch8 <= 16'd0;
end
else begin
case(state)
//in the state of IDLE ready to convst
IDLE: begin
ad_cs <= 1'b1;
ad_rd <= 1'b1;
ad_convstab <= 1'b1;
if(ad_reset == 0 && cycle_cnt == 9) begin
state<=AD_CONV;
end
end
//convst start at posedge so pull down and then pull up the ad_convstab
AD_CONV: begin
if(cycle_cnt == 11) begin
state <= Wait_1;
ad_convstab <= 1'b1;
end
else begin
ad_convstab <= 1'b0;
end
end
//wait in order to aovid BUSY have not pull up
Wait_1: begin
if(cycle_cnt == 16) begin
state<=Wait_busy;
end
end
//when BUSY pull down means convst finsih
Wait_busy: begin
if(ad_busy == 1'b0) begin
state<=READ_CH1;
end
end
//in the state of READ_CH1 pull down ad_cs for whole data deviler
//get the channel1 data
READ_CH1: begin
ad_cs <= 1'b0;
if(i == 3) begin
i <= 6'd0;
ad_rd <= 1'b1;
ad_ch1<=ad_data;
state<=READ_CH2;
end
else begin
i <= i + 6'd1;
ad_rd <= 1'b0;
end
end
//get the channel2 data
READ_CH2: begin
if(i == 3) begin
i <= 6'd0;
ad_rd <= 1'b1;
ad_ch2<=ad_data;
state<=READ_CH3;
end
else begin
i <= i + 6'd1;
ad_rd <= 1'b0;
end
end
//get the channel3 data
READ_CH3: begin
if(i == 3) begin
i <= 6'd0;
ad_rd <= 1'b1;
ad_ch3<=ad_data;
state<=READ_CH4;
end
else begin
i <= i + 6'd1;
ad_rd <= 1'b0;
end
end
//get the channel4 data
READ_CH4: begin
if(i == 3) begin
i <= 6'd0;
ad_rd <= 1'b1;
ad_ch4<=ad_data;
state<=READ_CH5;
end
else begin
i <= i + 6'd1;
ad_rd <= 1'b0;
end
end
//get the channel5 data
READ_CH5: begin
if(i == 3) begin
i <= 6'd0;
ad_rd <= 1'b1;
ad_ch5<=ad_data;
state<=READ_CH6;
end
else begin
i <= i + 6'd1;
ad_rd <= 1'b0;
end
end
//get the channel6 data
READ_CH6: begin
if(i == 3) begin
i <= 6'd0;
ad_rd <= 1'b1;
ad_ch6<=ad_data;
state<=READ_CH7;
end
else begin
i <= i + 6'd1;
ad_rd <= 1'b0;
end
end
//get the channel7 data
READ_CH7: begin
if(i == 3) begin
i <= 6'd0;
ad_rd <= 1'b1;
ad_ch7<=ad_data;
state<=READ_CH8;
end
else begin
i <= i + 6'd1;
ad_rd <= 1'b0;
end
end
//get the channel8 data
READ_CH8: begin
if(i == 3) begin
i <= 6'd0;
ad_rd <= 1'b1;
ad_ch8<=ad_data;
state<=READ_DONE;
end
else begin
i <= i + 6'd1;
ad_rd <= 1'b0;
end
end
//in the state of READ_DONE pull up the ad_rd and ad_cs
//finish a cycle then goto next cycle
READ_DONE: begin
ad_rd <= 1'b1;
ad_cs <= 1'b1;
if(cycle_cnt == cycle_time - 1) begin
state<=IDLE;
end
end
//if any error happen state goto IDLE
default: begin
state<=IDLE;
end
endcase
end
end
//cycle_cnt count a cycle of convert
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cycle_cnt <= 16'd0;
end
//only input sign is high then actie this convert module
//if cycle_cnt reach set num then empty cycle_cnt and into next cycle
else if(sign) begin
if(cycle_cnt == cycle_time - 1) begin
cycle_cnt <= 16'd0;
end
else begin
cycle_cnt <= cycle_cnt + 1'b1;
end
end
else begin
cycle_cnt <= 16'd0;
end
end
endmodule
AD7606 is a ADC IC and can collect 8 channels data in 16 bits at 200KSPS.
First let us know some parameters.
1.ad_os: this is a control of oversample, it means use low rate to get a stable data.
2.cycle_time: this parameter is created by me to control a whole cycle. It means a whole cycle count. If set cycle_time 250, ad_os 3'b000 and input clk is 50MHz. The turly change rate is 50,000,000 / 250 = 200KSPS.
Now let see how to control AD7606 convst.
CONVST AB controls whether the convst starts. When put it from 0 to 1, the convst starts, and the the BUSY line will be high means the IC is convsting the data. When BUSY line change to 0 means the convest is finished, and you can use CS' and RD' to get the data. When CS' and RD' both change from 1 to 0, the convest will be storage on DATA lines.
So the cycle_cnt in the code is always add 1 to confirm the rate.
The process code is below.
//AD7606 convert process
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
state <= IDLE;
ad_cs <= 1'b1;
ad_rd <= 1'b1;
ad_convstab <= 1'b1;
i <= 6'd0;
ad_ch1 <= 16'd0;
ad_ch2 <= 16'd0;
ad_ch3 <= 16'd0;
ad_ch4 <= 16'd0;
ad_ch5 <= 16'd0;
ad_ch6 <= 16'd0;
ad_ch7 <= 16'd0;
ad_ch8 <= 16'd0;
end
else begin
case(state)
//in the state of IDLE ready to convst
IDLE: begin
ad_cs <= 1'b1;
ad_rd <= 1'b1;
ad_convstab <= 1'b1;
if(ad_reset == 0 && cycle_cnt == 9) begin
state<=AD_CONV;
end
end
//convst start at posedge so pull down and then pull up the ad_convstab
AD_CONV: begin
if(cycle_cnt == 11) begin
state <= Wait_1;
ad_convstab <= 1'b1;
end
else begin
ad_convstab <= 1'b0;
end
end
//wait in order to aovid BUSY have not pull up
Wait_1: begin
if(cycle_cnt == 16) begin
state<=Wait_busy;
end
end
//when BUSY pull down means convst finsih
Wait_busy: begin
if(ad_busy == 1'b0) begin
state<=READ_CH1;
end
end
//in the state of READ_CH1 pull down ad_cs for whole data deviler
//get the channel1 data
READ_CH1: begin
ad_cs <= 1'b0;
if(i == 3) begin
i <= 6'd0;
ad_rd <= 1'b1;
ad_ch1<=ad_data;
state<=READ_CH2;
end
else begin
i <= i + 6'd1;
ad_rd <= 1'b0;
end
end
//get the channel2 data
READ_CH2: begin
if(i == 3) begin
i <= 6'd0;
ad_rd <= 1'b1;
ad_ch2<=ad_data;
state<=READ_CH3;
end
else begin
i <= i + 6'd1;
ad_rd <= 1'b0;
end
end
//get the channel3 data
READ_CH3: begin
if(i == 3) begin
i <= 6'd0;
ad_rd <= 1'b1;
ad_ch3<=ad_data;
state<=READ_CH4;
end
else begin
i <= i + 6'd1;
ad_rd <= 1'b0;
end
end
//get the channel4 data
READ_CH4: begin
if(i == 3) begin
i <= 6'd0;
ad_rd <= 1'b1;
ad_ch4<=ad_data;
state<=READ_CH5;
end
else begin
i <= i + 6'd1;
ad_rd <= 1'b0;
end
end
//get the channel5 data
READ_CH5: begin
if(i == 3) begin
i <= 6'd0;
ad_rd <= 1'b1;
ad_ch5<=ad_data;
state<=READ_CH6;
end
else begin
i <= i + 6'd1;
ad_rd <= 1'b0;
end
end
//get the channel6 data
READ_CH6: begin
if(i == 3) begin
i <= 6'd0;
ad_rd <= 1'b1;
ad_ch6<=ad_data;
state<=READ_CH7;
end
else begin
i <= i + 6'd1;
ad_rd <= 1'b0;
end
end
//get the channel7 data
READ_CH7: begin
if(i == 3) begin
i <= 6'd0;
ad_rd <= 1'b1;
ad_ch7<=ad_data;
state<=READ_CH8;
end
else begin
i <= i + 6'd1;
ad_rd <= 1'b0;
end
end
//get the channel8 data
READ_CH8: begin
if(i == 3) begin
i <= 6'd0;
ad_rd <= 1'b1;
ad_ch8<=ad_data;
state<=READ_DONE;
end
else begin
i <= i + 6'd1;
ad_rd <= 1'b0;
end
end
//in the state of READ_DONE pull up the ad_rd and ad_cs
//finish a cycle then goto next cycle
READ_DONE: begin
ad_rd <= 1'b1;
ad_cs <= 1'b1;
if(cycle_cnt == cycle_time - 1) begin
state<=IDLE;
end
end
//if any error happen state goto IDLE
default: begin
state<=IDLE;
end
endcase
end
end