mirror of https://github.com/meshcore-dev/MeshCore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
113 lines
5.0 KiB
113 lines
5.0 KiB
#ifdef WITH_W5100S_POE
|
|
|
|
#include <Arduino.h>
|
|
#include <nrf.h>
|
|
#include "W5100SPoE.h"
|
|
|
|
// ── Early power-rail + RST release (constructor priority 200) ────────────────
|
|
// Runs before setup(), right after SystemInit. Two jobs, as early as possible
|
|
// so the W5100S draws its full operating current before the RAK19018
|
|
// (Silvertel) converter folds back during PoE cold-start:
|
|
//
|
|
// 1. Drive PIN_3V3_EN (P1.02 / WB_IO2 / Arduino 34) HIGH — this is the
|
|
// RAK19007 3.3 V PERIPHERAL POWER ENABLE that feeds the RAK13800/W5100S.
|
|
// Meshtastic does this in initVariant(); stock MeshCore never did, so our
|
|
// W5100S was only weakly powered via a default path (responds on USB but
|
|
// can't pull its full ~130 mA on the marginal PoE rail).
|
|
// 2. Drive W5100S RST (P0.21 / WB_IO3 / Arduino 21) HIGH — out of reset.
|
|
//
|
|
// Raw registers because the Arduino GPIO layer isn't up this early.
|
|
static void __attribute__((constructor(200))) w5100s_early_power_init() {
|
|
// P1.02 = 3V3_EN → HIGH (power the peripheral rail FIRST)
|
|
NRF_P1->PIN_CNF[2] =
|
|
(GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos) |
|
|
(GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) |
|
|
(GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) |
|
|
(GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) |
|
|
(GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
|
|
NRF_P1->OUTSET = (1UL << 2);
|
|
|
|
// P0.21 = W5100S RST → HIGH (release from reset)
|
|
NRF_P0->PIN_CNF[21] =
|
|
(GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos) |
|
|
(GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) |
|
|
(GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) |
|
|
(GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) |
|
|
(GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
|
|
NRF_P0->OUTSET = (1UL << 21);
|
|
}
|
|
|
|
// ── Bit-banged SPI to the W5100S ────────────────────────────────────────────
|
|
// Shares the SPI bus (SCK=3 / MOSI=30 / MISO=29) with the SX1262 radio; only
|
|
// the chip-select differs (W5100S CS=26, SX1262 NSS=42). Bit-banged so it
|
|
// works regardless of which SPIClass owns the bus and runs before RadioLib.
|
|
// W5100S frame: write [0xF0][hi][lo][data], read [0x0F][hi][lo]->[data].
|
|
#define ETH_SCK_PIN 3
|
|
#define ETH_MOSI_PIN 30
|
|
#define ETH_MISO_PIN 29
|
|
#define LORA_NSS_PIN 42
|
|
|
|
static void bb_write_reg(uint16_t addr, uint8_t data) {
|
|
const uint8_t frame[4] = { 0xF0, (uint8_t)(addr >> 8), (uint8_t)(addr & 0xFF), data };
|
|
digitalWrite(W5100S_CS_PIN, LOW);
|
|
for (uint8_t b = 0; b < 4; b++) {
|
|
uint8_t v = frame[b];
|
|
for (int8_t i = 7; i >= 0; i--) {
|
|
digitalWrite(ETH_MOSI_PIN, (v >> i) & 1);
|
|
digitalWrite(ETH_SCK_PIN, HIGH);
|
|
digitalWrite(ETH_SCK_PIN, LOW);
|
|
}
|
|
}
|
|
digitalWrite(W5100S_CS_PIN, HIGH);
|
|
}
|
|
|
|
static uint8_t bb_read_reg(uint16_t addr) {
|
|
const uint8_t frame[3] = { 0x0F, (uint8_t)(addr >> 8), (uint8_t)(addr & 0xFF) };
|
|
digitalWrite(W5100S_CS_PIN, LOW);
|
|
for (uint8_t b = 0; b < 3; b++) {
|
|
uint8_t v = frame[b];
|
|
for (int8_t i = 7; i >= 0; i--) {
|
|
digitalWrite(ETH_MOSI_PIN, (v >> i) & 1);
|
|
digitalWrite(ETH_SCK_PIN, HIGH);
|
|
digitalWrite(ETH_SCK_PIN, LOW);
|
|
}
|
|
}
|
|
uint8_t out = 0;
|
|
for (int8_t i = 7; i >= 0; i--) {
|
|
digitalWrite(ETH_SCK_PIN, HIGH);
|
|
out = (out << 1) | (digitalRead(ETH_MISO_PIN) & 1);
|
|
digitalWrite(ETH_SCK_PIN, LOW);
|
|
}
|
|
digitalWrite(W5100S_CS_PIN, HIGH);
|
|
return out;
|
|
}
|
|
|
|
// ── Full W5100S bring-up ────────────────────────────────────────────────────
|
|
// Called from RAK4631Board::begin(). Confirms the 3V3 rail + RST are driven
|
|
// (Arduino API, in case the core re-init touched them), then soft-resets and
|
|
// reads VERSIONR. Returns VERSIONR (0x51 = healthy W5100S).
|
|
uint8_t w5100s_poe_init() {
|
|
// Make sure the peripheral power rail stays driven HIGH.
|
|
pinMode(W5100S_3V3_EN_PIN, OUTPUT); digitalWrite(W5100S_3V3_EN_PIN, HIGH);
|
|
delay(20); // let the rail/W5100S settle after enable
|
|
|
|
// Park both chip-selects HIGH on the shared bus, RST released.
|
|
pinMode(LORA_NSS_PIN, OUTPUT); digitalWrite(LORA_NSS_PIN, HIGH);
|
|
pinMode(W5100S_CS_PIN, OUTPUT); digitalWrite(W5100S_CS_PIN, HIGH);
|
|
pinMode(W5100S_RST_PIN, OUTPUT); digitalWrite(W5100S_RST_PIN, HIGH);
|
|
|
|
pinMode(ETH_SCK_PIN, OUTPUT); digitalWrite(ETH_SCK_PIN, LOW);
|
|
pinMode(ETH_MOSI_PIN, OUTPUT); digitalWrite(ETH_MOSI_PIN, LOW);
|
|
pinMode(ETH_MISO_PIN, INPUT);
|
|
|
|
bb_write_reg(0x0000, 0x80); // MR: software reset
|
|
delay(2);
|
|
|
|
uint8_t ver = bb_read_reg(0x0080); // VERSIONR (0x51 on W5100S)
|
|
|
|
// Chip stays powered and out of reset; PHY auto-negotiates with the switch
|
|
// and the W5100S draws its full operating current.
|
|
return ver;
|
|
}
|
|
|
|
#endif // WITH_W5100S_POE
|
|
|