refactor: serialize CH390 runtime SPI access

Move runtime CH390 transactions behind a single ch390_runtime owner so main, lwIP glue, and EXTI no longer compete for SPI access. Keep the system stable under runtime load and capture the remaining CH390 readback failure as a credible low-level device-response issue in the handoff logs.
This commit is contained in:
2026-04-01 03:39:08 +08:00
parent e5fffaccdf
commit 14a532290d
11 changed files with 892 additions and 255 deletions
+14 -180
View File
@@ -18,175 +18,52 @@
#include "CH390.h"
#include "CH390_Interface.h"
#include "ch390_runtime.h"
#include "config.h"
#include "stm32f1xx_hal.h"
#include "SEGGER_RTT.h"
#define IFNAME0 'e'
#define IFNAME1 'n'
struct netif ch390_netif;
static volatile uint8_t g_ch390_irq_pending;
static void ethernetif_unlock(uint32_t primask);
static uint32_t ethernetif_lock(void)
{
uint32_t primask = __get_PRIMASK();
__disable_irq();
return primask;
}
sys_prot_t sys_arch_protect(void)
{
return (sys_prot_t)ethernetif_lock();
__disable_irq();
return 0u;
}
void sys_arch_unprotect(sys_prot_t pval)
{
ethernetif_unlock((uint32_t)pval);
}
static void ethernetif_unlock(uint32_t primask)
{
if ((primask & 1u) == 0u) {
__enable_irq();
}
LWIP_UNUSED_ARG(pval);
__enable_irq();
}
void ethernetif_set_irq_pending(void)
{
g_ch390_irq_pending = 1u;
ch390_runtime_set_irq_pending();
}
uint8_t ethernetif_is_irq_pending(void)
{
return g_ch390_irq_pending;
return 0u;
}
static void low_level_init(struct netif *netif)
{
struct ethernetif *ethernetif = netif->state;
ch390_gpio_init();
ch390_spi_init();
ch390_hardware_reset();
ch390_default_config();
ch390_set_mac_address((uint8_t *)config_get()->mac);
netif->hwaddr_len = ETHARP_HWADDR_LEN;
ch390_get_mac(netif->hwaddr);
netif->mtu = 1500;
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
ethernetif->rx_len = 0u;
ethernetif->rx_status = 0u;
ch390_interrupt_init();
ch390_runtime_init(netif, config_get()->mac);
}
static err_t low_level_output(struct netif *netif, struct pbuf *p)
{
struct pbuf *q;
uint32_t primask;
uint32_t start_tick;
LWIP_UNUSED_ARG(netif);
primask = ethernetif_lock();
#if ETH_PAD_SIZE
pbuf_remove_header(p, ETH_PAD_SIZE);
#endif
start_tick = HAL_GetTick();
while (ch390_read_reg(CH390_TCR) & TCR_TXREQ) {
if ((HAL_GetTick() - start_tick) > 10u) {
ethernetif_unlock(primask);
#if ETH_PAD_SIZE
pbuf_add_header(p, ETH_PAD_SIZE);
#endif
LINK_STATS_INC(link.drop);
return ERR_TIMEOUT;
}
}
for (q = p; q != NULL; q = q->next) {
ch390_write_mem(q->payload, q->len);
}
ch390_write_reg(CH390_TXPLL, p->tot_len & 0xFFu);
ch390_write_reg(CH390_TXPLH, (p->tot_len >> 8) & 0xFFu);
ch390_send_request();
ethernetif_unlock(primask);
#if ETH_PAD_SIZE
pbuf_add_header(p, ETH_PAD_SIZE);
#endif
LINK_STATS_INC(link.xmit);
return ERR_OK;
return ch390_runtime_output(netif, p);
}
static struct pbuf *low_level_input(struct netif *netif)
{
struct ethernetif *ethernetif = netif->state;
struct pbuf *p = NULL;
struct pbuf *q;
uint16_t len;
uint8_t rx_ready;
uint8_t rx_header[4];
uint32_t primask;
primask = ethernetif_lock();
ch390_read_reg(CH390_MRCMDX);
rx_ready = ch390_read_reg(CH390_MRCMDX);
if (rx_ready & CH390_PKT_ERR) {
ch390_write_reg(CH390_RCR, 0u);
ch390_write_reg(CH390_MPTRCR, 0x01u);
ch390_write_reg(CH390_MRRH, 0x0Cu);
ch390_delay_us(1000u);
ch390_write_reg(CH390_RCR, RCR_RXEN | RCR_DIS_CRC);
ethernetif->rx_len = 0u;
LINK_STATS_INC(link.drop);
ethernetif_unlock(primask);
return NULL;
}
if ((rx_ready & CH390_PKT_RDY) == 0u) {
ethernetif->rx_len = 0u;
ethernetif_unlock(primask);
return NULL;
}
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);
len = ethernetif->rx_len;
#if ETH_PAD_SIZE
len += ETH_PAD_SIZE;
#endif
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
if (p != NULL) {
#if ETH_PAD_SIZE
pbuf_remove_header(p, ETH_PAD_SIZE);
#endif
for (q = p; q != NULL; q = q->next) {
ch390_read_mem(q->payload, q->len);
}
#if ETH_PAD_SIZE
pbuf_add_header(p, ETH_PAD_SIZE);
#endif
ch390_drop_packet(4u);
LINK_STATS_INC(link.recv);
} else {
ch390_drop_packet((uint16_t)(ethernetif->rx_len + 4u));
LINK_STATS_INC(link.memerr);
LINK_STATS_INC(link.drop);
}
ethernetif_unlock(primask);
return p;
LWIP_UNUSED_ARG(netif);
return NULL;
}
void ethernetif_input(struct netif *netif)
@@ -237,55 +114,12 @@ void lwip_netif_init(const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const
void ethernetif_check_link(void)
{
uint8_t link_up;
uint32_t primask = ethernetif_lock();
link_up = (uint8_t)ch390_get_link_status();
ethernetif_unlock(primask);
if (link_up) {
if (!netif_is_link_up(&ch390_netif)) {
netif_set_link_up(&ch390_netif);
}
} else if (netif_is_link_up(&ch390_netif)) {
netif_set_link_down(&ch390_netif);
}
ch390_runtime_check_link(&ch390_netif);
}
void ethernetif_poll(void)
{
uint8_t int_status;
uint32_t primask;
if (g_ch390_irq_pending == 0u) {
return;
}
primask = ethernetif_lock();
int_status = ch390_read_reg(CH390_ISR);
ch390_write_reg(CH390_ISR, int_status);
g_ch390_irq_pending = 0u;
ethernetif_unlock(primask);
if ((int_status & ISR_LNKCHG) != 0u) {
ethernetif_check_link();
}
if ((int_status & ISR_ROS) != 0u) {
LINK_STATS_INC(link.err);
}
if ((int_status & ISR_PR) != 0u) {
while (1) {
struct pbuf *p = low_level_input(&ch390_netif);
if (p == NULL) {
break;
}
if (ch390_netif.input(p, &ch390_netif) != ERR_OK) {
pbuf_free(p);
}
}
}
ch390_runtime_poll(&ch390_netif);
}
u32_t sys_now(void)
+1
View File
@@ -8,6 +8,7 @@
#include "lwip/err.h"
#include "lwip/netif.h"
#include "ch390_runtime.h"
struct ethernetif {
uint16_t rx_len;