Saturday, May 28, 2011

Hi,

In this blog, I will publish VHDL models of different kind and usage.

I'll start with a simple block, that I hope to need in near future.

MCP3201 is 12-bit A/D converter, with semi-differential input and 100 ksps rate.

So here we go, more details in following posts...

$ ghdl --pp-html ic_mcp3201.vhdl >ic_mcp3201.vhdl.html


1 library ieee;
2 use ieee.std_logic_1164.all;
3 use ieee.numeric_std.all;
4 use ieee.math_real.all;
5
6 entity ic_mcp3201 is
7 port(
8 in_p_in: in real;
9 in_n_in: in real;
10 vref_in: in real;
11 vdd_in: in real := 5.0;
12 clk_in: in std_logic;
13 cs_in: in std_logic;
14 dout_out: out std_logic
15 );
16 end;
17
18 architecture behavioral of ic_mcp3201 is
19 constant tsucs_min: time := 100 ns;
20 constant ten_min: time := 0 ns;
21 constant ten_max: time := 200 ns;
22 constant tdo_min: time := 0 ns;
23 constant tdo_max: time := 200 ns;
24 constant thi_min: time := 312 ns;
25 constant tlo_min: time := 312 ns;
26 constant tr_min: time := 0 ns;
27 constant tr_max: time := 100 ns;
28 constant tf_min: time := 0 ns;
29 constant tf_max: time := 100 ns;
30 constant tdis_min: time := 0 ns;
31 constant tdis_max: time := 100 ns;
32 constant tcsh_min: time := 625 ns;
33
34 signal cs: std_logic;
35 signal clk: std_logic;
36
37 signal sh_active: std_logic;
38 signal v_c_sample: real := 0.0; -- Sample capacitor value.
39 signal ad_data: unsigned(11 downto 0);
40 signal dout_1: std_logic;
41 begin
42 cs <= to_x01(cs_in);
43 clk <= to_x01(clk_in);
44
45 SH_in: process(in_p_in, in_n_in, v_c_sample, sh_active)
46 constant r_res: real := 1.0e3;
47 constant c_cap: real := 20.0e-12;
48 constant resolution: real := 1.0/(2.0**12); -- 1.0 LSB.
49 variable v_res: real;
50 variable i_res: real;
51 variable delay: real;
52 variable t_delay: time;
53 variable v_in: real;
54 variable v_next: real;
55 variable res: real;
56 variable v_prev: real;
57 variable tolog: real;
58 begin
59 v_in := in_p_in - in_n_in;
60 v_prev := realmax(0.0,v_c_sample);
61 v_prev := realmin(vref_in,v_prev);
62 if false then
63 if sh_active = '1' then
64 v_c_sample <= v_in;
65 end if;
66 elsif sh_active = '1' then
67 res := vref_in*resolution;
68 tolog := (v_in-v_prev)/(v_in-v_prev-res);
69 if tolog>1.0+1.0e-12 then
70 delay := r_res*c_cap*log(tolog);
71 else
72 delay := 1.0;
73 end if;
74 delay := realmax(1.0e-12, delay);
75 delay := realmin(1.0, delay);
76 t_delay := delay * 1 sec;
77 v_next := v_prev + (v_in-v_prev)*(1.0-exp(-delay/(r_res*c_cap)));
78 v_next := realmax(0.0, v_next);
79 v_next := realmin(vref_in, v_next);
80 v_c_sample <= v_next after t_delay;
81 end if;
82 end process;
83
84 process(v_c_sample, vref_in)
85 variable r: real;
86 variable i: integer;
87 begin
88 r := v_c_sample/vref_in*4096.0;
89 r := realmin(r, 4095.0);
90 r := realmax(r, 0.0);
91 i := integer(round(r));
92 ad_data <= to_unsigned(i,12);
93 end process;
94
95 logic: process
96 variable i: integer;
97 begin
98 dout_1 <= 'Z';
99 sh_active <= '0';
100 wait until falling_edge(cs_in);
101 wait until rising_edge(clk_in) or to_x01(cs_in) /= '0';
102 if to_x01(cs_in) = '0' then
103 sh_active <= '1';
104 wait until rising_edge(clk_in) or to_x01(cs_in) /= '0';
105 if to_x01(cs_in) = '0' then
106 wait until falling_edge(clk_in) or to_x01(cs_in) /= '0';
107 sh_active <= '0';
108 if to_x01(cs_in) = '0' then
109 dout_1 <= 'X' after ten_min, '0' after ten_max;
110 for i in 11 downto 0 loop
111 wait until falling_edge(clk_in) or to_x01(cs_in) /= '0';
112 exit when to_x01(cs_in) /= '0';
113 dout_1 <= 'X' after tdo_min, ad_data(i) after tdo_max;
114 end loop;
115 for i in 1 to 11 loop
116 exit when to_x01(cs_in) /= '0';
117 wait until falling_edge(clk_in) or to_x01(cs_in) /= '0';
118 exit when to_x01(cs_in) /= '0';
119 dout_1 <= 'X' after tdo_min, ad_data(i) after tdo_max;
120 end loop;
121 loop
122 exit when to_x01(cs_in) /= '0';
123 wait until falling_edge(clk_in) or to_x01(cs_in) /= '0';
124 exit when to_x01(cs_in) /= '0';
125 dout_1 <= 'X' after tdo_min, '0' after tdo_max;
126 end loop;
127 end if;
128 end if;
129 end if;
130 end process;
131
132 dout_driver: process(dout_1, cs_in)
133 begin
134 if to_x01(cs_in) = 'X' then
135 dout_out <= 'X';
136 elsif to_x01(cs_in) = '1' then
137 dout_out <= 'X' after tdis_min, 'Z' after tdis_max;
138 else
139 dout_out <= dout_1;
140 end if;
141 end process;
142
143 check_tlo_thi: process(cs, clk)
144 variable prev_event: time := 0 ns;
145 begin
146 if cs /= '1' then
147 if rising_edge(clk) then
148 assert now-prev_event >= tlo_min report "TLO failure" severity error;
149 elsif falling_edge(clk) then
150 assert now-prev_event >= thi_min report "TLO failure" severity error;
151 end if;
152 end if;
153 if clk'event then
154 prev_event := now;
155 end if;
156 end process;
157
158 check_tsucs: process(cs, clk)
159 variable cs_fall_t: time := 0 ns;
160 variable clk_rise_t: time := 0 ns;
161 begin
162 if falling_edge(cs) then
163 cs_fall_t := now;
164 end if;
165 if cs /= '1' and rising_edge(clk) then
166 clk_rise_t := now;
167 assert clk_rise_t - cs_fall_t >= tsucs_min report "TSUCS failure" severity failure;
168 end if;
169 end process;
170
171 check_tcsh: process(cs)
172 variable prev_event: time := 0 ns;
173 begin
174 if falling_edge(cs) then
175 assert now-prev_event >= tcsh_min report "TCSH failure" severity failure;
176 end if;
177 if cs'event then
178 prev_event := now;
179 end if;
180 end process;
181 end;
182
183 library ieee;
184 use ieee.std_logic_1164.all;
185 use ieee.numeric_std.all;
186
187
188 entity tb_ic_mcp3201 is
189 end;
190
191 architecture tb of tb_ic_mcp3201 is
192 signal in_p: real;
193 signal in_n: real;
194 signal vref: real := 5.0;
195 signal vdd: real := 5.0;
196 signal clk: std_logic;
197 signal cs: std_logic;
198 signal dout: std_logic;
199
200 begin
201 clk_driver: process
202 begin
203 clk <= '0';
204 wait for 0.35 us;
205 clk <= '1';
206 wait for 0.4 us;
207 end process;
208
209 process
210 begin
211 in_n <= 0.0;
212 in_p <= 0.0;
213 vref <= 5.0;
214 vdd <= 5.0;
215 cs <= '1';
216 wait for 1 us;
217 cs <= '0';
218 wait for 1 us;
219 cs <= '1';
220 wait for 625 ns;
221 cs <= '0';
222 wait for 10 ns;
223 cs <= '1';
224 loop
225 wait for 10 us;
226 wait until falling_edge(clk);
227 cs <= '0';
228 wait for 40 us;
229 cs <= '1';
230 in_p <= in_p + 0.03;
231 end loop;
232 end process;
233
234 DUT: entity work.ic_mcp3201
235 port map(
236 in_p_in => in_p,
237 in_n_in => in_n,
238 vref_in => vref,
239 vdd_in => vdd,
240 clk_in => clk,
241 cs_in => cs,
242 dout_out => dout
243 );
244 end;
245