快速指南 :ESP-IDF 自定义以太网 PHY 驱动程序

news2024/11/13 15:07:23

“我想用我最喜欢的芯片开始新的产品设计,但它断货了!哦,不!我必须设计一个新的 PCB,并重新开发驱动程序!”如今,每个设计师都非常清楚这种感觉…

好消息是,至少在 ESP-IDF 以太网 PHY 驱动程序支持方面,您再也不用担心这种事情了。在本文中,我将向您演示创建一个新的以太网 PHY 驱动程序是多么简单。

首先,您需要找到当前 PHY 芯片的替代品。我刚好有个朋友在一家半导体经销公司工作,所以我直接拿起电话向他请教。这位朋友推荐了 ADIN1200。这是一款具有广泛功能的强大工业级芯片,对于我们的演示来说,是一个理想的候选产品,原因包括:

  1. 有现成的评估板;

  1. 该芯片来自目前 ESP-IDF 未支持的供应商(也就是说,我们有机会帮助客户解锁更多供应商),

  1. 该芯片符合 IEEE 802.3 标准。

正因如此,创建新驱动程序所需的工作量大大降低了,EMAC 和 PHY 之间的管理接口是标准化的,并且 ESP-IDF v5.0 也利用了这一点。ESP-IDF 以太网驱动程序ADIN1200 产品页面基本上由三层组成:

  • 以太网对象本身是公共 API,已经将 MAC 和 PHY 层封装为一个功能单元。

  • MAC 层控制媒体访问控制器的行为,并为驱动程序应用程序提供数据接口。

  • PHY 层控制物理层属性,并收集链路状态。

IEEE 802.3 标准的“22.2.4管理功能”章节定义了所谓的“MII 管理接口”,可控制 PHY 并通过 MAC 从PHY 收集状态;定义了一组管理寄存器,ESP-IDF 以太网驱动程序将此基本管理功能作为一组通用功能进行处理。因此,在准备新的 PHY 驱动程序时,您只需要关注芯片的特定功能,如:

  • 链路状态指示,这点几乎每款芯片都有不同。

  • 芯片初始化。这部分非常常见,不作严格要求。建议增加该部分,确保使用正确的芯片。

  • 芯片特定功能配置(如 LAN 唤醒、节能以太网、各种诊断功能等)。

接下来,让我们演示创建驱动程序的具体步骤

硬件方面建议可以先使用 EVAL-ADIN1200 评估板,您仅需进行少量修改即可通过 RMII 连接到ESP32。(当然,您也可以根据需求,选择从 PCB 设计从头开始。)

硬件准备:

  1. 查看 ADIN1200 产品页面,熟悉芯片和评估板的基本情况和特性。

  1. 在熟悉了评估版之后,需要进行以下修改:

  • ADIN1200 需外接一个 50 MHz RMI REF_CLK,因此需要拆焊 Y1 振荡器及其相关耦合电容器。

  • R120 处焊接 0R 电阻。

  • 在 RX_CTL (高)和 RX_CLK (高) 处焊接 10K 上拉电阻,配置 ADIN1200 进入 RMII 模式。

  • 有关其他配置选项,请见《EVAL-ADIN1200FMCZ 用户手册》中的“表5. EVAL-ADIN1200FMCZ 配置设置”。

3. 连接 ADIN1200 RMII 接口到 ESP32。我将电线焊接至暴露的 0R 电阻上(如下表所示)。请使电线尽可能短,并且长度相同。

注意,RMII REF_CLK 需要由外部 50 MHz 振荡器或 ESP32 在 ADIN1200 外部生成。在进行演示时,我使用了更简单的 ESP32,但实际上您需要使用 ESP32-WROOM 模组。

EVAL-ADIN1200 评估板的硬件修改结果见下图。

搭载 ESP32-WROOM 的 EVAL-ADIN1200

软件准备则更简单。

创建新的以太网 PHY 驱动程序的步骤:

  1. 前往 ESP-IDF 的 /components/esp_eth/src/ 文件夹,复制 esp_eth_phy_ip101.c 或任何其他 IEEE 802.3 兼容的 phy 芯片源文件至一个新的文件夹。

  1. 将所有 “ip101” 均替换为 “adin1200”。

  1. 前往“供应商特定寄存器”代码部分,将相关寄存器修改为 ADIN1200 的对应寄存器。由于我不准备使用任何高级功能,因此我这里只更新了“PHY Status 1 寄存器”。

/***************Vendor Specific Register***************/
/**
 * @brief PHY Status 1 Register
 *
 */
typedef union {
    struct {
        uint32_t lp_apause_adv : 1; /* The link partner has advertised asymmetric pause */
        uint32_t lp_pause_adv : 1; /* The link partner has advertised pause */
        uint32_t autoneg_sup : 1; /* Local and remote PHYs support autonegotiation */
        uint32_t col_stat : 1; /* Indicates that collision is asserted */
        uint32_t rx_dv_stat : 1; /* Indication that receive data valid (RX_DV) is asserted. */
        uint32_t tx_en_stat : 1; /* Indication that transmit enable (TX_EN) is asserted */
        uint32_t link_stat : 1; /* Link status */
        uint32_t hcd_tech : 3; /* Indication of the resolved technology after the link is established */
        uint32_t b_10_pol_inv : 1; /*  polarity of the 10BASE-T signal inversion */
        uint32_t pair_01_swap : 1; /* Pair 0 and Pair 1 swap */
        uint32_t autoneg_stat : 1; /* Autonegotiation Status Bit */
        uint32_t par_det_flt_stat: 1; /* Parallel Detection Fault Status Bit */
        uint32_t reserverd : 1; /* Reserved */
        uint32_t phy_in_stndby : 1; /* PHY is in standby state and does not attempt to bring up links */
    };
    uint32_t val;
} ps1r_reg_t;
#define ETH_PHY_PS1R_REG_ADDR (0x1A)
  1. 根据技术规格书中定义的“PHY Identifier ½ 寄存器”,更新 adin1200_init() 函数中的 oui 和 model。

/* Check PHY ID */
uint32_t oui;
uint8_t model;
ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_read_oui(phy_802_3, &oui), err, TAG, "read OUI failed");
ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_read_manufac_info(phy_802_3, &model, NULL), err, TAG, "read manufacturer's info failed");
ESP_GOTO_ON_FALSE(oui == 0xa0ef && model == 0x02, ESP_FAIL, err, TAG, "wrong chip ID (read oui=0x%" PRIx32 ", model=0x%" PRIx8 ")", oui, model);

5. 修改 update_link_duplex_speed() 函数以读取实际协商结果。该信息在 IEEE 802.3 中并未进行标准化,因此所有 PHY 芯片都不同。ADIN1200 使用 “PHY Status 1 寄存器”存储该数据。

...    
    ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)), err, TAG, "read ANLPAR failed");
    ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)), err, TAG, "read BMSR failed");
    eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
    /* check if link status changed */
    if (adin1200->phy_802_3.link_status != link) {
        /* when link up, read negotiation result */
        if (link == ETH_LINK_UP) {
            ps1r_reg_t ps1r;
            ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_PS1R_REG_ADDR, &(ps1r.val)), err, TAG, "read PS1R failed");
            switch (ps1r.hcd_tech) {
            case 0: //10Base-T half-duplex
                speed = ETH_SPEED_10M;
                duplex = ETH_DUPLEX_HALF;
                break;
            case 1: //10Base-T full-duplex
                speed = ETH_SPEED_10M;
                duplex = ETH_DUPLEX_FULL;
                break;
            case 2: //100Base-TX half-duplex
                speed = ETH_SPEED_100M;
                duplex = ETH_DUPLEX_HALF;
                break;
            case 3: //100Base-TX full-duplex
                speed = ETH_SPEED_100M;
                duplex = ETH_DUPLEX_FULL;
                break;
            default:
                break;
            }
...

6. 使用esp_eth_phy_new_adin1200() 函数创建一个新的头文件。

…至此,新的 PHY 驱动程序已准备完成,并可以使用了!

现在,我们只需按照之前的方式创建 MAC 和 PHY 对象,并在我们的应用程序中初始化 ESP-IDF 以太网驱动程序。

#include "esp_eth_phy_adin1200.h"

// Init common MAC and PHY configs to default
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();

// Update PHY config based on board specific configuration
phy_config.phy_addr = CONFIG_EXAMPLE_ETH_PHY_ADDR;
phy_config.reset_gpio_num = CONFIG_EXAMPLE_ETH_PHY_RST_GPIO;
// Init vendor specific MAC config to default
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
// Update vendor specific MAC config based on board configuration
esp32_emac_config.smi_mdc_gpio_num = CONFIG_EXAMPLE_ETH_MDC_GPIO;
esp32_emac_config.smi_mdio_gpio_num = CONFIG_EXAMPLE_ETH_MDIO_GPIO;
// Create new ESP32 Ethernet MAC instance
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);
// Create new PHY instance
esp_eth_phy_t *phy = esp_eth_phy_new_adin1200(&phy_config);
// Init Ethernet driver to default and install it
esp_eth_handle_t eth_handle = NULL;
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
ESP_GOTO_ON_FALSE(esp_eth_driver_install(&config, &eth_handle) == ESP_OK, NULL,
                    err, TAG, "Ethernet driver install failed");

ADIN1200 以太网 PHY 驱动程序的完整版本可见 ESP-IDF附加以太网驱动程序仓库或通过 IDF 组件管理器。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/141495.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[C语言]浮点型在内存中的存储

在上一篇文章,我们讲述了整型在内存中的存储,这篇文章我们就一起来看一下“浮点型在内存中的存储” 回顾:整型在内存中的存储[C语言]和我一起来认识“整型在内存中的存储”_HY_PIGIE的博客-CSDN博客 目录 1.浮点数家族 2.整型和浮点型的存储…

教你从零开始搭建自己的魔兽世界服务器

首先需要一份 WOW 的程序底包:1底包使用方法: 解压后,放到 d: 目录即可, 如下图 (最好是D盘下 因为有很多东西都是D:/连接的 )2运行http-mysql/下的文件INIT.CM_重命名为INIT.CMD 运行3设置登录器下载 ,在http-mysql/htdocs下创建DOWNLOAD文件…

再次改进MBR(从磁盘读入Loader加载器)

文章目录前言前置知识代码说明实验操作前言 本博客记录《操作系统真象还原》第二章第2个实验操作~ 实验环境:ubuntu18.04VMware , Bochs下载安装 实验内容:从磁盘读入Loader加载器 实验思路: MBR 受到512字节大小的限制&#…

kernel pwn gdb调试

前言 对于Linux的二进制程序,gdb调试是十分重要的,可以清楚的了解程序是如何运行的,这里单独拉一篇记录我在kernel pwn中遇到的一些调试 GDB选择 在三大件pwndbg,gef,peda中,用了一圈下来感觉gef和pwndbg都挺好 gdb安装 简单…

PaddleNLP教程文档

文章目录一、快速开始1.1 安装PaddleNLP并 加载数据集1.2 数据预处理1.3 加载预训练模型1.4 设置评价指标和训练策略1.5 模型训练与评估1.6 模型预测二、数据处理2.1 整体介绍2.2 加载内置数据集2.3 自定义数据集2.3.1 从本地文件创建数据集2.3.2 paddle.io.Dataset/IterableDa…

OpenShift Security - 用 RHACS 为应用自动生成 NetworkPolicy

《OpenShift / RHEL / DevSecOps / Ansible 汇总目录》 说明:本文已经在 OpenShift 4.12 RHACS 3.73.1 环境中验证 文章目录什么是 NP-Guard用 NP-Guard 自动生成 NetworkPolicy参考什么是 NP-Guard NP-Guard 是 IBM 发起的一个开源项目,用来自动创建 …

WindowsTerminal 安装 oh-my-posh

文章目录1 前言2 安装过程3 Posh Themes 自定义主题参考1 前言 在Linux中,有非常好用的oh-my-zsh,最近使用WindowsTerminal时想想有没有和oh-my-zsh相同好用的插件呢,答案是:oh-my-posh 2 安装过程 进入最新版PowerShell&#…

干货 | 解决 App 自动化测试的常见痛点(弹框及首页启动加载完成判断处理)

1. 常见痛点App 自动化测试中有些常见痛点问题,如果框架不能很好的处理,就可能出现元素定位超时找不到的情况,自动化也就被打断终止了。很容易打消做自动化的热情,导致从入门到放弃。比如下面的两个问题:一是 App 启动…

【代码题】链表面试题

目录 1.链表分割 2.相交链表 3.环形链表 4.环形链表 II 1.链表分割 点击进入该题 现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的…

国内注册Steam账号的快捷方法

本文介绍在国内注册Steam账号的快速、简便方法。 目前,在国内注册新的Steam账号变得越来越麻烦;尤其在最近,无论是无休止的谷歌人机身份验证,还是无法收到的验证邮件,都使得新建一个Steam账号与原来相比变得更加困难。…

[Linux_]make/Makefile

[Linux_]make/Makefile 心有所向,日复一日,必有精进专栏:《Linux_》作者:沂沐沐目录 [Linux]make/Makefile 前言 一、Mikefile 二、如何写Mikefile文件 三、原理 四、项目清理 报错:missing separator 前言 一个工…

Linux 命令

最基础的命令 1.我是谁 我用什么账号登录 whoami 2.我在那 在那个目录下 pwd 3.环顾四周 1.ll展示详细信息 2.ls 展示文件名称 4.cd 想去那 改变目录 cd 回家 cd ./ 定位到当前目录 cd../ 上级目录 cd../../上两级目录。 5.切换用户 su 从普通用户切换到root用户的…

C#应用程序配置文件(XML序列化) - 开源研究系列文章

上次写了一个C#线程池及管理器的博文( C#开发的线程池和管理器 - 开源研究系列文章 ),收到了不小的浏览量,在此感谢各位网友的支持。这次将另一个功能放出来单独讲解:C#应用程序的配置文件,使用的是XML文件保存程序的配置信息&…

数据结构(栈、队列、链表)

文章目录前言数据结构(栈、队列、链表)1、栈2、队列3、链表3.1、单向链表结构3.2、双向链表结构前言 如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。   而且听说点赞的人每天的运气都不会太差&…

多边形点集排序

一、问题描述已知多边形点集P {P1, P2, ... , PN},其排列顺序是杂乱,依次连接这N个点,无法形成确定的多边形,需要对点集P进行排序后,再绘制多边形。二、排序规则点集排序过程中,关键在于如何定义点的大小关…

STC32G 时钟系统

文章目录时钟系统代码配置总结时钟系统 系统时钟有4个时钟源可供选择: 内部高精度IRC内部32KHzIRC(精度较低)外部晶振内部PLL输出时钟 主要关心的是两个指标:SYSclk和HSCLK SYSclk是系统的时钟,决定了指令执行速度…

Android 深入系统完全讲解(三)

系统调用 操作系统提供了一些方法,让用户层可以调用,而为了安全起见,这些方法调用,都是在内核空间。于是,用户调用的时候,就会有个动作,叫做陷入内核。 当用户调用系统方法的时候,系…

【k8s-device plugin】如何编写 k8s device plugin

参考 Device Plugin 入门笔记(一) Device Plugin 入门笔记(二) 从零开始入门 K8s:GPU 管理和 Device Plugin 工作机制 Kubernetes开发知识–device-plugin的实现 https://github.com/oceanweave/cola-device-plugi…

基于springboot的智慧物业管理系统的设计与实现(前后端分离)

项目描述 临近学期结束,还是毕业设计,你还在做java程序网络编程,期末作业,老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下,你想解决的问…

mysql 中间件 mycat2 的详细安装及配置步骤

下载 首先打开mycat官网:MyCat2 右上角下载里面有个文件下载服务,点进去发现无法访问 这里需要配置一下host,把下面内容复制到host文件中。host文件位置在C:\Windows\System32\drivers\etc 210.51.26.184 mycat.org.cn www.mycat.org.cn …