Forum: FPGA, VHDL & Co. MII Synchronisierung, Ethernet


von Tobias P. (hubertus)


Angehängte Dateien:

Lesenswert?

Hallo Forum,

ich versuche, einem Ethernet PHY ein paar Pakete zu entlocken.
Dazu habe ich folgendes gemacht. Von

http://www.ece.ualberta.ca/~elliott/ee552/studentAppNotes/2001_w/interfacing/ethernet_mii/eth_mii.html

habe ich die Datei sub_sync.vhdl übernommen. Mit dieser werden die 
Signale vom PHY, die auf dessen TXCLK und RXCLK synchronisiert sind, auf 
den FPGA-Takt synchronisiert.

Mein FPGA arbeitet mit 50 MHz, der RXCLK vom PHY ist 25 MHz. Die 
Synchronisierung funktioniert ansich sehr zuverlässig, auf dem Logic 
Analyser sieht alles schön plausibel aus.

Um dann Daten zu empfangen, habe ich folgenden Code geschrieben:
1
library ieee;
2
use ieee.std_logic_1164.all;
3
use ieee.numeric_std.all;
4
5
--------------------------------------------------------------------------------
6
7
entity mii_inout is
8
  generic(
9
    PREAMBLE_LEN : natural := 7;
10
    IPGT_CLOCKS : natural := 48
11
  );
12
  port(
13
    -- clocking and reset
14
    clk : in  std_logic;
15
    rst : in  std_logic;
16
17
    -- mii interface
18
    phy_txd   : out std_logic_vector(3 downto 0);
19
    phy_txerr : out std_logic;
20
    phy_txen  : out std_logic;
21
    phy_txclk : in std_logic;
22
    phy_rxd   : in std_logic_vector(3 downto 0);
23
    phy_rxdv  : in std_logic;
24
    phy_rxerr : in std_logic;
25
    phy_rxclk : in std_logic;
26
    
27
  -- byte stream interface
28
    rx_data_o : out std_logic_vector(7 downto 0);
29
    rx_stb_o  : out std_logic;
30
    rx_dv_o   : out std_logic;
31
    tx_data_i : in  std_logic_vector(7 downto 0);
32
    tx_en_i   : in  std_logic;
33
    tx_ack_o  : out std_logic;
34
    
35
    frame_start : out std_logic;
36
    frame_end : out std_logic
37
  );
38
end mii_inout;
39
40
--------------------------------------------------------------------------------
41
42
architecture rtl of mii_inout is
43
 
44
  component sub_sync is
45
    port(
46
    clk_in, clk_out:  in std_logic;
47
    data_in:          in std_logic_vector(3 downto 0);
48
    data_out:          out std_logic_vector(3 downto 0);
49
    dv_in:            in std_logic;
50
    dv_out:            out std_logic
51
    );
52
  end component;
53
  
54
  signal rxd : std_logic_vector(3 downto 0);
55
  signal rxdv : std_logic;
56
  signal txd : std_logic_vector(3 downto 0);
57
  signal txen : std_logic;
58
  
59
  type state_t is (idle, wa, data_lo, data_hi);
60
  signal rxstate, txstate : state_t;
61
  
62
  signal rx_buffer : std_logic_vector(7 downto 0);
63
  signal rxclk_sync : std_logic;
64
  signal txclk_sync : std_logic;
65
  
66
begin
67
68
  rxsync : component sub_sync
69
    port map(
70
      clk_in => phy_rxclk,
71
      clk_out => clk,
72
      data_in => phy_rxd,
73
      dv_in => phy_rxdv,
74
      data_out => rxd,
75
      dv_out => rxdv
76
    );
77
  
78
  txsync : component sub_sync
79
    port map(
80
      clk_in => clk,
81
      clk_out => phy_txclk,
82
      data_in => txd,
83
      dv_in => txen,
84
      data_out => phy_txd,
85
      dv_out => phy_txen
86
    );
87
    
88
  -- txerr is not used
89
  phy_txerr <= '0';
90
  
91
  -- for test only
92
  txd <= (others => '0');
93
  txen <= '0';
94
  
95
  process(clk)
96
  begin
97
    if rising_edge(clk) then
98
      rxclk_sync <= phy_rxclk;
99
      txclk_sync <= phy_txclk;
100
    end if;
101
  end process;
102
  
103
  -- receiver process
104
  process(rst, clk)
105
  begin
106
    if rst = '1' then
107
      rxstate <= idle;
108
      rx_buffer <= (others => '0');
109
      
110
    elsif rising_edge(clk) and (rxclk_sync = '0') then
111
    
112
    rx_stb_o <= '0';
113
    frame_start <= '0';
114
    
115
      case rxstate is
116
        when idle =>
117
          if rxdv = '1' then
118
            rxstate <= wa;
119
            rx_buffer <= (others => '0');
120
          end if;
121
          
122
        when wa =>
123
          rxstate <= data_lo;
124
125
        when data_lo =>
126
          frame_start <= '1';
127
          if rxdv = '0' then
128
            rxstate <= idle;
129
          else
130
            rx_buffer(7 downto 4) <= rxd;
131
            rxstate <= data_hi;
132
          end if;
133
          
134
          
135
        when data_hi =>
136
          frame_start <= '1';
137
          if rxdv = '0' then
138
            rxstate <= idle;
139
          else
140
            rx_buffer(3 downto 0) <= rxd;
141
            rxstate <= data_lo;
142
            rx_stb_o <= '1';
143
            rx_data_o <= rx_buffer;
144
          end if;
145
          
146
 
147
          
148
      end case;
149
    end if;
150
  end process;
151
  
152
  
153
  -- transmitter process
154
  process(rst, clk)
155
  begin
156
    if rst = '1' then
157
      null;
158
    elsif rising_edge(clk) and (txclk_sync = '0') then
159
null;
160
    end if;
161
  end process;
162
end rtl;

Mit dem einen Prozess synchronisiere ich die Taktsignale ein, mit dem 
receiver Prozess versuche ich ein Paket zu empfangen und es als 
parallele 8 Bit Daten an ein paar IO-Pins auszugeben. Das Signal 
tx_stb_o soll auf 1 gehen, sobald 8 neue Datenbits vorhanden sind.

Das Signal frame_start soll so lange auf 1 sein, wie ein Frame 
übertragen wird.

Wie ihr im angehängten Bild sehen könnt, funktioniert es prinzipiell. 
Ich sende einen Ethernet Frame an den FPGA, der Als Ziel-MAC 
FF:FF:FF:FF:FF:FF hat und als Quell-Mac 00:16:35:ac:4b:ae. Ansich würde 
ich erwarten, dass ich auf dem Logic Analyser nun zuerst die Präambel 
sehen kann, 55 55 55 , ... D5, und dann die Ziel- und Quell-MAC.... 
Ansatzweise stimmt es, aber eben nicht ganz. Zu beginn sieht man ein F0, 
das ist definitiv falsch, woher kommt die 0? die bringt alles 
durcheinander. Wenn die eine 0 zu Beginn nicht wäre, dann würden 
wenigstens schon mal die richtigen Nibbles beieinander sein. Kann mir 
einer auf die Sprünge helfen, was ich anpassen könnte? Ich wäre sehr 
froh :-)

Vielen Dank.
Gruss Tobias.

von Holger H. (holger-h-hennef) Benutzerseite


Angehängte Dateien:

Lesenswert?

Tobias Plüss schrieb:
> Kann mir
> einer auf die Sprünge helfen, was ich anpassen könnte? Ich wäre sehr
> froh :-)

Um das 4Bit Nibble-Port RXD[3:0]
via RX_CLK sicher einzusychroiesieren sind minimal 65 @MHz nötig.

Zitat: Aus meinem SPARTAN 3E USER GUIDE ug230.pdf
############################################################
Ethernet MAC IP Cores for the Spartan-3E Starter Kit Board
The Ethernet MAC core requires design constraints to meet the required 
performance.
Refer to the OPB Ethernet MAC data sheet (v1.02) for details. The OPB 
bus clock frequency
must be 65 MHz or higher for 100 Mbps Ethernet operations and 6.5 MHz or 
faster for
10 Mbps Ethernet operations.

RX_CLK sample 2 times via sys_clk 50MHz
Anhang: PHY 83c185.pdf
Anhang: Bild: phy_rec_1dv.PNG
############
Viel Erfolg.
Gruss Holger.


###################################
SMSC  LAN83C185 10/100 Ethernet PHY
###################################

von Tobias P. (hubertus)


Lesenswert?

Nein. Meine Bits werden ja richtig erkannt. Dass das Low- und das 
High-Nibble vertauscht sind, liegt halt daran dass ich sie in der 
falschen Reihenfolge speichere. Das kann man einfach tauschen.
Was aber definitiv falsch ist, ist, dass das erste Nibble immer 0 ist. 
Das kann nicht sein. Es liegt garantiert an meiner FSM, die noch irgend 
einen Zustandsübergang hat, der falsch ist. Aber ich steh da grade auf 
dem Schlauch... :-(

von Holger H. (holger-h-hennef) Benutzerseite


Angehängte Dateien:

Lesenswert?

Anhang: phy_rec_1dv.PNG.
Mit dem Data-Valid Signal.

Gruss Holger.

von Tobias P. (hubertus)


Lesenswert?

Hallo Holger
ja genau so mache ich das ja im Prinzip auch.
Meine Statemachine wird vom normalen Systemclock (50MHz) getaktet. Der 
RXCLK vom PHY dient als Clock Enable.
So, und nun startet die FSM im Zustand idle. Dort wird RXDV abgefragt, 
ob es 1 ist. Wenn ja, dann wird in den data_lo state gewechselt. dort 
wird das low nibble empfangen. Anschliessend wird das high nibble 
empfangen. Sollte so ja gehen. Aber eben, wenn ich dann die Nibbles 
zusammensetze, ist da was vertauscht... und ich frage mich weshalb.

Gruss!

von Holger H. (holger-h-hennef) Benutzerseite


Lesenswert?

Tobias Plüss schrieb:
> Was aber definitiv falsch ist, ist, dass das erste Nibble immer 0 ist.
> Das kann nicht sein.

Das Verhalten "erste Nibble" J/K ist einstellbar. 0 oder 1 ..
Steht da im Datenblatt vom SMSC  LAN83C185 10/100 Ethernet PHY.


Frage:
Was hast du den da für einen PHY ?


#####################################################
Wichtig ist Data_Valid mit in die FSM einbezogen wird.
Siehe Bild.
0x5 0x5 0xD ...
Nach den Nibble 0xD kommt das erste Data-Nibble.

Gruss Holger.

von Holger H. (holger-h-hennef) Benutzerseite


Angehängte Dateien:

Lesenswert?

Frage: Was hast du für einen PHY ?.
Anhang: phy_mode_1rd.PNG
Tobias Plüss schrieb:
> FF:FF:FF:FF:FF:FF hat und als Quell-Mac 00:16:35:ac:4b:ae. Ansich würde
> ich erwarten, dass ich auf dem Logic Analyser nun zuerst die Präambel
> sehen kann, 55 55 55 , ... D5, und dann die Ziel- und Quell-MAC....
> Ansatzweise stimmt es, aber eben nicht ganz. Zu beginn sieht man ein F0,
> das ist definitiv falsch, woher kommt die 0? die bringt alles
> durcheinander. Wenn die eine 0 zu Beginn nicht wäre, dann würden

> Zu beginn sieht man ein F0,
woher kommt die 0?
Der PHY-Buss geht von über in die Data-Phase.
Der Bus macht einen Turn-Around '(TA),


für einen @25Mkz RX_CLK.
Jetz soll man den RX_ERR Pin auswerten.
--> wait ..@RX_ERR Pin =  bool_monitor.!

 (  and (not RX_ERR[0] and RXDV[0] ) )
######################################
4_Bit_Data-Port. Vector-Order[3:0]. (MSB to LSB)
kann jetz gelesen werden.

4_Bit_Data-Port. Vector-Order[3:0]. (MSB to LSB)
Also noch der 'Nibble-Port 0x5 0x5 ..0xD .. für eine 'clk-Periode, d.h
Stufige-Umschaltung der FSM-PHY
 via j/K.._(Präambel+Data_Valid)-State .. auf (Data)-State.

bingo>.
Und somit kommt der Bus auf <|NULL> .

RX_ERR[0] ist ein Status-Monitor in dem Mode mit 100Mbit.
RX_ERR[0] reflektiert somit in der Bedingung: via Bus-transit-.0 1 0.

Gleichung_: im (Data)-State.Data-Mode --> ( RXDV[0] and (not RX_ERR[0]) 
).

Gruss Holger.

von Holger H. (holger-h-hennef) Benutzerseite


Lesenswert?

Tobias Plüss schrieb:
> So, und nun startet die FSM im Zustand idle. Dort wird RXDV abgefragt,
> ob es 1 ist. Wenn ja, dann wird in den data_lo state gewechselt. dort
> wird das low nibble empfangen. Anschliessend wird das high nibble
> empfangen. Sollte so ja gehen. Aber eben, wenn ich dann die Nibbles
> zusammensetze, ist da was vertauscht... und ich frage mich weshalb.

vertauscht ?

Die Daten vom Pc sind gespiegelt via PHY-Port[3:0], vermute ich mal.
 a bit-mirrored 4-Bit-Port.

Rezept:
   Das Rezept aber nur in der Daten-Phase anwenden !


  RX_DATA_nibble         : out STD_LOGIC_VECTOR (3 to 0) := "0000");

  RX_DATA_nibble_mirrord : out STD_LOGIC_VECTOR (0 to 3) := "0000");
  -- Auf diese Art passiert das Tauschen der 4-Bits implizit und quasi 
automatisch...
  RX_DATA_nibble_mirrord(0) <= RX_DATA_nibble(3);
  ######################################################################## 
############

   Mit RX_DATA_nibble_mirrord wird jetzt weiter gemacht.
Test-Muster:
   ......0xBADCAFFE .... 0xFFEFE ... 0XD ...0x5
Gruss Holger.

von Holger H. (holger-h-hennef) Benutzerseite


Angehängte Dateien:

Lesenswert?

##########################################################
In einem 8Bit Port ist das auch so,
wo erwarte ich das 'LSB der 8-Bit Nachricht.
Siehe RS232: Da wird 'LSB Bit vom Data-Byte zuerst gesendet.
Und ich schiebe die empfangenen Data-Bits immer nach links,
 und nehme dann das neue databit und setze es zusammen
 via index 0 .


Anhang:  endian_to_phy.PNG
Daten im PC zu dem RX_4-Bit Port (3:0)
Also nur im 'Data-Read-Mode muss der Nibble-Bus-3:0 auf Bus-0:3
( '4_Nibble ''LSB kommt zuerst)
-blaue Linie --> siehe Bild.
umkopiert werden.

 Anhang:
 endian_to_phy.PNG
Bei $F bzw $FF. ist das erst mal nicht aufgefallen, aber wenn
aus $1 $8 werden muss man das 4rer-nibble ''MSB to 'LSB tauschen.
- mirrored bits in a Nibble-Byte.
Frage:
(expect LSB on D0, not on D3.)
(expect LSB on D3, not on D0.)

Gruss Holger.

von Tobias P. (hubertus)


Lesenswert?

Hallo Holger

vielen Dank für deine Hilfe. Ich glaube, ich habe das Problem gefunden. 
Morgen werde ich das ganze nochmals synthetisieren und auf den FPGA 
laden, ich glaube, das könnte fast funktionieren!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.