mirror of
https://github.com/rstrouse/ESPSomfy-RTS.git
synced 2026-10-31 13:52:15 +01:00
build: add the ESP32-P4 (#29)
For boards such as Waveshare's ESP32-P4-WIFI6-POE-ETH: WiFi through the board's ESP32-C6 on SDIO (esp-hosted), Ethernet on the P4's RMII MAC with an IP101. Not tested on a device: no P4 board was at hand. - platformio.ini: env esp32p4 (esp32-p4_r3, chip v3.01+) and esp32p4es (esp32-p4, the esp32p4_es libraries, chips before v2.0). An image runs on one of the two only, so each has its own release files, chip models "p4" and "p4es". Both keep the OTA slot: at level 2 they leave about 128 KB of it. - Ethernet clock mode: stored as eth_clock_id_t in the ESP32's numbering and translated by name, like the PHY id. The P4's eth_clock_mode_t is the IDF's emac_rmii_clock_mode_t, whose 0 is a deprecated default; only clock in (GPIO 50) translates there. - P4 Ethernet defaults: the Waveshare wiring (IP101 as TLK110, address 1, MDC 31, MDIO 52, reset 51), board type 8. The ESP32's put MDIO on an SDIO pin. - Settings take pins up to GPIO 54, the P4's last, instead of 48. - Radio defaults: SPI 32/33/27, CSN 46 (the framework's Waveshare variant), TX 2, RX 3. - Web UI: a Waveshare ESP32-P4-ETH preset, the P4's clock mode, pin lists up to GPIO 54 without the pins the C6 link, Ethernet, USB and UART0 use. - CI builds and releases both, with their ELFs; bootloader at 0x2000. - ADR 0003: amended. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
eadd9b801d
commit
dfb003d2f7
19 changed files with 282 additions and 38 deletions
|
|
@ -149,7 +149,7 @@ static net_record_t netRecord() {
|
|||
#if HAS_ETHERNET
|
||||
rec.ethBoardType = settings.Ethernet.boardType;
|
||||
rec.ethPhyType = settings.Ethernet.phyType;
|
||||
rec.ethClkMode = static_cast<uint8_t>(settings.Ethernet.CLKMode);
|
||||
rec.ethClkMode = settings.Ethernet.CLKMode;
|
||||
rec.ethPhyAddress = settings.Ethernet.phyAddress;
|
||||
rec.ethPWRPin = settings.Ethernet.PWRPin;
|
||||
rec.ethMDCPin = settings.Ethernet.MDCPin;
|
||||
|
|
@ -196,7 +196,7 @@ static void applyNetRecord(const net_record_t &rec, const restore_options_t &opt
|
|||
ESP_LOGI(TAG, "Restoring Ethernet adapter settings");
|
||||
settings.Ethernet.boardType = rec.ethBoardType;
|
||||
settings.Ethernet.phyType = rec.ethPhyType;
|
||||
settings.Ethernet.CLKMode = static_cast<eth_clock_mode_t>(rec.ethClkMode);
|
||||
settings.Ethernet.CLKMode = rec.ethClkMode;
|
||||
settings.Ethernet.phyAddress = rec.ethPhyAddress;
|
||||
settings.Ethernet.PWRPin = rec.ethPWRPin;
|
||||
settings.Ethernet.MDCPin = rec.ethMDCPin;
|
||||
|
|
|
|||
|
|
@ -145,6 +145,17 @@ bool ConfigSettings::begin() {
|
|||
strcpy(this->chipModel, "c6");
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32P4
|
||||
// Chips before v3.0 run their own build (esp32p4_es libraries), so they
|
||||
// get their own release files.
|
||||
case esp_chip_model_t::CHIP_ESP32P4:
|
||||
#if CONFIG_ESP32P4_SELECTS_REV_LESS_V3
|
||||
strcpy(this->chipModel, "p4es");
|
||||
#else
|
||||
strcpy(this->chipModel, "p4");
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
sprintf(this->chipModel, "UNK%d", static_cast<int>(ci.model));
|
||||
break;
|
||||
|
|
@ -499,7 +510,7 @@ bool EthernetSettings::begin() {
|
|||
bool EthernetSettings::fromJSON(JsonObject &obj) {
|
||||
if(!obj["boardType"].isNull()) this->boardType = obj["boardType"];
|
||||
if(!obj["phyAddress"].isNull()) this->phyAddress = obj["phyAddress"];
|
||||
if(!obj["CLKMode"].isNull()) this->CLKMode = static_cast<eth_clock_mode_t>(obj["CLKMode"]);
|
||||
if(!obj["CLKMode"].isNull()) this->CLKMode = obj["CLKMode"];
|
||||
if(!obj["phyType"].isNull()) this->phyType = obj["phyType"];
|
||||
if(!obj["PWRPin"].isNull()) this->PWRPin = obj["PWRPin"];
|
||||
if(!obj["MDCPin"].isNull()) this->MDCPin = obj["MDCPin"];
|
||||
|
|
@ -507,9 +518,7 @@ bool EthernetSettings::fromJSON(JsonObject &obj) {
|
|||
return true;
|
||||
}
|
||||
bool EthernetSettings::usesPin(uint8_t pin) {
|
||||
if((this->CLKMode == 0 || this->CLKMode == 1) && pin == 0) return true;
|
||||
else if(this->CLKMode == 2 && pin == 16) return true;
|
||||
else if(this->CLKMode == 3 && pin == 17) return true;
|
||||
if(ethClockPin(this->CLKMode) == pin) return true;
|
||||
else if(this->PWRPin == pin) return true;
|
||||
else if(this->MDCPin == pin) return true;
|
||||
else if(this->MDIOPin == pin) return true;
|
||||
|
|
@ -522,7 +531,7 @@ bool EthernetSettings::save() {
|
|||
pref.putChar("boardType", this->boardType);
|
||||
pref.putChar("phyAddress", this->phyAddress);
|
||||
pref.putChar("phyType", this->phyType);
|
||||
pref.putChar("CLKMode", static_cast<uint8_t>(this->CLKMode));
|
||||
pref.putChar("CLKMode", this->CLKMode);
|
||||
pref.putChar("PWRPin", this->PWRPin);
|
||||
pref.putChar("MDCPin", this->MDCPin);
|
||||
pref.putChar("MDIOPin", this->MDIOPin);
|
||||
|
|
@ -534,7 +543,7 @@ bool EthernetSettings::load() {
|
|||
pref.begin("ETH");
|
||||
this->boardType = pref.getChar("boardType", this->boardType);
|
||||
this->phyType = pref.getChar("phyType", this->phyType);
|
||||
this->CLKMode = static_cast<eth_clock_mode_t>(pref.getChar("CLKMode", ETH_CLOCK_GPIO0_IN));
|
||||
this->CLKMode = pref.getChar("CLKMode", this->CLKMode);
|
||||
this->phyAddress = pref.getChar("phyAddress", this->phyAddress);
|
||||
this->PWRPin = pref.getChar("PWRPin", this->PWRPin);
|
||||
this->MDCPin = pref.getChar("MDCPin", this->MDCPin);
|
||||
|
|
|
|||
|
|
@ -88,14 +88,26 @@ class WifiSettings: BaseSettings {
|
|||
class EthernetSettings: BaseSettings {
|
||||
public:
|
||||
EthernetSettings();
|
||||
uint8_t CLKMode = static_cast<uint8_t>(eth_clock_id_t::GPIO0_IN); // An eth_clock_id_t, see EthPhy.h.
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32P4)
|
||||
// The IP101 wiring of Espressif's P4 boards, which Waveshare's ESP32-P4-ETH
|
||||
// boards copy, and the web UI's board type for it. The ESP32's defaults
|
||||
// would put MDIO on an SDIO pin.
|
||||
uint8_t boardType = 8;
|
||||
uint8_t phyType = static_cast<uint8_t>(eth_phy_id_t::TLK110);
|
||||
int8_t phyAddress = 1;
|
||||
int8_t PWRPin = 51;
|
||||
int8_t MDCPin = 31;
|
||||
int8_t MDIOPin = 52;
|
||||
#else
|
||||
uint8_t boardType = 0; // These board types are enumerated in the ui and used to set the chip settings.
|
||||
uint8_t phyType = static_cast<uint8_t>(eth_phy_id_t::LAN8720); // An eth_phy_id_t, see EthPhy.h.
|
||||
eth_clock_mode_t CLKMode = ETH_CLOCK_GPIO0_IN;
|
||||
// The LAN8720 wiring Arduino 2.x defaulted to. 3.x has no defaults.
|
||||
int8_t phyAddress = 0;
|
||||
int8_t PWRPin = -1;
|
||||
int8_t MDCPin = 23;
|
||||
int8_t MDIOPin = 18;
|
||||
#endif
|
||||
|
||||
bool begin();
|
||||
bool fromJSON(JsonObject &obj);
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ static void writeSettings(ProtoWriter &w, settings_section_t section) {
|
|||
w.add(proto_field_t::hasEthernet, true);
|
||||
w.add(proto_field_t::boardType, settings.Ethernet.boardType);
|
||||
w.add(proto_field_t::phyType, settings.Ethernet.phyType);
|
||||
w.add(proto_field_t::CLKMode, static_cast<uint8_t>(settings.Ethernet.CLKMode));
|
||||
w.add(proto_field_t::CLKMode, settings.Ethernet.CLKMode);
|
||||
w.add(proto_field_t::phyAddress, settings.Ethernet.phyAddress);
|
||||
w.add(proto_field_t::PWRPin, settings.Ethernet.PWRPin);
|
||||
w.add(proto_field_t::MDCPin, settings.Ethernet.MDCPin);
|
||||
|
|
|
|||
|
|
@ -356,11 +356,14 @@ bool ESPNetwork::connectWired() {
|
|||
ETH.setHostname("ESPSomfy-RTS");
|
||||
ESP_LOGD(TAG, "Set hostname to: %s", ETH.getHostname());
|
||||
eth_phy_type_t phyType;
|
||||
eth_clock_mode_t clkMode;
|
||||
bool begun = false;
|
||||
if(!ethPhyType(settings.Ethernet.phyType, phyType))
|
||||
ESP_LOGE(TAG, "Ethernet PHY type %u is not supported", (unsigned int)settings.Ethernet.phyType);
|
||||
else if(!ethClockMode(settings.Ethernet.CLKMode, clkMode))
|
||||
ESP_LOGE(TAG, "Ethernet clock mode %u is not supported", (unsigned int)settings.Ethernet.CLKMode);
|
||||
else
|
||||
begun = ETH.begin(phyType, settings.Ethernet.phyAddress, settings.Ethernet.MDCPin, settings.Ethernet.MDIOPin, settings.Ethernet.PWRPin, settings.Ethernet.CLKMode);
|
||||
begun = ETH.begin(phyType, settings.Ethernet.phyAddress, settings.Ethernet.MDCPin, settings.Ethernet.MDIOPin, settings.Ethernet.PWRPin, clkMode);
|
||||
if(!begun) {
|
||||
ESP_LOGE(TAG, "Ethernet Begin failed");
|
||||
this->ethStarted = false;
|
||||
|
|
|
|||
45
src/EthPhy.h
45
src/EthPhy.h
|
|
@ -5,8 +5,8 @@
|
|||
#include <sdkconfig.h>
|
||||
#endif
|
||||
|
||||
// Ethernet needs the RMII MAC, which only the original ESP32 has. The C3, C5,
|
||||
// S3 and C6 build without it.
|
||||
// Ethernet needs the RMII MAC, which only the original ESP32 and the P4 have.
|
||||
// The C3, C5, S3 and C6 build without it.
|
||||
#if defined(CONFIG_ETH_USE_ESP32_EMAC) && CONFIG_ETH_USE_ESP32_EMAC
|
||||
#define HAS_ETHERNET 1
|
||||
#else
|
||||
|
|
@ -26,6 +26,32 @@ enum class eth_phy_id_t : uint8_t {
|
|||
KSZ8081 = 6
|
||||
};
|
||||
|
||||
// RMII clock ids as stored in NVS and backups and sent to the web UI: the
|
||||
// original ESP32's eth_clock_mode_t values. The P4's eth_clock_mode_t is the
|
||||
// IDF's emac_rmii_clock_mode_t, a different enum, so an id is translated.
|
||||
enum class eth_clock_id_t : uint8_t {
|
||||
GPIO0_IN = 0, // The clock comes in. On the P4, on GPIO 50.
|
||||
GPIO0_OUT = 1,
|
||||
GPIO16_OUT = 2,
|
||||
GPIO17_OUT = 3
|
||||
};
|
||||
|
||||
// The GPIO a stored clock id puts the RMII clock on, -1 for an id the chip
|
||||
// can't use. The P4's ETH.begin() takes the clock in on GPIO 50 only.
|
||||
inline int8_t ethClockPin(uint8_t id) {
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32P4)
|
||||
return static_cast<eth_clock_id_t>(id) == eth_clock_id_t::GPIO0_IN ? 50 : -1;
|
||||
#else
|
||||
switch(static_cast<eth_clock_id_t>(id)) {
|
||||
case eth_clock_id_t::GPIO0_IN:
|
||||
case eth_clock_id_t::GPIO0_OUT: return 0;
|
||||
case eth_clock_id_t::GPIO16_OUT: return 16;
|
||||
case eth_clock_id_t::GPIO17_OUT: return 17;
|
||||
default: return -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if HAS_ETHERNET
|
||||
#include <ETH.h>
|
||||
// Sets type to the framework's PHY for a stored id. False for an id the RMII
|
||||
|
|
@ -41,5 +67,20 @@ inline bool ethPhyType(uint8_t id, eth_phy_type_t &type) {
|
|||
default: return false;
|
||||
}
|
||||
}
|
||||
// Sets mode to the framework's clock mode for a stored id. False for an id
|
||||
// the chip can't use.
|
||||
inline bool ethClockMode(uint8_t id, eth_clock_mode_t &mode) {
|
||||
switch(static_cast<eth_clock_id_t>(id)) {
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32P4)
|
||||
case eth_clock_id_t::GPIO0_IN: mode = EMAC_CLK_EXT_IN; return true;
|
||||
#else
|
||||
case eth_clock_id_t::GPIO0_IN: mode = ETH_CLOCK_GPIO0_IN; return true;
|
||||
case eth_clock_id_t::GPIO0_OUT: mode = ETH_CLOCK_GPIO0_OUT; return true;
|
||||
case eth_clock_id_t::GPIO16_OUT: mode = ETH_CLOCK_GPIO16_OUT; return true;
|
||||
case eth_clock_id_t::GPIO17_OUT: mode = ETH_CLOCK_GPIO17_OUT; return true;
|
||||
#endif
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -47,9 +47,10 @@ static const settings_field_t FIELDS[] = {
|
|||
{settings_part_t::ethernet, proto_field_t::phyType, nullptr, 0, 255},
|
||||
{settings_part_t::ethernet, proto_field_t::CLKMode, nullptr, 0, 3},
|
||||
{settings_part_t::ethernet, proto_field_t::phyAddress, nullptr, -1, 31},
|
||||
{settings_part_t::ethernet, proto_field_t::PWRPin, nullptr, -1, 48},
|
||||
{settings_part_t::ethernet, proto_field_t::MDCPin, nullptr, 0, 48},
|
||||
{settings_part_t::ethernet, proto_field_t::MDIOPin, nullptr, 0, 48},
|
||||
// Pins run to GPIO 54, the P4's last.
|
||||
{settings_part_t::ethernet, proto_field_t::PWRPin, nullptr, -1, 54},
|
||||
{settings_part_t::ethernet, proto_field_t::MDCPin, nullptr, 0, 54},
|
||||
{settings_part_t::ethernet, proto_field_t::MDIOPin, nullptr, 0, 54},
|
||||
{settings_part_t::ip, proto_field_t::dhcp, nullptr, 0, 0},
|
||||
{settings_part_t::ip, proto_field_t::ip, nullptr, 0, 15},
|
||||
{settings_part_t::ip, proto_field_t::gateway, nullptr, 0, 15},
|
||||
|
|
@ -75,12 +76,12 @@ static const settings_field_t FIELDS[] = {
|
|||
// RTS, RTW, RTV, GP Relay or GP Remote (radio_proto), checked on its own.
|
||||
{settings_part_t::radio, proto_field_t::proto, nullptr, 0, 9},
|
||||
{settings_part_t::radio, proto_field_t::enabled, nullptr, 0, 0},
|
||||
{settings_part_t::radio, proto_field_t::TXPin, nullptr, 0, 48},
|
||||
{settings_part_t::radio, proto_field_t::RXPin, nullptr, 0, 48},
|
||||
{settings_part_t::radio, proto_field_t::SCKPin, nullptr, 0, 48},
|
||||
{settings_part_t::radio, proto_field_t::MOSIPin, nullptr, 0, 48},
|
||||
{settings_part_t::radio, proto_field_t::MISOPin, nullptr, 0, 48},
|
||||
{settings_part_t::radio, proto_field_t::CSNPin, nullptr, 0, 48},
|
||||
{settings_part_t::radio, proto_field_t::TXPin, nullptr, 0, 54},
|
||||
{settings_part_t::radio, proto_field_t::RXPin, nullptr, 0, 54},
|
||||
{settings_part_t::radio, proto_field_t::SCKPin, nullptr, 0, 54},
|
||||
{settings_part_t::radio, proto_field_t::MOSIPin, nullptr, 0, 54},
|
||||
{settings_part_t::radio, proto_field_t::MISOPin, nullptr, 0, 54},
|
||||
{settings_part_t::radio, proto_field_t::CSNPin, nullptr, 0, 54},
|
||||
// What the CC1101 can be set to, in MHz and kHz.
|
||||
{settings_part_t::radio, proto_field_t::frequency, nullptr, 30000, 92800},
|
||||
{settings_part_t::radio, proto_field_t::rxBandwidth, nullptr, 5803, 81250},
|
||||
|
|
|
|||
|
|
@ -506,6 +506,21 @@ void transceiver_config_t::load() {
|
|||
this->SCKPin = 6;
|
||||
this->CSNPin = 0;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32P4
|
||||
case esp_chip_model_t::CHIP_ESP32P4:
|
||||
// The SPI pins of the framework's variant for Waveshare's ESP32-P4-ETH
|
||||
// (variants/waveshare_p4_poe_eth); TX and RX take 2 and 3, which that
|
||||
// board leaves free. The C6's SDIO link holds 14-19 and 54, Ethernet
|
||||
// 28-31, 34, 35 and 49-52, and 34-38 are strapping pins. 46 is on LDO
|
||||
// channel 4, which the core turns on when a pin of it is used.
|
||||
this->TXPin = 2;
|
||||
this->RXPin = 3;
|
||||
this->MOSIPin = 32;
|
||||
this->MISOPin = 33;
|
||||
this->SCKPin = 27;
|
||||
this->CSNPin = 46;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
this->TXPin = 13;
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ const char *wifiAuthModeName(uint8_t authMode);
|
|||
bool otaProven(bool networkUp, unsigned long uptimeMs, unsigned long minUptimeMs);
|
||||
// A release asset's name: "SomfyController.<kind>.esp32<chipModel>.bin", kind
|
||||
// "ino" for the firmware or "littlefs" for the web UI image, chipModel as in
|
||||
// ConfigSettings ("" for the ESP32, "s3", "c3", "c5", "c6").
|
||||
// ConfigSettings ("" for the ESP32, "s3", "c3", "c5", "c6", "p4", "p4es").
|
||||
void releaseAssetName(char *buf, size_t size, const char *kind, const char *chipModel);
|
||||
// A coredump backtrace as " 0x%08x" per frame. bt holds maxFrames entries and
|
||||
// depth is how many the dump claims are valid.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue