From e1f4767e9a25276907a0d84f3703ec431a8832bf Mon Sep 17 00:00:00 2001 From: xiao Date: Fri, 15 May 2026 00:06:42 +0800 Subject: [PATCH] fix(ch390): deepen reset recovery --- Drivers/CH390/CH390.c | 44 +++++++++++++++++++---- Drivers/CH390/CH390.h | 12 +++++++ Drivers/CH390/CH390_Interface.c | 4 +-- Drivers/CH390/ch390_runtime.c | 52 +++++++++++++++++++--------- MDK-ARM/keil-build-viewer-record.txt | 8 ++--- 5 files changed, 91 insertions(+), 29 deletions(-) diff --git a/Drivers/CH390/CH390.c b/Drivers/CH390/CH390.c index 67c1d07..e97e2dc 100644 --- a/Drivers/CH390/CH390.c +++ b/Drivers/CH390/CH390.c @@ -13,6 +13,7 @@ #include "CH390_Interface.h" #define CH390_PHY_BUSY_TIMEOUT_LOOPS 2000u +#define CH390_RX_READ_PTR_HIGH 0x0Cu /** * @name ch390_receive_packet @@ -188,10 +189,36 @@ void ch390_write_eeprom(uint8_t reg, uint16_t value) void ch390_software_reset() { ch390_write_reg(CH390_NCR, NCR_RST); - ch390_delay_us(10); - ch390_write_reg(CH390_NCR, 0); - ch390_write_reg(CH390_NCR, NCR_RST); - ch390_delay_us(10); + for (uint8_t i = 0u; i < 20u; ++i) { + ch390_delay_us(10u); + if ((ch390_read_reg(CH390_NCR) & NCR_RST) == 0u) { + break; + } + } + ch390_delay_us(1000u); +} + +void ch390_reset_memory_pointers(void) +{ + ch390_write_reg(CH390_MPTRCR, (uint8_t)(MPTRCR_RST_TX | MPTRCR_RST_RX)); + for (uint8_t i = 0u; i < 20u; ++i) { + ch390_delay_us(1u); + if ((ch390_read_reg(CH390_MPTRCR) & (uint8_t)(MPTRCR_RST_TX | MPTRCR_RST_RX)) == 0u) { + break; + } + } + ch390_write_reg(CH390_MRRL, 0x00u); + ch390_write_reg(CH390_MRRH, CH390_RX_READ_PTR_HIGH); +} + +void ch390_phy_power_cycle(void) +{ + ch390_write_reg(CH390_IMR, IMR_NONE); + ch390_write_reg(CH390_RCR, 0x00u); + ch390_write_reg(CH390_GPR, (uint8_t)(ch390_read_reg(CH390_GPR) | GPR_PHYPD)); + ch390_delay_us(50000u); + ch390_write_reg(CH390_GPR, (uint8_t)(ch390_read_reg(CH390_GPR) & (uint8_t)(~GPR_PHYPD))); + ch390_delay_us(100000u); } /** @@ -209,6 +236,11 @@ void ch390_default_config() // Multicast address hash table uint8_t multicase_addr[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + ch390_write_reg(CH390_IMR, IMR_NONE); + ch390_write_reg(CH390_RCR, 0x00u); + ch390_write_reg(CH390_ISR, 0xFFu); + ch390_reset_memory_pointers(); + ch390_set_phy_mode(CH390_AUTO); ch390_write_reg(CH390_INTCR, (uint8_t)(INCR_TYPE_OD | INCR_POL_L)); // Clear status @@ -220,8 +252,8 @@ void ch390_default_config() // ch390_set_mac_address(mac_addr); ch390_set_multicast(multicase_addr); - // Enable only the interrupts needed by the NO_SYS polling path. - ch390_write_reg(CH390_IMR, (uint8_t)(IMR_PRI | IMR_LNKCHGI | IMR_ROOI | IMR_ROI)); + // Enable pointer auto-return and only the interrupts used by the NO_SYS polling path. + ch390_write_reg(CH390_IMR, (uint8_t)(IMR_PAR | IMR_PRI | IMR_LNKCHGI | IMR_ROOI | IMR_ROI)); // Enable RX with the reference receive filter. ch390_write_reg(CH390_RCR, RCR_DIS_CRC | RCR_RXEN); } diff --git a/Drivers/CH390/CH390.h b/Drivers/CH390/CH390.h index 50ad288..bf69da9 100644 --- a/Drivers/CH390/CH390.h +++ b/Drivers/CH390/CH390.h @@ -109,6 +109,7 @@ enum ch390_phy_mode #define CH390_MAR 0x16 #define CH390_GPCR 0x1E #define CH390_GPR 0x1F + #define GPR_PHYPD (1<<0) // PHY power down #define CH390_TRPAL 0x22 #define CH390_TRPAH 0x23 #define CH390_RWPAL 0x24 @@ -145,11 +146,14 @@ enum ch390_phy_mode #define INCR_POL_H 0x00 #define CH390_ALNCR 0x4A #define CH390_SCCR 0x50 + #define SCCR_DIS_CLK (1<<0) // Stop internal clock #define CH390_RSCCR 0x51 #define CH390_RLENCR 0x52 #define CH390_BCASTCR 0x53 #define CH390_INTCKCR 0x54 #define CH390_MPTRCR 0x55 + #define MPTRCR_RST_TX (1<<1) // Reset TX memory pointer + #define MPTRCR_RST_RX (1<<0) // Reset RX memory pointer #define CH390_MLEDCR 0x57 #define CH390_MRCMDX 0x70 #define CH390_MRCMDX1 0x71 @@ -263,6 +267,7 @@ enum ch390_phy_mode #define CH390_MAR 0x16 #define CH390_GPCR 0x1E #define CH390_GPR 0x1F + #define GPR_PHYPD (1<<0) // PHY power down #define CH390_TRPAL 0x22 #define CH390_TRPAH 0x23 #define CH390_RWPAL 0x24 @@ -298,10 +303,13 @@ enum ch390_phy_mode #define INCR_POL_L 0x01 #define INCR_POL_H 0x00 #define CH390_SCCR 0x50 + #define SCCR_DIS_CLK (1<<0) // Stop internal clock #define CH390_RSCCR 0x51 #define CH390_RLENCR 0x52 #define CH390_BCASTCR 0x53 #define CH390_MPTRCR 0x55 + #define MPTRCR_RST_TX (1<<1) // Reset TX memory pointer + #define MPTRCR_RST_RX (1<<0) // Reset RX memory pointer #define CH390_MRCMDX 0xF0 #define CH390_MRCMDX1 0xF1 #define CH390_MRCMD 0xF2 @@ -424,6 +432,10 @@ void ch390_write_eeprom(uint8_t reg, uint16_t value); */ void ch390_software_reset(void); +void ch390_reset_memory_pointers(void); + +void ch390_phy_power_cycle(void); + /** * @name ch390_default_config * @brief Config CH390 with default options: diff --git a/Drivers/CH390/CH390_Interface.c b/Drivers/CH390/CH390_Interface.c index c6c2a16..5bf0132 100644 --- a/Drivers/CH390/CH390_Interface.c +++ b/Drivers/CH390/CH390_Interface.c @@ -254,9 +254,9 @@ void ch390_hardware_reset(void) { ch390_delay_us(10000); /* Short delay before reset */ ch390_rst(0); /* Assert reset (low) */ - ch390_delay_us(3000); /* Hold reset for 3ms to satisfy datasheet minimum */ + ch390_delay_us(50000); /* Recover chips stuck after repeated MCU resets */ ch390_rst(1); /* Release reset (high) */ - ch390_delay_us(50000); /* Wait 50ms for CH390 to initialize reliably */ + ch390_delay_us(500000); /* Allow EEPROM load, PHY, and SPI state to settle */ } /*---------------------------------------------------------------------------- diff --git a/Drivers/CH390/ch390_runtime.c b/Drivers/CH390/ch390_runtime.c index 2ce0135..2a88bc8 100644 --- a/Drivers/CH390/ch390_runtime.c +++ b/Drivers/CH390/ch390_runtime.c @@ -329,6 +329,37 @@ static void ch390_runtime_refresh_diag(void) } } +static bool ch390_runtime_recover_chip(struct netif *netif, const uint8_t *mac) +{ + g_ch390_ready = 0u; + g_ch390_irq_pending = 0u; + + ch390_hardware_reset(); + if (ch390_runtime_probe_identity() == 0u) { + return false; + } + + ch390_software_reset(); + if (ch390_runtime_probe_identity() == 0u) { + return false; + } + + ch390_phy_power_cycle(); + ch390_default_config(); + + if (ch390_mac_address_valid(mac)) { + ch390_set_mac_address((uint8_t *)mac); + } + + ch390_runtime_prepare_netif(netif); + ch390_runtime_sync_mac(netif); + ch390_runtime_refresh_diag(); + g_ch390_ready = g_diag.id_valid; + g_ch390_irq_pending = 0u; + + return g_ch390_ready != 0u; +} + struct pbuf *ch390_runtime_input_frame(struct netif *netif) { struct ethernetif *ethernetif = (struct ethernetif *)netif->state; @@ -444,11 +475,8 @@ void ch390_runtime_init(struct netif *netif, const uint8_t *mac) ch390_gpio_init(); SEGGER_RTT_WriteString(0, "ETH init: spi\r\n"); ch390_spi_init(); - SEGGER_RTT_WriteString(0, "ETH init: reset\r\n"); - ch390_hardware_reset(); - - SEGGER_RTT_WriteString(0, "ETH init: probe\r\n"); - g_ch390_ready = ch390_runtime_probe_identity(); + SEGGER_RTT_WriteString(0, "ETH init: deep reset\r\n"); + g_ch390_ready = (uint8_t)ch390_runtime_recover_chip(netif, mac); if (g_ch390_ready == 0u) { ch390_runtime_prepare_netif(netif); netif_set_link_down(netif); @@ -456,11 +484,9 @@ void ch390_runtime_init(struct netif *netif, const uint8_t *mac) return; } - SEGGER_RTT_WriteString(0, "ETH init: default\r\n"); - ch390_default_config(); SEGGER_RTT_WriteString(0, "ETH init: mac\r\n"); if (ch390_mac_address_valid(mac)) { - ch390_set_mac_address((uint8_t *)mac); + ch390_runtime_sync_mac(netif); } else { if (mac != NULL) { @@ -660,15 +686,7 @@ bool ch390_runtime_emergency_reset(struct netif *netif) } g_tx_consecutive_timeout = 0u; - ch390_software_reset(); - ch390_delay_us(5000u); - ch390_default_config(); - ch390_runtime_prepare_netif(netif); - ch390_runtime_sync_mac(netif); - g_ch390_irq_pending = 0u; - - ch390_runtime_refresh_diag(); - g_ch390_ready = g_diag.id_valid; + (void)ch390_runtime_recover_chip(netif, (netif != NULL) ? netif->hwaddr : NULL); if (g_ch390_ready == 0u) { SEGGER_RTT_WriteString(0, "ETH emergency reset: chip not responding\r\n"); diff --git a/MDK-ARM/keil-build-viewer-record.txt b/MDK-ARM/keil-build-viewer-record.txt index 6b062e5..c93fe9e 100644 --- a/MDK-ARM/keil-build-viewer-record.txt +++ b/MDK-ARM/keil-build-viewer-record.txt @@ -1,7 +1,7 @@ Code (inc. data) RO Data RW Data ZI Data Debug Object Name - 632 0 0 0 0 0 ch390.o - 616 0 64 0 0 0 ch390_interface.o - 2546 0 85 6 136 0 ch390_runtime.o + 794 0 0 0 0 0 ch390.o + 618 0 64 0 0 0 ch390_interface.o + 2584 0 85 6 136 0 ch390_runtime.o 3958 0 591 8 1240 0 config.o 8 0 0 0 0 0 def.o 124 0 0 0 0 0 dma.o @@ -57,7 +57,7 @@ Memory Map of the image Load Region LR_IROM1 - Execution Region ER_IROM1 (Exec base: 0x08000000, Size: 0x0000DED8, Max: 0x00010000, END) + Execution Region ER_IROM1 (Exec base: 0x08000000, Size: 0x0000DFA0, Max: 0x00010000, END) Execution Region RW_IRAM1 (Exec base: 0x20000000, Size: 0x00004FD8, Max: 0x00005000, END)