diff --git a/.vscode/settings.json b/.vscode/settings.json index b27b960..238bb1e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -17,6 +17,7 @@ "etharp.h": "c", "dhcp.h": "c", "netif.h": "c", - "ch32v307gigabit.h": "c" + "ch32v307gigabit.h": "c", + "stats.h": "c" } } \ No newline at end of file diff --git a/main.c b/main.c index 4206632..3ce88a0 100644 --- a/main.c +++ b/main.c @@ -10,113 +10,132 @@ #include "netif/ethernet.h" #include "systick.h" -#define LED1_PIN 0 -#define LED2_PIN 2 +#define LED1_PIN 0 // PA0 +#define LED2_PIN 2 // PA2 + +#define HSE_STARTUP_TIMEOUT 10000 +#define PLL_LOCK_TIMEOUT 10000 +#define LED_TOGGLE_INTERVAL_MS 500 +#define LINK_POLL_INTERVAL_MS 500 #define RCC_PREDIV1_OFFSET 0 +#define HSE_CLOCK_MHZ 32 +#define PREDIV1_DIVISOR 4 +#define PLL_MULTIPLIER 15 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 clock_init(void); +void led_init(void); +void lwip_stack_init(void); -int main() { - SystemInit(); - - // 1. HSE (32MHz) - // 2. PREDIV1 / 4. - // 3. PLL source = HSE, PLL x15. - // 4. (32MHz / 4) * 15 = 120MHz SYSCLK - - RCC->INTR = 0x009F0000; +int clock_init(void) { + 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->CTLR |= RCC_HSE_ON; + for (int timeout = HSE_STARTUP_TIMEOUT; timeout > 0; timeout--) { + if (RCC->CTLR & RCC_HSERDY) break; + if (timeout == 1) { + 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->CFGR2 = (PREDIV1_DIVISOR - 1); 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--) { + printf("Main PLL en. Waiting for lock...\n"); + for (int timeout = PLL_LOCK_TIMEOUT; timeout > 0; timeout--) { if (RCC->CTLR & RCC_PLLRDY) break; - } - if (timeout == 0) { - printf("error: main pll lock failed\n"); - return -1; + if (timeout == 1) { + 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"); + printf("System clock set to %dMHz.\n", + (HSE_CLOCK_MHZ / PREDIV1_DIVISOR) * PLL_MULTIPLIER); + return 0; +} - systick_init(); - init_leds(); +void led_init(void) { + RCC->APB2PCENR |= RCC_APB2Periph_GPIOA; + GPIOA->CFGLR &= ~((0xf << (4 * LED1_PIN)) | (0xf << (4 * LED2_PIN))); + GPIOA->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * LED1_PIN); + GPIOA->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * LED2_PIN); +} + +void lwip_stack_init(void) { + ip_addr_t ipaddr, netmask, gw; 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, ðernetif_init, ðernet_input); - // netif_set_link_callback(&g_netif, link_status_callback); + netif_set_default(&g_netif); netif_set_up(&g_netif); + printf("Starting DHCP client...\n"); dhcp_start(&g_netif); +} - uint32_t last_led_toggle = 0; - uint32_t last_send_time = 0; +int main() { + SystemInit(); + + if (clock_init() != 0) { + // eating dirt? + while (1); + } + + systick_init(); + led_init(); + lwip_stack_init(); + + uint32_t last_led_toggle_time = 0; + uint32_t last_link_poll_time = 0; int led_state = 0; + int ip_address_printed = 0; while (1) { - ethernetif_link_poll(&g_netif); + ethernetif_input(&g_netif); - if (netif_is_link_up(&g_netif)) { - ethernetif_input(&g_netif); + if (millis() - last_link_poll_time > LINK_POLL_INTERVAL_MS) { + ethernetif_link_poll(&g_netif); + last_link_poll_time = millis(); } sys_check_timeouts(); - // run_tx_test(); - uint32_t now = millis(); - - if (now - last_led_toggle > 500) { + if (now - last_led_toggle_time > LED_TOGGLE_INTERVAL_MS) { if (led_state) { - GPIOA->BSHR = (1 << 0); + GPIOA->BSHR = (1 << LED1_PIN); } else { - GPIOA->BSHR = (1 << (0 + 16)); + GPIOA->BSHR = (1 << (LED1_PIN + 16)); } led_state = !led_state; - last_led_toggle = now; + last_led_toggle_time = now; } - static int ip_printed = 0; - if (g_netif.ip_addr.addr != 0 && !ip_printed) { + if (!ip_address_printed && g_netif.ip_addr.addr != 0) { printf("IP address assigned: %s\n", ip4addr_ntoa(netif_ip4_addr(&g_netif))); - ip_printed = 1; + ip_address_printed = 1; + + GPIOA->BSHR = (1 << LED2_PIN); } } } \ No newline at end of file diff --git a/port/ethernetif.c b/port/ethernetif.c index 29cf070..e55418c 100644 --- a/port/ethernetif.c +++ b/port/ethernetif.c @@ -1,19 +1,13 @@ #include "ethernetif.h" +#include #include #include #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' @@ -35,101 +29,82 @@ __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 volatile bool g_link_interrupt_flag = false; +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); -static void low_level_init(struct netif* netif); +void WritePHYReg(uint8_t reg_add, uint16_t reg_val); +uint16_t ReadPHYReg(uint8_t reg_add); -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); - } +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--); } } -void ETH_IRQHandler(void) __attribute__((interrupt)); -void ETH_IRQHandler(void) { - g_isr_call_count++; - uint8_t flags = ETH10M->EIR; - - if (flags & RB_ETH_EIR_RXIF) { - printf("<<< RX Interrupt Fired. EIR=0x%02X >>>>>\n", flags); +err_t ethernetif_init(struct netif* netif) { + struct ethernetif* ethernetif = mem_malloc(sizeof(struct ethernetif)); + if (ethernetif == NULL) { + LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n")); + return ERR_MEM; } - // 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 LWIP_NETIF_HOSTNAME + netif->hostname = "lwip-ch32"; +#endif - if (flags & RB_ETH_EIR_RXERIF) { - if (g_rx_error_cnt < 255) { - g_rx_error_cnt++; - } - } + netif->state = ethernetif; + netif->name[0] = IFNAME0; + netif->name[1] = IFNAME1; - ETH10M->EIR = flags; + 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; + uint8_t mac_addr[6]; + eth_get_mac_in_uc(mac_addr); + + printf("MAC Address: %02X:%02X:%02X:%02X:%02X:%02X\n", mac_addr[0], + mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); + + /* set MAC hardware address */ + netif->hwaddr[0] = mac_addr[0]; + netif->hwaddr[1] = mac_addr[1]; + netif->hwaddr[2] = mac_addr[2]; + netif->hwaddr[3] = mac_addr[3]; + netif->hwaddr[4] = mac_addr[4]; + netif->hwaddr[5] = mac_addr[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; - 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 + // clocks RCC->APB2PCENR |= RCC_APB2Periph_AFIO; - RCC->CFGR0 &= ~((uint32_t)1 << 28); - RCC->CFGR0 |= (RCC_ETHCLK_Div2 << 28); + RCC->CFGR0 = (RCC->CFGR0 & ~((uint32_t)1 << 28)) | (RCC_ETHCLK_Div2 << 28); + EXTEN->EXTEN_CTR |= EXTEN_ETH_10M_EN; - // interrupts - ETH10M->EIE = 0; // clear - ETH10M->EIE = RB_ETH_EIE_INTIE | 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 + // mac reset 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 + // mac regs + ETH10M->ERXFON = 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]; @@ -138,209 +113,138 @@ static void low_level_init(struct netif* netif) { 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); + ETH10M->ECON2 = (ETH10M->ECON2 & ~(0x07 << 1)) | (5 << 1); - // en PHY block - EXTEN->EXTEN_CTR |= EXTEN_ETH_10M_EN; + // DMA descriptors + ethernetif->DMATxDescToSet = &DMATxDscrTab[0]; + DMATxDscrTab[0].Status = 0; + DMATxDscrTab[0].Buffer1Addr = (uint32_t)MACTxBuf; + DMATxDscrTab[0].Buffer2NextDescAddr = (uint32_t)&DMATxDscrTab[0]; - // 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); + ethernetif->DMARxDescToGet = &DMARxDscrTab[0]; + 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]); + } - printf("set PHY to 10Mbps Full-Duplex mode\n"); + ETH10M->ERXST = (uint32_t)ethernetif->DMARxDescToGet->Buffer1Addr; + ETH10M->ECON1 |= RB_ETH_ECON1_RXEN; + + printf("Resetting PHY...\n"); + WritePHYReg(PHY_BMCR, PHY_BMCR_RESET); + Delay_Ms(200); + + printf("Starting PHY, Mode: 10BASE_T_FD\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); - + ETH10M->EIE = RB_ETH_EIE_INTIE | RB_ETH_EIE_TXIE | RB_ETH_EIE_LINKIE; + ETH10M->EIR = 0xFF; NVIC_EnableIRQ(ETH_IRQn); - printf("low_level_init : done\n"); + 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; + if (DMATxDscrTab[0].Status & ETH_DMATxDesc_OWN) return ERR_BUF; + 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) { + 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; } - ethernetif->DMATxDescToSet->Status |= ETH_DMATxDesc_OWN; ETH10M->ETXLN = len; ETH10M->ETXST = (uint32_t)tx_buf_ptr; + DMATxDscrTab[0].Status |= ETH_DMATxDesc_OWN; ETH10M->ECON1 |= RB_ETH_ECON1_TXRTS; - ethernetif->DMATxDescToSet = - (ETH_DMADESCTypeDef*)ethernetif->DMATxDescToSet->Buffer2NextDescAddr; - MIB2_STATS_NETIF_ADD(netif, ifoutoctets, len); return ERR_OK; } -struct pbuf* low_level_input(struct netif* netif) { +static struct pbuf* low_level_input(struct netif* netif) { struct ethernetif* ethernetif = netif->state; - struct pbuf *p = NULL, *q; - u16_t len; - ETH_DMADESCTypeDef* dmarxdesc; + uint16_t len; + uint8_t* current_rx_buffer_ptr; - if (ETH10M->EIR & RB_ETH_EIR_RXIF) { - dmarxdesc = ethernetif->DMARxDescToGet; + if ((ETH10M->EIR & RB_ETH_EIR_RXIF) == 0) return NULL; - if (ETH10M->ESTAT & (RB_ETH_ESTAT_BUFER | RB_ETH_ESTAT_RXCRCER)) { - len = 0; - printf("HW RX Error ESTAT: 0x%02X\n", (unsigned int)ETH10M->ESTAT); - ETH10M->ESTAT |= (RB_ETH_ESTAT_BUFER | RB_ETH_ESTAT_RXCRCER); - } else { - len = ETH10M->ERXLN; - } + len = ETH10M->ERXLN; + current_rx_buffer_ptr = (uint8_t*)ethernetif->DMARxDescToGet->Buffer1Addr; - if (len > 0) { - p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); - if (p != NULL) { - uint8_t* rx_buffer = (uint8_t*)dmarxdesc->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; - } - printf( - "\n>>> Packet Received (len=%d, MAC len=%d). Copied to LwIP. " - "<<<\n\n", - len, ETH10M->ERXLN); - } else { - printf("pbuf_alloc failed. Dropping packet.\n"); + ethernetif->DMARxDescToGet = + (ETH_DMADESCTypeDef*)ethernetif->DMARxDescToGet->Buffer2NextDescAddr; + ETH10M->ERXST = (uint32_t)ethernetif->DMARxDescToGet->Buffer1Addr; + ETH10M->ECON1 |= RB_ETH_ECON1_RXEN; + + struct pbuf* p = NULL; + if (len > 0) { + p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); + if (p != NULL) { + uint32_t bytes_copied = 0; + for (struct pbuf* q = p; q != NULL; q = q->next) { + memcpy(q->payload, current_rx_buffer_ptr + bytes_copied, q->len); + bytes_copied += q->len; } + MIB2_STATS_NETIF_ADD(netif, ifinoctets, len); + } else { + MIB2_STATS_NETIF_INC(netif, ifindiscards); } - - dmarxdesc->Status = ETH_DMARxDesc_OWN; - ethernetif->DMARxDescToGet = - (ETH_DMADESCTypeDef*)dmarxdesc->Buffer2NextDescAddr; - - ETH10M->ERXST = (uint32_t)ethernetif->DMARxDescToGet->Buffer1Addr; - ETH10M->EIR = RB_ETH_EIR_RXIF; - - return p; // return pbuf to LwIP } - return NULL; // No packet was available. + ETH10M->EIR = RB_ETH_EIR_RXIF; + return p; } void ethernetif_input(struct netif* netif) { struct pbuf* p; - - p = low_level_input(netif); - - if (p != NULL) { + while ((p = low_level_input(netif)) != 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) { - struct ethernetif* ethernetif = netif->state; - static uint32_t last_poll_time = 0; - uint32_t now = millis(); - - // every 500ms - if (now - last_poll_time < 500) { + if (!g_link_interrupt_flag) { return; } - last_poll_time = now; + g_link_interrupt_flag = false; uint16_t bmsr = ReadPHYReg(PHY_BMSR); - if (bmsr & PHY_Linked_Status) { + if (bmsr & PHY_BMSR_LINK_STATUS) { if (!netif_is_link_up(netif)) { - printf("Link is UP (10M-FD Mode)\n"); - - ETH10M->ERXST = (uint32_t)ethernetif->DMARxDescToGet->Buffer1Addr; - ETH10M->ECON1 |= RB_ETH_ECON1_RXEN; - + printf("Link is UP\n"); + ETH10M->MACON2 |= RB_ETH_MACON2_FULDPX; 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 ETH_IRQHandler(void) __attribute__((interrupt)); +void ETH_IRQHandler(void) { + uint32_t flags = ETH10M->EIR; + + if (flags & RB_ETH_EIR_TXIF) { + DMATxDscrTab[0].Status &= ~ETH_DMATxDesc_OWN; + ETH10M->EIR = RB_ETH_EIR_TXIF; + } + + 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_MIRDL) | (1 << 8) | (reg_val << 16); } @@ -348,4 +252,4 @@ void WritePHYReg(uint8_t reg_add, uint16_t reg_val) { uint16_t ReadPHYReg(uint8_t reg_add) { ETH10M->MIERGADR = reg_add; return ETH10M->MIRD; -} \ No newline at end of file +} diff --git a/port/ethernetif.h b/port/ethernetif.h index 3953010..9a50f1f 100644 --- a/port/ethernetif.h +++ b/port/ethernetif.h @@ -8,12 +8,19 @@ 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 ROM_CFG_USERADR_ID 0x1FFFF7E8 -#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_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_PHYSR 0x10 // PHY Status Register + +// Bits for CH32V20x PHYSR +#define PHY_PHYSR_FULL_10M (1 << 2) #define PHY_BMCR_RESET ((uint16_t)0x8000) // Reset PHY #define PHY_BMCR_AN_ENABLE \ @@ -21,109 +28,175 @@ uint16_t ReadPHYReg(uint8_t reg_add); #define PHY_BMCR_AN_RESTART \ ((uint16_t)0x0200) // Restart Auto-Negotiation (Bit 9) +#define PHY_BMSR_LINK_STATUS (1 << 2) +#define PHY_BMSR_AN_COMPLETE (1 << 5) + +#define PHY_MDIX_PN_MASK (3 << 2) // Mask for bits [3:2] -> 0x0C +#define PHY_MDIX_PN_REVERSED \ + (1 << 2) // Value for reversed polarity (01b) -> 0x04 + /** DMA Tx Desciptor ----------------------------------------------------------------------------------------------- - TDES0 | OWN(31) | CTRL[30:26] | Reserved[25:24] | CTRL[23:20] | Reserved[19:17] | Status[16:0] | + 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] | + TDES1 | Reserved[31:29] | Buffer2 ByteCount[28:16] | Reserved[15:13] | Buffer1 + ByteCount[12:0] | ----------------------------------------------------------------------------------------------- - TDES2 | Buffer1 Address [31:0] | + TDES2 | Buffer1 Address [31:0] | ----------------------------------------------------------------------------------------------- - TDES3 | Buffer2 Address [31:0] / Next Desciptor 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 */ +/* 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 */ +#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 */ +#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 */ +#define ETH_DMATxDesc_B2AP ((uint32_t)0xFFFFFFFF) /* Buffer2 Address Pointer \ + */ /** DMA Rx Desciptor --------------------------------------------------------------------------------------------------------------------- - RDES0 | OWN(31) | Status [30:0] | + 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] | + RDES1 | CTRL(31) | Reserved[30:29] | Buffer2 ByteCount[28:16] | CTRL[15:14] | + Reserved(13) | Buffer1 ByteCount[12:0] | --------------------------------------------------------------------------------------------------------------------- - RDES2 | Buffer1 Address [31:0] | + RDES2 | Buffer1 Address [31:0] | --------------------------------------------------------------------------------------------------------------------- - RDES3 | Buffer2 Address [31:0] / Next Desciptor 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 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 */ +#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 */ +#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_B2AP ((uint32_t)0xFFFFFFFF) /* Buffer2 Address Pointer \ + */ -#define ETH_DMARxDesc_FrameLengthShift 16 +#define ETH_DMARxDesc_FrameLengthShift 16 typedef struct { uint32_t volatile Status; /* Status */ diff --git a/port/lwipopts.h b/port/lwipopts.h index 5551785..25e3421 100644 --- a/port/lwipopts.h +++ b/port/lwipopts.h @@ -4,11 +4,11 @@ #define LWIP_DEBUG 1 #define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL -#define UDP_DEBUG LWIP_DBG_ON -#define IP_DEBUG LWIP_DBG_ON +// #define UDP_DEBUG LWIP_DBG_ON +// #define IP_DEBUG LWIP_DBG_ON #define DHCP_DEBUG LWIP_DBG_ON #define NETIF_DEBUG LWIP_DBG_ON -#define ETHARP_DEBUG LWIP_DBG_ON +// #define ETHARP_DEBUG LWIP_DBG_ON #define NO_SYS 1 @@ -52,6 +52,6 @@ // Statistics #define LWIP_STATS 0 -#define LWIP_NETIF_LINK_CALLBACK 1 +// #define LWIP_NETIF_LINK_CALLBACK 1 #endif /* __LWIPOPTS_H__ */