Skip to content

Commit 604acc6

Browse files
authored
feat(esp32-ethernet-kit): Add BSP component for esp32-ethernet-kit official development board (#677)
* add ethernet kit component * update readme * update doc * update example code link * add more callback; tear down when init error * update dox;
1 parent 88a7eb8 commit 604acc6

15 files changed

Lines changed: 996 additions & 2 deletions
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
idf_component_register(
2+
INCLUDE_DIRS "include"
3+
SRC_DIRS "src"
4+
REQUIRES
5+
"base_component"
6+
"esp_eth"
7+
"esp_netif"
8+
"esp_event"
9+
REQUIRED_IDF_TARGETS "esp32"
10+
)
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# ESP32-Ethernet-Kit A V1.2
2+
3+
[![Badge](https://components.espressif.com/components/espp/esp32-ethernet-kit/badge.svg)](https://components.espressif.com/components/espp/esp32-ethernet-kit)
4+
5+
Board Support Package (BSP) for the Espressif **ESP32-Ethernet-Kit A V1.2**.
6+
7+
## Official board documentation
8+
9+
- [ESP32-Ethernet-Kit overview](https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32/esp32-ethernet-kit/index.html)
10+
- [ESP32-Ethernet-Kit V1.2 User Guide](https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32/esp32-ethernet-kit/user_guide_v1.2.html)
11+
- [Board schematic V1.2](https://dl.espressif.com/dl/schematics/SCH_ESP32-ETHERNET-KIT_A_V1.2_20200528.pdf)
12+
13+
## What this BSP provides
14+
15+
The `espp::Esp32EthernetKit` class is a singleton hardware abstraction for:
16+
17+
- **10/100 Ethernet** — internal ESP32 EMAC + IP101GRI RMII PHY, selectable
18+
DHCP client **or** DHCP server mode
19+
20+
## Initialization API
21+
22+
The BSP exposes two initialization entry points:
23+
24+
- `initialize_ethernet()`
25+
- `initialize_ethernet(const EthernetConfig &config)`
26+
27+
The no-argument overload is equivalent to `EthernetConfig{}` (DHCP client mode,
28+
no callbacks).
29+
30+
```cpp
31+
auto &board = espp::Esp32EthernetKit::get();
32+
bool ok = board.initialize_ethernet();
33+
```
34+
35+
## DHCP modes and callbacks
36+
37+
Mode selection is done through `EthernetConfig::mode`:
38+
39+
- `DhcpMode::CLIENT` (default): obtains an address from an upstream DHCP server.
40+
- `DhcpMode::SERVER`: serves leases to connected hosts from a static interface IP.
41+
42+
Callback behavior:
43+
44+
- `on_link_up`: cable/link negotiated.
45+
- `on_link_down`: link lost.
46+
- `on_got_ip`: IPv4 becomes usable.
47+
- Client mode: after DHCP lease is obtained.
48+
- Server mode: when link comes up (static IP is already known).
49+
- `on_lost_ip`: IPv4 no longer usable.
50+
- `server_config.on_client_assigned` (server mode only): fires for each lease assignment.
51+
52+
### DHCP client (default)
53+
54+
```cpp
55+
using Kit = espp::Esp32EthernetKit;
56+
57+
Kit::EthernetConfig cfg;
58+
cfg.mode = Kit::DhcpMode::CLIENT;
59+
cfg.on_link_up = []() {
60+
// physical link is up
61+
};
62+
cfg.on_got_ip = [](esp_ip4_addr_t ip) {
63+
// DHCP lease acquired
64+
};
65+
cfg.on_lost_ip = []() {
66+
// lease lost or interface disconnected
67+
};
68+
69+
auto &board = Kit::get();
70+
bool ok = board.initialize_ethernet(cfg);
71+
```
72+
73+
### DHCP server
74+
75+
```cpp
76+
using Kit = espp::Esp32EthernetKit;
77+
78+
Kit::EthernetConfig cfg;
79+
cfg.mode = Kit::DhcpMode::SERVER;
80+
81+
// Leave ip_info all-zero to use default 192.168.4.1/24.
82+
// Or set custom static address information:
83+
// IP4_ADDR(&cfg.server_config.ip_info.ip, 10, 0, 0, 1);
84+
// IP4_ADDR(&cfg.server_config.ip_info.netmask, 255, 255, 255, 0);
85+
// IP4_ADDR(&cfg.server_config.ip_info.gw, 10, 0, 0, 1);
86+
87+
cfg.on_got_ip = [](esp_ip4_addr_t ip) {
88+
// server interface IP became active
89+
};
90+
cfg.server_config.on_client_assigned = [](esp_ip4_addr_t ip, std::array<uint8_t, 6> mac) {
91+
// a client received a lease
92+
};
93+
94+
auto &board = Kit::get();
95+
bool ok = board.initialize_ethernet(cfg);
96+
```
97+
98+
## RMII pin mapping
99+
100+
The ESP32 RMII data-plane signals are fixed to specific GPIOs via IO_MUX and
101+
**cannot be changed**. The control-plane signals (MDC/MDIO/PHY_RST) can be
102+
routed via the GPIO matrix.
103+
104+
| Signal | GPIO | Notes |
105+
|--------------|------|--------------------------------------------|
106+
| REF_CLK (in) | 0 | External 50 MHz oscillator on V1.2 |
107+
| TX_EN | 21 | IO_MUX — fixed |
108+
| TXD0 | 19 | IO_MUX — fixed |
109+
| TXD1 | 22 | IO_MUX — fixed |
110+
| CRS_DV | 27 | IO_MUX — fixed |
111+
| RXD0 | 25 | IO_MUX — fixed |
112+
| RXD1 | 26 | IO_MUX — fixed |
113+
| MDC | 23 | GPIO matrix — reconfigurable |
114+
| MDIO | 18 | GPIO matrix — reconfigurable |
115+
| PHY_RST | 5 | Active-low; set `eth_phy_reset_gpio = -1` to skip |
116+
117+
> [!WARNING]
118+
> **GPIO0 / REF_CLK conflict.** GPIO0 is both the RMII REF_CLK input (driven by
119+
> the on-board 50 MHz oscillator) and the BOOT strapping pin. Pressing BOOT while
120+
> Ethernet is running briefly pulls the clock line to GND, disrupting the 50 MHz
121+
> clock and corrupting active traffic. Do **not** use GPIO0 as a runtime input
122+
> while Ethernet is active.
123+
124+
## sdkconfig requirements
125+
126+
```
127+
CONFIG_ETH_ENABLED=y
128+
CONFIG_ETH_USE_ESP32_EMAC=y
129+
CONFIG_ETH_PHY_ENABLE_IP101=y
130+
```
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# The following lines of boilerplate have to be in your project's CMakeLists
2+
# in this exact order for cmake to work correctly
3+
cmake_minimum_required(VERSION 3.20)
4+
5+
set(ENV{IDF_COMPONENT_MANAGER} "0")
6+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
7+
8+
# add the component directories that we want to use
9+
set(EXTRA_COMPONENT_DIRS
10+
"../../../components/"
11+
)
12+
13+
set(
14+
COMPONENTS
15+
"main esptool_py esp32-ethernet-kit"
16+
CACHE STRING
17+
"List of components to include"
18+
)
19+
20+
project(esp32_ethernet_kit_example)
21+
22+
set(CMAKE_CXX_STANDARD 20)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# ESP32-Ethernet-Kit Example
2+
3+
This example shows how to use the `espp::Esp32EthernetKit` BSP to bring up the
4+
Ethernet interface and print the assigned IP address.
5+
6+
## Hardware
7+
8+
[ESP32-Ethernet-Kit A V1.2](https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32/esp32-ethernet-kit/index.html)
9+
10+
## How to build and flash
11+
12+
```bash
13+
idf.py set-target esp32
14+
idf.py -p PORT flash monitor
15+
```
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
idf_component_register(
2+
SRC_DIRS "."
3+
INCLUDE_DIRS "."
4+
)
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
menu "ESP32-Ethernet-Kit Example Configuration"
2+
3+
choice EXAMPLE_ETH_DHCP_MODE
4+
prompt "DHCP mode"
5+
default EXAMPLE_ETH_DHCP_CLIENT
6+
help
7+
Select whether the board acts as a DHCP client (acquires an IP from
8+
an upstream router) or as a DHCP server (assigns IPs to connected hosts).
9+
10+
config EXAMPLE_ETH_DHCP_CLIENT
11+
bool "DHCP client"
12+
help
13+
The ESP32 requests an IP address from the network's DHCP server.
14+
15+
config EXAMPLE_ETH_DHCP_SERVER
16+
bool "DHCP server"
17+
help
18+
The ESP32 acts as a DHCP server. It gets a static IP and hands out
19+
addresses to connected hosts. Configure the static IP below.
20+
endchoice
21+
22+
if EXAMPLE_ETH_DHCP_SERVER
23+
24+
config EXAMPLE_ETH_SERVER_IP
25+
string "Server static IP address"
26+
default "192.168.4.1"
27+
help
28+
Static IPv4 address assigned to the ESP32's Ethernet interface when
29+
operating as a DHCP server.
30+
31+
config EXAMPLE_ETH_SERVER_NETMASK
32+
string "Server netmask"
33+
default "255.255.255.0"
34+
help
35+
Netmask for the DHCP server subnet.
36+
37+
config EXAMPLE_ETH_SERVER_GW
38+
string "Server gateway"
39+
default "192.168.4.1"
40+
help
41+
Gateway address advertised to DHCP clients (usually the server's own IP).
42+
43+
endif # EXAMPLE_ETH_DHCP_SERVER
44+
45+
endmenu
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
#include <chrono>
2+
#include <thread>
3+
4+
#include <sdkconfig.h>
5+
6+
#include "esp32-ethernet-kit.hpp"
7+
#include "logger.hpp"
8+
9+
#if CONFIG_EXAMPLE_ETH_DHCP_SERVER
10+
#include <lwip/ip4_addr.h>
11+
#endif
12+
13+
using namespace std::chrono_literals;
14+
using DhcpMode = espp::Esp32EthernetKit::DhcpMode;
15+
using EthConfig = espp::Esp32EthernetKit::EthernetConfig;
16+
17+
extern "C" void app_main(void) {
18+
espp::Logger logger({.tag = "EthKitExample", .level = espp::Logger::Verbosity::INFO});
19+
logger.info("ESP32-Ethernet-Kit A V1.2 example starting");
20+
21+
// Example 1: get the singleton board instance
22+
//! [esp32 ethernet kit get instance]
23+
auto &board = espp::Esp32EthernetKit::get();
24+
//! [esp32 ethernet kit get instance]
25+
26+
#if CONFIG_EXAMPLE_ETH_DHCP_SERVER
27+
// Example 2: init as DHCP server -- ESP32 assigns IPs to connected hosts.
28+
// ServerConfig::ip_info zero -> default 192.168.4.1/24. Supply Kconfig
29+
// values (EXAMPLE_ETH_SERVER_IP / _NETMASK / _GW) for a custom static IP.
30+
//! [esp32 ethernet kit dhcp server]
31+
espp::Esp32EthernetKit::ServerConfig srv_cfg;
32+
ip4addr_aton(CONFIG_EXAMPLE_ETH_SERVER_IP, reinterpret_cast<ip4_addr_t *>(&srv_cfg.ip_info.ip));
33+
ip4addr_aton(CONFIG_EXAMPLE_ETH_SERVER_NETMASK,
34+
reinterpret_cast<ip4_addr_t *>(&srv_cfg.ip_info.netmask));
35+
ip4addr_aton(CONFIG_EXAMPLE_ETH_SERVER_GW, reinterpret_cast<ip4_addr_t *>(&srv_cfg.ip_info.gw));
36+
srv_cfg.on_client_assigned = [&](esp_ip4_addr_t ip, std::array<uint8_t, 6> mac) {
37+
logger.info("Client assigned {}.{}.{}.{} (mac {:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x})",
38+
esp_ip4_addr1_16(&ip), esp_ip4_addr2_16(&ip), esp_ip4_addr3_16(&ip),
39+
esp_ip4_addr4_16(&ip), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
40+
};
41+
bool eth_ok = board.initialize_ethernet({
42+
.mode = DhcpMode::SERVER,
43+
.server_config = srv_cfg,
44+
.on_link_up = [&]() { logger.info("Ethernet link up"); },
45+
.on_link_down = [&]() { logger.warn("Ethernet link down"); },
46+
.on_got_ip =
47+
[&](esp_ip4_addr_t ip) {
48+
logger.info("DHCP server up at {}.{}.{}.{}", esp_ip4_addr1_16(&ip),
49+
esp_ip4_addr2_16(&ip), esp_ip4_addr3_16(&ip), esp_ip4_addr4_16(&ip));
50+
},
51+
.on_lost_ip = [&]() { logger.warn("Ethernet lost IP"); },
52+
});
53+
//! [esp32 ethernet kit dhcp server]
54+
#else
55+
// Example 3: init as DHCP client -- ESP32 acquires an IP from the network.
56+
//! [esp32 ethernet kit dhcp client]
57+
bool eth_ok = board.initialize_ethernet({
58+
.mode = DhcpMode::CLIENT,
59+
.on_link_up = [&]() { logger.info("Ethernet link up"); },
60+
.on_link_down = [&]() { logger.warn("Ethernet link down"); },
61+
.on_got_ip =
62+
[&](esp_ip4_addr_t ip) {
63+
logger.info("DHCP lease acquired: {}.{}.{}.{}", esp_ip4_addr1_16(&ip),
64+
esp_ip4_addr2_16(&ip), esp_ip4_addr3_16(&ip), esp_ip4_addr4_16(&ip));
65+
},
66+
.on_lost_ip = [&]() { logger.warn("Ethernet lost IP"); },
67+
});
68+
//! [esp32 ethernet kit dhcp client]
69+
#endif
70+
71+
if (!eth_ok) {
72+
logger.error("Ethernet initialization failed");
73+
return;
74+
}
75+
76+
// SERVER mode: connected as soon as the cable is plugged in (static IP).
77+
// CLIENT mode: connected once the DHCP lease is granted (up to ~30 s).
78+
logger.info("Waiting for Ethernet...");
79+
for (int i = 0; i < 60 && !board.is_ethernet_connected(); ++i) {
80+
std::this_thread::sleep_for(500ms);
81+
}
82+
83+
if (board.is_ethernet_connected()) {
84+
auto ip = board.ethernet_ip();
85+
logger.info("Connected. IP: {}.{}.{}.{}", esp_ip4_addr1_16(&ip), esp_ip4_addr2_16(&ip),
86+
esp_ip4_addr3_16(&ip), esp_ip4_addr4_16(&ip));
87+
} else {
88+
logger.warn("Ethernet not ready within 30 s");
89+
}
90+
91+
while (true) {
92+
std::this_thread::sleep_for(5s);
93+
if (board.is_ethernet_connected()) {
94+
auto ip = board.ethernet_ip();
95+
logger.info("Ethernet up, IP: {}.{}.{}.{}", esp_ip4_addr1_16(&ip), esp_ip4_addr2_16(&ip),
96+
esp_ip4_addr3_16(&ip), esp_ip4_addr4_16(&ip));
97+
} else {
98+
logger.warn("Ethernet not connected");
99+
}
100+
}
101+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CONFIG_IDF_TARGET="esp32"
2+
3+
# Ethernet
4+
CONFIG_ETH_ENABLED=y
5+
CONFIG_ETH_USE_ESP32_EMAC=y
6+
CONFIG_ETH_PHY_ENABLE_IP101=y
7+
8+
# FreeRTOS tick rate
9+
CONFIG_FREERTOS_HZ=1000
10+
11+
# Allow RMII clock on GPIO0 (strapping pin warning suppressed by IDF when used
12+
# as EMAC_CLK_EXT_IN input — GPIO0 is configured as input by the EMAC driver).
13+
CONFIG_ESP_SYSTEM_GPIO_MATRIX_BYPASS=n
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
## IDF Component Manager Manifest File
2+
license: "MIT"
3+
description: "ESP32-Ethernet-Kit A V1.2 Board Support Package (BSP) component in C++"
4+
url: "https://github.com/esp-cpp/espp/tree/main/components/esp32-ethernet-kit"
5+
repository: "git://github.com/esp-cpp/espp.git"
6+
maintainers:
7+
- William Emfinger <waemfinger@gmail.com>
8+
documentation: "https://esp-cpp.github.io/espp/dev_boards/espressif/esp32_ethernet_kit.html"
9+
examples:
10+
- path: example
11+
tags:
12+
- cpp
13+
- Component
14+
- BSP
15+
- ESP32
16+
- Ethernet
17+
- EthernetKit
18+
dependencies:
19+
idf: ">=5.0"
20+
espp/base_component: ">=1.0"
21+
targets:
22+
- esp32

0 commit comments

Comments
 (0)