fix: restore CH390 bridge flow and sync driver docs

This commit is contained in:
2026-04-03 05:18:02 +08:00
parent 1ef1ba9490
commit fd1fae8ad7
18 changed files with 501 additions and 178 deletions
+3 -3
View File
@@ -220,9 +220,9 @@ void ch390_default_config()
// ch390_set_mac_address(mac_addr);
ch390_set_multicast(multicase_addr);
// Enable all interrupt and PAR
ch390_write_reg(CH390_IMR, IMR_ALL);
// Enable RX
// 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 RX with the reference receive filter.
ch390_write_reg(CH390_RCR, RCR_DIS_CRC | RCR_RXEN);
}
+6 -29
View File
@@ -86,23 +86,6 @@ static inline void ch390_rst(uint8_t state)
state ? GPIO_PIN_SET : GPIO_PIN_RESET);
}
static inline void ch390_sck(uint8_t state)
{
HAL_GPIO_WritePin(CH390_SCK_PORT, CH390_SCK_PIN,
state ? GPIO_PIN_SET : GPIO_PIN_RESET);
}
static inline void ch390_mosi(uint8_t state)
{
HAL_GPIO_WritePin(CH390_MOSI_PORT, CH390_MOSI_PIN,
state ? GPIO_PIN_SET : GPIO_PIN_RESET);
}
static inline uint8_t ch390_miso(void)
{
return (uint8_t)(HAL_GPIO_ReadPin(CH390_MISO_PORT, CH390_MISO_PIN) == GPIO_PIN_SET);
}
/*----------------------------------------------------------------------------
* SPI Communication
*---------------------------------------------------------------------------*/
@@ -197,11 +180,9 @@ void ch390_interrupt_init(void)
void ch390_spi_init(void)
{
/* SPI1 is initialized by MX_SPI1_Init() in main.c */
/* We need to ensure correct SPI mode for CH390: */
/* - CPOL = High (idle clock is high) */
/* - CPHA = 2Edge (data captured on second edge) */
ch390_spi_apply_mode(SPI_POLARITY_LOW, SPI_PHASE_1EDGE); /* Start with Mode 0 */
/* Reference CH390 SPI path uses mode 3. */
ch390_spi_apply_mode(SPI_POLARITY_HIGH, SPI_PHASE_2EDGE);
SEGGER_RTT_WriteString(0, "CH390 SPI mode=3 (CPOL=1 CPHA=1)\r\n");
}
/**
@@ -252,7 +233,7 @@ void ch390_delay_us(uint32_t time)
*/
void ch390_hardware_reset(void)
{
ch390_delay_us(3000); /* Short delay before reset */
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_rst(1); /* Release reset (high) */
@@ -287,13 +268,9 @@ uint8_t ch390_read_reg(uint8_t reg)
*/
void ch390_write_reg(uint8_t reg, uint8_t value)
{
uint8_t frame[2];
frame[0] = reg | OPC_REG_W;
frame[1] = value;
ch390_cs(0); /* CS low - select */
ch390_spi_exchange_byte(frame[0]); /* Send write command */
ch390_spi_exchange_byte(frame[1]); /* Send write data */
(void)ch390_spi_exchange_byte(reg | OPC_REG_W);
(void)ch390_spi_exchange_byte(value);
ch390_cs(1); /* CS high - deselect */
}
+109 -33
View File
@@ -9,6 +9,32 @@
#include "lwip/pbuf.h"
#include "lwip/stats.h"
#include <string.h>
static void ch390_runtime_dispatch_frame(struct netif *netif, struct pbuf *p)
{
if ((p != NULL) && (netif->input(p, netif) != ERR_OK)) {
pbuf_free(p);
}
}
static uint8_t ch390_runtime_drain_rx(struct netif *netif, uint8_t max_frames)
{
struct pbuf *p;
uint8_t drained = 0u;
while (drained < max_frames) {
p = ch390_runtime_input_frame(netif);
if (p == NULL) {
break;
}
ch390_runtime_dispatch_frame(netif, p);
drained++;
}
return drained;
}
static volatile uint8_t g_ch390_irq_pending;
static uint8_t g_ch390_ready;
static ch390_diag_t g_diag;
@@ -18,6 +44,13 @@ static uint8_t ch390_runtime_probe_identity(void)
g_diag.vendor_id = ch390_get_vendor_id();
g_diag.product_id = ch390_get_product_id();
g_diag.revision = ch390_get_revision();
g_diag.phy_bmcr = ch390_read_phy(CH390_PHY_BMCR);
g_diag.phy_bmsr = ch390_read_phy(CH390_PHY_BMSR);
g_diag.phy_id1 = ch390_read_phy(CH390_PHY_PHYID1);
g_diag.phy_id2 = ch390_read_phy(CH390_PHY_PHYID2);
g_diag.phy_anar = ch390_read_phy(CH390_PHY_ANAR);
g_diag.phy_anlpar = ch390_read_phy(CH390_PHY_ANLPAR);
g_diag.phy_aner = ch390_read_phy(CH390_PHY_ANER);
g_diag.nsr = ch390_read_reg(CH390_NSR);
g_diag.ncr = ch390_read_reg(CH390_NCR);
g_diag.rcr = ch390_read_reg(CH390_RCR);
@@ -25,6 +58,8 @@ static uint8_t ch390_runtime_probe_identity(void)
g_diag.intcr = ch390_read_reg(CH390_INTCR);
g_diag.gpr = ch390_read_reg(CH390_GPR);
g_diag.isr = ch390_read_reg(CH390_ISR);
g_diag.phy_speed_10m = 0u;
g_diag.phy_full_duplex = 0u;
g_diag.link_up = (uint8_t)0u;
g_diag.id_valid = (uint8_t)((g_diag.vendor_id != 0x0000u) &&
(g_diag.vendor_id != 0xFFFFu) &&
@@ -36,22 +71,25 @@ static uint8_t ch390_runtime_probe_identity(void)
static void ch390_runtime_refresh_diag(void)
{
uint8_t id_valid = ch390_runtime_probe_identity();
g_diag.int_pin = (uint8_t)ch390_get_int_pin();
if (id_valid != 0u) {
g_diag.phy_speed_10m = (uint8_t)ch390_get_phy_speed();
g_diag.phy_full_duplex = (uint8_t)ch390_get_duplex_mode();
g_diag.link_up = (uint8_t)ch390_get_link_status();
}
}
static struct pbuf *ch390_runtime_input(struct netif *netif)
struct pbuf *ch390_runtime_input_frame(struct netif *netif)
{
struct ethernetif *ethernetif = (struct ethernetif *)netif->state;
struct pbuf *p = NULL;
struct pbuf *q;
uint16_t len;
uint16_t frame_len;
uint8_t rcr;
uint8_t rx_ready;
uint8_t rx_header[4];
ch390_read_reg(CH390_MRCMDX);
rx_ready = ch390_read_reg(CH390_MRCMDX);
@@ -64,6 +102,7 @@ static struct pbuf *ch390_runtime_input(struct netif *netif)
ch390_write_reg(CH390_RCR, rcr);
ethernetif->rx_len = 0u;
LINK_STATS_INC(link.drop);
g_diag.rx_packets_drop++;
return NULL;
}
@@ -72,16 +111,21 @@ static struct pbuf *ch390_runtime_input(struct netif *netif)
return NULL;
}
g_diag.rx_ready_hits++;
ch390_read_mem(rx_header, 4);
ethernetif->rx_status = rx_header[1];
ethernetif->rx_len = (uint16_t)(((uint16_t)rx_header[2] | ((uint16_t)rx_header[3] << 8)) - 4u);
frame_len = (uint16_t)((uint16_t)rx_header[2] | ((uint16_t)rx_header[3] << 8));
if ((ethernetif->rx_status & 0x3Fu) != 0u || ethernetif->rx_len == 0u || ethernetif->rx_len > 1520u) {
ch390_drop_packet((uint16_t)(ethernetif->rx_len + 4u));
if ((ethernetif->rx_status & 0x3Fu) != 0u || frame_len == 0u || frame_len > CH390_PKT_MAX) {
ethernetif->rx_len = 0u;
ch390_drop_packet(frame_len);
LINK_STATS_INC(link.drop);
g_diag.rx_packets_drop++;
return NULL;
}
ethernetif->rx_len = frame_len;
len = ethernetif->rx_len;
#if ETH_PAD_SIZE
len += ETH_PAD_SIZE;
@@ -98,12 +142,16 @@ static struct pbuf *ch390_runtime_input(struct netif *netif)
#if ETH_PAD_SIZE
pbuf_add_header(p, ETH_PAD_SIZE);
#endif
ch390_drop_packet(4u);
LINK_STATS_INC(link.recv);
g_diag.rx_packets_ok++;
g_diag.last_frame_len = frame_len;
g_diag.last_payload_len = p->tot_len;
} else {
ch390_drop_packet((uint16_t)(ethernetif->rx_len + 4u));
ch390_drop_packet(ethernetif->rx_len);
LINK_STATS_INC(link.memerr);
LINK_STATS_INC(link.drop);
g_diag.rx_packets_drop++;
}
return p;
@@ -125,7 +173,7 @@ void ch390_runtime_init(struct netif *netif, const uint8_t *mac)
if (g_ch390_ready == 0u) {
netif->hwaddr_len = ETHARP_HWADDR_LEN;
netif->mtu = 1500;
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET;
ethernetif->rx_len = 0u;
ethernetif->rx_status = 0u;
@@ -144,7 +192,7 @@ void ch390_runtime_init(struct netif *netif, const uint8_t *mac)
SEGGER_RTT_WriteString(0, "ETH init: getmac\r\n");
ch390_get_mac(netif->hwaddr);
netif->mtu = 1500;
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET;
ethernetif->rx_len = 0u;
ethernetif->rx_status = 0u;
@@ -162,56 +210,82 @@ void ch390_runtime_set_irq_pending(void)
g_ch390_irq_pending = 1u;
}
uint8_t ch390_runtime_is_irq_pending(void)
{
return g_ch390_irq_pending;
}
void ch390_runtime_poll(struct netif *netif)
{
uint8_t int_status;
uint8_t rx_ready;
uint8_t rx_budget;
uint8_t rx_hint;
if (!g_ch390_ready) {
return;
}
if (g_ch390_irq_pending == 0u) {
return;
}
g_diag.rx_poll_calls++;
g_ch390_irq_pending = 0u;
int_status = ch390_read_reg(CH390_ISR);
ch390_write_reg(CH390_ISR, int_status);
rx_budget = 1u;
rx_hint = 0u;
if ((int_status & ISR_LNKCHG) != 0u) {
HAL_Delay(65u);
ch390_runtime_check_link(netif);
}
if ((g_ch390_irq_pending != 0u) || (ch390_get_int_pin() == GPIO_PIN_RESET)) {
g_ch390_irq_pending = 0u;
int_status = ch390_get_int_status();
if ((int_status & ISR_ROS) != 0u) {
LINK_STATS_INC(link.err);
}
if ((int_status & ISR_PR) != 0u) {
uint8_t loops = 0u;
while (loops++ < 8u) {
struct pbuf *p = ch390_runtime_input(netif);
if (p == NULL) {
break;
}
if (netif->input(p, netif) != ERR_OK) {
pbuf_free(p);
}
if ((int_status & ISR_LNKCHG) != 0u) {
ch390_runtime_check_link(netif);
}
if ((int_status & ISR_ROS) != 0u) {
LINK_STATS_INC(link.err);
}
if ((int_status & (ISR_PR | ISR_ROS | ISR_ROO)) != 0u) {
rx_hint = 1u;
rx_budget = 8u;
}
}
ch390_read_reg(CH390_MRCMDX);
rx_ready = ch390_read_reg(CH390_MRCMDX);
if ((rx_ready & CH390_PKT_RDY) != 0u) {
rx_hint = 1u;
if (rx_budget < 4u) {
rx_budget = 4u;
}
}
if (rx_hint != 0u) {
(void)ch390_runtime_drain_rx(netif, rx_budget);
}
}
void ch390_runtime_check_link(struct netif *netif)
{
uint8_t link_up;
static uint8_t s_last_reported = 0xFFu;
if (!g_ch390_ready) {
netif_set_link_down(netif);
return;
}
ch390_runtime_refresh_diag();
link_up = (uint8_t)ch390_get_link_status();
if (link_up != s_last_reported) {
SEGGER_RTT_printf(0,
"ETH link %s nsr=0x%02X bmsr=0x%04X anlpar=0x%04X\r\n",
link_up ? "up" : "down",
g_diag.nsr,
g_diag.phy_bmsr,
g_diag.phy_anlpar);
s_last_reported = link_up;
}
if (link_up) {
if (!netif_is_link_up(netif)) {
netif_set_link_up(netif);
@@ -244,6 +318,7 @@ err_t ch390_runtime_output(struct netif *netif, struct pbuf *p)
pbuf_add_header(p, ETH_PAD_SIZE);
#endif
LINK_STATS_INC(link.drop);
g_diag.tx_packets_timeout++;
return ERR_TIMEOUT;
}
}
@@ -261,6 +336,7 @@ err_t ch390_runtime_output(struct netif *netif, struct pbuf *p)
#endif
LINK_STATS_INC(link.xmit);
g_diag.tx_packets_ok++;
return ERR_OK;
}
+27
View File
@@ -13,6 +13,13 @@ typedef struct {
uint16_t vendor_id;
uint16_t product_id;
uint8_t revision;
uint16_t phy_bmcr;
uint16_t phy_bmsr;
uint16_t phy_id1;
uint16_t phy_id2;
uint16_t phy_anar;
uint16_t phy_anlpar;
uint16_t phy_aner;
uint8_t nsr;
uint8_t ncr;
uint8_t rcr;
@@ -20,12 +27,32 @@ typedef struct {
uint8_t intcr;
uint8_t gpr;
uint8_t isr;
uint8_t int_pin;
uint8_t phy_speed_10m;
uint8_t phy_full_duplex;
uint8_t link_up;
uint8_t id_valid;
uint32_t rx_poll_calls;
uint32_t rx_ready_hits;
uint32_t rx_packets_ok;
uint32_t rx_packets_drop;
uint32_t tx_packets_ok;
uint32_t tx_packets_timeout;
uint32_t rx_arp_frames;
uint32_t rx_ip_frames;
uint32_t rx_other_frames;
uint32_t rx_unicast_self_frames;
uint32_t rx_broadcast_frames;
uint32_t rx_multicast_frames;
uint16_t last_frame_len;
uint16_t last_payload_len;
uint16_t last_eth_type;
} ch390_diag_t;
void ch390_runtime_init(struct netif *netif, const uint8_t *mac);
struct pbuf *ch390_runtime_input_frame(struct netif *netif);
void ch390_runtime_set_irq_pending(void);
uint8_t ch390_runtime_is_irq_pending(void);
void ch390_runtime_poll(struct netif *netif);
void ch390_runtime_check_link(struct netif *netif);
err_t ch390_runtime_output(struct netif *netif, struct pbuf *p);
-1
View File
@@ -645,7 +645,6 @@ etharp_input(struct pbuf *p, struct netif *netif)
/* these are aligned properly, whereas the ARP header fields might not be */
ip4_addr_t sipaddr, dipaddr;
u8_t for_us, from_us;
LWIP_ASSERT_CORE_LOCKED();
LWIP_ERROR("netif != NULL", (netif != NULL), return;);
-1
View File
@@ -87,7 +87,6 @@ icmp_input(struct pbuf *p, struct netif *inp)
const struct ip_hdr *iphdr_in;
u16_t hlen;
const ip4_addr_t *src;
ICMP_STATS_INC(icmp.recv);
MIB2_STATS_INC(mib2.icmpinmsgs);
+2 -3
View File
@@ -47,7 +47,7 @@ void ethernetif_set_irq_pending(void)
uint8_t ethernetif_is_irq_pending(void)
{
return 0u;
return ch390_runtime_is_irq_pending();
}
static void low_level_init(struct netif *netif)
@@ -62,8 +62,7 @@ static err_t low_level_output(struct netif *netif, struct pbuf *p)
static struct pbuf *low_level_input(struct netif *netif)
{
LWIP_UNUSED_ARG(netif);
return NULL;
return ch390_runtime_input_frame(netif);
}
void ethernetif_input(struct netif *netif)