#前置き
A/D Converter制御用コードを作成したので載せます。
今回使用したICはAD7982です。
変換時間はadc_tconv,回路遅延によるデータ取得の同期ずれはadc_taqcで調整してます。
あとは普通のSPIです。
AD7982.vhd
library IEEE;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity ad7982 is
port(
clk: in std_logic;
cnv_st: in std_logic;
cnv_ed: out std_logic;
dres: out std_logic_vector(17 downto 0);
--To AD5542
sdi: out std_logic;
sdo: in std_logic;
cnv: out std_logic;
sclk: out std_logic
);
end ad7982;
Architecture RTL of ad7982 is
signal pclk: std_logic :='0';
constant pclk_cnt_bit: integer := 4;
constant pclk_cnt_max: std_logic_vector(pclk_cnt_bit -1 downto 0) :=x"e";
signal pclk_cnt: std_logic_vector(pclk_cnt_bit -1 downto 0) :=(others=>'0');
constant adc_bit: integer :=18;
constant adc_rectime: std_logic_vector(5 downto 0) := "011000"; --24
constant adc_cnt_zero: std_logic_vector(5 downto 0) := (others=>'0'); --0
constant adc_tconv: std_logic_vector(5 downto 0) := "111111"; --63
constant adc_taqc: std_logic_vector(5 downto 0) := "010011"; --19
signal adc_cnv: std_logic :='0';
signal adc_cnvcnt: std_logic_vector(5 downto 0) := (others=>'0'); --0
signal adc_cnvend: std_logic :='0';
signal adc_data: std_logic_vector(adc_bit-1 downto 0) :=(others=>'0');
signal adc_data_spl: std_logic_vector(adc_bit-1 downto 0) :=(others=>'0');
signal adc_streamcnt: std_logic_vector(5 downto 0) := (others=>'0');
signal adc_streamend: std_logic :='0';
signal adc_start: std_logic :='0';
signal sclk_in: std_logic :='0';
signal cnv_in: std_logic :='0';
signal sdi_in: std_logic :='0';
signal rec_ed: std_logic :='0';
--state machine
signal adc_state: std_logic_vector(1 downto 0) :=(others=>'0');
--state 0: wait;
--state 1: change a clock source from main one to divided one;
--state 2: conv start;
--state 3: data acquistion;
begin
--to ad5542a
sclk <= sclk_in;
sdi<=sdi_in;
cnv<=adc_cnv;
dres<=adc_data_spl;
cnv_ed<=rec_ed;
--From master system
adc_start <= cnv_st;
--Clock divider
process(clk) begin
if clk'event and clk='1' then
--Timing manager for clock generator
if pclk_cnt=pclk_cnt_max then pclk_cnt <= (others=>'0');
else pclk_cnt <= pclk_cnt+'1'; end if;
--Clock generator
if pclk_cnt=pclk_cnt_max then pclk <= not pclk;
else pclk <= pclk; end if;
end if;
end process;
--State machine
process(clk) begin
if clk'event and clk='1' then
case adc_state is
when "00" =>
if adc_start='1' then adc_state <="01";
else adc_state <= adc_state; end if;
when "01" =>
if adc_cnvend='1' then adc_state <="10";
else adc_state <= adc_state; end if;
when "10" =>
if pclk_cnt=pclk_cnt_max and pclk='1' then adc_state <= "11";
else adc_state <= adc_state; end if;
when "11" =>
if rec_ed='1' then adc_state <="00";
else adc_state <= adc_state; end if;
when others =>
adc_state <= adc_state;
end case;
end if;
end process;
--Communicator
process(clk) begin
if clk'event and clk='1' then
--Conv start
if adc_state="01" then
--Stream Data
if adc_cnvcnt="000001" then adc_cnv <= '1';
elsif adc_cnvcnt=adc_tconv then adc_cnv <= '0';
else adc_cnv<=adc_cnv; end if;
--Stream Count
if adc_cnvcnt=adc_tconv then adc_cnvcnt<=(others=>'0');
else adc_cnvcnt <= adc_cnvcnt+'1'; end if;
--Conv End Flag
if adc_cnvcnt=adc_tconv then adc_cnvend<='1';
else adc_cnvend <= '0'; end if;
else
adc_cnv<='0';
adc_cnvcnt <= (others=>'0');
adc_cnvend <= '0';
end if;
--Data acquisition
if pclk_cnt=pclk_cnt_max and pclk='1' then
if adc_state="11" then
if adc_streamcnt=adc_cnt_zero then adc_data <= (others=>'0');
else adc_data <= adc_data(adc_bit-2 downto 0) & sdo; end if;
else adc_data <= (others=>'0'); end if;
if adc_streamcnt=adc_taqc then adc_data_spl<=adc_data; else adc_data_spl<=adc_data_spl; end if;
end if;
--Data acquisition
if pclk_cnt=pclk_cnt_max and pclk='1' then
if adc_state="11" then
--Stream Count
if adc_streamcnt=adc_rectime then adc_streamcnt<=(others=>'0');
else adc_streamcnt <= adc_streamcnt+'1'; end if;
--Stream End Flag
if adc_streamcnt=adc_rectime then adc_streamend<='1';
else adc_streamend <= '0'; end if;
--Receive end
if adc_streamcnt=adc_rectime then rec_ed<='1';
else rec_ed<='0'; end if;
else
adc_streamcnt <= (others=>'0');
adc_streamend <= '0';
rec_ed<='0';
end if;
end if;
end if;
end process;
sclk_in <= pclk when adc_state ="11" else '0';
sdi_in <= '1' when adc_state/="00" else '0';
end RTL;
AD7982.vhd
module ad7982(clk,cnv_st,dres,sdo,sdi,sclk,conv);
input clk,cnv_st;
output [17:0] dres;
input sdo;
output sdi,sclk,conv;
reg pclk; initial pclk=0;
reg [3:0] pcnt; initial pcnt=2'b0;
parameter pmax=4'h4;
always@(posedge clk)
begin
pcnt<=(pcnt==pmax)? 4'h0:pcnt+4'h1;
pclk<=(pcnt==pmax)? ~pclk:pclk;
end
reg [1:0] state; initial state=2'b0;
reg [6:0] convcnt; initial convcnt=7'b0;
reg convend; initial convend=1'b0;
parameter [6:0] convtime=7'd75;
reg [4:0] reccnt; initial reccnt=5'b0;
reg recend; initial recend=1'b0;
reg [17:0] recdata; initial recdata=18'b0;
reg [17:0] getdata; initial getdata=18'b0;
parameter [4:0] rectime=5'd22;
assign sdi=(state!=2'b00)? 1'b1:1'b0;
assign conv=(convcnt!=7'd0&convcnt!=convtime)? 1'b1:1'b0;
assign sclk=(state==2'b11)? pclk:1'b0;
assign dres=getdata;
always@(posedge clk)
begin
case(state)
2'b00: state<=(cnv_st==1'b1)? state+2'b1:state;
2'b01: state<=(convend==1'b1)? state+2'b1:state;
2'b10: state<=(pcnt==pmax&pclk==1'b1)? state+2'b1:state;
2'b11: state<=(recend==1'b1)? state+2'b1:state;
default: state=2'b00;
endcase
end
always@(posedge clk)
begin
if(state==2'b01)
begin
convcnt<=(convcnt==convtime)? convcnt:convcnt+7'd1;
convend<=(convcnt==convtime)? 1'b1:1'b0;
end
else begin convcnt<=7'd0; convend<=1'b0; end
if(pcnt==pmax&pclk==1'b1)
begin
if(state==2'b11)
begin
reccnt<=(reccnt==rectime)? reccnt:reccnt+5'b1;
recend<=(reccnt==rectime)? 1'b1:1'b0;
end
else begin reccnt<=5'd0; recend<=1'b0; end
end
if(pcnt==pmax&pclk==1'b1)
begin
if(state==2'b11)
begin
recdata<=(reccnt==5'd0)? 18'b0:{recdata[16:0],sdo};
getdata<=(reccnt==5'd19)? recdata:getdata;
end
else begin recdata<=18'b0; getdata<=getdata; end
end
end
endmodule