first commit

This commit is contained in:
2025-11-07 17:02:04 +06:00
commit d577c5193c
16 changed files with 951 additions and 0 deletions

60
.gitignore vendored Normal file
View File

@@ -0,0 +1,60 @@
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
# debug information files
*.dwo
# z
main.lst
main_ext.bin
main.bin

6
.gitmodules vendored Normal file
View File

@@ -0,0 +1,6 @@
[submodule "ch32fun"]
path = ch32fun
url = https://github.com/cnlohr/ch32fun.git
[submodule "lwip"]
path = lwip
url = git://git.git.savannah.gnu.org/lwip.git

16
.vscode/c_cpp_properties.json vendored Normal file
View File

@@ -0,0 +1,16 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [],
"compilerPath": "/usr/bin/clang",
"cStandard": "c17",
"cppStandard": "c++17",
"intelliSenseMode": "linux-clang-x64"
}
],
"version": 4
}

22
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"files.associations": {
"*.rmd": "markdown",
"sys.h": "c",
"cstdio": "c",
"__verbose_abort": "c",
"*.inc": "c",
"ch32fun.h": "c",
"stdio.h": "c",
"systick.h": "c",
"def.h": "c",
"ch32v20xhw.h": "c",
"future": "c",
"compare": "c",
"cstdint": "c",
"snmp.h": "c",
"etharp.h": "c",
"dhcp.h": "c",
"netif.h": "c",
"ch32v307gigabit.h": "c"
}
}

54
Makefile Normal file
View File

@@ -0,0 +1,54 @@
TARGET ?= main
TARGET_MCU ?= CH32V208
TARGET_MCU_PACKAGE ?= CH32V208WBU6
CH32V003FUN ?= ./ch32fun/ch32fun
MINICHLINK ?= ./ch32fun/minichlink
PREFIX ?= riscv64-elf
NEWLIB ?= /usr/riscv64-elf/include/
# LwIP
LWIP_DIR := ./lwip
PORT_DIR := ./port
LWIPDIR := $(LWIP_DIR)/src
include $(LWIP_DIR)/src/Filelists.mk
LWIP_C_FILES :=
LWIP_C_FILES += $(COREFILES)
LWIP_C_FILES += $(CORE4FILES)
LWIP_C_FILES += $(NETIFFILES)
# Add APIFILES if you are using the Netconn/Socket API
# ifeq ($(USE_API), 1)
# LWIP_C_FILES += $(APIFILES)
# endif
LWIP_C_FILES_WITH_PATH := $(LWIP_C_FILES)
LWIP_PORT_FILES := $(wildcard $(PORT_DIR)/*.c)
INCLUDE_DIRS ?= \
-I./inc \
-I$(LWIP_DIR)/src/include \
-I$(PORT_DIR)
PROJECT_C_FILES := $(filter-out ./main.c, $(wildcard ./*.c))
LIB_C_FILES :=
# Add all lwIP sources to the main build variable
ADDITIONAL_C_FILES := \
$(PROJECT_C_FILES) \
$(LIB_C_FILES) \
$(LWIP_C_FILES_WITH_PATH) \
$(LWIP_PORT_FILES)
$(info Final ADDITIONAL_C_FILES is: [$(ADDITIONAL_C_FILES)])
include $(CH32V003FUN)/ch32fun.mk
CFLAGS += -Wall -Wextra $(INCLUDE_DIRS)
all: flash
flash: cv_flash
clean: cv_clean
.PHONY: all flash clean

1
ch32fun Submodule

Submodule ch32fun added at 57b2ad6b56

9
funconfig.h Normal file
View File

@@ -0,0 +1,9 @@
#ifndef _FUNCONFIG_H
#define _FUNCONFIG_H
#define FUNCONF_USE_HSE 1
#define FUNCONF_SYSTEM_CORE_CLOCK 120000000
#define FUNCONF_PLL_MULTIPLIER 15
#define FUNCONF_SYSTICK_USE_HCLK 1
#endif

19
inc/systick.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef SYSTICK_H
#define SYSTICK_H
#include <stdint.h>
#include "ch32fun.h"
#include "ch32v20xhw.h"
#define SYSTICK_ONE_MILLISECOND ((uint32_t)FUNCONF_SYSTEM_CORE_CLOCK / 1000)
#define SYSTICK_ONE_MICROSECOND ((uint32_t)FUNCONF_SYSTEM_CORE_CLOCK / 1000000)
extern volatile uint32_t systick_millis;
#define millis() (systick_millis)
#define micros() (SysTick->CNT / SYSTICK_ONE_MICROSECOND)
void systick_init(void);
#endif // SYSTICK_H

1
lwip Submodule

Submodule lwip added at 4599f551de

124
main.c Normal file
View File

@@ -0,0 +1,124 @@
#include <stdio.h>
#include "ch32fun.h"
#include "ch32v20xhw.h"
#include "ethernetif.h"
#include "lwip/dhcp.h"
#include "lwip/init.h"
#include "lwip/netif.h"
#include "lwip/timeouts.h"
#include "netif/ethernet.h"
#include "systick.h"
#define LED1_PIN 0
#define LED2_PIN 2
#define RCC_PREDIV1_OFFSET 0
struct netif g_netif;
void init_leds() {
RCC->APB2PCENR |= RCC_APB2Periph_GPIOA;
GPIOA->CFGLR &= ~((0xf << (4 * 0)) | (0xf << (4 * 2)));
GPIOA->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * 0);
GPIOA->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * 2);
}
int main() {
SystemInit();
// 1. HSE (32MHz)
// 2. PREDIV1 / 4.
// 3. PLL source = HSE, PLL x15.
// 4. (32MHz / 4) * 15 = 120MHz SYSCLK
RCC->INTR = 0x009F0000;
RCC->CTLR &= ~(RCC_HSE_ON | RCC_PLLON);
RCC->CFGR0 = 0x00000000;
RCC->CTLR |= RCC_HSE_ON;
int timeout;
for (timeout = 10000; timeout > 0; timeout--) {
if (RCC->CTLR & RCC_HSERDY) break; // wait for HSE
}
if (timeout == 0) {
printf("Error: HSE failed to start\n");
return -1;
}
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
RCC->CFGR2 = ((3) << 0); // PREDIV1 divisor = 3+1 = 4
RCC->CFGR0 |= RCC_PLLSource_HSE_Div1 | RCC_PLLMul_15;
RCC->CTLR |= RCC_PLLON;
printf("Main PLL enabled. Waiting for lock...\n");
for (timeout = 10000; timeout > 0; timeout--) {
if (RCC->CTLR & RCC_PLLRDY) break;
}
if (timeout == 0) {
printf("error: main pll lock failed\n");
return -1;
}
printf("Main PLL Locked\n");
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL;
while ((RCC->CFGR0 & RCC_SWS) != RCC_SWS_PLL);
printf("SysClock set to 120MHz\n");
systick_init();
init_leds();
lwip_init();
ip_addr_t ipaddr, netmask, gw;
IP4_ADDR(&ipaddr, 0, 0, 0, 0);
IP4_ADDR(&netmask, 0, 0, 0, 0);
IP4_ADDR(&gw, 0, 0, 0, 0);
netif_add(&g_netif, &ipaddr, &netmask, &gw, NULL, &ethernetif_init,
&ethernet_input);
netif_set_default(&g_netif);
netif_set_up(&g_netif);
dhcp_start(&g_netif);
ethernetif_init(&g_netif);
uint32_t last_led_toggle = 0;
uint32_t last_send_time = 0;
int led_state = 0;
while (1) {
ethernetif_link_poll(&g_netif);
if (netif_is_link_up(&g_netif)) {
ethernetif_input(&g_netif);
}
sys_check_timeouts();
// run_tx_test();
uint32_t now = millis();
if (now - last_led_toggle > 500) {
if (led_state) {
GPIOA->BSHR = (1 << 0);
} else {
GPIOA->BSHR = (1 << (0 + 16));
}
led_state = !led_state;
last_led_toggle = now;
}
static int ip_printed = 0;
if (g_netif.ip_addr.addr != 0 && !ip_printed) {
printf("IP address assigned: %s\n",
ip4addr_ntoa(netif_ip4_addr(&g_netif)));
ip_printed = 1;
}
}
}

35
port/arch/cc.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef LWIP_ARCH_CC_H
#define LWIP_ARCH_CC_H
#include <ch32fun.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define BYTE_ORDER LITTLE_ENDIAN
#define LWIP_PLATFORM_DIAG(x) \
do { \
printf x; \
} while (0)
#define LWIP_PLATFORM_ASSERT(x) \
do { \
printf("Assertion \"%s\" failed at line %d in %s\n", x, __LINE__, \
__FILE__); \
while (1); \
} while (0)
#define X8_F "02x"
#define U16_F "u"
#define S16_F "d"
#define X16_F "x"
#define U32_F "u"
#define S32_F "d"
#define X32_F "x"
#define SZT_F "u"
#define LWIP_RAND() ((u32_t)rand())
#endif /* LWIP_ARCH_CC_H */

344
port/ethernetif.c Normal file
View File

@@ -0,0 +1,344 @@
#include "ethernetif.h"
#include <stdio.h>
#include <string.h>
#include "ch32fun.h"
#include "ch32v20xhw.h"
#include "lwip/def.h"
#include "lwip/etharp.h"
#include "lwip/ethip6.h"
#include "lwip/mem.h"
#include "lwip/opt.h"
#include "lwip/pbuf.h"
#include "lwip/snmp.h"
#include "lwip/stats.h"
#include "netif/ethernet.h"
#include "systick.h"
#define IFNAME0 'e'
#define IFNAME1 'n'
#define ETH_RXBUFNB 4
#define ETH_TXBUFNB 1
#define ETH_MAX_PACKET_SIZE 1520
#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 uint8_t g_rx_error_cnt = 0;
volatile uint32_t g_isr_call_count = 0;
static err_t low_level_output(struct netif* netif, struct pbuf* p);
static struct pbuf* low_level_input(struct netif* netif);
static void low_level_init(struct netif* netif);
void eth_dma_tx_desc_chain_init(struct ethernetif* ethernetif,
ETH_DMADESCTypeDef* DMATxDescTab,
uint8_t* TxBuff, uint32_t TxBuffCount) {
ethernetif->DMATxDescToSet = DMATxDescTab;
DMATxDescTab->Status = 0;
DMATxDescTab->Buffer1Addr = (uint32_t)TxBuff;
DMATxDescTab->Buffer2NextDescAddr = (uint32_t)DMATxDescTab; // ring of 1
}
void eth_dma_rx_desc_chain_init(struct ethernetif* ethernetif,
ETH_DMADESCTypeDef* DMARxDescTab,
uint8_t* RxBuff, uint32_t RxBuffCount) {
ethernetif->DMARxDescToGet = DMARxDescTab;
for (uint32_t i = 0; i < RxBuffCount; i++) {
DMARxDescTab[i].Status = ETH_DMARxDesc_OWN; // give descriptor to DMA
DMARxDescTab[i].ControlBufferSize = ETH_RX_BUF_SZE;
DMARxDescTab[i].Buffer1Addr = (uint32_t)(&RxBuff[i * ETH_RX_BUF_SZE]);
if (i < (RxBuffCount - 1)) {
DMARxDescTab[i].Buffer2NextDescAddr = (uint32_t)(DMARxDescTab + i + 1);
} else {
DMARxDescTab[i].Buffer2NextDescAddr = (uint32_t)(DMARxDescTab);
}
}
}
void ETH_IRQHandler(void) __attribute__((interrupt));
void ETH_IRQHandler(void) {
g_isr_call_count++;
uint8_t flags = ETH10M->EIR;
// tx complete/error
if (flags & (RB_ETH_EIR_TXIF | RB_ETH_EIR_TXERIF)) {
// release DMA descriptor back to cpu
if (DMATxDscrTab[0].Status & ETH_DMATxDesc_OWN) {
DMATxDscrTab[0].Status &= ~ETH_DMATxDesc_OWN;
}
}
if (flags & RB_ETH_EIR_RXERIF) {
if (g_rx_error_cnt < 255) {
g_rx_error_cnt++;
}
}
ETH10M->EIR = flags;
}
static void low_level_init(struct netif* netif) {
struct ethernetif* ethernetif = netif->state;
uint8_t i;
netif->hwaddr_len = ETH_HWADDR_LEN;
netif->hwaddr[0] = 0x00;
netif->hwaddr[1] = 0x80;
netif->hwaddr[2] = 0xE1;
netif->hwaddr[3] = 0x00;
netif->hwaddr[4] = 0x00;
netif->hwaddr[5] = 0x01;
netif->mtu = 1500;
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
// clock
RCC->APB2PCENR |= RCC_APB2Periph_AFIO;
RCC->CFGR0 &= ~((uint32_t)1 << 28);
RCC->CFGR0 |= (RCC_ETHCLK_Div2 << 28);
// interrupts
ETH10M->EIE = 0; // clear
ETH10M->EIE = RB_ETH_EIE_INTIE | RB_ETH_EIE_RXIE | RB_ETH_EIE_LINKIE |
RB_ETH_EIE_TXIE | RB_ETH_EIE_TXERIE | RB_ETH_EIE_RXERIE;
ETH10M->EIE |= RB_ETH_EIE_R_EN50; // 50 ohm pull-up
ETH10M->EIR = 0xFF;
ETH10M->ESTAT |= RB_ETH_ESTAT_INT | RB_ETH_ESTAT_BUFER;
// reset mac
ETH10M->ECON1 |= (RB_ETH_ECON1_TXRST | RB_ETH_ECON1_RXRST);
ETH10M->ECON1 &= ~(RB_ETH_ECON1_TXRST | RB_ETH_ECON1_RXRST);
// // mac regs
ETH10M->ERXFON = 0; // accept unicast, multicast, broadcast
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];
ETH10M->MACON1 = RB_ETH_MACON1_MARXEN;
ETH10M->MACON2 &= ~RB_ETH_MACON2_PADCFG;
ETH10M->MACON2 |= PADCFG_AUTO_3 | RB_ETH_MACON2_TXCRCEN;
ETH10M->MACON2 &= ~RB_ETH_MACON2_HFRMEN; // disable huge frames
ETH10M->MACON2 |= RB_ETH_MACON2_FULDPX;
ETH10M->MAMXFL = ETH_MAX_PACKET_SIZE;
// PHY analog block
ETH10M->ECON2 &= ~(0x07 << 1);
ETH10M->ECON2 |= (5 << 1);
// en PHY block
EXTEN->EXTEN_CTR |= EXTEN_ETH_10M_EN;
// tx desc
eth_dma_tx_desc_chain_init(ethernetif, DMATxDscrTab, MACTxBuf, ETH_TXBUFNB);
// rx desc
eth_dma_rx_desc_chain_init(ethernetif, DMARxDscrTab, MACRxBuf, ETH_RXBUFNB);
printf("set PHY to 10Mbps Full-Duplex mode\n");
WritePHYReg(PHY_BMCR, PHY_BMCR_FORCE_10BASE_T_FD);
// init phy and auto neg
// WritePHYReg(PHY_BMCR, PHY_BMCR_RESET);
// Delay_Ms(200);
// WritePHYReg(PHY_BMCR, PHY_BMCR_FORCE_10BASE_T_FD | PHY_BMCR_AN_ENABLE |
// PHY_BMCR_AN_RESTART);
// Delay_Ms(1000);
NVIC_EnableIRQ(ETH_IRQn);
printf("low_level_init : done\n");
}
static err_t low_level_output(struct netif* netif, struct pbuf* p) {
struct ethernetif* ethernetif = netif->state;
struct pbuf* q;
uint32_t len = 0;
uint8_t* tx_buf_ptr = (uint8_t*)ethernetif->DMATxDescToSet->Buffer1Addr;
if (ethernetif->DMATxDescToSet->Status & ETH_DMATxDesc_OWN) {
return ERR_BUF;
}
for (q = p; q != NULL; q = q->next) {
memcpy(&tx_buf_ptr[len], q->payload, q->len);
len += q->len;
}
ethernetif->DMATxDescToSet->Status |= ETH_DMATxDesc_OWN;
ETH10M->ETXLN = len;
ETH10M->ETXST = (uint32_t)tx_buf_ptr;
ETH10M->ECON1 |= RB_ETH_ECON1_TXRTS;
ethernetif->DMATxDescToSet =
(ETH_DMADESCTypeDef*)ethernetif->DMATxDescToSet->Buffer2NextDescAddr;
MIB2_STATS_NETIF_ADD(netif, ifoutoctets, len);
return ERR_OK;
}
static struct pbuf* low_level_input(struct netif* netif) {
struct ethernetif* ethernetif = netif->state;
struct pbuf *p = NULL, *q;
u16_t len;
if ((ethernetif->DMARxDescToGet->Status & ETH_DMARxDesc_OWN) == 0) {
if (ETH10M->ESTAT & (RB_ETH_ESTAT_BUFER | RB_ETH_ESTAT_RXCRCER)) {
len = 0; // drop packet
// printf("RX ESTAT Error: 0x%02X\n", ETH10M->ESTAT);
ETH10M->ESTAT |= (RB_ETH_ESTAT_BUFER | RB_ETH_ESTAT_RXCRCER);
} else {
len = ETH10M->ERXLN;
if (len > 4) {
len -= 4;
} else {
len = 0;
}
}
// copy valid packet to pbuf
if (len > 0) {
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
if (p != NULL) {
uint8_t* rx_buffer = (uint8_t*)ethernetif->DMARxDescToGet->Buffer1Addr;
uint32_t bytes_copied = 0;
for (q = p; q != NULL; q = q->next) {
memcpy(q->payload, rx_buffer + bytes_copied, q->len);
bytes_copied += q->len;
}
MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len);
}
}
ethernetif->DMARxDescToGet->Status |= ETH_DMARxDesc_OWN;
ethernetif->DMARxDescToGet =
(ETH_DMADESCTypeDef*)ethernetif->DMARxDescToGet->Buffer2NextDescAddr;
// tell hw where next free buffer is?
ETH10M->ERXST = (uint32_t)ethernetif->DMARxDescToGet->Buffer1Addr;
return p;
}
return NULL; // no packet
}
void ethernetif_input(struct netif* netif) {
struct pbuf* p;
p = low_level_input(netif);
if (p != NULL) {
if (netif->input(p, netif) != ERR_OK) {
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
pbuf_free(p);
}
}
}
err_t ethernetif_init(struct netif* netif) {
struct ethernetif* ethernetif;
LWIP_ASSERT("netif != NULL", (netif != NULL));
ethernetif = mem_malloc(sizeof(struct ethernetif));
if (ethernetif == NULL) {
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));
return ERR_MEM;
}
#if LWIP_NETIF_HOSTNAME
netif->hostname = "lwip-wch";
#endif
MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, 10000000); // 10 Mbps
netif->state = ethernetif;
netif->name[0] = IFNAME0;
netif->name[1] = IFNAME1;
#if LWIP_IPV4
netif->output = etharp_output;
#endif
#if LWIP_IPV6
netif->output_ip6 = ethip6_output;
#endif
netif->linkoutput = low_level_output;
low_level_init(netif);
return ERR_OK;
}
void ethernetif_link_poll(struct netif* netif) {
static uint32_t last_poll_time = 0;
uint32_t now = millis();
// every 500ms
if (now - last_poll_time < 500) {
return;
}
last_poll_time = now;
uint16_t bmsr = ReadPHYReg(PHY_BMSR);
if (bmsr & PHY_Linked_Status) {
if (!netif_is_link_up(netif)) {
printf("Link is UP (10M-FD Mode)\n");
ETH10M->ECON1 |= RB_ETH_ECON1_RXEN;
netif_set_link_up(netif);
g_rx_error_cnt = 0;
}
// polarity check
// https://github.com/openwch/ch32v20x/blob/main/EVT/EXAM/ETH/NetLib/eth_driver.c#L262
if (g_rx_error_cnt > 5) {
printf("RX error count: %d. Flipping PHY polarity\n", g_rx_error_cnt);
uint16_t mdix_val = ReadPHYReg(PHY_MDIX);
if ((mdix_val >> 2) & 0x01) {
mdix_val &= ~(3 << 2); // normal
} else {
mdix_val |= (1 << 2); // reverse
}
WritePHYReg(PHY_MDIX, mdix_val);
g_rx_error_cnt = 0;
}
} else {
if (netif_is_link_up(netif)) {
printf("Link is DOWN\n");
netif_set_link_down(netif);
ETH10M->ECON1 &= ~RB_ETH_ECON1_RXEN;
}
}
}
void WritePHYReg(uint8_t reg_add, uint16_t reg_val) {
R32_ETH_MIWR = (reg_add & RB_ETH_MIREGADR_MIRDL) | (1 << 8) | (reg_val << 16);
}
uint16_t ReadPHYReg(uint8_t reg_add) {
ETH10M->MIERGADR = reg_add;
return ETH10M->MIRD;
}

161
port/ethernetif.h Normal file
View File

@@ -0,0 +1,161 @@
#ifndef __ETHERNETIF_H
#define __ETHERNETIF_H
#include "lwip/err.h"
#include "lwip/netif.h"
void run_tx_test(void);
void WritePHYReg(uint8_t reg_add, uint16_t reg_val);
uint16_t ReadPHYReg(uint8_t reg_add);
#define PHY_BMCR_FORCE_10BASE_T_HD ((uint16_t)0x0000)
#define PHY_BMCR_FORCE_10BASE_T_FD ((uint16_t)0x0100) // 10M, Full Duplex
#define PHY_ANAR_SELECTOR_FIELD 0x0001 // Selector for 802.3
#define PHY_ANAR_10BASET_HD 0x0020 // 10M Half-Duplex
#define PHY_ANAR_10BASET_FD 0x0040 // 10M Full-Duplex
#define PHY_BMCR_RESET ((uint16_t)0x8000) // Reset PHY
#define PHY_BMCR_AN_ENABLE \
((uint16_t)0x1000) // Enable Auto-Negotiation (Bit 12)
#define PHY_BMCR_AN_RESTART \
((uint16_t)0x0200) // Restart Auto-Negotiation (Bit 9)
/**
DMA Tx Desciptor
-----------------------------------------------------------------------------------------------
TDES0 | OWN(31) | CTRL[30:26] | Reserved[25:24] | CTRL[23:20] | Reserved[19:17] | Status[16:0] |
-----------------------------------------------------------------------------------------------
TDES1 | Reserved[31:29] | Buffer2 ByteCount[28:16] | Reserved[15:13] | Buffer1 ByteCount[12:0] |
-----------------------------------------------------------------------------------------------
TDES2 | Buffer1 Address [31:0] |
-----------------------------------------------------------------------------------------------
TDES3 | Buffer2 Address [31:0] / Next Desciptor Address [31:0] |
------------------------------------------------------------------------------------------------
*/
/* Bit or field definition of TDES0 register (DMA Tx descriptor status register)*/
#define ETH_DMATxDesc_OWN ((uint32_t)0x80000000) /* OWN bit: descriptor is owned by DMA engine */
#define ETH_DMATxDesc_IC ((uint32_t)0x40000000) /* Interrupt on Completion */
#define ETH_DMATxDesc_LS ((uint32_t)0x20000000) /* Last Segment */
#define ETH_DMATxDesc_FS ((uint32_t)0x10000000) /* First Segment */
#define ETH_DMATxDesc_DC ((uint32_t)0x08000000) /* Disable CRC */
#define ETH_DMATxDesc_DP ((uint32_t)0x04000000) /* Disable Padding */
#define ETH_DMATxDesc_TTSE ((uint32_t)0x02000000) /* Transmit Time Stamp Enable */
#define ETH_DMATxDesc_CIC ((uint32_t)0x00C00000) /* Checksum Insertion Control: 4 cases */
#define ETH_DMATxDesc_CIC_ByPass ((uint32_t)0x00000000) /* Do Nothing: Checksum Engine is bypassed */
#define ETH_DMATxDesc_CIC_IPV4Header ((uint32_t)0x00400000) /* IPV4 header Checksum Insertion */
#define ETH_DMATxDesc_CIC_TCPUDPICMP_Segment ((uint32_t)0x00800000) /* TCP/UDP/ICMP Checksum Insertion calculated over segment only */
#define ETH_DMATxDesc_CIC_TCPUDPICMP_Full ((uint32_t)0x00C00000) /* TCP/UDP/ICMP Checksum Insertion fully calculated */
#define ETH_DMATxDesc_TER ((uint32_t)0x00200000) /* Transmit End of Ring */
#define ETH_DMATxDesc_TCH ((uint32_t)0x00100000) /* Second Address Chained */
#define ETH_DMATxDesc_TTSS ((uint32_t)0x00020000) /* Tx Time Stamp Status */
#define ETH_DMATxDesc_IHE ((uint32_t)0x00010000) /* IP Header Error */
#define ETH_DMATxDesc_ES ((uint32_t)0x00008000) /* Error summary: OR of the following bits: UE || ED || EC || LCO || NC || LCA || FF || JT */
#define ETH_DMATxDesc_JT ((uint32_t)0x00004000) /* Jabber Timeout */
#define ETH_DMATxDesc_FF ((uint32_t)0x00002000) /* Frame Flushed: DMA/MTL flushed the frame due to SW flush */
#define ETH_DMATxDesc_PCE ((uint32_t)0x00001000) /* Payload Checksum Error */
#define ETH_DMATxDesc_LCA ((uint32_t)0x00000800) /* Loss of Carrier: carrier lost during tramsmission */
#define ETH_DMATxDesc_NC ((uint32_t)0x00000400) /* No Carrier: no carrier signal from the tranceiver */
#define ETH_DMATxDesc_LCO ((uint32_t)0x00000200) /* Late Collision: transmission aborted due to collision */
#define ETH_DMATxDesc_EC ((uint32_t)0x00000100) /* Excessive Collision: transmission aborted after 16 collisions */
#define ETH_DMATxDesc_VF ((uint32_t)0x00000080) /* VLAN Frame */
#define ETH_DMATxDesc_CC ((uint32_t)0x00000078) /* Collision Count */
#define ETH_DMATxDesc_ED ((uint32_t)0x00000004) /* Excessive Deferral */
#define ETH_DMATxDesc_UF ((uint32_t)0x00000002) /* Underflow Error: late data arrival from the memory */
#define ETH_DMATxDesc_DB ((uint32_t)0x00000001) /* Deferred Bit */
/* Field definition of TDES1 register */
#define ETH_DMATxDesc_TBS2 ((uint32_t)0x1FFF0000) /* Transmit Buffer2 Size */
#define ETH_DMATxDesc_TBS1 ((uint32_t)0x00001FFF) /* Transmit Buffer1 Size */
/* Field definition of TDES2 register */
#define ETH_DMATxDesc_B1AP ((uint32_t)0xFFFFFFFF) /* Buffer1 Address Pointer */
/* Field definition of TDES3 register */
#define ETH_DMATxDesc_B2AP ((uint32_t)0xFFFFFFFF) /* Buffer2 Address Pointer */
/**
DMA Rx Desciptor
---------------------------------------------------------------------------------------------------------------------
RDES0 | OWN(31) | Status [30:0] |
---------------------------------------------------------------------------------------------------------------------
RDES1 | CTRL(31) | Reserved[30:29] | Buffer2 ByteCount[28:16] | CTRL[15:14] | Reserved(13) | Buffer1 ByteCount[12:0] |
---------------------------------------------------------------------------------------------------------------------
RDES2 | Buffer1 Address [31:0] |
---------------------------------------------------------------------------------------------------------------------
RDES3 | Buffer2 Address [31:0] / Next Desciptor Address [31:0] |
----------------------------------------------------------------------------------------------------------------------
*/
/* Bit or field definition of RDES0 register (DMA Rx descriptor status register) */
#define ETH_DMARxDesc_OWN ((uint32_t)0x80000000) /* OWN bit: descriptor is owned by DMA engine */
#define ETH_DMARxDesc_AFM ((uint32_t)0x40000000) /* DA Filter Fail for the rx frame */
#define ETH_DMARxDesc_FL ((uint32_t)0x3FFF0000) /* Receive descriptor frame length */
#define ETH_DMARxDesc_ES ((uint32_t)0x00008000) /* Error summary: OR of the following bits: DE || OE || IPC || LC || RWT || RE || CE */
#define ETH_DMARxDesc_DE ((uint32_t)0x00004000) /* Desciptor error: no more descriptors for receive frame */
#define ETH_DMARxDesc_SAF ((uint32_t)0x00002000) /* SA Filter Fail for the received frame */
#define ETH_DMARxDesc_LE ((uint32_t)0x00001000) /* Frame size not matching with length field */
#define ETH_DMARxDesc_OE ((uint32_t)0x00000800) /* Overflow Error: Frame was damaged due to buffer overflow */
#define ETH_DMARxDesc_VLAN ((uint32_t)0x00000400) /* VLAN Tag: received frame is a VLAN frame */
#define ETH_DMARxDesc_FS ((uint32_t)0x00000200) /* First descriptor of the frame */
#define ETH_DMARxDesc_LS ((uint32_t)0x00000100) /* Last descriptor of the frame */
#define ETH_DMARxDesc_IPV4HCE ((uint32_t)0x00000080) /* IPC Checksum Error: Rx Ipv4 header checksum error */
#define ETH_DMARxDesc_LC ((uint32_t)0x00000040) /* Late collision occurred during reception */
#define ETH_DMARxDesc_FT ((uint32_t)0x00000020) /* Frame type - Ethernet, otherwise 802.3 */
#define ETH_DMARxDesc_RWT ((uint32_t)0x00000010) /* Receive Watchdog Timeout: watchdog timer expired during reception */
#define ETH_DMARxDesc_RE ((uint32_t)0x00000008) /* Receive error: error reported by MII interface */
#define ETH_DMARxDesc_DBE ((uint32_t)0x00000004) /* Dribble bit error: frame contains non int multiple of 8 bits */
#define ETH_DMARxDesc_CE ((uint32_t)0x00000002) /* CRC error */
#define ETH_DMARxDesc_MAMPCE ((uint32_t)0x00000001) /* Rx MAC Address/Payload Checksum Error: Rx MAC address matched/ Rx Payload Checksum Error */
/* Bit or field definition of RDES1 register */
#define ETH_DMARxDesc_DIC ((uint32_t)0x80000000) /* Disable Interrupt on Completion */
#define ETH_DMARxDesc_RBS2 ((uint32_t)0x1FFF0000) /* Receive Buffer2 Size */
#define ETH_DMARxDesc_RER ((uint32_t)0x00008000) /* Receive End of Ring */
#define ETH_DMARxDesc_RCH ((uint32_t)0x00004000) /* Second Address Chained */
#define ETH_DMARxDesc_RBS1 ((uint32_t)0x00001FFF) /* Receive Buffer1 Size */
/* Field definition of RDES2 register */
#define ETH_DMARxDesc_B1AP ((uint32_t)0xFFFFFFFF) /* Buffer1 Address Pointer */
/* Field definition of RDES3 register */
#define ETH_DMARxDesc_B2AP ((uint32_t)0xFFFFFFFF) /* Buffer2 Address Pointer */
#define ETH_DMARxDesc_FrameLengthShift 16
typedef struct {
uint32_t volatile Status; /* Status */
uint32_t ControlBufferSize; /* Control and Buffer1, Buffer2 lengths */
uint32_t Buffer1Addr; /* Buffer1 address pointer */
uint32_t Buffer2NextDescAddr; /* Buffer2 or next descriptor address pointer */
} ETH_DMADESCTypeDef;
/**
* @brief Initialize the ethernet interface and lwIP network stack.
* This function should be passed as the init function to netif_add().
*
* @param netif The lwIP network interface structure to be initialized.
* @return ERR_OK if the loopif is initialized, ERR_MEM if private data couldn't
* be allocated.
*/
err_t ethernetif_init(struct netif* netif);
/**
* @brief This function should be called periodically from your main loop
* to check for incoming packets and pass them to lwIP.
*
* @param netif The lwIP network interface structure.
*/
void ethernetif_input(struct netif* netif);
/**
* @brief This function should be called periodically from your main loop
* to check the link status and update lwIP accordingly.
*
* @param netif The lwIP network interface structure..
*/
void ethernetif_link_poll(struct netif* netif);
#endif /* __ETHERNETIF_H */

53
port/lwipopts.h Normal file
View File

@@ -0,0 +1,53 @@
#ifndef __LWIPOPTS_H__
#define __LWIPOPTS_H__
#define LWIP_DEBUG 1
#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL
#define DHCP_DEBUG LWIP_DBG_ON
#define NETIF_DEBUG LWIP_DBG_ON
#define ETHARP_DEBUG LWIP_DBG_ON
#define NO_SYS 1
// Core locking
#define SYS_LIGHTWEIGHT_PROT 0
// Memory options
#define MEM_ALIGNMENT 4
#define MEM_SIZE (4 * 1024) // 4KB of RAM for lwIP heap
// Pbuf options
#define PBUF_POOL_SIZE 8
#define PBUF_POOL_BUFSIZE 1524
// TCP options
#define LWIP_TCP 1
#define TCP_MSS 1460
#define TCP_SND_BUF (2 * TCP_MSS)
// UDP options
#define LWIP_UDP 1
// ICMP options
#define LWIP_ICMP 1
// DHCP options
#define LWIP_DHCP 1
// Checksum options
// #define CHECKSUM_GEN_IP 0
// #define CHECKSUM_GEN_UDP 0
// #define CHECKSUM_GEN_TCP 0
// #define CHECKSUM_CHECK_IP 0
// #define CHECKSUM_CHECK_UDP 0
// #define CHECKSUM_CHECK_TCP 0
// #define LWIP_CHECKSUM_ON_COPY 1
#define LWIP_NETCONN 0
#define LWIP_SOCKET 0
// Statistics
#define LWIP_STATS 0
#endif /* __LWIPOPTS_H__ */

25
port/sys_arch.c Normal file
View File

@@ -0,0 +1,25 @@
#include "ch32fun.h"
#include "lwip/def.h"
#include "systick.h"
typedef uint32_t sys_prot_t;
static unsigned long next = 1;
int rand(void) {
next = next * 1103515245 + 12345;
return (unsigned int)(next / 65536) % 32768;
}
void srand(unsigned int seed) { next = seed; }
uint32_t sys_now(void) { return systick_millis; }
sys_prot_t sys_arch_protect(void) {
unsigned int old_mstatus;
__asm__ volatile("csrrci %0, mstatus, 8" : "=r"(old_mstatus));
return old_mstatus;
}
void sys_arch_unprotect(sys_prot_t pval) {
__asm__ volatile("csrw mstatus, %0" : : "r"(pval));
}

21
systick.c Normal file
View File

@@ -0,0 +1,21 @@
#include "systick.h"
volatile uint32_t systick_millis;
void systick_init(void) {
SysTick->CTLR = 0x0000;
SysTick->CMP = SysTick->CNT + SYSTICK_ONE_MILLISECOND;
systick_millis = 0;
SysTick->CTLR = SYSTICK_CTLR_STE | // Enable Counter
SYSTICK_CTLR_STIE | // Enable Interrupts
SYSTICK_CTLR_STCLK; // Set Clock Source to HCLK/1
NVIC_EnableIRQ(SysTick_IRQn);
}
void SysTick_Handler(void) __attribute__((interrupt));
void SysTick_Handler(void) {
SysTick->CMP = SysTick->CNT + SYSTICK_ONE_MILLISECOND;
SysTick->SR = 0;
systick_millis++;
}