Skip to content

Commit 30a4ddd

Browse files
committed
stm32/eth: Add link state detection and fix active() method.
This implements automatic detection of Ethernet cable connect/disconnect events and fixes the active() method to return interface state instead of link state. Changes: - Add PHY interrupt register support and link tracking in eth_t - Implement periodic PHY link status polling in ETH_IRQHandler - Update LWIP netif link state based on cable connection - Add enabled flag to track interface state vs physical link - Fix active() to return eth_is_enabled() instead of link status - Trigger DHCP renewal when link comes back up The implementation polls link status every ~100 RX interrupts, providing good responsiveness while minimizing overhead. The active() method now correctly reflects whether the interface has been explicitly enabled/disabled by the user, independent of cable state. Signed-off-by: Andrew Leech <[email protected]>
1 parent 4ce2dd2 commit 30a4ddd

File tree

4 files changed

+50
-1
lines changed

4 files changed

+50
-1
lines changed

ports/stm32/eth.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ typedef struct _eth_t {
119119
struct dhcp dhcp_struct;
120120
uint32_t phy_addr;
121121
int16_t (*phy_get_link_status)(uint32_t phy_addr);
122+
bool last_link_status;
123+
bool enabled;
122124
} eth_t;
123125

124126
static eth_dma_t eth_dma MICROPY_HW_ETH_DMA_ATTRIBUTE;
@@ -188,6 +190,8 @@ int eth_init(eth_t *self, int mac_idx, uint32_t phy_addr, int phy_type) {
188190
mp_hal_get_mac(mac_idx, &self->netif.hwaddr[0]);
189191
self->netif.hwaddr_len = 6;
190192
self->phy_addr = phy_addr;
193+
self->last_link_status = false;
194+
self->enabled = false;
191195
if (phy_type == ETH_PHY_DP83825 || phy_type == ETH_PHY_DP83848) {
192196
self->phy_get_link_status = eth_phy_dp838xx_get_link_status;
193197
} else if (phy_type == ETH_PHY_LAN8720 || phy_type == ETH_PHY_LAN8742) {
@@ -396,6 +400,13 @@ static int eth_mac_init(eth_t *self) {
396400
// Get register with link status
397401
uint16_t phy_scsr = self->phy_get_link_status(self->phy_addr);
398402

403+
// Initialize link status tracking
404+
uint16_t bsr = eth_phy_read(self->phy_addr, PHY_BSR);
405+
self->last_link_status = (bsr & PHY_BSR_LINK_STATUS) != 0;
406+
407+
// Enable PHY link change interrupts (for future use if PHY interrupt pin available)
408+
eth_phy_enable_link_interrupts(self->phy_addr);
409+
399410
// Burst mode configuration
400411
#if defined(STM32H5) || defined(STM32H7)
401412
ETH->DMASBMR = ETH->DMASBMR & ~ETH_DMASBMR_AAL & ~ETH_DMASBMR_FB;
@@ -713,6 +724,36 @@ void ETH_IRQHandler(void) {
713724
eth_dma_rx_free();
714725
}
715726
}
727+
728+
// Check for PHY link status changes (polled approach)
729+
// This runs on every RX interrupt, providing reasonable responsiveness
730+
static uint32_t link_check_counter = 0;
731+
if (++link_check_counter >= 100) { // Check every ~100 RX interrupts
732+
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+
}
756+
}
716757
}
717758

718759
/*******************************************************************************/
@@ -849,6 +890,10 @@ int eth_link_status(eth_t *self) {
849890
}
850891
}
851892

893+
bool eth_is_enabled(eth_t *self) {
894+
return self->enabled;
895+
}
896+
852897
int eth_start(eth_t *self) {
853898
eth_lwip_deinit(self);
854899

@@ -860,12 +905,14 @@ int eth_start(eth_t *self) {
860905
return ret;
861906
}
862907
eth_lwip_init(self);
908+
self->enabled = true;
863909
return 0;
864910
}
865911

866912
int eth_stop(eth_t *self) {
867913
eth_lwip_deinit(self);
868914
eth_mac_deinit(self);
915+
self->enabled = false;
869916
return 0;
870917
}
871918

ports/stm32/eth.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ int eth_init(eth_t *self, int mac_idx, uint32_t phy_addr, int phy_type);
4040
void eth_set_trace(eth_t *self, uint32_t value);
4141
struct netif *eth_netif(eth_t *self);
4242
int eth_link_status(eth_t *self);
43+
bool eth_is_enabled(eth_t *self);
4344
int eth_start(eth_t *self);
4445
int eth_stop(eth_t *self);
4546
void eth_low_power_mode(eth_t *self, bool enable);

ports/stm32/eth_phy.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
#define PHY_SPEED_100FULL (6)
5757
#define PHY_DUPLEX (4)
5858

59+
5960
uint32_t eth_phy_read(uint32_t phy_addr, uint32_t reg);
6061
void eth_phy_write(uint32_t phy_addr, uint32_t reg, uint32_t val);
6162

ports/stm32/network_lan.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ static mp_obj_t network_lan_make_new(const mp_obj_type_t *type, size_t n_args, s
7373
static mp_obj_t network_lan_active(size_t n_args, const mp_obj_t *args) {
7474
network_lan_obj_t *self = MP_OBJ_TO_PTR(args[0]);
7575
if (n_args == 1) {
76-
return mp_obj_new_bool(eth_link_status(self->eth));
76+
return mp_obj_new_bool(eth_is_enabled(self->eth));
7777
} else {
7878
int ret;
7979
if (mp_obj_is_true(args[1])) {

0 commit comments

Comments
 (0)