• 【以太网通信】MDIO 管理接口及控制器设计


    MDIO 管理接口是以太网 MAC 和 PHY 之间的接口,用于管理/配置以太网 PHY 芯片。本文主要介绍 MDIO 管理接口定义,以及 MDIO 控制器设计。

    目录

    1 MDIO 管理接口

    2 MDIO 控制器设计


    1 MDIO 管理接口

            MDIO 管理接口是以太网 MAC 和 PHY 之间的接口,用于管理/配置以太网 PHY 芯片。MDIO 接口通过 MDC 和 MDIO 两根引脚访问 PHY 芯片的内部寄存器,详细可参考 IEEE 802.3u secton 22 中的定义。

    序号名称方向功能说明
    1MDC单向,MAC -> PHYMDIO 参考时钟
    2MDIO双向,MAC <-> PHYMDIO 数据

            MDC 信号是由以太网 MAC 提供的参考时钟,MDIO 是数据输入/输出,与 MDC 信号同步运行的双向信号。在硬件设计上,MDIO 引脚需要一个 1.5k 欧姆的上拉电阻,以在空闲和周转期间保持 MDIO 高电平。

            多个 PHY 芯片可以共享同一个 MDIO 接口。在交换机或路由器应用中,每个 PHY 芯片会分配一个唯一的地址,并且只能通过该唯一的 PHY 地址对其进行寻址。有关管理寄存器的详细信息,请参阅 PHY 对应芯片手册。

    2 MDIO 控制器设计

            MDIO 管理接口分读和写两种操作方式,读/写帧格式见下表。

            MDIO 读/写时序按照先后顺序分别为:32 位前导码、帧头、操作符、PHY 地址、寄存器地址、TA 标志,最后是 16 位数据。

    可以使用有限状态机设计 MDIO 控制器,设计代码如下:

    1. library ieee;
    2. use ieee.std_logic_1164.all;
    3. use ieee.std_logic_arith.all;
    4. use ieee.std_logic_unsigned.all;
    5. entity mdio_core is
    6. port(
    7. -- System level
    8. sys_rst : in std_logic;
    9. sys_clk : in std_logic;
    10. -- MDIO control/data ports
    11. mdio_req : in std_logic;
    12. mdio_ack : out std_logic;
    13. mdio_done : out std_logic;
    14. phy_addr : in std_logic_vector(7 downto 0);
    15. reg_addr : in std_logic_vector(7 downto 0);
    16. reg_wdata : in std_logic_vector(15 downto 0);
    17. reg_rdata : out std_logic_vector(15 downto 0);
    18. reg_rw : in std_logic;
    19. -- MDIO Interface
    20. phy_mdc : out std_logic;
    21. phy_mdio_id : in std_logic;
    22. phy_mdio_od : out std_logic;
    23. phy_mdio_oe : out std_logic
    24. );
    25. end entity;
    26. architecture behav of mdio_core is
    27. -- internal signal declarations
    28. type state is(
    29. idle,
    30. preamble,
    31. start,
    32. op_read,
    33. op_write,
    34. write_addr,
    35. turn_around,
    36. read_data,
    37. write_data
    38. );
    39. signal pstate : state := idle;
    40. signal phy_mdio_id_r1 : std_logic;
    41. signal phy_mdio_id_r2 : std_logic;
    42. signal reg_rdwr_r : std_logic;
    43. signal mdc_buf : std_logic_vector(7 downto 0);
    44. signal buf_mdio_ack : std_logic;
    45. signal pulse_cnt : std_logic_vector(5 downto 0);
    46. signal step_cnt : std_logic_vector(6 downto 0);
    47. signal addr_buf : std_logic_vector(9 downto 0);
    48. signal reg_wdata_buf : std_logic_vector(15 downto 0);
    49. signal reg_rdata_buf : std_logic_vector(15 downto 0);
    50. ---------------------------------------------------------
    51. begin
    52. ---------------------------------------------------------
    53. phy_mdc <= mdc_buf(mdc_buf'high);
    54. process(sys_rst,sys_clk)
    55. begin
    56. if sys_rst = '1' then
    57. pulse_cnt <= (0 => '1', others => '0');
    58. elsif rising_edge(sys_clk) then
    59. if pstate /= idle then
    60. if pulse_cnt(5) = '1' then
    61. pulse_cnt <= (0 => '1', others => '0');
    62. else
    63. pulse_cnt <= pulse_cnt + 1;
    64. end if;
    65. else
    66. pulse_cnt <= (others => '0');
    67. end if;
    68. end if;
    69. end process;
    70. process(sys_rst,sys_clk)
    71. begin
    72. if sys_rst = '1' then
    73. mdc_buf <= (others => '1');
    74. elsif rising_edge(sys_clk) then
    75. mdc_buf <= mdc_buf(mdc_buf'high-1 downto 0) & pulse_cnt(4);
    76. end if;
    77. end process;
    78. process(sys_rst,sys_clk)
    79. begin
    80. if sys_rst = '1' then
    81. phy_mdio_id_r1 <= '1';
    82. phy_mdio_id_r2 <= '1';
    83. elsif rising_edge(sys_clk) then
    84. phy_mdio_id_r1 <= phy_mdio_id;
    85. phy_mdio_id_r2 <= phy_mdio_id_r1;
    86. end if;
    87. end process;
    88. --================================================================
    89. mdio_ack <= buf_mdio_ack;
    90. reg_rdata <= reg_rdata_buf;
    91. process(sys_rst,sys_clk)
    92. begin
    93. if sys_rst = '1' then
    94. step_cnt <= (0 => '1', others => '0');
    95. elsif rising_edge(sys_clk) then
    96. case(pstate) is
    97. when idle =>
    98. step_cnt <= (0 => '1', others => '0');
    99. when preamble =>
    100. if mdc_buf(1 downto 0) = "10" then
    101. if step_cnt(5) = '1' then
    102. step_cnt <= (0 => '1', others => '0');
    103. else
    104. step_cnt <= step_cnt + 1;
    105. end if;
    106. end if;
    107. when start | op_read | op_write | turn_around =>
    108. if mdc_buf(1 downto 0) = "10" then
    109. if step_cnt(1) = '1' then
    110. step_cnt <= (0 => '1', others => '0');
    111. else
    112. step_cnt <= step_cnt + 1;
    113. end if;
    114. end if;
    115. when write_addr =>
    116. if mdc_buf(1 downto 0) = "10" then
    117. if step_cnt(3) = '1' and step_cnt(1) = '1' then
    118. step_cnt <= (0 => '1', others => '0');
    119. else
    120. step_cnt <= step_cnt + 1;
    121. end if;
    122. end if;
    123. when write_data | read_data =>
    124. if mdc_buf(1 downto 0) = "10" then
    125. if step_cnt(4) = '1' then
    126. step_cnt <= (0 => '1', others => '0');
    127. else
    128. step_cnt <= step_cnt + 1;
    129. end if;
    130. end if;
    131. when others => NULL;
    132. end case;
    133. end if;
    134. end process;
    135. process(sys_rst,sys_clk)
    136. begin
    137. if sys_rst = '1' then
    138. pstate <= idle;
    139. reg_rdwr_r <= '0';
    140. buf_mdio_ack <= '0';
    141. mdio_done <= '0';
    142. elsif rising_edge(sys_clk) then
    143. case(pstate) is
    144. when idle =>
    145. mdio_done <= '0';
    146. if mdio_req = '1' and buf_mdio_ack = '1' then
    147. buf_mdio_ack <= '0';
    148. reg_rdwr_r <= reg_rw;
    149. pstate <= preamble;
    150. elsif mdio_req = '1' and buf_mdio_ack = '0' then
    151. buf_mdio_ack <= '1';
    152. pstate <= idle;
    153. end if;
    154. when preamble =>
    155. if mdc_buf(1 downto 0) = "10" and step_cnt(5) = '1' then
    156. pstate <= start;
    157. else
    158. pstate <= preamble;
    159. end if;
    160. when start =>
    161. if mdc_buf(1 downto 0) = "10" then
    162. if step_cnt(1) = '1' and reg_rdwr_r = '1' then
    163. pstate <= op_write;
    164. elsif step_cnt(1) = '1' and reg_rdwr_r = '0' then
    165. pstate <= op_read;
    166. end if;
    167. end if;
    168. when op_read | op_write =>
    169. -- Send Read or Write OP Code
    170. if mdc_buf(1 downto 0) = "10" and step_cnt(1) = '1' then
    171. pstate <= write_addr;
    172. end if;
    173. when write_addr =>
    174. -- Send PHY Address and REG Address
    175. if mdc_buf(1 downto 0) = "10" then
    176. if step_cnt(3) = '1' and step_cnt(1) = '1' then
    177. pstate <= turn_around;
    178. end if;
    179. else
    180. pstate <= write_addr;
    181. end if;
    182. when turn_around =>
    183. if mdc_buf(1 downto 0) = "10" then
    184. if step_cnt(1) = '1' and reg_rdwr_r = '1' then
    185. pstate <= write_data;
    186. elsif step_cnt(1) = '1' and reg_rdwr_r = '0' then
    187. pstate <= read_data;
    188. end if;
    189. else
    190. pstate <= turn_around;
    191. end if;
    192. when write_data | read_data =>
    193. if mdc_buf(1 downto 0) = "10" and step_cnt(4) = '1' then
    194. pstate <= idle;
    195. mdio_done <= '1';
    196. end if;
    197. when others => NULL;
    198. end case;
    199. end if;
    200. end process;
    201. process(sys_rst,sys_clk)
    202. begin
    203. if sys_rst = '1' then
    204. addr_buf <= (others => '0');
    205. reg_wdata_buf <= (others => '0');
    206. reg_rdata_buf <= (others => '0');
    207. elsif rising_edge(sys_clk) then
    208. case(pstate) is
    209. when idle =>
    210. if mdio_req = '1' and buf_mdio_ack = '1' then
    211. reg_wdata_buf <= reg_wdata;
    212. addr_buf <= phy_addr(4 downto 0) & reg_addr(4 downto 0);
    213. end if;
    214. when preamble =>
    215. reg_rdata_buf <= (others => '1');
    216. when write_addr =>
    217. if mdc_buf(1 downto 0) = "10" then
    218. addr_buf <= addr_buf(8 downto 0) & '0';
    219. end if;
    220. when write_data =>
    221. if mdc_buf(1 downto 0) = "10" then
    222. reg_wdata_buf <= reg_wdata_buf(14 downto 0) & '0';
    223. end if;
    224. when read_data =>
    225. if mdc_buf(1 downto 0)= "01" then
    226. reg_rdata_buf <= reg_rdata_buf(14 downto 0) & phy_mdio_id_r2;
    227. end if;
    228. when others => NULL;
    229. end case;
    230. end if;
    231. end process;
    232. mdio_od_pro: process(sys_rst,sys_clk)
    233. begin
    234. if sys_rst = '1' then
    235. phy_mdio_od <= '1';
    236. elsif rising_edge(sys_clk) then
    237. case(pstate) is
    238. when idle | read_data | preamble =>
    239. phy_mdio_od <= '1';
    240. when start | op_write =>
    241. case(step_cnt(1 downto 0)) is
    242. when "01" => phy_mdio_od <= '0';
    243. when "10" => phy_mdio_od <= '1';
    244. when others => phy_mdio_od <= '1';
    245. end case;
    246. when op_read =>
    247. case(step_cnt(1 downto 0)) is
    248. when "01" => phy_mdio_od <= '1';
    249. when "10" => phy_mdio_od <= '0';
    250. when others => phy_mdio_od <= '1';
    251. end case;
    252. when write_addr =>
    253. phy_mdio_od <= addr_buf(9);
    254. when turn_around =>
    255. if reg_rdwr_r = '1' then
    256. -- Turn around for write
    257. case(step_cnt(1 downto 0)) is
    258. when "01" => phy_mdio_od <= '1';
    259. when "10" => phy_mdio_od <= '0';
    260. when others => phy_mdio_od <= '1';
    261. end case;
    262. else
    263. -- Turn around for read
    264. phy_mdio_od <= '1';
    265. end if;
    266. when write_data =>
    267. phy_mdio_od <= reg_wdata_buf(15);
    268. when others =>
    269. phy_mdio_od <= '1';
    270. end case;
    271. end if;
    272. end process;
    273. mdio_oe_pro: process(sys_rst,sys_clk)
    274. begin
    275. if sys_rst = '1' then
    276. phy_mdio_oe <= '0';
    277. elsif rising_edge(sys_clk) then
    278. case(pstate) is
    279. when idle | read_data =>
    280. phy_mdio_oe <= '0';
    281. when preamble | start | op_write | op_read | write_addr | write_data =>
    282. phy_mdio_oe <= '1';
    283. when turn_around =>
    284. if reg_rdwr_r = '1' then
    285. phy_mdio_oe <= '1';
    286. else
    287. phy_mdio_oe <= '0';
    288. end if;
    289. when others =>
    290. phy_mdio_oe <= '0';
    291. end case;
    292. end if;
    293. end process;
    294. end architecture;

  • 相关阅读:
    利用systemd实现ssl证书的自动续期
    Nlog详解---非常详细
    基于HTML+CSS+JavaScript的MIUI10官网网站设计与开发
    华为OCR识别技术 [C#]
    四川轻化工大学计算机考研资料汇总
    vue3中父组件与子组件的通信传值
    B树和B+树的区别
    DirectX11 With Windows SDK--19(Dev) 编译Assimp并加载模型、新的Effects框架
    flutter系列之:深入理解布局的基础constraints
    LeetCode每日一题(911. Online Election)
  • 原文地址:https://blog.csdn.net/sxyang2018/article/details/132779947