1 |
2 |
DavidRAMBA |
--=============================================================================
|
2 |
|
|
-- TITRE : AUTOBAUD
|
3 |
|
|
-- DESCRIPTION :
|
4 |
|
|
-- Détermine le baudrate utilisé pour la communication
|
5 |
|
|
-- Fourni un diviseur de l'horloge système correspondant à la durée d'un bit
|
6 |
|
|
-- Principe : mesure le temps entre 2 fronts opposés sur rx1 et rx2 et
|
7 |
|
|
-- conserve le minimum. Ce temps donne une indication de la durée du bit.
|
8 |
|
|
-- Il est utilisé pour déterminer une des 8 valeurs discrètes de communication
|
9 |
|
|
|
10 |
|
|
-- FICHIER : autobaud.vhd
|
11 |
|
|
--=============================================================================
|
12 |
|
|
-- CREATION
|
13 |
|
|
-- DATE AUTEUR PROJET REVISION
|
14 |
|
|
-- 10/04/2014 DRA SATURN V1.0
|
15 |
|
|
--=============================================================================
|
16 |
|
|
-- HISTORIQUE DES MODIFICATIONS :
|
17 |
|
|
-- DATE AUTEUR PROJET REVISION
|
18 |
|
|
--=============================================================================
|
19 |
|
|
|
20 |
|
|
LIBRARY IEEE;
|
21 |
|
|
USE IEEE.STD_LOGIC_1164.ALL;
|
22 |
|
|
USE IEEE.STD_LOGIC_ARITH.ALL;
|
23 |
|
|
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
|
24 |
|
|
|
25 |
|
|
ENTITY autobaud IS
|
26 |
|
|
PORT (
|
27 |
|
|
-- Ports système
|
28 |
|
|
clk_sys : IN STD_LOGIC; -- Clock système
|
29 |
|
|
rst_n : IN STD_LOGIC; -- Reset général système
|
30 |
|
|
|
31 |
|
|
-- Interfaces série
|
32 |
|
|
rx1 : IN STD_LOGIC; -- Réception série port 1
|
33 |
|
|
rx2 : IN STD_LOGIC; -- Réception série port 2
|
34 |
|
|
|
35 |
|
|
-- Interface avec les modules d'analyse Layer 2
|
36 |
|
|
val_rx1 : IN STD_LOGIC; -- 1 caractère reçu sur le port 1
|
37 |
|
|
eof1 : IN STD_LOGIC; -- Fin de trame port 1
|
38 |
|
|
dat_rx1 : IN STD_LOGIC_VECTOR(7 DOWNTO 0); -- Donnée reçue sur RX1
|
39 |
|
|
l2_ok1 : IN STD_LOGIC; -- Flag de trame correcte port 1
|
40 |
|
|
val_rx2 : IN STD_LOGIC; -- 1 caractère reçu sur le port 2
|
41 |
|
|
eof2 : IN STD_LOGIC; -- Fin de trame port 2
|
42 |
|
|
dat_rx2 : IN STD_LOGIC_VECTOR(7 DOWNTO 0); -- Donnée reçue sur RX1
|
43 |
|
|
l2_ok2 : IN STD_LOGIC; -- Flag de trame correcte port 2
|
44 |
|
|
|
45 |
|
|
-- Sorties du module
|
46 |
|
|
tc_divclk : OUT STD_LOGIC_VECTOR (10 DOWNTO 0); -- Diviseur d'horloge système. Un bit dure tc_dibclk+1 cycles de clk_sys
|
47 |
|
|
baud_locked : OUT STD_LOGIC -- Indique que l'auto baudrate est locké
|
48 |
|
|
);
|
49 |
|
|
END autobaud;
|
50 |
|
|
|
51 |
|
|
ARCHITECTURE rtl of autobaud is
|
52 |
|
|
-- Ne peuvent pas être traitée en générique car le dernier process est optimisé pour freq_clk = 96
|
53 |
|
|
CONSTANT freq_clk : INTEGER := 96; -- Fréquence de l'horloge système en MHz
|
54 |
|
|
CONSTANT nbbit : INTEGER := 11; -- Nombre de bits nécessaires pour mesurer 20µs à freq_clk
|
55 |
|
|
|
56 |
|
|
SIGNAL rx_r1 : STD_LOGIC; -- Délai pour détecter les fronts de rx1
|
57 |
|
|
SIGNAL front_des_rx_c1 : STD_LOGIC; -- 1 pulse de clk_sys sur front descendant de rx1
|
58 |
|
|
SIGNAL front_mon_rx_c1 : STD_LOGIC; -- 1 pulse de clk_sys sur front montant de rx1
|
59 |
|
|
SIGNAL rx_encours1 : STD_LOGIC; -- Indique qu'on a déjà détecté au moins 1 front sur rx1
|
60 |
|
|
SIGNAL divclk1 : STD_LOGIC_VECTOR(nbbit-1 downto 0); -- mesure le nombre de clk_sys sur rx1
|
61 |
|
|
SIGNAL cpt_car1 : STD_LOGIC_VECTOR(9 downto 0); -- nb car reçu sur rx1 depuis la mise à jour du diviseur
|
62 |
|
|
-- lorsque l'algo a convergé, compte les trames mauvaises
|
63 |
|
|
SIGNAL rx_r2 : STD_LOGIC; -- Délai pour détecter les fronts de rx2
|
64 |
|
|
SIGNAL front_des_rx_c2 : STD_LOGIC; -- 1 pulse de clk_sys sur front descendant de rx2
|
65 |
|
|
SIGNAL front_mon_rx_c2 : STD_LOGIC; -- 1 pulse de clk_sys sur front montant de rx2
|
66 |
|
|
SIGNAL rx_encours2 : STD_LOGIC; -- Indique qu'on a déjà détecté au moins 1 front sur rx2
|
67 |
|
|
SIGNAL divclk2 : STD_LOGIC_VECTOR(nbbit-1 downto 0); -- mesure le nombre de clk_sys sur rx2
|
68 |
|
|
SIGNAL cpt_car2 : STD_LOGIC_VECTOR(9 downto 0); -- nb car reçu sur rx2 depuis la mise à jour du diviseur
|
69 |
|
|
SIGNAL memmin_div : STD_LOGIC_VECTOR(nbbit-1 downto 0); -- mémorise la plus petite durée mesurée sur rx1 ou rx2
|
70 |
|
|
SIGNAL mux_divclk_c : STD_LOGIC_VECTOR(nbbit-1 downto 0); -- pour muxer divclk1 et divclk2 avant de comparer à memmin_div
|
71 |
|
|
SIGNAL baud_locked_buf : STD_LOGIC; -- 1 indique que le baudrate est figé.
|
72 |
|
|
|
73 |
|
|
SIGNAL cpt_fanion1 : STD_LOGIC_VECTOR(2 DOWNTO 0); -- Compte le nombre de fanions consécutifs sur RX1
|
74 |
|
|
SIGNAL cpt_fanion2 : STD_LOGIC_VECTOR(2 DOWNTO 0); -- Compte le nombre de fanions consécutifs sur RX2
|
75 |
|
|
|
76 |
|
|
BEGIN
|
77 |
|
|
--------------------------------------------
|
78 |
|
|
-- Détection des fronts montants et descendants sur rx1
|
79 |
|
|
--------------------------------------------
|
80 |
|
|
front_rx1 : PROCESS(clk_sys, rst_n)
|
81 |
|
|
BEGIN
|
82 |
|
|
IF (rst_n = '0') THEN
|
83 |
|
|
rx_r1 <= '1';
|
84 |
|
|
ELSIF (clk_sys'EVENT and clk_sys = '1') THEN
|
85 |
|
|
rx_r1 <= rx1;
|
86 |
|
|
END IF;
|
87 |
|
|
END PROCESS;
|
88 |
|
|
front_des_rx_c1 <= NOT(rx1) AND rx_r1;
|
89 |
|
|
front_mon_rx_c1 <= rx1 AND NOT(rx_r1);
|
90 |
|
|
|
91 |
|
|
--------------------------------------------
|
92 |
|
|
-- Mesure la durée entre 2 front opposés sur rx1
|
93 |
|
|
--------------------------------------------
|
94 |
|
|
mes_bit_1 : PROCESS(clk_sys, rst_n)
|
95 |
|
|
BEGIN
|
96 |
|
|
IF (rst_n = '0') THEN
|
97 |
|
|
divclk1 <= (others => '0');
|
98 |
|
|
rx_encours1 <= '0';
|
99 |
|
|
ELSIF (clk_sys'EVENT and clk_sys = '1') THEN
|
100 |
|
|
IF (baud_locked_buf = '0') THEN
|
101 |
|
|
-- On ne mesure que si l'algo n'a pas encore convergé
|
102 |
|
|
IF (front_des_rx_c1 = '1' OR front_mon_rx_c1 = '1') THEN
|
103 |
|
|
-- A chaque front détecté (montant ou descendant)
|
104 |
|
|
rx_encours1 <= '1'; -- Pour se souvenir qu'on a déjà vu un front
|
105 |
|
|
divclk1 <= (others => '0');-- On initialise le comptage de cycle
|
106 |
|
|
ELSIF (rx_encours1 = '1') THEN
|
107 |
|
|
-- Si on a déjà détecté un front (i.e. le compteur a été correctement initialisé)
|
108 |
|
|
IF (divclk1 /= SXT("11", nbbit)) THEN
|
109 |
|
|
-- On compte le nombre de cycles depuis le front précédent
|
110 |
|
|
divclk1 <= divclk1 + 1;
|
111 |
|
|
ELSE
|
112 |
|
|
-- Si le compteur atteind son max, on recommence l'algo au début
|
113 |
|
|
rx_encours1 <= '0';
|
114 |
|
|
END IF;
|
115 |
|
|
END IF;
|
116 |
|
|
ELSE
|
117 |
|
|
rx_encours1 <= '0';
|
118 |
|
|
END IF;
|
119 |
|
|
END IF;
|
120 |
|
|
END PROCESS;
|
121 |
|
|
|
122 |
|
|
--------------------------------------------
|
123 |
|
|
-- Détection des fronts montants et descendants sur rx2
|
124 |
|
|
--------------------------------------------
|
125 |
|
|
front_rx2 : PROCESS(clk_sys, rst_n)
|
126 |
|
|
BEGIN
|
127 |
|
|
IF (rst_n = '0') THEN
|
128 |
|
|
rx_r2 <= '1';
|
129 |
|
|
ELSIF (clk_sys'EVENT and clk_sys = '1') THEN
|
130 |
|
|
rx_r2 <= rx2;
|
131 |
|
|
END IF;
|
132 |
|
|
END PROCESS;
|
133 |
|
|
front_des_rx_c2 <= NOT(rx2) AND rx_r2;
|
134 |
|
|
front_mon_rx_c2 <= rx2 AND NOT(rx_r2);
|
135 |
|
|
|
136 |
|
|
--------------------------------------------
|
137 |
|
|
-- Mesure la durée entre 2 front opposés sur rx2
|
138 |
|
|
--------------------------------------------
|
139 |
|
|
mes_bit_2 : PROCESS(clk_sys, rst_n)
|
140 |
|
|
BEGIN
|
141 |
|
|
IF (rst_n = '0') THEN
|
142 |
|
|
divclk2 <= (others => '0');
|
143 |
|
|
rx_encours2 <= '0';
|
144 |
|
|
ELSIF (clk_sys'EVENT and clk_sys = '1') THEN
|
145 |
|
|
IF (baud_locked_buf = '0') THEN
|
146 |
|
|
IF (front_des_rx_c2 = '1' OR front_mon_rx_c2 = '1') THEN
|
147 |
|
|
rx_encours2 <= '1';
|
148 |
|
|
divclk2 <= (others => '0');
|
149 |
|
|
ELSIF (rx_encours2 = '1') THEN
|
150 |
|
|
IF (divclk2 /= SXT("11", nbbit)) THEN
|
151 |
|
|
divclk2 <= divclk2 + 1;
|
152 |
|
|
ELSE
|
153 |
|
|
rx_encours2 <= '0';
|
154 |
|
|
END IF;
|
155 |
|
|
END IF;
|
156 |
|
|
ELSE
|
157 |
|
|
rx_encours2 <= '0';
|
158 |
|
|
END IF;
|
159 |
|
|
END IF;
|
160 |
|
|
END PROCESS;
|
161 |
|
|
|
162 |
|
|
--------------------------------------------
|
163 |
|
|
-- Mémorise le minimum mesuré sur rx1 ou rx2
|
164 |
|
|
--------------------------------------------
|
165 |
|
|
-- On donne arbitrairement la priorité à rx1. Sur un front de rx1 on le traite, sinon on traite rx2
|
166 |
|
|
mux_divclk_c <= divclk1 WHEN (front_mon_rx_c1 = '1' OR front_des_rx_c1 = '1') ELSE divclk2;
|
167 |
|
|
|
168 |
|
|
compare : PROCESS(clk_sys, rst_n)
|
169 |
|
|
BEGIN
|
170 |
|
|
IF (rst_n = '0') THEN
|
171 |
|
|
memmin_div <= (others => '1');
|
172 |
|
|
cpt_car1 <= (others => '0');
|
173 |
|
|
cpt_car2 <= (others => '0');
|
174 |
|
|
cpt_fanion1 <= (OTHERS => '0');
|
175 |
|
|
cpt_fanion2 <= (OTHERS => '0');
|
176 |
|
|
baud_locked_buf <= '0';
|
177 |
|
|
ELSIF (clk_sys'EVENT and clk_sys = '1') THEN
|
178 |
|
|
IF (baud_locked_buf = '0') THEN
|
179 |
|
|
-- Si l'algo n'est pas fini
|
180 |
|
|
IF ((((front_des_rx_c1 = '1' OR front_mon_rx_c1 = '1') and rx_encours1 = '1') OR
|
181 |
|
|
((front_des_rx_c2 = '1' OR front_mon_rx_c2 = '1') and rx_encours2 = '1')) AND
|
182 |
|
|
(('0' & mux_divclk_c) < ('0' & memmin_div))) THEN
|
183 |
|
|
-- Si on a un front sur rx1 ou rx2, et que ce n'est pas le premier (i.e. on peut
|
184 |
|
|
-- utiliser la valeur du compteur), Et si cette valeur est plus petite que la valeur
|
185 |
|
|
-- mémorisée
|
186 |
|
|
memmin_div <= mux_divclk_c; -- on met à jour avec le nouveau compteur
|
187 |
|
|
cpt_car1 <= (others => '0'); -- on réinitialise les ompteurs de caractères
|
188 |
|
|
cpt_car2 <= (others => '0');
|
189 |
|
|
ELSE
|
190 |
|
|
-- En dehors des fronts, on compte les octets reçus
|
191 |
|
|
IF (cpt_car1 = "1111111111") OR (cpt_car2 = "1111111111") THEN
|
192 |
|
|
-- Si on reçu 1023 caractère sur une interface depuis la dernière mise à jour
|
193 |
|
|
-- et que l'algo n'est pas fini
|
194 |
|
|
memmin_div <= (others => '1'); -- on recommence au départ en prenant la valeur max
|
195 |
|
|
ELSE
|
196 |
|
|
IF (val_rx1 = '1') THEN -- on compte chaque caratère reçu par le module de réception
|
197 |
|
|
cpt_car1 <= cpt_car1 + 1;
|
198 |
|
|
END IF;
|
199 |
|
|
IF (val_rx2 = '1') THEN
|
200 |
|
|
cpt_car2 <= cpt_car2 + 1;
|
201 |
|
|
END IF;
|
202 |
|
|
END IF;
|
203 |
|
|
END IF;
|
204 |
|
|
IF (val_rx1 = '1') THEN
|
205 |
|
|
-- Si on a reçu un caractère sur RX1, on comtpe les fanions succesifs
|
206 |
|
|
IF (dat_rx1 = x"7E" OR dat_rx1 = x"F9") THEN
|
207 |
|
|
-- On teste les F9 aussi car une succession de 7E mal débutée peut être vu comme des F9
|
208 |
|
|
cpt_fanion1 <= cpt_fanion1 + 1;
|
209 |
|
|
ELSE
|
210 |
|
|
cpt_fanion1 <= (OTHERS => '0');
|
211 |
|
|
END IF;
|
212 |
|
|
END IF;
|
213 |
|
|
IF (val_rx2 = '1') THEN
|
214 |
|
|
IF (dat_rx2 = x"7E" OR dat_rx2 = x"F9") THEN
|
215 |
|
|
cpt_fanion2 <= cpt_fanion2 + 1;
|
216 |
|
|
ELSE
|
217 |
|
|
cpt_fanion2 <= (OTHERS => '0');
|
218 |
|
|
END IF;
|
219 |
|
|
END IF;
|
220 |
|
|
IF (eof1 = '1' AND l2_ok1 = '1') OR
|
221 |
|
|
(eof2 = '1' AND l2_ok2 = '1') OR
|
222 |
|
|
(cpt_fanion1 = "111") OR
|
223 |
|
|
(cpt_fanion2 = "111") THEN
|
224 |
|
|
-- On considère que l'algo a convergé lorsque une trame a été reçue correcte (CRC compris)
|
225 |
|
|
-- ou bien qu'on a reçu 7 fanions consécutifs
|
226 |
|
|
baud_locked_buf <= '1';
|
227 |
|
|
cpt_car1 <= (others => '0');
|
228 |
|
|
END IF;
|
229 |
|
|
ELSE
|
230 |
|
|
-- Si on est en mode locké
|
231 |
|
|
IF ((val_rx1 = '1' AND dat_rx1 /= x"7E" AND dat_rx1 /= x"F9") OR
|
232 |
|
|
(val_rx2 = '1' AND dat_rx2 /= x"7E" AND dat_rx2 /= x"F9")) THEN
|
233 |
|
|
-- Si on reçoit un caractère différent du fanion
|
234 |
|
|
cpt_car1 <= cpt_car1 + 1;
|
235 |
|
|
IF (cpt_car1 = "0111111111") THEN
|
236 |
|
|
-- Si on a reçu 511 caractères sans avoir vu un seule trame correcte
|
237 |
|
|
baud_locked_buf <= '0'; -- On réinitialise la recherche
|
238 |
|
|
memmin_div <= (others => '1');
|
239 |
|
|
cpt_car1 <= (others => '0');
|
240 |
|
|
cpt_car2 <= (others => '0');
|
241 |
|
|
cpt_fanion1 <= (OTHERS => '0');
|
242 |
|
|
cpt_fanion2 <= (OTHERS => '0');
|
243 |
|
|
END IF;
|
244 |
|
|
ELSIF (eof1 = '1' AND l2_ok1 = '1') OR
|
245 |
|
|
(eof2 = '1' AND l2_ok2 = '1') THEN
|
246 |
|
|
-- A chaque trame bonne d'un coté ou de l'autre
|
247 |
|
|
cpt_car1 <= (others => '0'); --on considère que l'algo est bon et on reste locké
|
248 |
|
|
END IF;
|
249 |
|
|
END IF;
|
250 |
|
|
END IF;
|
251 |
|
|
END PROCESS;
|
252 |
|
|
baud_locked <= baud_locked_buf;
|
253 |
|
|
|
254 |
|
|
--------------------------------------------
|
255 |
|
|
-- Retourne une valeur quantifiée de diviseur d'horloge correspondant à la durée d'un bit
|
256 |
|
|
-- en fonction de la mesure effectuée
|
257 |
|
|
-- Le process est optimisé pour freq_clk = 96MHz. Il faut modifier les comparaison si différent
|
258 |
|
|
--------------------------------------------
|
259 |
|
|
selectbaud : PROCESS(clk_sys, rst_n)
|
260 |
|
|
BEGIN
|
261 |
|
|
IF (rst_n = '0') THEN
|
262 |
|
|
tc_divclk <= CONV_STD_LOGIC_VECTOR(freq_clk*1000/50-1, tc_divclk'length);
|
263 |
|
|
ELSIF (clk_sys'EVENT and clk_sys = '1') THEN
|
264 |
|
|
IF (memmin_div(10) = '1') THEN
|
265 |
|
|
-- Si la mesure est entre 1024 et 2047 clk_sys (nominal : 1920), on est à 50kbit/s
|
266 |
|
|
tc_divclk <= CONV_STD_LOGIC_VECTOR(freq_clk*1000/50-1, tc_divclk'length);
|
267 |
|
|
ELSIF (memmin_div(9) = '1') THEN
|
268 |
|
|
-- Si la mesure est entre 512 et 1023 clk_sys (nominal : 960) , on est à 100kbit/s
|
269 |
|
|
tc_divclk <= CONV_STD_LOGIC_VECTOR(freq_clk*1000/100-1, tc_divclk'length);
|
270 |
|
|
ELSIF (memmin_div(8) = '1') THEN
|
271 |
|
|
-- Si la mesure est entre 256 et 511 clk_sys (nominal : 480), on est à 200kbit/s
|
272 |
|
|
tc_divclk <= CONV_STD_LOGIC_VECTOR(freq_clk*1000/200-1, tc_divclk'length);
|
273 |
|
|
ELSIF (memmin_div(7) = '1') THEN
|
274 |
|
|
-- Si la mesure est entre 128 et 255 clk_sys (nominal : 192), on est à 500kbit/s
|
275 |
|
|
tc_divclk <= CONV_STD_LOGIC_VECTOR(freq_clk*1000/500-1, tc_divclk'length);
|
276 |
|
|
ELSIF (memmin_div(6) = '1') THEN
|
277 |
|
|
-- Si la mesure est entre 64 et 127 clk_sys (nominal : 96), on est à 1Mbit/s
|
278 |
|
|
tc_divclk <= CONV_STD_LOGIC_VECTOR(freq_clk*1000/1000-1, tc_divclk'length);
|
279 |
|
|
ELSIF (memmin_div(5) = '1') THEN
|
280 |
|
|
-- Si la mesure est entre 32 et 63 clk_sys (nominal : 48), on est à 2Mbit/s
|
281 |
|
|
tc_divclk <= CONV_STD_LOGIC_VECTOR(freq_clk*1000/2000-1, tc_divclk'length);
|
282 |
|
|
ELSIF (memmin_div(4) = '1' OR
|
283 |
|
|
memmin_div(3 downto 2) = "11") THEN
|
284 |
|
|
-- Si la mesure est entre 12 et 31 clk_sys (nominal : 16), on est à 6Mbit/s
|
285 |
|
|
tc_divclk <= CONV_STD_LOGIC_VECTOR(freq_clk*1000/6000-1, tc_divclk'length);
|
286 |
|
|
ELSE
|
287 |
|
|
-- Si la mesure est entre 0 et 11 clk_sys (nominal : 8), on est à 12Mbit/s
|
288 |
|
|
tc_divclk <= CONV_STD_LOGIC_VECTOR(freq_clk*1000/12000-1, tc_divclk'length);
|
289 |
|
|
END IF;
|
290 |
|
|
END IF;
|
291 |
|
|
END PROCESS;
|
292 |
|
|
|
293 |
|
|
END rtl;
|
294 |
|
|
|