Guide rapide du pilote PHY Ethernet personnalisé ESP-IDF
« J'aimerais commencer un nouveau design de produit avec ma puce préférée mais elle est en rupture de stock ! Oh non! Je vais devoir concevoir une nouvelle mise en page et développer de nouveaux pilotes pour cela ! Chaque designer connaît très bien ce sentiment de nos jours…
La bonne nouvelle est que vous n'avez plus à vous soucier de cela, du moins en termes de prise en charge du pilote ESP-IDF Ethernet PHY. Dans cet article, je vais vous montrer à quel point il est simple de créer un nouveau pilote Ethernet PHY.
Tout d'abord, vous devez trouver un remplacement pour votre puce PHY actuelle. J'ai un ami qui travaille pour une société de distribution de semi-conducteurs, alors j'ai juste pris mon téléphone et lui ai demandé des conseils. Il a recommandé ADIN1200. C'est une puce de qualité industrielle robuste avec un large éventail de fonctionnalités. D'un autre côté, c'est plus cher et il peut également être plus difficile de le trouver en stock si vous n'êtes pas assez chanceux. Dans tous les cas, c'est le candidat idéal pour nos besoins de démonstration, car une carte d'évaluation existe, la puce provient d'un fournisseur qui n'est actuellement pas pris en charge par ESP-IDF (c'est-à-dire que nous limitons la possibilité de verrouillage du fournisseur pour nos clients) et la puce est IEEE plainte 802.3. Ce dernier fait nous aidera le plus à réduire l'effort nécessaire à la création d'un nouveau pilote puisqu'une interface de gestion entre EMAC et PHY est standardisée et que l'ESP-IDFv5.0 en profite. Le pilote Ethernet ESP-IDF se compose essentiellement de trois couches :
- L'objet Ethernet lui-même qui est l'API publique et qui encapsule les couches MAC et PHY dans une seule unité fonctionnelle.
- La couche MAC, qui contrôle le comportement de Media Access Controller et fournit une interface de données à l'application du pilote.
- La couche PHY, qui contrôle les propriétés de la couche physique et recueille l'état du lien.
- Indication de l'état du lien qui est presque toujours spécifique à la puce.
- Initialisation de la puce. Cette partie n'est pas strictement requise, car elle est généralement courante. Il est bon de l'ajouter pour s'assurer que la puce attendue est utilisée.
- Configuration des fonctionnalités spécifiques à la puce (telles que Wake on LAN, Energy Efficient Ethernet, diverses capacités de diagnostic, etc.).
En termes de matériel, il est plus facile de commencer avec la carte d'évaluation EVAL-ADIN1200. Cette carte d'évaluation ne nécessite que quelques modifications pour être connectée à ESP32 via RMII. (Vous pouvez, bien sûr, commencer avec une nouvelle conception de PCB si vous le trouvez plus approprié.)
Étapes pour préparer le matériel :
1) Étudiez les matériaux sur la page produit ADIN1200 et familiarisez-vous avec la puce et la carte d'évaluation.
2) Une fois familiarisé avec la carte d'évaluation, les modifications suivantes sont nécessaires :
- L'ADIN1200 nécessite un RMII REF_CLK externe de 50 MHz, donc dessoudez l'oscillateur Y1 et ses condensateurs de couplage associés.
- Souder R120 avec résistance 0R
- Soudez des pull-ups 10K à RX_CTL (élevé) et RX_CLK (élevé) pour configurer ADIN1200 en mode RMII.
- Pour des options de configuration supplémentaires, consultez le « Tableau 5. Paramètres de configuration du EVAL-ADIN1200FMCZ » dans le Guide de l'utilisateur du EVAL-ADIN1200FMCZ.
Notez que RMII REF_CLK doit être généré en externe à ADIN1200 soit par un oscillateur externe de 50 MHz, soit par ESP32. Il est plus simple d'utiliser ESP32 à des fins de démonstration, j'ai donc utilisé cette solution, mais gardez à l'esprit que le module ESP32 WROOM est requis.
╔════════════════════╦═════════════════╦═════════════╗
║ RMII Interface Pin ║ EVAL-ADIN1200 ║ ESP32 WROOM ║
╠════════════════════╬═════════════════╬═════════════╣
║ TX_EN ║ R80 ║ GPIO21 ║
║ TXD[0] ║ R90 ║ GPIO19 ║
║ TXD[1] ║ R88 ║ GPIO22 ║
║ RXD[0] ║ R99 ║ GPIO25 ║
║ RXD[1] ║ R86 ║ GPIO26 ║
║ CRS_DV ║ R81 ║ GPIO27 ║
║ RESET ║ R213 ║ GPIO5 ║
║ REF_CLK ║ C92 ║ GPIO17 ║
║ MDIO ║ MDIO Test Point ║ GPIO18 ║
║ MDC ║ MDC Test Point ║ GPIO23 ║
╚════════════════════╩═════════════════╩═════════════╝

D'un point de vue logiciel, c'est encore plus simple.
Étapes pour créer le nouveau pilote Ethernet PHY :
1) Créez une copie de esp_eth_phy_ip101.c ou de tout autre fichier source de puce PHY compatible IEEE 802.3 du dossier ESP-IDF /components/esp_eth/src/ vers un nouveau dossier.
2) Renommez toutes les occurrences de "ip101" en "adin1200".
3) Mettez à jour la section de code "Vendor Specific Registers" avec les registres ADIN1200 que vous prévoyez d'utiliser. Je n'ai mis à jour que le «registre d'état PHY 1» car je ne prévois pas encore d'utiliser les fonctionnalités avancées.
/***************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)
/* 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);
...
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;
}
...
… et le nouveau pilote PHY est terminé et prêt à être utilisé !
Maintenant, nous créons simplement des objets MAC et PHY comme nous en avons l'habitude et initialisons le pilote Ethernet ESP-IDF dans notre application.
#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, ð_handle) == ESP_OK, NULL,
err, TAG, "Ethernet driver install failed");