Skip to content

Commit cb3833e

Browse files
committed
stm32/eth: Permanently register netif with lwip during startup.
This restructures LWIP initialization and removes blocking PHY loops to support static IP configuration before active(True) and eliminate timeouts when starting without cable. Changes: - Split netif init into eth_netif_init_early() and eth_lwip_init() - Initialize netif structure in eth_init() for early IP config - Move netif stack registration to eth_start() - Remove blocking PHY autonegotiation loop from eth_mac_init() - Add eth_phy_configure_autoneg() for non-blocking setup - Add eth_phy_link_status_poll() for link state management - Only start DHCP if no static IP configured (0.0.0.0) - Use default MAC speed/duplex config until autoneg completes Benefits: - Static IP can be configured before active(True) - active(True) succeeds immediately without cable - No more 10-second timeout on startup - Link detection works properly when cable plugged later Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
1 parent bfe6794 commit cb3833e

File tree

1 file changed

+140
-102
lines changed

1 file changed

+140
-102
lines changed

ports/stm32/eth.c

Lines changed: 140 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ eth_t eth_instance;
129129

130130
static void eth_mac_deinit(eth_t *self);
131131
static void eth_process_frame(eth_t *self, size_t len, const uint8_t *buf);
132+
static void eth_netif_init_early(eth_t *self);
133+
static void eth_phy_link_status_poll(eth_t *self);
134+
static void eth_phy_configure_autoneg(eth_t *self);
132135

133136
void eth_phy_write(uint32_t phy_addr, uint32_t reg, uint32_t val) {
134137
#if defined(STM32H5) || defined(STM32H7)
@@ -223,6 +226,10 @@ int eth_init(eth_t *self, int mac_idx, uint32_t phy_addr, int phy_type) {
223226
#else
224227
__HAL_RCC_ETH_CLK_ENABLE();
225228
#endif
229+
230+
// Initialize netif structure early so static IP can be configured before active(True)
231+
eth_netif_init_early(self);
232+
226233
return 0;
227234
}
228235

@@ -253,6 +260,7 @@ static int eth_mac_init(eth_t *self) {
253260
#if defined(STM32H5)
254261
__HAL_RCC_SBS_CLK_ENABLE();
255262
SBS->PMCR = (SBS->PMCR & ~SBS_PMCR_ETH_SEL_PHY_Msk) | SBS_PMCR_ETH_SEL_PHY_2;
263+
HAL_SBS_ETHInterfaceSelect(SBS_ETH_RMII);
256264
#elif defined(STM32H7)
257265
SYSCFG->PMCR = (SYSCFG->PMCR & ~SYSCFG_PMCR_EPIS_SEL_Msk) | SYSCFG_PMCR_EPIS_SEL_2;
258266
#else
@@ -262,22 +270,10 @@ static int eth_mac_init(eth_t *self) {
262270

263271
#if defined(STM32H5)
264272
__HAL_RCC_ETH_RELEASE_RESET();
265-
266-
__HAL_RCC_ETH_CLK_SLEEP_ENABLE();
267-
__HAL_RCC_ETHTX_CLK_SLEEP_ENABLE();
268-
__HAL_RCC_ETHRX_CLK_SLEEP_ENABLE();
269273
#elif defined(STM32H7)
270274
__HAL_RCC_ETH1MAC_RELEASE_RESET();
271-
272-
__HAL_RCC_ETH1MAC_CLK_SLEEP_ENABLE();
273-
__HAL_RCC_ETH1TX_CLK_SLEEP_ENABLE();
274-
__HAL_RCC_ETH1RX_CLK_SLEEP_ENABLE();
275275
#else
276276
__HAL_RCC_ETHMAC_RELEASE_RESET();
277-
278-
__HAL_RCC_ETHMAC_CLK_SLEEP_ENABLE();
279-
__HAL_RCC_ETHMACTX_CLK_SLEEP_ENABLE();
280-
__HAL_RCC_ETHMACRX_CLK_SLEEP_ENABLE();
281277
#endif
282278

283279
// Do a soft reset of the MAC core
@@ -353,57 +349,30 @@ static int eth_mac_init(eth_t *self) {
353349
ETH->DMACCR &= ~(ETH_DMACCR_DSL_Msk);
354350
#endif
355351

356-
// Reset the PHY
352+
// Reset the PHY and wait for reset to complete
357353
eth_phy_write(self->phy_addr, PHY_BCR, PHY_BCR_SOFT_RESET);
358354
mp_hal_delay_ms(50);
359355

360-
// Wait for the PHY link to be established
361-
int phy_state = 0;
356+
// Wait for PHY reset to complete (but don't wait for link)
362357
t0 = mp_hal_ticks_ms();
363-
while (phy_state != 3) {
364-
if (mp_hal_ticks_ms() - t0 > PHY_INIT_TIMEOUT_MS) {
358+
while (eth_phy_read(self->phy_addr, PHY_BCR) & PHY_BCR_SOFT_RESET) {
359+
if (mp_hal_ticks_ms() - t0 > 1000) { // 1 second timeout for reset
365360
eth_mac_deinit(self);
366361
return -MP_ETIMEDOUT;
367362
}
368-
uint16_t bcr = eth_phy_read(self->phy_addr, PHY_BCR);
369-
uint16_t bsr = eth_phy_read(self->phy_addr, PHY_BSR);
370-
switch (phy_state) {
371-
case 0:
372-
if (!(bcr & PHY_BCR_SOFT_RESET)) {
373-
phy_state = 1;
374-
}
375-
break;
376-
case 1:
377-
if (bsr & PHY_BSR_LINK_STATUS) {
378-
// Announce all modes
379-
eth_phy_write(self->phy_addr, PHY_ANAR,
380-
PHY_ANAR_SPEED_10HALF |
381-
PHY_ANAR_SPEED_10FULL |
382-
PHY_ANAR_SPEED_100HALF |
383-
PHY_ANAR_SPEED_100FULL |
384-
PHY_ANAR_IEEE802_3);
385-
// Start autonegotiate.
386-
eth_phy_write(self->phy_addr, PHY_BCR, PHY_BCR_AUTONEG_EN);
387-
phy_state = 2;
388-
}
389-
break;
390-
case 2:
391-
if ((bsr & (PHY_BSR_AUTONEG_DONE | PHY_BSR_LINK_STATUS))
392-
== (PHY_BSR_AUTONEG_DONE | PHY_BSR_LINK_STATUS)) {
393-
phy_state = 3;
394-
}
395-
break;
396-
}
397363
mp_hal_delay_ms(2);
398364
}
399365

400-
// Get register with link status
401-
uint16_t phy_scsr = self->phy_get_link_status(self->phy_addr);
402-
403-
// Initialize link status tracking
366+
// Initialize link status tracking (current state, whatever it is)
404367
uint16_t bsr = eth_phy_read(self->phy_addr, PHY_BSR);
405368
self->last_link_status = (bsr & PHY_BSR_LINK_STATUS) != 0;
406369

370+
// Configure autonegotiation if link is already up, otherwise it will be
371+
// configured when link comes up via the polling function
372+
if (self->last_link_status) {
373+
eth_phy_configure_autoneg(self);
374+
}
375+
407376
// Enable PHY link change interrupts (for future use if PHY interrupt pin available)
408377
eth_phy_enable_link_interrupts(self->phy_addr);
409378

@@ -512,13 +481,9 @@ static int eth_mac_init(eth_t *self) {
512481
ETH->MACA0LR = mac[3] << 24 | mac[2] << 16 | mac[1] << 8 | mac[0];
513482
mp_hal_delay_ms(2);
514483

515-
// Set main MAC control register
516-
ETH->MACCR =
517-
phy_scsr == PHY_SPEED_10FULL ? ETH_MACCR_DM
518-
: phy_scsr == PHY_SPEED_100HALF ? ETH_MACCR_FES
519-
: phy_scsr == PHY_SPEED_100FULL ? (ETH_MACCR_FES | ETH_MACCR_DM)
520-
: 0
521-
;
484+
// Set main MAC control register with default configuration
485+
// The PHY speed/duplex will be auto-detected and updated via autonegotiation
486+
ETH->MACCR = ETH_MACCR_FES | ETH_MACCR_DM; // Default: 100Mbps, Full Duplex
522487
mp_hal_delay_ms(2);
523488

524489
// Start MAC layer
@@ -730,29 +695,7 @@ void ETH_IRQHandler(void) {
730695
static uint32_t link_check_counter = 0;
731696
if (++link_check_counter >= 100) { // Check every ~100 RX interrupts
732697
link_check_counter = 0;
733-
734-
// Read current PHY link status
735-
uint16_t bsr = eth_phy_read(eth_instance.phy_addr, PHY_BSR);
736-
bool current_link_status = (bsr & PHY_BSR_LINK_STATUS) != 0;
737-
738-
// Check if link status changed
739-
if (current_link_status != eth_instance.last_link_status) {
740-
eth_instance.last_link_status = current_link_status;
741-
742-
// Update LWIP netif link status to reflect physical cable connection
743-
struct netif *netif = &eth_instance.netif;
744-
if (current_link_status) {
745-
// Cable is physically connected
746-
netif_set_link_up(netif);
747-
// Restart DHCP if interface is up and DHCP is enabled
748-
if (netif_is_up(netif) && netif_dhcp_data(netif)) {
749-
dhcp_renew(netif);
750-
}
751-
} else {
752-
// Cable is physically disconnected
753-
netif_set_link_down(netif);
754-
}
755-
}
698+
eth_phy_link_status_poll(&eth_instance);
756699
}
757700
}
758701

@@ -815,39 +758,127 @@ static err_t eth_netif_init(struct netif *netif) {
815758
return ERR_OK;
816759
}
817760

818-
static void eth_lwip_init(eth_t *self) {
761+
static void eth_netif_init_early(eth_t *self) {
762+
// Initialize netif structure but don't add to network stack yet
763+
struct netif *n = &self->netif;
764+
n->name[0] = 'e';
765+
n->name[1] = '0';
766+
n->state = self;
767+
768+
// Set default IP configuration (0.0.0.0 = use DHCP)
819769
ip_addr_t ipconfig[4];
820-
IP4_ADDR(&ipconfig[0], 0, 0, 0, 0);
821-
IP4_ADDR(&ipconfig[2], 192, 168, 0, 1);
822-
IP4_ADDR(&ipconfig[1], 255, 255, 255, 0);
823-
IP4_ADDR(&ipconfig[3], 8, 8, 8, 8);
770+
IP_ADDR4(&ipconfig[0], 0, 0, 0, 0); // IP: 0.0.0.0 (DHCP)
771+
IP_ADDR4(&ipconfig[1], 255, 255, 255, 0); // Netmask
772+
IP_ADDR4(&ipconfig[2], 192, 168, 0, 1); // Gateway
773+
IP_ADDR4(&ipconfig[3], 8, 8, 8, 8); // DNS
774+
775+
netif_set_addr(n, ip_2_ip4(&ipconfig[0]), ip_2_ip4(&ipconfig[1]), ip_2_ip4(&ipconfig[2]));
776+
777+
// Initialize DHCP structure
778+
dhcp_set_struct(n, &self->dhcp_struct);
779+
}
824780

781+
static void eth_lwip_init(eth_t *self) {
825782
MICROPY_PY_LWIP_ENTER
826783

827784
struct netif *n = &self->netif;
828-
n->name[0] = 'e';
829-
n->name[1] = '0';
830-
netif_add(n, &ipconfig[0], &ipconfig[1], &ipconfig[2], self, eth_netif_init, ethernet_input);
831-
netif_set_hostname(n, mod_network_hostname_data);
832-
netif_set_default(n);
833-
netif_set_up(n);
834785

835-
dns_setserver(0, &ipconfig[3]);
836-
dhcp_set_struct(n, &self->dhcp_struct);
837-
dhcp_start(n);
786+
// Add netif to network stack (only if not already added)
787+
if (netif_find(n->name) == NULL) {
788+
ip_addr_t dns_addr;
789+
IP_ADDR4(&dns_addr, 8, 8, 8, 8);
838790

839-
netif_set_link_up(n);
791+
netif_add(n, netif_ip4_addr(n), netif_ip4_netmask(n), netif_ip4_gw(n), self, eth_netif_init, ethernet_input);
792+
netif_set_hostname(n, mod_network_hostname_data);
793+
netif_set_default(n);
794+
netif_set_up(n);
795+
796+
dns_setserver(0, &dns_addr);
797+
798+
#if LWIP_IPV6
799+
netif_create_ip6_linklocal_address(n, 1);
800+
#endif
801+
}
840802

841803
MICROPY_PY_LWIP_EXIT
842804
}
843805

806+
static void eth_start_dhcp_if_needed(eth_t *self) {
807+
MICROPY_PY_LWIP_ENTER
808+
struct netif *netif = &self->netif;
809+
810+
// Check if a static IP address has been configured
811+
if (ip4_addr_isany_val(*netif_ip4_addr(netif))) {
812+
// No static IP configured, start DHCP
813+
dhcp_start(netif);
814+
}
815+
// If static IP is already configured, don't start DHCP
816+
817+
MICROPY_PY_LWIP_EXIT
818+
}
819+
820+
static void eth_phy_configure_autoneg(eth_t *self) {
821+
// Configure PHY for autonegotiation (non-blocking)
822+
// This sets up the PHY but doesn't wait for link establishment
823+
824+
// Announce all supported modes
825+
eth_phy_write(self->phy_addr, PHY_ANAR,
826+
PHY_ANAR_SPEED_10HALF |
827+
PHY_ANAR_SPEED_10FULL |
828+
PHY_ANAR_SPEED_100HALF |
829+
PHY_ANAR_SPEED_100FULL |
830+
PHY_ANAR_IEEE802_3);
831+
832+
// Start autonegotiation
833+
eth_phy_write(self->phy_addr, PHY_BCR, PHY_BCR_AUTONEG_EN);
834+
}
835+
836+
static void eth_phy_link_status_poll(eth_t *self) {
837+
// Poll PHY link status and handle state changes
838+
uint16_t bsr = eth_phy_read(self->phy_addr, PHY_BSR);
839+
bool current_link_status = (bsr & PHY_BSR_LINK_STATUS) != 0;
840+
841+
// Check if link status changed
842+
if (current_link_status != self->last_link_status) {
843+
self->last_link_status = current_link_status;
844+
845+
// Update LWIP netif link status to reflect physical cable connection
846+
struct netif *netif = &self->netif;
847+
if (current_link_status) {
848+
// Cable is physically connected
849+
netif_set_link_up(netif);
850+
851+
// If this is a new connection, configure autonegotiation
852+
uint16_t bcr = eth_phy_read(self->phy_addr, PHY_BCR);
853+
if (!(bcr & PHY_BCR_AUTONEG_EN)) {
854+
eth_phy_configure_autoneg(self);
855+
}
856+
857+
// Restart DHCP if interface is up and DHCP is enabled
858+
if (netif_is_up(netif) && netif_dhcp_data(netif)) {
859+
dhcp_renew(netif);
860+
}
861+
} else {
862+
// Cable is physically disconnected
863+
netif_set_link_down(netif);
864+
}
865+
}
866+
}
867+
844868
static void eth_lwip_deinit(eth_t *self) {
845869
MICROPY_PY_LWIP_ENTER
846-
for (struct netif *netif = netif_list; netif != NULL; netif = netif->next) {
847-
if (netif == &self->netif) {
848-
netif_remove(netif);
849-
netif->ip_addr.addr = 0;
850-
netif->flags = 0;
870+
struct netif *netif = &self->netif;
871+
872+
// Stop DHCP if running
873+
if (netif_dhcp_data(netif)) {
874+
dhcp_stop(netif);
875+
}
876+
877+
// Remove from network stack but keep netif structure for reuse
878+
for (struct netif *n = netif_list; n != NULL; n = n->next) {
879+
if (n == netif) {
880+
netif_remove(n);
881+
break;
851882
}
852883
}
853884
MICROPY_PY_LWIP_EXIT
@@ -895,16 +926,23 @@ bool eth_is_enabled(eth_t *self) {
895926
}
896927

897928
int eth_start(eth_t *self) {
898-
eth_lwip_deinit(self);
899-
900929
// Make sure Eth is Not in low power mode.
901930
eth_low_power_mode(self, false);
902931

903932
int ret = eth_mac_init(self);
904933
if (ret < 0) {
905934
return ret;
906935
}
936+
937+
// Initialize LWIP netif (only once, safe to call multiple times)
907938
eth_lwip_init(self);
939+
940+
// Start DHCP if no static IP has been configured
941+
eth_start_dhcp_if_needed(self);
942+
943+
// Do an initial link status poll
944+
eth_phy_link_status_poll(self);
945+
908946
self->enabled = true;
909947
return 0;
910948
}

0 commit comments

Comments
 (0)