@@ -129,6 +129,9 @@ eth_t eth_instance;
129129
130130static void eth_mac_deinit (eth_t * self );
131131static 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
133136void 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+
844868static 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
897928int 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