feat(bsp): Add esp32-p4-eth and esp32-p4-nano Ethernet BSPs - #690
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds two new ESP32-P4 Ethernet BSP components (for Waveshare ESP32-P4-ETH and ESP32-P4-NANO) that configure RMII pins and delegate bring-up to the shared espp::Ethernet component, along with documentation pages and CI example builds.
Changes:
- Added
esp32-p4-ethandesp32-p4-nanoBSP components (headers, sources, manifests) plus per-board examples. - Wired the new BSPs into Sphinx dev-board docs (Waveshare toctree + per-board pages) and Doxygen input/example lists.
- Added both examples to the GitHub Actions build matrix for
esp32p4.
Reviewed changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| doc/en/dev_boards/waveshare/index.rst | Adds the two new Waveshare board pages to the toctree. |
| doc/en/dev_boards/waveshare/esp32_p4_nano.rst | New dev-board documentation page for ESP32-P4-NANO BSP. |
| doc/en/dev_boards/waveshare/esp32_p4_nano_example.md | Includes the component example README into the docs. |
| doc/en/dev_boards/waveshare/esp32_p4_eth.rst | New dev-board documentation page for ESP32-P4-ETH BSP. |
| doc/en/dev_boards/waveshare/esp32_p4_eth_example.md | Includes the component example README into the docs. |
| doc/Doxyfile | Registers new BSP headers and examples for Doxygen/Sphinx integration. |
| components/esp32-p4-nano/src/esp32-p4-nano.cpp | Implements Ethernet initialization via espp::Ethernet with board RMII pins. |
| components/esp32-p4-nano/README.md | Documents the new esp32-p4-nano BSP and example. |
| components/esp32-p4-nano/include/esp32-p4-nano.hpp | Public BSP API, config structs, and RMII pin constants. |
| components/esp32-p4-nano/idf_component.yml | Component Manager manifest for esp32-p4-nano. |
| components/esp32-p4-nano/example/sdkconfig.defaults | Example defaults enabling internal EMAC RMII for esp32p4. |
| components/esp32-p4-nano/example/README.md | Example usage/build/flash instructions. |
| components/esp32-p4-nano/example/main/esp32_p4_nano_example.cpp | Example app that brings up Ethernet and logs link/IP status. |
| components/esp32-p4-nano/example/main/CMakeLists.txt | Registers the example “main” component. |
| components/esp32-p4-nano/example/CMakeLists.txt | ESP-IDF example project config referencing local components. |
| components/esp32-p4-nano/CMakeLists.txt | Registers the BSP component with its dependencies and target. |
| components/esp32-p4-eth/src/esp32-p4-eth.cpp | Implements Ethernet initialization via espp::Ethernet with board RMII pins. |
| components/esp32-p4-eth/README.md | Documents the new esp32-p4-eth BSP and example. |
| components/esp32-p4-eth/include/esp32-p4-eth.hpp | Public BSP API, config structs, and RMII pin constants. |
| components/esp32-p4-eth/idf_component.yml | Component Manager manifest for esp32-p4-eth. |
| components/esp32-p4-eth/example/sdkconfig.defaults | Example defaults enabling internal EMAC RMII for esp32p4. |
| components/esp32-p4-eth/example/README.md | Example usage/build/flash instructions. |
| components/esp32-p4-eth/example/main/esp32_p4_eth_example.cpp | Example app that brings up Ethernet and logs link/IP status. |
| components/esp32-p4-eth/example/main/CMakeLists.txt | Registers the example “main” component. |
| components/esp32-p4-eth/example/CMakeLists.txt | ESP-IDF example project config referencing local components. |
| components/esp32-p4-eth/CMakeLists.txt | Registers the BSP component with its dependencies and target. |
| .github/workflows/build.yml | Adds both new examples to the CI build matrix. |
Suppressed comments (1)
doc/Doxyfile:272
- The
INPUTlist appears to be maintained in alphabetical order in this region, but the new ESP32-P4 BSP headers are added afteresp32-p4-function-ev-board. Please reorder these entries soesp32-p4-ethandesp32-p4-nanoare listed beforeesp32-p4-function-ev-boardand beforeesp32-timer-cam.
$(PROJECT_PATH)/components/esp32-ethernet-kit/include/esp32-ethernet-kit.hpp \
$(PROJECT_PATH)/components/esp32-p4-function-ev-board/include/esp32-p4-function-ev-board.hpp \
$(PROJECT_PATH)/components/esp32-p4-eth/include/esp32-p4-eth.hpp \
$(PROJECT_PATH)/components/esp32-p4-nano/include/esp32-p4-nano.hpp \
$(PROJECT_PATH)/components/esp32-timer-cam/include/esp32-timer-cam.hpp \
bdc2366 to
e12b885
Compare
|
✅Static analysis result - no issues found! ✅ |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 27 out of 27 changed files in this pull request and generated 2 comments.
Suppressed comments (4)
doc/en/dev_boards/waveshare/esp32_p4_eth.rst:12
- The
:doc:role is split across lines, which can break parsing/rendering in Sphinx/ReST. Keep the entire role on one line (e.g.,:doc:espp::Ethernet <../../network/ethernet>``) to avoid documentation build warnings/errors.
The ``espp::Esp32P4Eth`` component provides a singleton hardware abstraction for
bringing up the board's Ethernet, delegating to the reusable :doc:`espp::Ethernet
<../../network/ethernet>` component and supplying the board-specific RMII pins.
doc/en/dev_boards/waveshare/esp32_p4_nano.rst:12
- Same as
esp32_p4_eth.rst: the:doc:role should not be broken across lines. Put:doc:espp::Ethernet <../../network/ethernet>`` on a single line to ensure Sphinx parses it correctly.
The ``espp::Esp32P4Nano`` component provides a singleton hardware abstraction for
bringing up the board's Ethernet, delegating to the reusable :doc:`espp::Ethernet
<../../network/ethernet>` component and supplying the board-specific RMII pins.
components/esp32-p4-eth/idf_component.yml:5
- Using the unauthenticated
git://transport can be blocked in some environments and provides no transport security. Preferhttps://github.com/esp-cpp/espp.git(orssh://) for integrity/confidentiality and better compatibility.
repository: "git://github.com/esp-cpp/espp.git"
components/esp32-p4-nano/src/esp32-p4-nano.cpp:47
- The Ethernet initialization logic here appears byte-identical to
Esp32P4Eth(and the pinout constants are also identical per the PR description). To prevent the two BSPs from drifting, consider factoring this into a shared helper/base (e.g., a commonconfigure_ethernet(Config&, EthernetConfig&)function or a smallRmiiPinstraits struct reused by both). This keeps future changes (new callbacks/fields inespp::Ethernet::Config, pin updates, logging changes) from needing to be duplicated.
bool Esp32P4Nano::initialize_ethernet() { return initialize_ethernet(EthernetConfig{}); }
bool Esp32P4Nano::initialize_ethernet(const EthernetConfig &config) {
if (ethernet_ && ethernet_->is_initialized()) {
logger_.warn("Ethernet already initialized");
return true;
}
logger_.info("Initializing Ethernet (EMAC + IP101GRI RMII, DHCP {})",
config.mode == DhcpMode::SERVER ? "server" : "client");
espp::Ethernet::Config eth_config{};
eth_config.interface = espp::Ethernet::RmiiConfig{
.mdc_gpio = eth_mdc_io,
.mdio_gpio = eth_mdio_io,
.phy_addr = eth_phy_addr,
.phy_reset_gpio = eth_phy_reset_gpio,
.clock_ext_in = true,
.clock_gpio = eth_ref_clk_io,
.data_pins = espp::Ethernet::RmiiConfig::DataPins{.tx_en = eth_tx_en_io,
.txd0 = eth_txd0_io,
.txd1 = eth_txd1_io,
.crs_dv = eth_crs_dv_io,
.rxd0 = eth_rxd0_io,
.rxd1 = eth_rxd1_io},
};
eth_config.mode = (config.mode == DhcpMode::SERVER) ? espp::Ethernet::DhcpMode::SERVER
: espp::Ethernet::DhcpMode::CLIENT;
if (config.mode == DhcpMode::SERVER) {
eth_config.ip_info = config.server_config.ip_info;
eth_config.on_client_assigned = config.server_config.on_client_assigned;
}
eth_config.on_link_up = config.on_link_up;
eth_config.on_link_down = config.on_link_down;
eth_config.on_got_ip = config.on_got_ip;
eth_config.on_lost_ip = config.on_lost_ip;
ethernet_ = std::make_unique<espp::Ethernet>(eth_config);
return ethernet_->initialize();
}
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 27 out of 27 changed files in this pull request and generated 1 comment.
Suppressed comments (3)
doc/en/dev_boards/waveshare/esp32_p4_eth.rst:12
- The
:doc:role is split across lines, which can break Sphinx/ReST parsing or render the link incorrectly. Keep the:doc:inline in a single line (or switch to an explicit reference) and mirror the same fix indoc/en/dev_boards/waveshare/esp32_p4_nano.rst.
The ``espp::Esp32P4Eth`` component provides a singleton hardware abstraction for
bringing up the board's Ethernet, delegating to the reusable :doc:`espp::Ethernet
<../../network/ethernet>` component and supplying the board-specific RMII pins.
components/esp32-p4-eth/idf_component.yml:5
- Using the
git://transport is unencrypted and commonly blocked in CI/networks. Prefer the HTTPS URL (e.g.,https://github.com/esp-cpp/espp.git) for integrity/confidentiality. Apply the same change incomponents/esp32-p4-nano/idf_component.yml.
repository: "git://github.com/esp-cpp/espp.git"
components/esp32-p4-eth/src/esp32-p4-eth.cpp:47
- The ETH and NANO BSP implementations appear byte-identical besides class/pin constants, which increases maintenance cost (any future behavior change needs to be duplicated). Consider factoring the shared Ethernet bring-up logic into a common helper (e.g., a small internal function or a shared base/templated utility that takes the pin mapping) so only the pin definitions differ per board.
bool Esp32P4Eth::initialize_ethernet() { return initialize_ethernet(EthernetConfig{}); }
bool Esp32P4Eth::initialize_ethernet(const EthernetConfig &config) {
if (ethernet_ && ethernet_->is_initialized()) {
logger_.warn("Ethernet already initialized");
return true;
}
logger_.info("Initializing Ethernet (EMAC + IP101GRI RMII, DHCP {})",
config.mode == DhcpMode::SERVER ? "server" : "client");
espp::Ethernet::Config eth_config{};
eth_config.interface = espp::Ethernet::RmiiConfig{
.mdc_gpio = eth_mdc_io,
.mdio_gpio = eth_mdio_io,
.phy_addr = eth_phy_addr,
.phy_reset_gpio = eth_phy_reset_gpio,
.clock_ext_in = true,
.clock_gpio = eth_ref_clk_io,
.data_pins = espp::Ethernet::RmiiConfig::DataPins{.tx_en = eth_tx_en_io,
.txd0 = eth_txd0_io,
.txd1 = eth_txd1_io,
.crs_dv = eth_crs_dv_io,
.rxd0 = eth_rxd0_io,
.rxd1 = eth_rxd1_io},
};
eth_config.mode = (config.mode == DhcpMode::SERVER) ? espp::Ethernet::DhcpMode::SERVER
: espp::Ethernet::DhcpMode::CLIENT;
if (config.mode == DhcpMode::SERVER) {
eth_config.ip_info = config.server_config.ip_info;
eth_config.on_client_assigned = config.server_config.on_client_assigned;
}
eth_config.on_link_up = config.on_link_up;
eth_config.on_link_down = config.on_link_down;
eth_config.on_got_ip = config.on_got_ip;
eth_config.on_lost_ip = config.on_lost_ip;
ethernet_ = std::make_unique<espp::Ethernet>(eth_config);
return ethernet_->initialize();
}
e12b885 to
c3a7670
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 27 out of 27 changed files in this pull request and generated no new comments.
Suppressed comments (6)
components/esp32-p4-eth/idf_component.yml:5
repositoryuses thegit://protocol, which is unencrypted and commonly blocked/disabled in some environments. Prefer anhttps://repository URL to avoid MITM risk and improve compatibility (and apply the same change to the esp32-p4-nano manifest as well).
url: "https://github.com/esp-cpp/espp/tree/main/components/esp32-p4-eth"
repository: "git://github.com/esp-cpp/espp.git"
components/esp32-p4-nano/idf_component.yml:5
repositoryuses thegit://protocol, which is unencrypted and commonly blocked/disabled in some environments. Prefer anhttps://repository URL to avoid MITM risk and improve compatibility (and keep it consistent with other component manifests).
url: "https://github.com/esp-cpp/espp/tree/main/components/esp32-p4-nano"
repository: "git://github.com/esp-cpp/espp.git"
components/esp32-p4-eth/include/esp32-p4-eth.hpp:62
- Spelling is inconsistent within the same header (
initialize_ethernet/initializedelsewhere uses American English). Consider changingzero-initialisedtozero-initializedfor consistency (and apply the same change inesp32-p4-nano.hpp).
/// Leave \c ip_info zero-initialised to use the built-in defaults
components/esp32-p4-eth/src/esp32-p4-eth.cpp:10
- The Ethernet config mapping logic appears duplicated verbatim between
esp32-p4-ethandesp32-p4-nano. To reduce the risk of future divergence, consider extracting a small shared helper (e.g., a private function or shared internal header) that buildsespp::Ethernet::Configfrom pins +EthernetConfig.
bool Esp32P4Eth::initialize_ethernet(const EthernetConfig &config) {
components/esp32-p4-eth/src/esp32-p4-eth.cpp:43
- The Ethernet config mapping logic appears duplicated verbatim between
esp32-p4-ethandesp32-p4-nano. To reduce the risk of future divergence, consider extracting a small shared helper (e.g., a private function or shared internal header) that buildsespp::Ethernet::Configfrom pins +EthernetConfig.
espp::Ethernet::Config eth_config{};
eth_config.interface = espp::Ethernet::RmiiConfig{
.mdc_gpio = eth_mdc_io,
.mdio_gpio = eth_mdio_io,
.phy_addr = eth_phy_addr,
.phy_reset_gpio = eth_phy_reset_gpio,
.clock_ext_in = true,
.clock_gpio = eth_ref_clk_io,
.data_pins = espp::Ethernet::RmiiConfig::DataPins{.tx_en = eth_tx_en_io,
.txd0 = eth_txd0_io,
.txd1 = eth_txd1_io,
.crs_dv = eth_crs_dv_io,
.rxd0 = eth_rxd0_io,
.rxd1 = eth_rxd1_io},
};
eth_config.mode = (config.mode == DhcpMode::SERVER) ? espp::Ethernet::DhcpMode::SERVER
: espp::Ethernet::DhcpMode::CLIENT;
if (config.mode == DhcpMode::SERVER) {
eth_config.ip_info = config.server_config.ip_info;
eth_config.on_client_assigned = config.server_config.on_client_assigned;
}
eth_config.on_link_up = config.on_link_up;
eth_config.on_link_down = config.on_link_down;
eth_config.on_got_ip = config.on_got_ip;
eth_config.on_lost_ip = config.on_lost_ip;
components/esp32-p4-eth/example/main/esp32_p4_eth_example.cpp:34
- If initialization fails, the example keeps running and will repeatedly log
connected=false ip=false, which can hide the original failure. Consider returning early (or adding a retry/backoff loop) after logging the error; apply the same improvement to the nano example too.
if (!ok) {
logger.error("Failed to initialize Ethernet");
}
//! [esp32 p4 eth example]
while (true) {
logger.info("connected={} ip={}", board.is_ethernet_connected(), board.ethernet_ip().addr != 0);
std::this_thread::sleep_for(5s);
}
Add two ESP32-P4 board support packages that expose their 10/100 Ethernet (internal EMAC + IP101GRI RMII PHY) via the reusable espp::Ethernet component: - espp::Esp32P4Eth (Waveshare ESP32-P4-ETH) - espp::Esp32P4Nano (Waveshare ESP32-P4-NANO) Both boards use the standard ESP32-P4 RMII pinout (MDC=31, MDIO=52, REF_CLK=50, TX_EN=49, TXD0=34, TXD1=35, CRS_DV=28, RXD0=29, RXD1=30, PHY reset=51, IP101 at addr 1), so each BSP is a thin singleton that supplies those board pins as an Ethernet::RmiiConfig (with routable data_pins) and maps a DHCP client/server + callback config onto espp::Ethernet. Each ships an example, README, and dev-board docs (rst + example include, added to the Waveshare toctree and the Doxyfile), plus CI build-matrix entries. Verified: both examples build for esp32p4; cppcheck and a Doxygen parse are clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
c3a7670 to
2c3a04d
Compare
|
Added `components/esp32-p4-eth` and `components/esp32-p4-nano` to the `upload_components` CI job so the two new BSPs are published to the component registry. They are listed after `components/ethernet` (their dependency), keeping the `esp32-p4-*` cluster alphabetical (eth → function-ev-board → nano). |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 28 out of 28 changed files in this pull request and generated 1 comment.
Suppressed comments (4)
components/esp32-p4-eth/include/esp32-p4-eth.hpp:45
- The new type alias name
client_ip_callback_tuses snake_case +_t, while the surrounding aliases use PascalCase (EthernetLinkCallback,EthernetIpCallback). For consistency and readability, rename this alias to match the local convention (e.g.,ClientIpCallback). (Same naming appears incomponents/esp32-p4-nano/include/esp32-p4-nano.hpp.)
using client_ip_callback_t = std::function<void(esp_ip4_addr_t ip, std::array<uint8_t, 6> mac)>;
doc/en/dev_boards/waveshare/esp32_p4_eth.rst:12
- The
:doc:role is split across a newline. reStructuredText/Sphinx inline roles can be fragile when line-wrapped inside the role markup and may fail to parse depending on the builder/config. Put the entire:doc:role on a single line (keep line wrapping outside the backticks). (Same pattern appears indoc/en/dev_boards/waveshare/esp32_p4_nano.rst.)
The ``espp::Esp32P4Eth`` component provides a singleton hardware abstraction for
bringing up the board's Ethernet, delegating to the reusable :doc:`espp::Ethernet
<../../network/ethernet>` component and supplying the board-specific RMII pins.
components/esp32-p4-eth/idf_component.yml:5
- Using the
git://transport can fail in many CI/corporate networks (port 9418 often blocked) and is increasingly uncommon. Prefer an HTTPS repository URL to improve reliability of fetching in constrained environments. (Same value appears incomponents/esp32-p4-nano/idf_component.yml.)
repository: "git://github.com/esp-cpp/espp.git"
components/esp32-p4-eth/src/esp32-p4-eth.cpp:14
- This BSP and the ESP32-P4-NANO BSP share near-identical implementation and pin mapping, which creates duplicated maintenance surfaces (bug fixes/feature changes must be made twice). Consider factoring the shared Ethernet bring-up logic into a small internal helper (or a shared base) and keeping only the board identity/pin constants in the two BSPs. This is optional, but it will likely reduce future drift.
bool Esp32P4Eth::initialize_ethernet() { return initialize_ethernet(EthernetConfig{}); }
bool Esp32P4Eth::initialize_ethernet(const EthernetConfig &config) {
if (ethernet_ && ethernet_->is_initialized()) {
logger_.warn("Ethernet already initialized");
return true;
}
| espp::Ethernet::Config eth_config{}; | ||
| eth_config.interface = espp::Ethernet::RmiiConfig{ | ||
| .mdc_gpio = eth_mdc_io, | ||
| .mdio_gpio = eth_mdio_io, | ||
| .phy_addr = eth_phy_addr, | ||
| .phy_reset_gpio = eth_phy_reset_gpio, | ||
| .clock_ext_in = true, | ||
| .clock_gpio = eth_ref_clk_io, | ||
| .data_pins = espp::Ethernet::RmiiConfig::DataPins{.tx_en = eth_tx_en_io, | ||
| .txd0 = eth_txd0_io, | ||
| .txd1 = eth_txd1_io, | ||
| .crs_dv = eth_crs_dv_io, | ||
| .rxd0 = eth_rxd0_io, | ||
| .rxd1 = eth_rxd1_io}, | ||
| }; |
Description
Adds two ESP32-P4 board support packages that expose their 10/100 Ethernet
(internal EMAC + IP101GRI RMII PHY) via the reusable
espp::Ethernetcomponentintroduced in #689:
espp::Esp32P4Eth— Waveshare ESP32-P4-ETHespp::Esp32P4Nano— Waveshare ESP32-P4-NANOBoth boards use the standard ESP32-P4 RMII pinout (MDC=31, MDIO=52, REF_CLK=50,
TX_EN=49, TXD0=34, TXD1=35, CRS_DV=28, RXD0=29, RXD1=30, PHY reset=51, IP101 at
addr 1), so each BSP is a thin singleton that supplies those board pins as an
Ethernet::RmiiConfig(with routabledata_pins) and maps a DHCP client/server +callback config onto
espp::Ethernet.Each ships an example, README, and dev-board docs (rst + example include, added
to the Waveshare toctree and the Doxyfile), plus CI build-matrix entries.
Motivation and Context
Demonstrates the new Ethernet component on two more real boards and adds
first-class BSP support for them. Because these P4 boards share the exact RMII
pinout, each BSP reduces to a few lines of board pins on top of the shared
component.
How has this been tested?
DHCP + IP); see feat(ethernet): Add a reusable Ethernet component (RMII + SPI) #689. The ESP32-P4-NANO uses a byte-identical RMII pinout, so
it is validated by extension (not separately flashed).
with zero warnings.
The pinouts come from the Waveshare wikis; the
TXD[1:0]/RXD[1:0]bit-orderingin those docs is slightly ambiguous, but the DHCP success on ESP32-P4-ETH (a full
bidirectional exchange) confirms the ordering used here.
Screenshots (if appropriate, e.g. schematic, board, console logs, lab pictures):
Console (ESP32-P4-ETH):
Types of changes
Checklist:
Software
.github/workflows/build.ymlfile to add my new test to the automated cloud build github action.