1 | LIBRARY IEEE;
|
2 | USE IEEE.STD_LOGIC_1164.ALL;
|
3 | USE IEEE.NUMERIC_STD.ALL;
|
4 |
|
5 | ENTITY ADC_Module_SPI IS
|
6 | PORT(
|
7 | CLK :IN STD_LOGIC; -- external clock comes from FPGA
|
8 | GO : IN STD_LOGIC; -- to start the conversion by external key for example
|
9 | RESET : IN STD_LOGIC; -- reset the system
|
10 | CS_n : OUT STD_LOGIC; -- select line
|
11 | SCLK : OUT STD_LOGIC; -- SPI clock for ADC conversion and transfer
|
12 | BUSY : IN STD_LOGIC; -- indicates if the conversion is complete or not
|
13 | EOC : IN STD_LOGIC; -- indicate the end of conversion
|
14 | iDOUT : IN STD_LOGIC; -- SDOUT, data comes from the ADC
|
15 | CNVST : OUT STD_LOGIC; -- this line initiates the conversion
|
16 | AD_RESET : OUT STD_LOGIC; -- reset the ADC module
|
17 | DATA_AOUT : OUT STD_LOGIC_VECTOR(15 DOWNTO 0); -- data comes from the channel A
|
18 | DATA_BOUT : OUT STD_LOGIC_VECTOR(15 DOWNTO 0)-- data comes from the channel B
|
19 |
|
20 |
|
21 | );
|
22 | END ADC_Module_SPI;
|
23 |
|
24 |
|
25 | ARCHITECTURE ADC_ARCH OF ADC_Module_SPI IS
|
26 | TYPE ADC_STATE IS (IDLE,START,CONV_A,CONV_B,CATCH); --Define the FSM(Finite State Machine)'s state
|
27 | SIGNAL STATE_START,STATE_NEXT : ADC_STATE;
|
28 | SIGNAL BUSY_R : STD_LOGIC := 'Z'; --BUSY_R => to judge the rising edge of BUSY
|
29 | SIGNAL EOC_R : STD_LOGIC := 'Z'; --EOC_R => to judge the rising edge of EOC
|
30 | SIGNAL BUSY_D,EOC_D : STD_LOGIC := 'Z'; --BUSY_D,EOC_D => to save the signal BUSY and EOC
|
31 | SIGNAL DATA_ATEMP,DATA_BTEMP : STD_LOGIC_VECTOR(15 DOWNTO 0); -- to save the AD reading data from two channel
|
32 | signal go_en: STD_LOGIC;
|
33 | signal iCLK: STD_LOGIC;
|
34 |
|
35 | BEGIN
|
36 | CLKPLL: SPICLK port map (CLK, iCLK);
|
37 |
|
38 | with go_en select
|
39 | SCLK <= iCLK when '1', -- generate the ADC clock
|
40 | '1' when '0',
|
41 | '1' when others;
|
42 | Start_ADC_proc: process(GO)
|
43 | begin
|
44 | if(GO = '1') then
|
45 | go_en <= '1'; -- go_en is low when the push button is pressed or reset is high
|
46 | else
|
47 | go_en <= '0'; -- if the push-button is not pressed, the level is high
|
48 | end if;
|
49 | end process Start_ADC_proc;
|
50 |
|
51 | PROCESS(iCLK,RESET)
|
52 |
|
53 | VARIABLE CONV_AC : INTEGER := 0;
|
54 | VARIABLE CONV_AFC : INTEGER := 16; -- cont the number of the cycles during the Channel A conversion
|
55 | VARIABLE CONV_BC : INTEGER := 0;
|
56 | VARIABLE CONV_BFC : INTEGER := 16; -- cont the number of the cycles during the Channel B conversion
|
57 |
|
58 | BEGIN
|
59 | IF (RESET='1') THEN -- when reset is selected
|
60 | AD_RESET <= '1'; -- the ADC is reset
|
61 | CONV_AC := 0;
|
62 | CONV_BC := 0;
|
63 | STATE_START <= IDLE; -- The state machine enter to the idle mode
|
64 | DATA_ATEMP <= (OTHERS => '0');
|
65 | DATA_BTEMP <= (OTHERS => '0');
|
66 | ELSIF (iCLK'EVENT AND iCLK ='1') THEN --when the iCLK is rising edge and do the following thing
|
67 | STATE_START <= STATE_NEXT;
|
68 | BUSY_D <= BUSY; -- save the actual state of the busy signal
|
69 | EOC_D <= EOC; -- save the actual state of EOC signal
|
70 | BUSY_R <= (NOT BUSY_D) AND BUSY; -- this line is mainly for the rising edge detector for BUSY,
|
71 | EOC_R <= (NOT EOC_D) AND EOC; -- this line is mainly for the rising edge detector for EOC ,
|
72 | CASE STATE_START IS --the finite state machine with five states
|
73 |
|
74 | WHEN IDLE => -- in the IDLE state
|
75 | IF go_en='1' THEN --when you start, turn off the AD_reset,and make the CNVST to high
|
76 | AD_RESET <= '0'; -- the reset ADC signal is disabled by putting it high
|
77 | CNVST <= '1'; -- the conversion can start
|
78 | STATE_NEXT <= START; -- the next state take the value start
|
79 | ELSE
|
80 | STATE_NEXT <= IDLE;
|
81 | END IF;
|
82 |
|
83 | WHEN START => -- in the Start state when is conversion can be started
|
84 | CNVST <='0';
|
85 | IF BUSY_R='1' THEN --when BUSY rising, change the state, rising edge is detected
|
86 | STATE_NEXT <= CONV_A; -- the CONV state is activated in the next rising edge of SCLK
|
87 | END IF;
|
88 |
|
89 | WHEN CONV_A =>
|
90 | IF BUSY ='1' THEN -- when the busy signal is always high, that means the conversion is occurring
|
91 |
|
92 | IF CONV_AC = CONV_AFC THEN
|
93 | STATE_NEXT <= CONV_B; -- The conversion of channel A is complete, the next step is to convert the channel A
|
94 | ELSE
|
95 | DATA_ATEMP <= DATA_ATEMP(14 downto 0) & iDOUT;
|
96 | CONV_AC := CONV_AC +1;
|
97 | STATE_NEXT <= CONV_A;
|
98 | END IF;
|
99 | END IF;
|
100 |
|
101 | WHEN CONV_B =>
|
102 | IF BUSY ='1' THEN -- when the busy signal is always high, that means the conversion is occurring
|
103 |
|
104 | IF CONV_BC = CONV_BFC THEN
|
105 | STATE_NEXT <= CATCH; -- The conversion of channel B is complete
|
106 | ELSE
|
107 | IF EOC_R='1' THEN -- if busy=1 and a rising edge is detected on EOC_R, that means the channel B is ready to be converted and sent
|
108 | DATA_BTEMP <= DATA_BTEMP(14 downto 0) & iDOUT;
|
109 | CONV_BC := CONV_BC +1;
|
110 | STATE_NEXT <= CONV_B;
|
111 | END IF;
|
112 | END IF;
|
113 | END IF;
|
114 | WHEN CATCH => --reading the two channel data
|
115 |
|
116 | DATA_AOUT <= DATA_ATEMP;
|
117 | DATA_BOUT <= DATA_ATEMP;
|
118 |
|
119 | STATE_NEXT <= IDLE;
|
120 | END CASE;
|
121 | END IF;
|
122 | END PROCESS;
|
123 |
|
124 | END ADC_ARCH;
|