#include "ethernetif.h" #include #include #include #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_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 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); 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) { struct ethernetif* 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-ch32"; #endif netif->state = ethernetif; 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; 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; // clocks RCC->APB2PCENR |= RCC_APB2Periph_AFIO; RCC->CFGR0 = (RCC->CFGR0 & ~((uint32_t)1 << 28)) | (RCC_ETHCLK_Div2 << 28); EXTEN->EXTEN_CTR |= EXTEN_ETH_10M_EN; // 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 = 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 = (ETH10M->ECON2 & ~(0x07 << 1)) | (5 << 1); // DMA descriptors ethernetif->DMATxDescToSet = &DMATxDscrTab[0]; DMATxDscrTab[0].Status = 0; DMATxDscrTab[0].Buffer1Addr = (uint32_t)MACTxBuf; DMATxDscrTab[0].Buffer2NextDescAddr = (uint32_t)&DMATxDscrTab[0]; 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]); } 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); 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"); } static err_t low_level_output(struct netif* netif, struct pbuf* p) { if (DMATxDscrTab[0].Status & ETH_DMATxDesc_OWN) 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; 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; uint8_t* current_rx_buffer_ptr; if ((ETH10M->EIR & RB_ETH_EIR_RXIF) == 0) return NULL; len = ETH10M->ERXLN; current_rx_buffer_ptr = (uint8_t*)ethernetif->DMARxDescToGet->Buffer1Addr; 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); } } ETH10M->EIR = RB_ETH_EIR_RXIF; return p; } void ethernetif_input(struct netif* netif) { struct pbuf* p; while ((p = low_level_input(netif)) != 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; uint16_t bmsr = ReadPHYReg(PHY_BMSR); if (bmsr & PHY_BMSR_LINK_STATUS) { if (!netif_is_link_up(netif)) { printf("Link is UP\n"); ETH10M->MACON2 |= RB_ETH_MACON2_FULDPX; netif_set_link_up(netif); } } else { if (netif_is_link_up(netif)) { printf("Link is DOWN\n"); netif_set_link_down(netif); } } } 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); } uint16_t ReadPHYReg(uint8_t reg_add) { ETH10M->MIERGADR = reg_add; return ETH10M->MIRD; }