Merge branch 'bugfix/remove_enc28j60' into 'master'

Bugfix/remove enc28j60

See merge request espressif/esp-idf!33791
This commit is contained in:
morris 2024-09-25 10:29:41 +08:00
commit 004e427ed5
14 changed files with 0 additions and 2216 deletions

View File

@ -538,8 +538,6 @@ Application Examples
* :example:`ethernet/iperf` demonstrates how to use the Ethernet capabilities to measure the throughput/bandwidth using iPerf.
* :example:`ethernet/enc28j60` demonstrates how to use the ENC28J60 Ethernet controller by integrating a new Ethernet MAC driver into the `esp_eth` component and attaching it to the TCP/IP stack.
* :example:`network/vlan_support` demonstrates how to create virtual network interfaces over Ethernet, including VLAN and non-VLAN interfaces.
* :example:`network/sta2eth` demonstrates how to create a 1-to-1 bridge using a Wi-Fi station and a wired interface such as Ethernet or USB.

View File

@ -538,8 +538,6 @@ ESP-IDF 在宏 :c:macro:`ETH_DEFAULT_CONFIG` 中为安装驱动程序提供了
* :example:`ethernet/iperf` 演示了如何使用以太网功能,使用 iPerf 测量吞吐量/带宽。
* :example:`ethernet/enc28j60` 演示了如何使用 ENC28J60 以太网控制器,通过将新的以太网 MAC 驱动程序集成到 ``esp_eth`` 组件中,并将其连接到 TCP/IP 栈。
* :example:`network/vlan_support` 演示了如何在以太网上创建虚拟网络接口,包括 VLAN 和非 VLAN 接口。
* :example:`network/sta2eth` 演示了如何使用 Wi-Fi station 和有线接口(如以太网或 USB创建 1 对 1 的桥接。

View File

@ -15,15 +15,6 @@ examples/ethernet/basic:
- esp_driver_gpio
- esp_driver_spi
examples/ethernet/enc28j60:
depends_components:
- esp_eth
- esp_netif
- lwip
- esp_event
- esp_driver_gpio
- esp_driver_spi
examples/ethernet/iperf:
disable_test:
- if: IDF_TARGET not in ["esp32"]

View File

@ -1,6 +0,0 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(enc28j60)

View File

@ -1,117 +0,0 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- |
# ENC28J60 Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
---
## !!! Warning !!!
Espressif doesn't recommend using ENC28J60 Ethernet controller in new designs based on ESP32 series of chips. This is due to the following facts:
* ENC28J60 has low performance in half-duplex mode and various errata exist to the half-duplex mode.
* ENC28J60 does not support automatic duplex negotiation when configured to full-duplex mode.
* ENC28J60 has high current consumption - up to 180mA in comparison to e.g. 79mA of `W5500` or 75mA of `KSZ8851SNL` @ 10Mbps Tx.
Therefore, we rather recommend using `W5500`, `KSZ8851SNL` or `DM9051`, which are also supported in ESP-IDF.
---
## Overview
ENC28J60 is a standalone Ethernet controller with a standard SPI interface. This example demonstrates how to drive this controller as an SPI device and then attach to TCP/IP stack.
This is also an example of how to integrate a new Ethernet MAC driver into the `esp_eth` component, without needing to modify the ESP-IDF component.
If you have a more complicated application to go (for example, connect to some IoT cloud via MQTT), you can always reuse the initialization codes in this example.
## How to use example
### Hardware Required
To run this example, you need to prepare following hardwares:
* [ESP32 dev board](https://www.espressif.com/en/products/devkits) (e.g. ESP32-PICO, ESP32 DevKitC, etc)
* ENC28J60 Ethernet module (the latest revision should be 6)
* **!! IMPORTANT !!** Proper input power source since ENC28J60 is quite power consuming device (it consumes more than 200 mA in peaks when transmitting). If improper power source is used, input voltage may drop and ENC28J60 may either provide nonsense response to host controller via SPI (fail to read registers properly) or it may enter to some strange state in the worst case. There are several options how to resolve it:
* Power ESP32 dev board from `USB 3.0`, if the dev board is used as source of power to the ENC28J60 module.
* Power ESP32 dev board from external 5 V power supply with current limit at least 1 A, if the dev board is used as source of power to the ENC28J60 module.
* Power ENC28J60 from external 3.3 V power supply with common GND to ESP32 dev board. Note that there might be some ENC28J60 modules with integrated voltage regulator on market and so powered by 5 V. Please consult documentation of your board for details.
If an ESP32 dev board is used as the source of power to the ENC28J60 module, ensure that that the particular dev board is assembled with a voltage regulator capable to deliver current of 1 A. This is a case of ESP32-DevKitC or ESP-WROVER-KIT, for example. Such setup was tested and works as expected. Other dev boards may use different voltage regulators and may perform differently.
**WARNING:** Always consult documentation/schematics associated with particular ENC28J60 and ESP32 dev boards used in your use-case first.
#### Pin Assignment
* ENC28J60 Ethernet module consumes one SPI interface plus an interrupt GPIO. By default they're connected as follows, in case of ESP32 dev boards:
| ESP32 GPIO | ENC28J60 |
| ---------- | ----------- |
| GPIO14 | SPI_CLK |
| GPIO13 | SPI_MOSI |
| GPIO12 | SPI_MISO |
| GPIO15 | SPI_CS |
| GPIO4 | Interrupt |
### Configure the project
```
idf.py menuconfig
```
In the `Example Configuration` menu, set SPI specific configuration, such as SPI host number, GPIO used for MISO/MOSI/CS signal, GPIO for interrupt event and the SPI clock rate, duplex mode.
**Note:** According to ENC28J60 data sheet and our internal testing, SPI clock could reach up to 20MHz, but in practice, the clock speed may depend on your PCB layout/wiring/power source. In this example, the default clock rate is set to 8 MHz since some ENC28J60 silicon revisions may not properly work at frequencies less than 8 MHz.
### Build, Flash, and Run
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py -p PORT build flash monitor
```
(Replace PORT with the name of the serial port to use.)
(To exit the serial monitor, type ``Ctrl-]``.)
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
## Example Output
```bash
I (0) cpu_start: Starting scheduler on APP CPU.
I (401) enc28j60: revision: 6
I (411) esp_eth.netif.glue: 00:04:a3:12:34:56
I (411) esp_eth.netif.glue: ethernet attached to netif
I (421) eth_example: Ethernet Started
I (2421) enc28j60: working in 10Mbps
I (2421) enc28j60: working in half duplex
I (2421) eth_example: Ethernet Link Up
I (2421) eth_example: Ethernet HW Addr 00:04:a3:12:34:56
I (4391) esp_netif_handlers: eth ip: 192.168.2.34, mask: 255.255.255.0, gw: 192.168.2.2
I (4391) eth_example: Ethernet Got IP Address
I (4391) eth_example: ~~~~~~~~~~~
I (4391) eth_example: ETHIP:192.168.2.34
I (4401) eth_example: ETHMASK:255.255.255.0
I (4401) eth_example: ETHGW:192.168.2.2
I (4411) eth_example: ~~~~~~~~~~~
```
Now you can ping your ESP32 in the terminal by entering `ping 192.168.2.34` (it depends on the actual IP address you get).
**Notes:**
1. ENC28J60 hasn't burned any valid MAC address in the chip, you need to write an unique MAC address into its internal MAC address register before any traffic happened on TX and RX line.
2. It is recommended to operate the ENC28J60 in full-duplex mode since various errata exist to the half-duplex mode (even though addressed in the example) and due to its poor performance in the half-duplex mode (especially in TCP connections). However, ENC28J60 does not support automatic duplex negotiation. If it is connected to an automatic duplex negotiation enabled network switch or Ethernet controller, then ENC28J60 will be detected as a half-duplex device. To communicate in Full-Duplex mode, ENC28J60 and the remote node (switch, router or Ethernet controller) **must be manually configured for full-duplex operation**:
* The ENC28J60 can be set to full-duplex in the `Example Configuration` menu.
* On Ubuntu/Debian Linux distribution use:
```
sudo ethtool -s YOUR_INTERFACE_NAME speed 10 duplex full autoneg off
```
* On Windows, go to `Network Connections` -> `Change adapter options` -> open `Properties` of selected network card -> `Configure` -> `Advanced` -> `Link Speed & Duplex` -> select `10 Mbps Full Duplex in dropdown menu`.
3. Ensure that your wiring between ESP32 dev board and the ENC28J60 module is realized by short wires with the same length and no wire crossings.
4. CS Hold Time needs to be configured to be at least 210 ns to properly read MAC and MII registers as defined by ENC28J60 Data Sheet. This is automatically configured in the example based on selected SPI clock frequency by computing amount of SPI bit-cycles the CS should stay active after the transmission. However, if your PCB design/wiring requires different value, please update `cs_ena_posttrans` member of `devcfg` structure per your actual needs.
## Troubleshooting
(For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.)

View File

@ -1,4 +0,0 @@
idf_component_register(SRCS "esp_eth_mac_enc28j60.c"
"esp_eth_phy_enc28j60.c"
PRIV_REQUIRES driver esp_eth
INCLUDE_DIRS ".")

View File

@ -1,238 +0,0 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief SPI Instruction Set
*
*/
#define ENC28J60_SPI_CMD_RCR (0x00) // Read Control Register
#define ENC28J60_SPI_CMD_RBM (0x01) // Read Buffer Memory
#define ENC28J60_SPI_CMD_WCR (0x02) // Write Control Register
#define ENC28J60_SPI_CMD_WBM (0x03) // Write Buffer Memory
#define ENC28J60_SPI_CMD_BFS (0x04) // Bit Field Set
#define ENC28J60_SPI_CMD_BFC (0x05) // Bit Field Clear
#define ENC28J60_SPI_CMD_SRC (0x07) // Soft Reset
/**
* @brief Shared Registers in ENC28J60 (accessible on each bank)
*
*/
#define ENC28J60_EIE (0x1B) // Ethernet Interrupt Enable
#define ENC28J60_EIR (0x1C) // Ethernet Interrupt flags
#define ENC28J60_ESTAT (0x1D) // Ethernet Status
#define ENC28J60_ECON2 (0x1E) // Ethernet Control Register2
#define ENC28J60_ECON1 (0x1F) // Ethernet Control Register1
/**
* @brief Per-bank Registers in ENC28J60
* @note Address[15:12]: Register Type, 0 -> ETH, 1 -> MII/MAC
* Address[11:8] : Bank address
* Address[7:0] : Register Index
*/
// Bank 0 Registers
#define ENC28J60_ERDPTL (0x0000) // Read Pointer Low Byte ERDPT<7:0>)
#define ENC28J60_ERDPTH (0x0001) // Read Pointer High Byte (ERDPT<12:8>)
#define ENC28J60_EWRPTL (0x0002) // Write Pointer Low Byte (EWRPT<7:0>)
#define ENC28J60_EWRPTH (0x0003) // Write Pointer High Byte (EWRPT<12:8>)
#define ENC28J60_ETXSTL (0x0004) // TX Start Low Byte (ETXST<7:0>)
#define ENC28J60_ETXSTH (0x0005) // TX Start High Byte (ETXST<12:8>)
#define ENC28J60_ETXNDL (0x0006) // TX End Low Byte (ETXND<7:0>)
#define ENC28J60_ETXNDH (0x0007) // TX End High Byte (ETXND<12:8>)
#define ENC28J60_ERXSTL (0x0008) // RX Start Low Byte (ERXST<7:0>)
#define ENC28J60_ERXSTH (0x0009) // RX Start High Byte (ERXST<12:8>)
#define ENC28J60_ERXNDL (0x000A) // RX End Low Byte (ERXND<7:0>)
#define ENC28J60_ERXNDH (0x000B) // RX End High Byte (ERXND<12:8>)
#define ENC28J60_ERXRDPTL (0x000C) // RX RD Pointer Low Byte (ERXRDPT<7:0>)
#define ENC28J60_ERXRDPTH (0x000D) // RX RD Pointer High Byte (ERXRDPT<12:8>)
#define ENC28J60_ERXWRPTL (0x000E) // RX WR Pointer Low Byte (ERXWRPT<7:0>)
#define ENC28J60_ERXWRPTH (0x000F) // RX WR Pointer High Byte (ERXWRPT<12:8>)
#define ENC28J60_EDMASTL (0x0010) // DMA Start Low Byte (EDMAST<7:0>)
#define ENC28J60_EDMASTH (0x0011) // DMA Start High Byte (EDMAST<12:8>)
#define ENC28J60_EDMANDL (0x0012) // DMA End Low Byte (EDMAND<7:0>)
#define ENC28J60_EDMANDH (0x0013) // DMA End High Byte (EDMAND<12:8>)
#define ENC28J60_EDMADSTL (0x0014) // DMA Destination Low Byte (EDMADST<7:0>)
#define ENC28J60_EDMADSTH (0x0015) // DMA Destination High Byte (EDMADST<12:8>)
#define ENC28J60_EDMACSL (0x0016) // DMA Checksum Low Byte (EDMACS<7:0>)
#define ENC28J60_EDMACSH (0x0017) // DMA Checksum High Byte (EDMACS<15:8>)
// Bank 1 Registers
#define ENC28J60_EHT0 (0x0100) // Hash Table Byte 0 (EHT<7:0>)
#define ENC28J60_EHT1 (0x0101) // Hash Table Byte 1 (EHT<15:8>)
#define ENC28J60_EHT2 (0x0102) // Hash Table Byte 2 (EHT<23:16>)
#define ENC28J60_EHT3 (0x0103) // Hash Table Byte 3 (EHT<31:24>)
#define ENC28J60_EHT4 (0x0104) // Hash Table Byte 4 (EHT<39:32>)
#define ENC28J60_EHT5 (0x0105) // Hash Table Byte 5 (EHT<47:40>)
#define ENC28J60_EHT6 (0x0106) // Hash Table Byte 6 (EHT<55:48>)
#define ENC28J60_EHT7 (0x0107) // Hash Table Byte 7 (EHT<63:56>)
#define ENC28J60_EPMM0 (0x0108) // Pattern Match Mask Byte 0 (EPMM<7:0>)
#define ENC28J60_EPMM1 (0x0109) // Pattern Match Mask Byte 1 (EPMM<15:8>)
#define ENC28J60_EPMM2 (0x010A) // Pattern Match Mask Byte 2 (EPMM<23:16>)
#define ENC28J60_EPMM3 (0x010B) // Pattern Match Mask Byte 3 (EPMM<31:24>)
#define ENC28J60_EPMM4 (0x010C) // Pattern Match Mask Byte 4 (EPMM<39:32>)
#define ENC28J60_EPMM5 (0x010D) // Pattern Match Mask Byte 5 (EPMM<47:40>)
#define ENC28J60_EPMM6 (0x010E) // Pattern Match Mask Byte 6 (EPMM<55:48>)
#define ENC28J60_EPMM7 (0x010F) // Pattern Match Mask Byte 7 (EPMM<63:56>)
#define ENC28J60_EPMCSL (0x0110) // Pattern Match Checksum Low Byte (EPMCS<7:0>)
#define ENC28J60_EPMCSH (0x0111) // Pattern Match Checksum High Byte (EPMCS<15:0>)
#define ENC28J60_EPMOL (0x0114) // Pattern Match Offset Low Byte (EPMO<7:0>)
#define ENC28J60_EPMOH (0x0115) // Pattern Match Offset High Byte (EPMO<12:8>)
#define ENC28J60_ERXFCON (0x0118) // Receive Fileter Control
#define ENC28J60_EPKTCNT (0x0119) // Ethernet Packet Count
// Bank 2 Register
#define ENC28J60_MACON1 (0x1200) // MAC Control Register 1
#define ENC28J60_MACON2 (0x1201) // MAC Control Register 2
#define ENC28J60_MACON3 (0x1202) // MAC Control Register 3
#define ENC28J60_MACON4 (0x1203) // MAC Control Register 4
#define ENC28J60_MABBIPG (0x1204) // Back-to-Back Inter-Packet Gap (BBIPG<6:0>)
#define ENC28J60_MAIPGL (0x1206) // Non-Back-to-Back Inter-Packet Gap Low Byte (MAIPGL<6:0>)
#define ENC28J60_MAIPGH (0x1207) // Non-Back-to-Back Inter-Packet Gap High Byte (MAIPGH<6:0>)
#define ENC28J60_MACLCON1 (0x1208) // Retransmission Maximum (RETMAX<3:0>)
#define ENC28J60_MACLCON2 (0x1209) // Collision Window (COLWIN<5:0>)
#define ENC28J60_MAMXFLL (0x120A) // Maximum Frame Length Low Byte (MAMXFL<7:0>)
#define ENC28J60_MAMXFLH (0x120B) // Maximum Frame Length High Byte (MAMXFL<15:8>)
#define ENC28J60_MICMD (0x1212) // MII Command Register
#define ENC28J60_MIREGADR (0x1214) // MII Register Address (MIREGADR<4:0>)
#define ENC28J60_MIWRL (0x1216) // MII Write Data Low Byte (MIWR<7:0>)
#define ENC28J60_MIWRH (0x1217) // MII Write Data High Byte (MIWR<15:8>)
#define ENC28J60_MIRDL (0x1218) // MII Read Data Low Byte (MIRD<7:0>)
#define ENC28J60_MIRDH (0x1219) // MII Read Data High Byte(MIRD<15:8>)
// Bank 3 Registers
#define ENC28J60_MAADR5 (0x1300) // MAC Address Byte 5 (MAADR<15:8>)
#define ENC28J60_MAADR6 (0x1301) // MAC Address Byte 6 (MAADR<7:0>)
#define ENC28J60_MAADR3 (0x1302) // MAC Address Byte 3 (MAADR<31:24>), OUI Byte 3
#define ENC28J60_MAADR4 (0x1303) // MAC Address Byte 4 (MAADR<23:16>)
#define ENC28J60_MAADR1 (0x1304) // MAC Address Byte 1 (MAADR<47:40>), OUI Byte 1
#define ENC28J60_MAADR2 (0x1305) // MAC Address Byte 2 (MAADR<39:32>), OUI Byte 2
#define ENC28J60_EBSTSD (0x0306) // Built-in Self-Test Fill Seed (EBSTSD<7:0>)
#define ENC28J60_EBSTCON (0x0307) // Built-in Self-Test Control
#define ENC28J60_EBSTCSL (0x0308) // Built-in Self-Test Checksum Low Byte (EBSTCS<7:0>)
#define ENC28J60_EBSTCSH (0x0309) // Built-in Self-Test Checksum High Byte (EBSTCS<15:8>)
#define ENC28J60_MISTAT (0x130A) // MII Status Register
#define ENC28J60_EREVID (0x0312) // Ethernet Revision ID (EREVID<4:0>)
#define ENC28J60_ECOCON (0x0315) // Clock Output Control Register
#define ENC28J60_EFLOCON (0x0317) // Ethernet Flow Control
#define ENC28J60_EPAUSL (0x0318) // Pause Timer Value Low Byte (EPAUS<7:0>)
#define ENC28J60_EPAUSH (0x0319) // Pause Timer Value High Byte (EPAUS<15:8>)
/**
* @brief status and flag of ENC28J60 specific registers
*
*/
// EIE bit definitions
#define EIE_INTIE (1<<7) // Global INT Interrupt Enable
#define EIE_PKTIE (1<<6) // Receive Packet Pending Interrupt Enable
#define EIE_DMAIE (1<<5) // DMA Interrupt Enable
#define EIE_LINKIE (1<<4) // Link Status Change Interrupt Enable
#define EIE_TXIE (1<<3) // Transmit Enable
#define EIE_TXERIE (1<<1) // Transmit Error Interrupt Enable
#define EIE_RXERIE (1<<0) // Receive Error Interrupt Enable
// EIR bit definitions
#define EIR_PKTIF (1<<6) // Receive Packet Pending Interrupt Flag
#define EIR_DMAIF (1<<5) // DMA Interrupt Flag
#define EIR_LINKIF (1<<4) // Link Change Interrupt Flag
#define EIR_TXIF (1<<3) // Transmit Interrupt Flag
#define EIR_TXERIF (1<<1) // Transmit Error Interrupt Flag
#define EIR_RXERIF (1<<0) // Receive Error Interrupt Flag
// ESTAT bit definitions
#define ESTAT_INT (1<<7) // INT Interrupt Flag
#define ESTAT_BUFER (1<<6) // Buffer Error Status
#define ESTAT_LATECOL (1<<4) // Late Collision Error
#define ESTAT_RXBUSY (1<<2) // Receive Busy
#define ESTAT_TXABRT (1<<1) // Transmit Abort Error
#define ESTAT_CLKRDY (1<<0) // Clock Ready
// ECON2 bit definitions
#define ECON2_AUTOINC (1<<7) // Automatic Buffer Pointer Increment Enable
#define ECON2_PKTDEC (1<<6) // Packet Decrement
#define ECON2_PWRSV (1<<5) // Power Save Enable
#define ECON2_VRPS (1<<3) // Voltage Regulator Power Save Enable
// ECON1 bit definitions
#define ECON1_TXRST (1<<7) // Transmit Logic Reset
#define ECON1_RXRST (1<<6) // Receive Logic Reset
#define ECON1_DMAST (1<<5) // DMA Start and Busy Status
#define ECON1_CSUMEN (1<<4) // DMA Checksum Enable
#define ECON1_TXRTS (1<<3) // Transmit Request to Send
#define ECON1_RXEN (1<<2) // Receive Enable
#define ECON1_BSEL1 (1<<1) // Bank Select1
#define ECON1_BSEL0 (1<<0) // Bank Select0
// ERXFCON bit definitions
#define ERXFCON_UCEN (1<<7) // Unicast Filter Enable
#define ERXFCON_ANDOR (1<<6) // AND/OR Filter Select
#define ERXFCON_CRCEN (1<<5) // Post-Filter CRC Check Enable
#define ERXFCON_PMEN (1<<4) // Pattern Match Filter Enable
#define ERXFCON_MPEN (1<<3) // Magic Packet Filter Enable
#define ERXFCON_HTEN (1<<2) // Hash Table Filter Enable
#define ERXFCON_MCEN (1<<1) // Multicast Filter Enable
#define ERXFCON_BCEN (1<<0) // Broadcast Filter Enable
// MACON1 bit definitions
#define MACON1_TXPAUS (1<<3) // Pause Control Frame Transmission Enable
#define MACON1_RXPAUS (1<<2) // Pause Control Frame Reception Enable
#define MACON1_PASSALL (1<<1) // Pass All Received Frames Enable
#define MACON1_MARXEN (1<<0) // MAC Receive Enable
// MACON3 bit definitions
#define MACON3_PADCFG2 (1<<7) // Automatic Pad and CRC Configuration bit 2
#define MACON3_PADCFG1 (1<<6) // Automatic Pad and CRC Configuration bit 1
#define MACON3_PADCFG0 (1<<5) // Automatic Pad and CRC Configuration bit 0
#define MACON3_TXCRCEN (1<<4) // Transmit CRC Enable
#define MACON3_PHDRLEN (1<<3) // Proprietary Header Enable
#define MACON3_HFRMLEN (1<<2) // Huge Frame Enable
#define MACON3_FRMLNEN (1<<1) // Frame Length Checking Enable
#define MACON3_FULDPX (1<<0) // MAC Full-Duplex Enable
// MACON4 bit definitions
#define MACON4_DEFER (1<<6) // Defer Transmission Enable
#define MACON4_BPEN (1<<5) // No Backoff During Backpressure Enable
#define MACON4_NOBKFF (1<<4) // No Backoff Enable
// MICMD bit definitions
#define MICMD_MIISCAN (1<<1) // MII Scan Enable
#define MICMD_MIIRD (1<<0) // MII Read Enable
// EBSTCON bit definitions
#define EBSTCON_PSV2 (1<<7) // Pattern Shift Value 2
#define EBSTCON_PSV1 (1<<6) // Pattern Shift Value 1
#define EBSTCON_PSV0 (1<<5) // Pattern Shift Value 0
#define EBSTCON_PSEL (1<<4) // Port Select
#define EBSTCON_TMSEL1 (1<<3) // Test Mode Select 1
#define EBSTCON_TMSEL0 (1<<2) // Test Mode Select 0
#define EBSTCON_TME (1<<1) // Test Mode Enable
#define EBSTCON_BISTST (1<<0) // Built-in Self-Test Start/Busy
// MISTAT bit definitions
#define MISTAT_NVALID (1<<2) // MII Management Read Data Not Valid
#define MISTAT_SCAN (1<<1) // MII Management Scan Operation in Progress
#define MISTAT_BUSY (1<<0) // MII Management Busy
// EFLOCON bit definitions
#define EFLOCON_FULDPXS (1<<2) // Full-Duplex Shadown
#define EFLOCON_FCEN1 (1<<1) // Flow Control Enable 1
#define EFLOCON_FCEN0 (1<<0) // Flow Control Enable 0
#ifdef __cplusplus
}
#endif

View File

@ -1,106 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_eth_phy.h"
#include "esp_eth_mac.h"
#include "driver/spi_master.h"
#define CS_HOLD_TIME_MIN_NS 210
/**
* @brief ENC28J60 specific configuration
*
*/
typedef struct {
spi_host_device_t spi_host_id; /*!< SPI peripheral */
spi_device_interface_config_t *spi_devcfg; /*!< SPI device configuration */
int int_gpio_num; /*!< Interrupt GPIO number */
} eth_enc28j60_config_t;
/**
* @brief ENC28J60 Supported Revisions
*
*/
typedef enum {
ENC28J60_REV_B1 = 0b00000010,
ENC28J60_REV_B4 = 0b00000100,
ENC28J60_REV_B5 = 0b00000101,
ENC28J60_REV_B7 = 0b00000110
} eth_enc28j60_rev_t;
/**
* @brief Default ENC28J60 specific configuration
*
*/
#define ETH_ENC28J60_DEFAULT_CONFIG(spi_host, spi_devcfg_p) \
{ \
.spi_host_id = spi_host, \
.spi_devcfg = spi_devcfg_p, \
.int_gpio_num = 4, \
}
/**
* @brief Compute amount of SPI bit-cycles the CS should stay active after the transmission
* to meet ENC28J60 CS Hold Time specification.
*
* @param clock_speed_mhz SPI Clock frequency in MHz (valid range is <1, 20>)
* @return uint8_t
*/
static inline uint8_t enc28j60_cal_spi_cs_hold_time(int clock_speed_mhz)
{
if (clock_speed_mhz <= 0 || clock_speed_mhz > 20) {
return 0;
}
int temp = clock_speed_mhz * CS_HOLD_TIME_MIN_NS;
uint8_t cs_posttrans = temp / 1000;
if (temp % 1000) {
cs_posttrans += 1;
}
return cs_posttrans;
}
/**
* @brief Create ENC28J60 Ethernet MAC instance
*
* @param[in] enc28j60_config: ENC28J60 specific configuration
* @param[in] mac_config: Ethernet MAC configuration
*
* @return
* - instance: create MAC instance successfully
* - NULL: create MAC instance failed because some error occurred
*/
esp_eth_mac_t *esp_eth_mac_new_enc28j60(const eth_enc28j60_config_t *enc28j60_config, const eth_mac_config_t *mac_config);
/**
* @brief Create a PHY instance of ENC28J60
*
* @param[in] config: configuration of PHY
*
* @return
* - instance: create PHY instance successfully
* - NULL: create PHY instance failed because some error occurred
*/
esp_eth_phy_t *esp_eth_phy_new_enc28j60(const eth_phy_config_t *config);
/**
* @brief Get ENC28J60 silicon revision ID
*
* @param mac ENC28J60 MAC Handle
* @return eth_enc28j60_rev_t
* - returns silicon revision ID read during initialization
*/
eth_enc28j60_rev_t emac_enc28j60_get_chip_info(esp_eth_mac_t *mac);
#ifdef __cplusplus
}
#endif

View File

@ -1,367 +0,0 @@
/*
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <stdlib.h>
#include <sys/cdefs.h>
#include "esp_log.h"
#include "esp_eth.h"
#include "eth_phy_802_3_regs.h"
#include "esp_eth_enc28j60.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
static const char *TAG = "enc28j60";
#define PHY_CHECK(a, str, goto_tag, ...) \
do \
{ \
if (!(a)) \
{ \
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
goto goto_tag; \
} \
} while (0)
/***************Vendor Specific Register***************/
/**
* @brief PHCON2(PHY Control Register 2)
*
*/
typedef union {
struct {
uint32_t reserved_7_0 : 8; // Reserved
uint32_t pdpxmd : 1; // PHY Duplex Mode bit
uint32_t reserved_10_9: 2; // Reserved
uint32_t ppwrsv: 1; // PHY Power-Down bit
uint32_t reserved_13_12: 2; // Reserved
uint32_t ploopbk: 1; // PHY Loopback bit
uint32_t prst: 1; // PHY Software Reset bit
};
uint32_t val;
} phcon1_reg_t;
#define ETH_PHY_PHCON1_REG_ADDR (0x00)
/**
* @brief PHCON2(PHY Control Register 2)
*
*/
typedef union {
struct {
uint32_t reserved_7_0 : 8; // Reserved
uint32_t hdldis : 1; // Half-Duplex Loopback Disable
uint32_t reserved_9: 1; // Reserved
uint32_t jabber: 1; // Disable Jabber Correction
uint32_t reserved_12_11: 2; // Reserved
uint32_t txdis: 1; // Disable Twist-Pair Transmitter
uint32_t frclnk: 1; // Force Linkup
uint32_t reserved_15: 1; //Reserved
};
uint32_t val;
} phcon2_reg_t;
#define ETH_PHY_PHCON2_REG_ADDR (0x10)
/**
* @brief PHSTAT2(PHY Status Register 2)
*
*/
typedef union {
struct {
uint32_t reserved_4_0 : 5; // Reserved
uint32_t plrity : 1; // Polarity Status
uint32_t reserved_8_6 : 3; // Reserved
uint32_t dpxstat : 1; // PHY Duplex Status
uint32_t lstat : 1; // PHY Link Status (non-latching)
uint32_t colstat : 1; // PHY Collision Status
uint32_t rxstat : 1; // PHY Receive Status
uint32_t txstat : 1; // PHY Transmit Status
uint32_t reserved_15_14 : 2; // Reserved
};
uint32_t val;
} phstat2_reg_t;
#define ETH_PHY_PHSTAT2_REG_ADDR (0x11)
typedef struct {
esp_eth_phy_t parent;
esp_eth_mediator_t *eth;
uint32_t addr;
uint32_t reset_timeout_ms;
eth_link_t link_status;
int reset_gpio_num;
} phy_enc28j60_t;
static esp_err_t enc28j60_update_link_duplex_speed(phy_enc28j60_t *enc28j60)
{
esp_eth_mediator_t *eth = enc28j60->eth;
eth_speed_t speed = ETH_SPEED_10M; // enc28j60 speed is fixed to 10Mbps
eth_duplex_t duplex = ETH_DUPLEX_HALF;
phstat2_reg_t phstat;
PHY_CHECK(eth->phy_reg_read(eth, enc28j60->addr, ETH_PHY_PHSTAT2_REG_ADDR, &(phstat.val)) == ESP_OK,
"read PHSTAT2 failed", err);
eth_link_t link = phstat.lstat ? ETH_LINK_UP : ETH_LINK_DOWN;
/* check if link status changed */
if (enc28j60->link_status != link) {
/* when link up, read result */
if (link == ETH_LINK_UP) {
if (phstat.dpxstat) {
duplex = ETH_DUPLEX_FULL;
} else {
duplex = ETH_DUPLEX_HALF;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK,
"change speed failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK,
"change duplex failed", err);
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK,
"change link failed", err);
enc28j60->link_status = link;
}
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t enc28j60_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
{
PHY_CHECK(eth, "can't set mediator for enc28j60 to null", err);
phy_enc28j60_t *enc28j60 = __containerof(phy, phy_enc28j60_t, parent);
enc28j60->eth = eth;
return ESP_OK;
err:
return ESP_ERR_INVALID_ARG;
}
static esp_err_t enc28j60_get_link(esp_eth_phy_t *phy)
{
phy_enc28j60_t *enc28j60 = __containerof(phy, phy_enc28j60_t, parent);
/* Updata information about link, speed, duplex */
PHY_CHECK(enc28j60_update_link_duplex_speed(enc28j60) == ESP_OK, "update link duplex speed failed", err);
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t enc28j60_reset(esp_eth_phy_t *phy)
{
phy_enc28j60_t *enc28j60 = __containerof(phy, phy_enc28j60_t, parent);
enc28j60->link_status = ETH_LINK_DOWN;
esp_eth_mediator_t *eth = enc28j60->eth;
bmcr_reg_t bmcr = {.reset = 1};
PHY_CHECK(eth->phy_reg_write(eth, enc28j60->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
/* Wait for reset complete */
uint32_t to = 0;
for (to = 0; to < enc28j60->reset_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, enc28j60->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!bmcr.reset) {
break;
}
}
PHY_CHECK(to < enc28j60->reset_timeout_ms / 10, "PHY reset timeout", err);
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t enc28j60_reset_hw(esp_eth_phy_t *phy)
{
phy_enc28j60_t *enc28j60 = __containerof(phy, phy_enc28j60_t, parent);
// set reset_gpio_num minus zero can skip hardware reset phy chip
if (enc28j60->reset_gpio_num >= 0) {
gpio_reset_pin(enc28j60->reset_gpio_num);
gpio_set_direction(enc28j60->reset_gpio_num, GPIO_MODE_OUTPUT);
gpio_set_level(enc28j60->reset_gpio_num, 0);
gpio_set_level(enc28j60->reset_gpio_num, 1);
}
return ESP_OK;
}
static esp_err_t enc28j60_autonego_ctrl(esp_eth_phy_t *phy, eth_phy_autoneg_cmd_t cmd, bool *autoneg_en_stat)
{
/**
* ENC28J60 does not support automatic duplex negotiation.
* If it is connected to an automatic duplex negotiation enabled network switch,
* ENC28J60 will be detected as a half-duplex device.
* To communicate in Full-Duplex mode, ENC28J60 and the remote node
* must be manually configured for full-duplex operation.
*/
switch (cmd)
{
case ESP_ETH_PHY_AUTONEGO_RESTART:
/* Fallthrough */
case ESP_ETH_PHY_AUTONEGO_EN:
return ESP_ERR_NOT_SUPPORTED;
case ESP_ETH_PHY_AUTONEGO_DIS:
/* Fallthrough */
case ESP_ETH_PHY_AUTONEGO_G_STAT:
*autoneg_en_stat = false;
break;
default:
return ESP_ERR_INVALID_ARG;
}
return ESP_OK;
}
esp_err_t enc28j60_set_speed(esp_eth_phy_t *phy, eth_speed_t speed)
{
/* ENC28J60 supports only 10Mbps */
if (speed == ETH_SPEED_10M) {
return ESP_OK;
}
return ESP_ERR_NOT_SUPPORTED;
}
esp_err_t enc28j60_set_duplex(esp_eth_phy_t *phy, eth_duplex_t duplex)
{
phy_enc28j60_t *enc28j60 = __containerof(phy, phy_enc28j60_t, parent);
esp_eth_mediator_t *eth = enc28j60->eth;
phcon1_reg_t phcon1;
/* Since the link is going to be reconfigured, consider it down to be status updated once the driver re-started */
enc28j60->link_status = ETH_LINK_DOWN;
PHY_CHECK(eth->phy_reg_read(eth, enc28j60->addr, 0, &phcon1.val) == ESP_OK,
"read PHCON1 failed", err);
switch (duplex) {
case ETH_DUPLEX_HALF:
phcon1.pdpxmd = 0;
break;
case ETH_DUPLEX_FULL:
phcon1.pdpxmd = 1;
break;
default:
PHY_CHECK(false, "unknown duplex", err);
break;
}
PHY_CHECK(eth->phy_reg_write(eth, enc28j60->addr, 0, phcon1.val) == ESP_OK,
"write PHCON1 failed", err);
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t enc28j60_pwrctl(esp_eth_phy_t *phy, bool enable)
{
phy_enc28j60_t *enc28j60 = __containerof(phy, phy_enc28j60_t, parent);
esp_eth_mediator_t *eth = enc28j60->eth;
bmcr_reg_t bmcr;
PHY_CHECK(eth->phy_reg_read(eth, enc28j60->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!enable) {
/* Enable IEEE Power Down Mode */
bmcr.power_down = 1;
} else {
/* Disable IEEE Power Down Mode */
bmcr.power_down = 0;
}
PHY_CHECK(eth->phy_reg_write(eth, enc28j60->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, enc28j60->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!enable) {
PHY_CHECK(bmcr.power_down == 1, "power down failed", err);
} else {
PHY_CHECK(bmcr.power_down == 0, "power up failed", err);
}
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t enc28j60_set_addr(esp_eth_phy_t *phy, uint32_t addr)
{
phy_enc28j60_t *enc28j60 = __containerof(phy, phy_enc28j60_t, parent);
enc28j60->addr = addr;
return ESP_OK;
}
static esp_err_t enc28j60_get_addr(esp_eth_phy_t *phy, uint32_t *addr)
{
PHY_CHECK(addr, "addr can't be null", err);
phy_enc28j60_t *enc28j60 = __containerof(phy, phy_enc28j60_t, parent);
*addr = enc28j60->addr;
return ESP_OK;
err:
return ESP_ERR_INVALID_ARG;
}
static esp_err_t enc28j60_del(esp_eth_phy_t *phy)
{
phy_enc28j60_t *enc28j60 = __containerof(phy, phy_enc28j60_t, parent);
free(enc28j60);
return ESP_OK;
}
static esp_err_t enc28j60_init(esp_eth_phy_t *phy)
{
phy_enc28j60_t *enc28j60 = __containerof(phy, phy_enc28j60_t, parent);
esp_eth_mediator_t *eth = enc28j60->eth;
/* Power on Ethernet PHY */
PHY_CHECK(enc28j60_pwrctl(phy, true) == ESP_OK, "power control failed", err);
/* Reset Ethernet PHY */
PHY_CHECK(enc28j60_reset(phy) == ESP_OK, "reset failed", err);
/* Check PHY ID */
phyidr1_reg_t id1;
phyidr2_reg_t id2;
PHY_CHECK(eth->phy_reg_read(eth, enc28j60->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK,
"read ID1 failed", err);
PHY_CHECK(eth->phy_reg_read(eth, enc28j60->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK,
"read ID2 failed", err);
PHY_CHECK(id1.oui_msb == 0x0083 && id2.oui_lsb == 0x05 && id2.vendor_model == 0x00,
"wrong chip ID", err);
/* Disable half duplex loopback */
phcon2_reg_t phcon2;
PHY_CHECK(eth->phy_reg_read(eth, enc28j60->addr, ETH_PHY_PHCON2_REG_ADDR, &(phcon2.val)) == ESP_OK,
"read PHCON2 failed", err);
phcon2.hdldis = 1;
PHY_CHECK(eth->phy_reg_write(eth, enc28j60->addr, ETH_PHY_PHCON2_REG_ADDR, phcon2.val) == ESP_OK,
"write PHCON2 failed", err);
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t enc28j60_deinit(esp_eth_phy_t *phy)
{
/* Power off Ethernet PHY */
PHY_CHECK(enc28j60_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err);
return ESP_OK;
err:
return ESP_FAIL;
}
esp_eth_phy_t *esp_eth_phy_new_enc28j60(const eth_phy_config_t *config)
{
PHY_CHECK(config, "can't set phy config to null", err);
phy_enc28j60_t *enc28j60 = calloc(1, sizeof(phy_enc28j60_t));
PHY_CHECK(enc28j60, "calloc enc28j60 failed", err);
enc28j60->addr = config->phy_addr; // although PHY addr is meaningless to ENC28J60
enc28j60->reset_timeout_ms = config->reset_timeout_ms;
enc28j60->reset_gpio_num = config->reset_gpio_num;
enc28j60->link_status = ETH_LINK_DOWN;
enc28j60->parent.reset = enc28j60_reset;
enc28j60->parent.reset_hw = enc28j60_reset_hw;
enc28j60->parent.init = enc28j60_init;
enc28j60->parent.deinit = enc28j60_deinit;
enc28j60->parent.set_mediator = enc28j60_set_mediator;
enc28j60->parent.autonego_ctrl = enc28j60_autonego_ctrl;
enc28j60->parent.get_link = enc28j60_get_link;
enc28j60->parent.pwrctl = enc28j60_pwrctl;
enc28j60->parent.get_addr = enc28j60_get_addr;
enc28j60->parent.set_addr = enc28j60_set_addr;
enc28j60->parent.set_speed = enc28j60_set_speed;
enc28j60->parent.set_duplex = enc28j60_set_duplex;
enc28j60->parent.del = enc28j60_del;
return &(enc28j60->parent);
err:
return NULL;
}

View File

@ -1,4 +0,0 @@
set(srcs "enc28j60_example_main.c")
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS ".")

View File

@ -1,93 +0,0 @@
menu "Example Configuration"
orsource "$IDF_PATH/examples/common_components/env_caps/$IDF_TARGET/Kconfig.env_caps"
config EXAMPLE_ENC28J60_SPI_HOST
int "SPI Host Number"
range 0 2
default 1
help
Set the SPI host used to communicate with the SPI Ethernet Controller.
config EXAMPLE_ENC28J60_SCLK_GPIO
int "SPI SCLK GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 14 if IDF_TARGET_ESP32
default 12 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 6 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C6
default 4 if IDF_TARGET_ESP32H2
default 33 if IDF_TARGET_ESP32P4
default 8 if IDF_TARGET_ESP32C5
help
Set the GPIO number used by SPI SCLK.
config EXAMPLE_ENC28J60_MOSI_GPIO
int "SPI MOSI GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 13 if IDF_TARGET_ESP32
default 11 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 7 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C6
default 5 if IDF_TARGET_ESP32H2
default 32 if IDF_TARGET_ESP32P4
default 10 if IDF_TARGET_ESP32C5
help
Set the GPIO number used by SPI MOSI.
config EXAMPLE_ENC28J60_MISO_GPIO
int "SPI MISO GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_IN_RANGE_MAX
default 12 if IDF_TARGET_ESP32
default 13 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 2 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C6
default 0 if IDF_TARGET_ESP32H2
default 52 if IDF_TARGET_ESP32P4
default 9 if IDF_TARGET_ESP32C5
help
Set the GPIO number used by SPI MISO.
config EXAMPLE_ENC28J60_CS_GPIO
int "SPI CS GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 15 if IDF_TARGET_ESP32
default 10 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C2
default 3 if IDF_TARGET_ESP32C6 || IDF_TARGET_ESP32C5
default 1 if IDF_TARGET_ESP32H2
default 53 if IDF_TARGET_ESP32P4
help
Set the GPIO number used by SPI CS.
config EXAMPLE_ENC28J60_SPI_CLOCK_MHZ
int "SPI clock speed (MHz)"
range 5 20
default 8
help
Set the clock speed (MHz) of SPI interface.
config EXAMPLE_ENC28J60_INT_GPIO
int "Interrupt GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_IN_RANGE_MAX
default 4 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3
default 4 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C6 || IDF_TARGET_ESP32C5
default 10 if IDF_TARGET_ESP32H2
default 48 if IDF_TARGET_ESP32P4
help
Set the GPIO number used by ENC28J60 interrupt.
choice EXAMPLE_ENC28J60_DUPLEX_MODE
prompt "Duplex Mode"
default EXAMPLE_ENC28J60_DUPLEX_HALF
help
Select ENC28J60 Duplex operation mode.
config EXAMPLE_ENC28J60_DUPLEX_FULL
bool "Full Duplex"
help
Set ENC28J60 to Full Duplex mode. Do not forget to manually set the remote node (switch, router
or Ethernet controller) to full-duplex operation mode too.
config EXAMPLE_ENC28J60_DUPLEX_HALF
bool "Half Duplex"
help
Set ENC28J60 to Half Duplex mode.
endchoice # EXAMPLE_ENC28J60_DUPLEX_MODE
endmenu

View File

@ -1,137 +0,0 @@
/* ENC28J60 Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <string.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_netif.h"
#include "esp_eth.h"
#include "esp_event.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "esp_eth_enc28j60.h"
#include "driver/spi_master.h"
static const char *TAG = "eth_example";
/** Event handler for Ethernet events */
static void eth_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
uint8_t mac_addr[6] = {0};
/* we can get the ethernet driver handle from event data */
esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data;
switch (event_id) {
case ETHERNET_EVENT_CONNECTED:
esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr);
ESP_LOGI(TAG, "Ethernet Link Up");
ESP_LOGI(TAG, "Ethernet HW Addr %02x:%02x:%02x:%02x:%02x:%02x",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
break;
case ETHERNET_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "Ethernet Link Down");
break;
case ETHERNET_EVENT_START:
ESP_LOGI(TAG, "Ethernet Started");
break;
case ETHERNET_EVENT_STOP:
ESP_LOGI(TAG, "Ethernet Stopped");
break;
default:
break;
}
}
/** Event handler for IP_EVENT_ETH_GOT_IP */
static void got_ip_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
const esp_netif_ip_info_t *ip_info = &event->ip_info;
ESP_LOGI(TAG, "Ethernet Got IP Address");
ESP_LOGI(TAG, "~~~~~~~~~~~");
ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip_info->ip));
ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask));
ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info->gw));
ESP_LOGI(TAG, "~~~~~~~~~~~");
}
void app_main(void)
{
ESP_ERROR_CHECK(gpio_install_isr_service(0));
// Initialize TCP/IP network interface (should be called only once in application)
ESP_ERROR_CHECK(esp_netif_init());
// Create default event loop that running in background
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH();
esp_netif_t *eth_netif = esp_netif_new(&netif_cfg);
spi_bus_config_t buscfg = {
.miso_io_num = CONFIG_EXAMPLE_ENC28J60_MISO_GPIO,
.mosi_io_num = CONFIG_EXAMPLE_ENC28J60_MOSI_GPIO,
.sclk_io_num = CONFIG_EXAMPLE_ENC28J60_SCLK_GPIO,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
};
ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ENC28J60_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO));
/* ENC28J60 ethernet driver is based on spi driver */
spi_device_interface_config_t spi_devcfg = {
.mode = 0,
.clock_speed_hz = CONFIG_EXAMPLE_ENC28J60_SPI_CLOCK_MHZ * 1000 * 1000,
.spics_io_num = CONFIG_EXAMPLE_ENC28J60_CS_GPIO,
.queue_size = 20,
.cs_ena_posttrans = enc28j60_cal_spi_cs_hold_time(CONFIG_EXAMPLE_ENC28J60_SPI_CLOCK_MHZ),
};
eth_enc28j60_config_t enc28j60_config = ETH_ENC28J60_DEFAULT_CONFIG(CONFIG_EXAMPLE_ENC28J60_SPI_HOST, &spi_devcfg);
enc28j60_config.int_gpio_num = CONFIG_EXAMPLE_ENC28J60_INT_GPIO;
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
esp_eth_mac_t *mac = esp_eth_mac_new_enc28j60(&enc28j60_config, &mac_config);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
phy_config.autonego_timeout_ms = 0; // ENC28J60 doesn't support auto-negotiation
phy_config.reset_gpio_num = -1; // ENC28J60 doesn't have a pin to reset internal PHY
esp_eth_phy_t *phy = esp_eth_phy_new_enc28j60(&phy_config);
esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy);
esp_eth_handle_t eth_handle = NULL;
ESP_ERROR_CHECK(esp_eth_driver_install(&eth_config, &eth_handle));
/* ENC28J60 doesn't burn any factory MAC address, we need to set it manually.
02:00:00 is a Locally Administered OUI range so should not be used except when testing on a LAN under your control.
*/
mac->set_addr(mac, (uint8_t[]) {
0x02, 0x00, 0x00, 0x12, 0x34, 0x56
});
// ENC28J60 Errata #1 check
if (emac_enc28j60_get_chip_info(mac) < ENC28J60_REV_B5 && CONFIG_EXAMPLE_ENC28J60_SPI_CLOCK_MHZ < 8) {
ESP_LOGE(TAG, "SPI frequency must be at least 8 MHz for chip revision less than 5");
ESP_ERROR_CHECK(ESP_FAIL);
}
/* attach Ethernet driver to TCP/IP stack */
ESP_ERROR_CHECK(esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handle)));
// Register user defined event handers
ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL));
/* It is recommended to use ENC28J60 in Full Duplex mode since multiple errata exist to the Half Duplex mode */
#if CONFIG_EXAMPLE_ENC28J60_DUPLEX_FULL
eth_duplex_t duplex = ETH_DUPLEX_FULL;
ESP_ERROR_CHECK(esp_eth_ioctl(eth_handle, ETH_CMD_S_DUPLEX_MODE, &duplex));
#endif
/* start Ethernet driver state machine */
ESP_ERROR_CHECK(esp_eth_start(eth_handle));
}

View File

@ -965,8 +965,6 @@ examples/cxx/exceptions/main/exception_example_main.cpp
examples/cxx/pthread/main/cpp_pthread.cpp
examples/cxx/rtti/main/rtti_example_main.cpp
examples/ethernet/basic/main/ethernet_example_main.c
examples/ethernet/enc28j60/components/eth_enc28j60/enc28j60.h
examples/ethernet/enc28j60/main/enc28j60_example_main.c
examples/get-started/blink/main/blink_example_main.c
examples/mesh/internal_communication/main/include/mesh_light.h
examples/mesh/internal_communication/main/mesh_light.c