Files
ch32v208_sens/port/ethernetif.c
2025-11-08 21:01:04 +06:00

286 lines
7.6 KiB
C

#include "ethernetif.h"
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "ch32fun.h"
#include "ch32v20xhw.h"
#include "lwip/etharp.h"
#include "lwip/snmp.h"
#include "systick.h"
#define IFNAME0 'e'
#define IFNAME1 'n'
#define ETH_RXBUFNB 4
#define ETH_TXBUFNB 1
#define ETH_RX_BUF_SZE ETH_MAX_PACKET_SIZE
#define ETH_TX_BUF_SZE ETH_MAX_PACKET_SIZE
struct ethernetif {
ETH_DMADESCTypeDef* DMARxDescToGet;
ETH_DMADESCTypeDef* DMATxDescToSet;
};
__attribute__((aligned(4))) ETH_DMADESCTypeDef DMARxDscrTab[ETH_RXBUFNB];
__attribute__((aligned(4))) ETH_DMADESCTypeDef DMATxDscrTab[ETH_TXBUFNB];
__attribute__((aligned(4))) uint8_t MACRxBuf[ETH_RXBUFNB * ETH_RX_BUF_SZE];
__attribute__((aligned(4))) uint8_t MACTxBuf[ETH_TXBUFNB * ETH_TX_BUF_SZE];
static volatile bool g_link_interrupt_flag = false;
static volatile bool g_packet_received_flag = false;
static struct ethernetif eth_state;
static void low_level_init(struct netif* netif);
static err_t low_level_output(struct netif* netif, struct pbuf* p);
static struct pbuf* low_level_input(struct netif* netif);
void WritePHYReg(uint8_t reg_add, uint16_t reg_val);
uint16_t ReadPHYReg(uint8_t reg_add);
static void eth_get_mac_in_uc(uint8_t* mac) {
// Mac is backwards.
const uint8_t* macaddr = (const uint8_t*)(ROM_CFG_USERADR_ID + 5);
for (int i = 0; i < 6; i++) {
mac[i] = *(macaddr--);
}
}
err_t ethernetif_init(struct netif* netif) {
#if LWIP_NETIF_HOSTNAME
netif->hostname = "lwip-ch32";
#endif
netif->state = &eth_state;
netif->name[0] = IFNAME0;
netif->name[1] = IFNAME1;
netif->output = etharp_output;
netif->linkoutput = low_level_output;
MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, 10000000); // 10Mbps
netif->hwaddr_len = ETH_HWADDR_LEN;
eth_get_mac_in_uc(netif->hwaddr);
printf("MAC Address: %02X:%02X:%02X:%02X:%02X:%02X\n", netif->hwaddr[0],
netif->hwaddr[1], netif->hwaddr[2], netif->hwaddr[3], netif->hwaddr[4],
netif->hwaddr[5]);
netif->mtu = 1500;
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
low_level_init(netif);
return ERR_OK;
}
static void low_level_init(struct netif* netif) {
struct ethernetif* ethernetif = netif->state;
// clocks
RCC->APB2PCENR |= RCC_APB2Periph_AFIO;
RCC->CFGR0 |= RCC_ETHPRE; // div 2
EXTEN->EXTEN_CTR |= EXTEN_ETH_10M_EN;
// reset mac rx and tx
ETH10M->ECON1 = RB_ETH_ECON1_TXRST | RB_ETH_ECON1_RXRST;
ETH10M->ECON1 = 0;
// mac regs
ETH10M->ERXFCON = RB_ETH_ERXFCON_BCEN | RB_ETH_ERXFCON_MCEN;
ETH10M->MACON1 = RB_ETH_MACON1_MARXEN;
ETH10M->MACON2 = PADCFG_AUTO_3 | RB_ETH_MACON2_TXCRCEN;
ETH10M->MAMXFL = ETH_MAX_PACKET_SIZE;
R8_ETH_MAADRL1 = netif->hwaddr[5];
R8_ETH_MAADRL2 = netif->hwaddr[4];
R8_ETH_MAADRL3 = netif->hwaddr[3];
R8_ETH_MAADRL4 = netif->hwaddr[2];
R8_ETH_MAADRL5 = netif->hwaddr[1];
R8_ETH_MAADRL6 = netif->hwaddr[0];
// PHY analog block
ETH10M->ECON2 = RB_ETH_ECON2_DEFAULT;
// init TX descriptors
ethernetif->DMATxDescToSet = DMATxDscrTab;
for (int i = 0; i < ETH_TXBUFNB; i++) {
DMATxDscrTab[i].Status = 0;
DMATxDscrTab[i].Buffer1Addr = (uint32_t)&MACTxBuf[i * ETH_TX_BUF_SZE];
DMATxDscrTab[i].Buffer2NextDescAddr =
(uint32_t)&DMATxDscrTab[(i + 1) % ETH_TXBUFNB];
}
// init RX descriptors
ethernetif->DMARxDescToGet = DMARxDscrTab;
for (int i = 0; i < ETH_RXBUFNB; i++) {
DMARxDscrTab[i].Status = 0;
DMARxDscrTab[i].Buffer1Addr = (uint32_t)&MACRxBuf[i * ETH_RX_BUF_SZE];
DMARxDscrTab[i].Buffer2NextDescAddr =
(uint32_t)&DMARxDscrTab[(i + 1) % ETH_RXBUFNB];
}
// set RX buffer start and enable receiver
ETH10M->ERXST = ethernetif->DMARxDescToGet->Buffer1Addr;
ETH10M->ECON1 = RB_ETH_ECON1_RXEN;
WritePHYReg(PHY_BMCR, PHY_BMCR_RESET);
Delay_Ms(200);
WritePHYReg(PHY_BMCR, PHY_BMCR_FULL_DUPLEX);
ETH10M->EIR = 0xFF; // clear all interrupt flags
ETH10M->EIE = RB_ETH_EIE_INTIE | RB_ETH_EIE_RXIE | RB_ETH_EIE_TXIE |
RB_ETH_EIE_LINKIE | RB_ETH_EIE_TXERIE | RB_ETH_EIE_RXERIE |
RB_ETH_EIE_R_EN50;
NVIC_EnableIRQ(ETH_IRQn);
}
static err_t low_level_output(struct netif* netif, struct pbuf* p) {
(void)netif;
if (DMATxDscrTab[0].Status & ETH_DMATxDesc_OWN) {
LINK_STATS_INC(link.drop);
return ERR_BUF;
}
uint32_t len = 0;
uint8_t* tx_buf_ptr = (uint8_t*)DMATxDscrTab[0].Buffer1Addr;
for (struct pbuf* q = p; q != NULL; q = q->next) {
memcpy(&tx_buf_ptr[len], q->payload, q->len);
len += q->len;
}
ETH10M->ETXLN = len;
ETH10M->ETXST = (uint32_t)tx_buf_ptr;
DMATxDscrTab[0].Status |= ETH_DMATxDesc_OWN;
ETH10M->ECON1 |= RB_ETH_ECON1_TXRTS;
LINK_STATS_INC(link.xmit);
MIB2_STATS_NETIF_ADD(netif, ifoutoctets, len);
return ERR_OK;
}
static struct pbuf* low_level_input(struct netif* netif) {
struct ethernetif* ethernetif = netif->state;
uint16_t len = ETH10M->ERXLN;
if (len < MIN_ETH_FRAME_SIZE || len > ETH_MAX_PACKET_SIZE) {
LINK_STATS_INC(link.lenerr);
ETH10M->ECON1 |= RB_ETH_ECON1_RXEN;
return NULL;
}
uint8_t* current_rx_buffer_ptr =
(uint8_t*)ethernetif->DMARxDescToGet->Buffer1Addr;
struct pbuf* p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
if (p != NULL) {
uint32_t offset = 0;
for (struct pbuf* q = p; q != NULL; q = q->next) {
memcpy(q->payload, current_rx_buffer_ptr + offset, q->len);
offset += q->len;
}
LINK_STATS_INC(link.recv);
MIB2_STATS_NETIF_ADD(netif, ifinoctets, len);
} else {
LINK_STATS_INC(link.memerr);
LINK_STATS_INC(link.drop);
MIB2_STATS_NETIF_INC(netif, ifindiscards);
}
// move to next descriptor
ethernetif->DMARxDescToGet =
(ETH_DMADESCTypeDef*)ethernetif->DMARxDescToGet->Buffer2NextDescAddr;
ETH10M->ERXST = (uint32_t)ethernetif->DMARxDescToGet->Buffer1Addr;
ETH10M->ECON1 |= RB_ETH_ECON1_RXEN;
return p;
}
void ethernetif_input(struct netif* netif) {
if (!g_packet_received_flag) {
return;
}
NVIC_DisableIRQ(ETH_IRQn);
if (g_packet_received_flag) {
g_packet_received_flag = false;
}
NVIC_EnableIRQ(ETH_IRQn);
struct pbuf* p = low_level_input(netif);
if (p != NULL) {
if (netif->input(p, netif) != ERR_OK) {
pbuf_free(p);
}
}
}
void ethernetif_link_poll(struct netif* netif) {
if (!g_link_interrupt_flag) return;
g_link_interrupt_flag = false;
// supposedly, first read latches link status 2nd get cur val
(void)ReadPHYReg(PHY_BMSR);
uint16_t bmsr = ReadPHYReg(PHY_BMSR);
if (bmsr & PHY_BMSR_LINK_STATUS) {
if (!netif_is_link_up(netif)) {
ETH10M->MACON2 |= RB_ETH_MACON2_FULDPX;
netif_set_link_up(netif);
}
} else {
if (netif_is_link_up(netif)) {
netif_set_link_down(netif);
}
}
}
void ETH_IRQHandler(void) __attribute__((interrupt)) __attribute__((used));
void ETH_IRQHandler(void) {
uint32_t flags = ETH10M->EIR;
if (flags & RB_ETH_EIR_RXIF) {
g_packet_received_flag = true;
ETH10M->EIR = RB_ETH_EIR_RXIF;
}
if (flags & RB_ETH_EIR_TXIF) {
DMATxDscrTab[0].Status &= ~ETH_DMATxDesc_OWN;
ETH10M->EIR = RB_ETH_EIR_TXIF;
}
if (flags & RB_ETH_EIR_TXERIF) {
DMATxDscrTab[0].Status &= ~ETH_DMATxDesc_OWN;
ETH10M->EIR = RB_ETH_EIR_TXERIF;
LINK_STATS_INC(link.err);
}
if (flags & RB_ETH_EIR_RXERIF) {
ETH10M->EIR = RB_ETH_EIR_RXERIF;
ETH10M->ECON1 |= RB_ETH_ECON1_RXEN;
LINK_STATS_INC(link.err);
}
if (flags & RB_ETH_EIR_LINKIF) {
g_link_interrupt_flag = true;
ETH10M->EIR = RB_ETH_EIR_LINKIF;
}
}
void WritePHYReg(uint8_t reg_add, uint16_t reg_val) {
R32_ETH_MIWR = (reg_add & RB_ETH_MIREGADR_MASK) | RB_ETH_MIWR_MIIWR |
(reg_val << RB_ETH_MIWR_DATA_SHIFT);
}
uint16_t ReadPHYReg(uint8_t reg_add) {
ETH10M->MIERGADR = reg_add;
return ETH10M->MIRD;
}