OpenCores
URL https://opencores.org/ocsvn/saturn/saturn/trunk

Subversion Repositories saturn

[/] [saturn/] [trunk/] [IPCommunication/] [autobaud.vhd] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
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
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.