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:
+19
-2
@@ -12,6 +12,8 @@
|
||||
#include "CH390.h"
|
||||
#include "CH390_Interface.h"
|
||||
|
||||
#define CH390_PHY_BUSY_TIMEOUT_LOOPS 2000u
|
||||
|
||||
/**
|
||||
* @name ch390_receive_packet
|
||||
* @brief Receive packet
|
||||
@@ -119,10 +121,17 @@ void ch390_drop_packet(uint16_t len)
|
||||
*/
|
||||
uint16_t ch390_read_phy(uint8_t reg)
|
||||
{
|
||||
uint32_t timeout = CH390_PHY_BUSY_TIMEOUT_LOOPS;
|
||||
|
||||
ch390_write_reg(CH390_EPAR, CH390_PHY | reg);
|
||||
// Chose PHY, send read command
|
||||
ch390_write_reg(CH390_EPCR, EPCR_ERPRR | EPCR_EPOS);
|
||||
while(ch390_read_reg(CH390_EPCR) & 0x01);
|
||||
while ((ch390_read_reg(CH390_EPCR) & EPCR_ERRE) != 0u) {
|
||||
if (timeout-- == 0u) {
|
||||
ch390_write_reg(CH390_EPCR, 0x00);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// Clear read command
|
||||
ch390_write_reg(CH390_EPCR, 0x00);
|
||||
return (ch390_read_reg(CH390_EPDRH) << 8) |
|
||||
@@ -137,12 +146,19 @@ uint16_t ch390_read_phy(uint8_t reg)
|
||||
*/
|
||||
void ch390_write_phy(uint8_t reg, uint16_t value)
|
||||
{
|
||||
uint32_t timeout = CH390_PHY_BUSY_TIMEOUT_LOOPS;
|
||||
|
||||
ch390_write_reg(CH390_EPAR, CH390_PHY | reg);
|
||||
ch390_write_reg(CH390_EPDRL, (value & 0xff)); // Low byte
|
||||
ch390_write_reg(CH390_EPDRH, ((value >> 8) & 0xff)); // High byte
|
||||
// Chose PHY, send write command
|
||||
ch390_write_reg(CH390_EPCR, 0x0A);
|
||||
while(ch390_read_reg(CH390_EPCR) & 0x01);
|
||||
while ((ch390_read_reg(CH390_EPCR) & EPCR_ERRE) != 0u) {
|
||||
if (timeout-- == 0u) {
|
||||
ch390_write_reg(CH390_EPCR, 0x00);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Clear write command
|
||||
ch390_write_reg(CH390_EPCR, 0x00);
|
||||
}
|
||||
@@ -194,6 +210,7 @@ void ch390_default_config()
|
||||
uint8_t multicase_addr[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
|
||||
ch390_set_phy_mode(CH390_AUTO);
|
||||
ch390_write_reg(CH390_INTCR, (uint8_t)(INCR_TYPE_OD | INCR_POL_L));
|
||||
// Clear status
|
||||
ch390_write_reg(CH390_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
|
||||
ch390_write_reg(CH390_ISR, 0xFF); // Clear interrupt status
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "main.h"
|
||||
#include "CH390.h"
|
||||
#include "CH390_Interface.h"
|
||||
#include "SEGGER_RTT.h"
|
||||
|
||||
/* FreeRTOS includes */
|
||||
#ifdef USE_FREERTOS
|
||||
@@ -47,6 +48,13 @@
|
||||
#define CH390_INT_PORT GPIOB
|
||||
#define CH390_INT_PIN GPIO_PIN_0
|
||||
|
||||
#define CH390_SCK_PORT GPIOA
|
||||
#define CH390_SCK_PIN GPIO_PIN_5
|
||||
#define CH390_MISO_PORT GPIOA
|
||||
#define CH390_MISO_PIN GPIO_PIN_6
|
||||
#define CH390_MOSI_PORT GPIOA
|
||||
#define CH390_MOSI_PIN GPIO_PIN_7
|
||||
|
||||
/* External SPI handle from spi.c */
|
||||
extern SPI_HandleTypeDef hspi1;
|
||||
|
||||
@@ -65,6 +73,7 @@ static inline void ch390_cs(uint8_t state)
|
||||
{
|
||||
HAL_GPIO_WritePin(CH390_CS_PORT, CH390_CS_PIN,
|
||||
state ? GPIO_PIN_SET : GPIO_PIN_RESET);
|
||||
ch390_delay_us(2);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,10 +98,24 @@ static inline void ch390_rst(uint8_t state)
|
||||
static uint8_t ch390_spi_exchange_byte(uint8_t byte)
|
||||
{
|
||||
uint8_t rx_data = 0;
|
||||
HAL_SPI_TransmitReceive(&hspi1, &byte, &rx_data, 1, SPI_TIMEOUT);
|
||||
if (HAL_SPI_TransmitReceive(&hspi1, &byte, &rx_data, 1, SPI_TIMEOUT) != HAL_OK)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return rx_data;
|
||||
}
|
||||
|
||||
static void ch390_spi_apply_mode(uint32_t polarity, uint32_t phase)
|
||||
{
|
||||
hspi1.Init.CLKPolarity = polarity;
|
||||
hspi1.Init.CLKPhase = phase;
|
||||
hspi1.Init.NSS = SPI_NSS_SOFT;
|
||||
if (HAL_SPI_Init(&hspi1) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read a dummy byte (send 0x00)
|
||||
* @return Received byte
|
||||
@@ -161,16 +184,7 @@ void ch390_spi_init(void)
|
||||
/* - CPOL = High (idle clock is high) */
|
||||
/* - CPHA = 2Edge (data captured on second edge) */
|
||||
|
||||
/* Reconfigure SPI for CH390 if needed */
|
||||
hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH;
|
||||
hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;
|
||||
hspi1.Init.NSS = SPI_NSS_SOFT; /* We control CS manually */
|
||||
|
||||
if (HAL_SPI_Init(&hspi1) != HAL_OK)
|
||||
{
|
||||
/* Handle error */
|
||||
Error_Handler();
|
||||
}
|
||||
ch390_spi_apply_mode(SPI_POLARITY_HIGH, SPI_PHASE_2EDGE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -222,9 +236,9 @@ void ch390_delay_us(uint32_t time)
|
||||
void ch390_hardware_reset(void)
|
||||
{
|
||||
ch390_rst(0); /* Assert reset (low) */
|
||||
ch390_delay_us(100); /* Hold reset for 100us (min 10us required) */
|
||||
ch390_delay_us(1000); /* Hold reset for 1ms to satisfy datasheet minimum */
|
||||
ch390_rst(1); /* Release reset (high) */
|
||||
ch390_delay_us(10000); /* Wait 10ms for CH390 to initialize */
|
||||
ch390_delay_us(50000); /* Wait 50ms for CH390 to initialize reliably */
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@@ -255,9 +269,13 @@ 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(reg | OPC_REG_W); /* Send write command */
|
||||
ch390_spi_exchange_byte(value); /* Write register value */
|
||||
ch390_spi_exchange_byte(frame[0]); /* Send write command */
|
||||
ch390_spi_exchange_byte(frame[1]); /* Send write data */
|
||||
ch390_cs(1); /* CS high - deselect */
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,249 @@
|
||||
#include "ch390_runtime.h"
|
||||
|
||||
#include "CH390.h"
|
||||
#include "CH390_Interface.h"
|
||||
#include "SEGGER_RTT.h"
|
||||
#include "ethernetif.h"
|
||||
#include "stm32f1xx_hal.h"
|
||||
#include "lwip/etharp.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/stats.h"
|
||||
|
||||
static volatile uint8_t g_ch390_irq_pending;
|
||||
static uint8_t g_ch390_ready;
|
||||
static ch390_diag_t g_diag;
|
||||
|
||||
static void ch390_runtime_refresh_diag(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.nsr = ch390_read_reg(CH390_NSR);
|
||||
g_diag.ncr = ch390_read_reg(CH390_NCR);
|
||||
g_diag.rcr = ch390_read_reg(CH390_RCR);
|
||||
g_diag.imr = ch390_read_reg(CH390_IMR);
|
||||
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.link_up = (uint8_t)ch390_get_link_status();
|
||||
g_diag.id_valid = (uint8_t)((g_diag.vendor_id != 0x0000u) &&
|
||||
(g_diag.vendor_id != 0xFFFFu) &&
|
||||
(g_diag.product_id != 0x0000u) &&
|
||||
(g_diag.product_id != 0xFFFFu));
|
||||
}
|
||||
|
||||
static struct pbuf *ch390_runtime_input(struct netif *netif)
|
||||
{
|
||||
struct ethernetif *ethernetif = (struct ethernetif *)netif->state;
|
||||
struct pbuf *p = NULL;
|
||||
struct pbuf *q;
|
||||
uint16_t len;
|
||||
uint8_t rx_ready;
|
||||
uint8_t rx_header[4];
|
||||
|
||||
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);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((rx_ready & CH390_PKT_RDY) == 0u) {
|
||||
ethernetif->rx_len = 0u;
|
||||
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);
|
||||
|
||||
if ((ethernetif->rx_status & 0x3Fu) != 0u || ethernetif->rx_len == 0u || ethernetif->rx_len > 1520u) {
|
||||
ch390_drop_packet((uint16_t)(ethernetif->rx_len + 4u));
|
||||
LINK_STATS_INC(link.drop);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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((uint8_t *)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);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void ch390_runtime_init(struct netif *netif, const uint8_t *mac)
|
||||
{
|
||||
struct ethernetif *ethernetif = (struct ethernetif *)netif->state;
|
||||
|
||||
SEGGER_RTT_WriteString(0, "ETH init: gpio\r\n");
|
||||
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: default\r\n");
|
||||
ch390_default_config();
|
||||
SEGGER_RTT_WriteString(0, "ETH init: mac\r\n");
|
||||
ch390_set_mac_address((uint8_t *)mac);
|
||||
|
||||
netif->hwaddr_len = ETHARP_HWADDR_LEN;
|
||||
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;
|
||||
|
||||
ethernetif->rx_len = 0u;
|
||||
ethernetif->rx_status = 0u;
|
||||
|
||||
ch390_runtime_refresh_diag();
|
||||
g_ch390_ready = g_diag.id_valid;
|
||||
|
||||
SEGGER_RTT_WriteString(0, "ETH init: irq\r\n");
|
||||
ch390_interrupt_init();
|
||||
SEGGER_RTT_WriteString(0, "ETH init: done\r\n");
|
||||
}
|
||||
|
||||
void ch390_runtime_set_irq_pending(void)
|
||||
{
|
||||
g_ch390_irq_pending = 1u;
|
||||
}
|
||||
|
||||
void ch390_runtime_poll(struct netif *netif)
|
||||
{
|
||||
uint8_t int_status;
|
||||
|
||||
if (!g_ch390_ready) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_ch390_irq_pending == 0u) {
|
||||
return;
|
||||
}
|
||||
|
||||
g_ch390_irq_pending = 0u;
|
||||
int_status = ch390_read_reg(CH390_ISR);
|
||||
ch390_write_reg(CH390_ISR, int_status);
|
||||
|
||||
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) != 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ch390_runtime_check_link(struct netif *netif)
|
||||
{
|
||||
uint8_t link_up;
|
||||
|
||||
if (!g_ch390_ready) {
|
||||
netif_set_link_down(netif);
|
||||
return;
|
||||
}
|
||||
|
||||
link_up = (uint8_t)ch390_get_link_status();
|
||||
|
||||
if (link_up) {
|
||||
if (!netif_is_link_up(netif)) {
|
||||
netif_set_link_up(netif);
|
||||
}
|
||||
} else if (netif_is_link_up(netif)) {
|
||||
netif_set_link_down(netif);
|
||||
}
|
||||
}
|
||||
|
||||
err_t ch390_runtime_output(struct netif *netif, struct pbuf *p)
|
||||
{
|
||||
struct pbuf *q;
|
||||
uint32_t start_tick;
|
||||
|
||||
LWIP_UNUSED_ARG(netif);
|
||||
|
||||
if (!g_ch390_ready) {
|
||||
LINK_STATS_INC(link.drop);
|
||||
return ERR_IF;
|
||||
}
|
||||
|
||||
#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) {
|
||||
#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((uint8_t *)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();
|
||||
|
||||
#if ETH_PAD_SIZE
|
||||
pbuf_add_header(p, ETH_PAD_SIZE);
|
||||
#endif
|
||||
|
||||
LINK_STATS_INC(link.xmit);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
void ch390_runtime_get_diag(ch390_diag_t *diag)
|
||||
{
|
||||
if (diag != NULL) {
|
||||
ch390_runtime_refresh_diag();
|
||||
*diag = g_diag;
|
||||
}
|
||||
}
|
||||
|
||||
bool ch390_runtime_is_ready(void)
|
||||
{
|
||||
return g_ch390_ready != 0u;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef __CH390_RUNTIME_H__
|
||||
#define __CH390_RUNTIME_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "lwip/err.h"
|
||||
|
||||
struct netif;
|
||||
struct pbuf;
|
||||
|
||||
typedef struct {
|
||||
uint16_t vendor_id;
|
||||
uint16_t product_id;
|
||||
uint8_t revision;
|
||||
uint8_t nsr;
|
||||
uint8_t ncr;
|
||||
uint8_t rcr;
|
||||
uint8_t imr;
|
||||
uint8_t intcr;
|
||||
uint8_t gpr;
|
||||
uint8_t isr;
|
||||
uint8_t link_up;
|
||||
uint8_t id_valid;
|
||||
} ch390_diag_t;
|
||||
|
||||
void ch390_runtime_init(struct netif *netif, const uint8_t *mac);
|
||||
void ch390_runtime_set_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);
|
||||
void ch390_runtime_get_diag(ch390_diag_t *diag);
|
||||
bool ch390_runtime_is_ready(void);
|
||||
|
||||
#endif
|
||||
@@ -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)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "ch390_runtime.h"
|
||||
|
||||
struct ethernetif {
|
||||
uint16_t rx_len;
|
||||
|
||||
Reference in New Issue
Block a user