/* * Copyright (c) 2006-2024, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2021-09-09 WCH the first version */ #include "board.h" #include #ifdef BSP_USING_ETH #include #include "lwipopts.h" #include #define LOG_TAG "drv.eth" #include #define MAX_ADDR_LEN 6 #define ETH_DMARxDesc_FrameLengthShift 16 #define define_O(a,b) \ GPIO_InitStructure.GPIO_Pin = b;\ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;\ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;\ GPIO_Init(a, &GPIO_InitStructure) #define define_I(a,b) \ GPIO_InitStructure.GPIO_Pin = b;\ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;\ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;\ GPIO_Init(a, &GPIO_InitStructure) /* globe variable */ extern ETH_DMADESCTypeDef *DMATxDescToSet; //set tx Desc then send it extern ETH_DMADESCTypeDef *DMARxDescToGet; //current rx Desc /* rt-thread eth */ struct rt_ch32_eth { /* inherit from ethernet device */ struct eth_device parent; #ifndef PHY_USING_INTERRUPT_MODE rt_timer_t poll_link_timer; #endif /* interface address info, hw address */ rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* ETH_Speed */ uint32_t ETH_Speed; /* ETH_Duplex_Mode */ uint32_t ETH_Mode; }; static ETH_DMADESCTypeDef DMARxDscrTab[ETH_RXBUFNB], DMATxDscrTab[ETH_TXBUFNB]; static rt_uint8_t Rx_Buff[ETH_RXBUFNB][ETH_MAX_PACKET_SIZE],Tx_Buff[ETH_TXBUFNB][ETH_MAX_PACKET_SIZE]; struct rt_ch32_eth ch32v30x_eth_device; //#define ETH_RX_DUMP #if defined(ETH_RX_DUMP) || defined(ETH_TX_DUMP) #define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ') static void dump_hex(const rt_uint8_t *ptr, rt_size_t buflen) { unsigned char *buf = (unsigned char *)ptr; int i, j; for (i = 0; i < buflen; i += 16) { rt_kprintf("%08X: ", i); for (j = 0; j < 16; j++) if (i + j < buflen) rt_kprintf("%02X ", buf[i + j]); else rt_kprintf(" "); rt_kprintf(" "); for (j = 0; j < 16; j++) if (i + j < buflen) rt_kprintf("%c", __is_print(buf[i + j]) ? buf[i + j] : '.'); rt_kprintf("\r\n"); } } #endif /* received data */ FrameTypeDef ETH_RxPkt_ChainMode(void) { u32 framelength = 0; FrameTypeDef frame = {0,0,NULL}; /* Check if the descriptor is owned by the ETHERNET DMA (when set) or CPU (when reset) */ if((DMARxDescToGet->Status & ETH_DMARxDesc_OWN) != (u32)RESET) { frame.length = ETH_ERROR; if ((ETH->DMASR & ETH_DMASR_RBUS) != (u32)RESET) { /* Clear RBUS ETHERNET DMA flag */ ETH->DMASR = ETH_DMASR_RBUS; /* Resume DMA reception */ ETH->DMARPDR = 0; } LOG_E("Error:ETH_DMARxDesc_OWN.\r\n"); /* Return error: OWN bit set */ return frame; } if( ((DMARxDescToGet->Status & ETH_DMARxDesc_ES) == (u32)RESET) && ((DMARxDescToGet->Status & ETH_DMARxDesc_LS) != (u32)RESET) && ((DMARxDescToGet->Status & ETH_DMARxDesc_FS) != (u32)RESET)) { /* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */ framelength = ((DMARxDescToGet->Status & ETH_DMARxDesc_FL) >> ETH_DMARxDesc_FrameLengthShift) - 4; /* Get the addrees of the actual buffer */ frame.buffer = DMARxDescToGet->Buffer1Addr; } else { /* Return ERROR */ framelength = ETH_ERROR; rt_kprintf("Error:recv error frame,status:0x%08x.\r\n",DMARxDescToGet->Status); } DMARxDescToGet->Status|=ETH_DMARxDesc_OWN; frame.length = framelength; frame.descriptor = DMARxDescToGet; /* Update the ETHERNET DMA global Rx descriptor with next Rx decriptor */ /* Chained Mode */ /* Selects the next DMA Rx descriptor list for next buffer to read */ DMARxDescToGet = (ETH_DMADESCTypeDef*) (DMARxDescToGet->Buffer2NextDescAddr); /* Return Frame */ return (frame); } /******************************************************************************* * Function Name : GETH_pin_init * Description : PHY RGMII interface GPIO initialization. * Input : None. * Return : None. *******************************************************************************/ void GETH_pin_init(void) { GPIO_InitTypeDef GPIO_InitStructure; /* PB12/13 set AF_PP_OUT */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC, ENABLE); GPIOB->CFGHR&=~(0xff<<16); GPIOB->CFGHR|= (0xbb<<16); GPIOB->CFGLR&=~(0xff<<4); define_O(GPIOA,GPIO_Pin_2); define_O(GPIOA,GPIO_Pin_3); define_O(GPIOA,GPIO_Pin_7); define_O(GPIOC,GPIO_Pin_4); define_O(GPIOC,GPIO_Pin_5); define_O(GPIOB,GPIO_Pin_0); define_I(GPIOC,GPIO_Pin_0); define_I(GPIOC,GPIO_Pin_1); define_I(GPIOC,GPIO_Pin_2); define_I(GPIOC,GPIO_Pin_3); define_I(GPIOA,GPIO_Pin_0); define_I(GPIOA,GPIO_Pin_1); define_I(GPIOB,GPIO_Pin_1);/* 125m in */ } /******************************************************************************* * Function Name : GETH_pin_init * Description : PHY MII/RMII interface GPIO initialization. * Input : None. * Return : None. *******************************************************************************/ void FETH_pin_init(void) { GPIO_InitTypeDef GPIO_InitStructure; #ifdef USE_RMII RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO, ENABLE); GPIO_ETH_MediaInterfaceConfig(GPIO_ETH_MediaInterface_RMII); define_O(GPIOA,GPIO_Pin_2);/* MDC */ define_O(GPIOC,GPIO_Pin_1);/* MDIO */ define_O(GPIOB,GPIO_Pin_11);//txen define_O(GPIOB,GPIO_Pin_12);//txd0 define_O(GPIOB,GPIO_Pin_13);//txd1 define_I(GPIOA,GPIO_Pin_1);/* PA1 REFCLK */ define_I(GPIOA,GPIO_Pin_7);/* PA7 CRSDV */ define_I(GPIOC,GPIO_Pin_4);/* RXD0 */ define_I(GPIOC,GPIO_Pin_5);/* RXD1 */ #else RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC, ENABLE); /* tx */ define_O(GPIOA,GPIO_Pin_2);/* MDC */ define_O(GPIOC,GPIO_Pin_1);/* MDIO */ define_I(GPIOC,GPIO_Pin_3);//txclk define_O(GPIOB,GPIO_Pin_11);//txen define_O(GPIOB,GPIO_Pin_12);//txd0 define_O(GPIOB,GPIO_Pin_13);//txd1 define_O(GPIOC,GPIO_Pin_2); //txd2 define_O(GPIOB,GPIO_Pin_8);//txd3 /* tx */ define_I(GPIOA,GPIO_Pin_1);/* PA1 RXC */ define_I(GPIOA,GPIO_Pin_7);/* PA7 RXDV */ define_I(GPIOC,GPIO_Pin_4);/* RXD0 */ define_I(GPIOC,GPIO_Pin_5);/* RXD1 */ define_I(GPIOB,GPIO_Pin_0);/* RXD2 */ define_I(GPIOB,GPIO_Pin_1);/* RXD3 */ define_I(GPIOB,GPIO_Pin_10);/* RXER */ define_O(GPIOA,GPIO_Pin_0);/* PA0 */ define_O(GPIOA,GPIO_Pin_3);/* PA3 */ #endif } /******************************************************************************* * Function Name : ETH_Init * Description : ETH initialization. * Input : ETH_InitStruct:initialization struct. * PHYAddress:PHY address. * Return : Initialization status. *******************************************************************************/ uint32_t ETH_Init(ETH_InitTypeDef* ETH_InitStruct, uint16_t PHYAddress) { uint32_t tmpreg = 0; uint16_t RegValue = 0; uint32_t tickstart=0; /* config phy */ tmpreg = ETH->MACMIIAR; tmpreg &= MACMIIAR_CR_MASK; /* set SMI clock */ tmpreg |= (uint32_t)ETH_MACMIIAR_CR_Div42; ETH->MACMIIAR = (uint32_t)tmpreg; /* reset phy */ ETH_WritePHYRegister(PHYAddress, PHY_BCR, PHY_Reset); tickstart= rt_tick_get_millisecond(); do{ asm("nop"); /* waiting for finish */ }while((rt_tick_get_millisecond()-tickstart)<1000); tickstart= rt_tick_get_millisecond(); RegValue = 0; while( (RegValue&(PHY_Reset)) ) { RegValue = ETH_ReadPHYRegister(PHYAddress, PHY_BCR); if((rt_tick_get_millisecond()-tickstart)>10000) { LOG_E("Error:Wait phy reset timeout!\r\n"); while(1); } } /* waiting for link up */ tickstart= rt_tick_get_millisecond(); RegValue = 0; while((RegValue&(PHY_Linked_Status)) == 0) { RegValue = ETH_ReadPHYRegister(PHYAddress, PHY_BSR); if((rt_tick_get_millisecond()-tickstart)>10000) { LOG_E("Error:Wait phy linking timeout!\r\n"); while(1); } } /* waiting for auto-negotiation */ tickstart= rt_tick_get_millisecond(); RegValue = 0; while((RegValue&PHY_AutoNego_Complete) == 0) { RegValue = ETH_ReadPHYRegister(PHYAddress, PHY_BSR); if((rt_tick_get_millisecond()-tickstart)>10000) { LOG_E("Error:Wait phy auto-negotiation complete timeout!\r\n"); while(1); } } #ifdef USE10BASE_T RegValue = ETH_ReadPHYRegister(PHYAddress, PHY_BMCR); LOG_D("PHY_BMCR:%d,value:%04x.\n",PHY_BMCR,RegValue); if((RegValue & (1<<8)) != (uint32_t)RESET) { ETH_InitStruct->ETH_Mode = ETH_Mode_FullDuplex; ch32v30x_eth_device.ETH_Mode=ETH_Mode_FullDuplex; LOG_D("Full-Duplex.\n"); } else { ETH_InitStruct->ETH_Mode = ETH_Mode_HalfDuplex; ch32v30x_eth_device.ETH_Mode=ETH_Mode_HalfDuplex; LOG_D("Half-Duplex.\n"); } if(RegValue & (1<<13)) { ETH_InitStruct->ETH_Speed = ETH_Speed_100M; ch32v30x_eth_device.ETH_Speed=ETH_Speed_100M; /* send link up. */ eth_device_linkchange(&ch32v30x_eth_device.parent, RT_TRUE); LOG_D("Link speed:100M.\n"); } else { ETH_InitStruct->ETH_Speed = ETH_Speed_10M; ch32v30x_eth_device.ETH_Speed=ETH_Speed_10M; /* send link up. */ eth_device_linkchange(&ch32v30x_eth_device.parent, RT_TRUE); LOG_D("Link speed:10M.\n"); } #endif #ifdef USE_FAST_MAC /* 100M MAC,RMII */ RegValue = ETH_ReadPHYRegister(PHYAddress, PHY_BMCR); LOG_D("PHY_BMCR:%d,value:%04x.\n",PHY_BMCR,RegValue); if((RegValue & (1<<8)) != (uint32_t)RESET) { ETH_InitStruct->ETH_Mode = ETH_Mode_FullDuplex; ch32v30x_eth_device.ETH_Mode = ETH_Mode_FullDuplex; LOG_D("Full-Duplex.\n"); } else { ETH_InitStruct->ETH_Mode = ETH_Mode_HalfDuplex; ch32v30x_eth_device.ETH_Mode = ETH_Mode_HalfDuplex; LOG_D("Half-Duplex.\n"); } if(RegValue & (1<<13)) { ETH_InitStruct->ETH_Speed = ETH_Speed_100M; ch32v30x_eth_device.ETH_Speed=ETH_Speed_100M; /* send link up. */ eth_device_linkchange(&ch32v30x_eth_device.parent, RT_TRUE); LOG_D("Link speed:100M.\n"); } else { ETH_InitStruct->ETH_Speed = ETH_Speed_10M; ch32v30x_eth_device.ETH_Speed=ETH_Speed_10M; /* send link up. */ eth_device_linkchange(&ch32v30x_eth_device.parent, RT_TRUE); LOG_D("Link speed:10M.\n"); } #endif #ifdef USE_GIGA_MAC /* GMAC,RGMI */ ETH_WritePHYRegister(PHYAddress, 31,0x0a43 ); RegValue = ETH_ReadPHYRegister(PHYAddress, 26); if( RegValue & 0x0008 ) { ETH_InitStruct->ETH_Mode = ETH_Mode_FullDuplex; ch32v30x_eth_device.ETH_Mode = ETH_Mode_FullDuplex; LOG_D("full duplex.\n"); } else { ETH_InitStruct->ETH_Mode = ETH_Mode_HalfDuplex; ch32v30x_eth_device.ETH_Mode = ETH_Mode_HalfDuplex; LOG_D("half duplex!\n"); } if(( RegValue & 0x0030 ) == 0x0000) { ETH_InitStruct->ETH_Speed = ETH_Speed_10M; ch32v30x_eth_device.ETH_Speed= ETH_Speed_10M; eth_device_linkchange(&ch32v30x_eth_device.parent, RT_TRUE); LOG_D("Link speed:10Mbps.\n"); } else if(( RegValue & 0x0030 ) == 0x0010) { ETH_InitStruct->ETH_Speed = ETH_Speed_100M; ch32v30x_eth_device.ETH_Speed= ETH_Speed_100M; eth_device_linkchange(&ch32v30x_eth_device.parent, RT_TRUE); LOG_D("Link speed:100Mbps.\n"); } else if(( RegValue & 0x0030 ) == 0x0020) { ETH_InitStruct->ETH_Speed = ETH_Speed_1000M; ch32v30x_eth_device.ETH_Speed= ETH_Speed_1000M; eth_device_linkchange(&ch32v30x_eth_device.parent, RT_TRUE); LOG_D("Link speed:1000Mbps.\n"); } #endif tickstart= rt_tick_get_millisecond(); do{ asm("nop"); }while((rt_tick_get_millisecond()-tickstart)<1000); /* MAC config */ /* if use RGMII,should config RGMII clock delay register */ tmpreg = ETH->MACCR; tmpreg &= MACCR_CLEAR_MASK; tmpreg |= (uint32_t)(ETH_InitStruct->ETH_Watchdog | ETH_InitStruct->ETH_Jabber | ETH_InitStruct->ETH_InterFrameGap | ETH_InitStruct->ETH_CarrierSense | ETH_InitStruct->ETH_Speed | ETH_InitStruct->ETH_ReceiveOwn | ETH_InitStruct->ETH_LoopbackMode | ETH_InitStruct->ETH_Mode | ETH_InitStruct->ETH_ChecksumOffload | ETH_InitStruct->ETH_RetryTransmission | ETH_InitStruct->ETH_AutomaticPadCRCStrip | ETH_InitStruct->ETH_BackOffLimit | ETH_InitStruct->ETH_DeferralCheck); ETH->MACCR = (uint32_t)tmpreg; #ifdef USE10BASE_T /* enable internal pull up resistance,50Ω */ ETH->MACCR|=ETH_Internal_Pull_Up_Res_Enable; #endif ETH->MACFFR = (uint32_t)(ETH_InitStruct->ETH_ReceiveAll | ETH_InitStruct->ETH_SourceAddrFilter | ETH_InitStruct->ETH_PassControlFrames | ETH_InitStruct->ETH_BroadcastFramesReception | ETH_InitStruct->ETH_DestinationAddrFilter | ETH_InitStruct->ETH_PromiscuousMode | ETH_InitStruct->ETH_MulticastFramesFilter | ETH_InitStruct->ETH_UnicastFramesFilter); /* Write to ETHERNET MACHTHR */ ETH->MACHTHR = (uint32_t)ETH_InitStruct->ETH_HashTableHigh; /* Write to ETHERNET MACHTLR */ ETH->MACHTLR = (uint32_t)ETH_InitStruct->ETH_HashTableLow; /* Get the ETHERNET MACFCR value */ tmpreg = ETH->MACFCR; /* Clear xx bits */ tmpreg &= MACFCR_CLEAR_MASK; tmpreg |= (uint32_t)((ETH_InitStruct->ETH_PauseTime << 16) | ETH_InitStruct->ETH_ZeroQuantaPause | ETH_InitStruct->ETH_PauseLowThreshold | ETH_InitStruct->ETH_UnicastPauseFrameDetect | ETH_InitStruct->ETH_ReceiveFlowControl | ETH_InitStruct->ETH_TransmitFlowControl); ETH->MACFCR = (uint32_t)tmpreg; ETH->MACVLANTR = (uint32_t)(ETH_InitStruct->ETH_VLANTagComparison | ETH_InitStruct->ETH_VLANTagIdentifier); tmpreg = ETH->DMAOMR; /* Clear xx bits */ tmpreg &= DMAOMR_CLEAR_MASK; tmpreg |= (uint32_t)(ETH_InitStruct->ETH_DropTCPIPChecksumErrorFrame | ETH_InitStruct->ETH_ReceiveStoreForward | ETH_InitStruct->ETH_FlushReceivedFrame | ETH_InitStruct->ETH_TransmitStoreForward | ETH_InitStruct->ETH_TransmitThresholdControl | ETH_InitStruct->ETH_ForwardErrorFrames | ETH_InitStruct->ETH_ForwardUndersizedGoodFrames | ETH_InitStruct->ETH_ReceiveThresholdControl | ETH_InitStruct->ETH_SecondFrameOperate); ETH->DMAOMR = (uint32_t)tmpreg; ETH->DMABMR = (uint32_t)(ETH_InitStruct->ETH_AddressAlignedBeats | ETH_InitStruct->ETH_FixedBurst | ETH_InitStruct->ETH_RxDMABurstLength | /* !! if 4xPBL is selected for Tx or Rx it is applied for the other */ ETH_InitStruct->ETH_TxDMABurstLength | (ETH_InitStruct->ETH_DescriptorSkipLength << 2) | ETH_InitStruct->ETH_DMAArbitration | ETH_DMABMR_USP); return ETH_SUCCESS; } /* eth initialization function */ static rt_err_t rt_ch32_eth_init(rt_device_t dev) { ETH_InitTypeDef ETH_InitStructure={0}; RCC_PLL3Cmd(DISABLE); RCC_PREDIV2Config(RCC_PREDIV2_Div2); RCC_PLL3Config(RCC_PLL3Mul_15); RCC_PLL3Cmd(ENABLE); while(RESET == RCC_GetFlagStatus(RCC_FLAG_PLL3RDY)); LOG_D("PLL3 Init Finish\r\n"); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ETH_MAC|RCC_AHBPeriph_ETH_MAC_Tx|RCC_AHBPeriph_ETH_MAC_Rx,ENABLE); #ifdef USE10BASE_T /* Enable internal 10BASE-T PHY*/ EXTEN->EXTEN_CTR |=EXTEN_ETH_10M_EN; #endif #ifdef USE_GIGA_MAC /* Enable 1G MAC*/ EXTEN->EXTEN_CTR |= EXTEN_ETH_RGMII_SEL; /* mac clock use external 125MHz,input from PB1 */ RCC_ETH1GCLKConfig(RCC_ETH1GCLKSource_PB1_IN); RCC_ETH1G_125Mcmd(ENABLE); /* Enable RGMII GPIO */ GETH_pin_init(); #endif #ifdef USE_FAST_MAC /* Enable MII or RMII GPIO */ FETH_pin_init(); #endif /* Reset ETHERNET on AHB Bus */ ETH_DeInit(); /* Software reset */ ETH_SoftwareReset(); /* Wait for software reset */ while(ETH->DMABMR & ETH_DMABMR_SR); LOG_D("ETH RST Finish\r\n"); ETH_StructInit(Ð_InitStructure); ETH_InitStructure.ETH_Mode = ETH_Mode_FullDuplex; ETH_InitStructure.ETH_Speed = ETH_Speed_1000M; ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Enable ; ETH_InitStructure.ETH_LoopbackMode = ETH_LoopbackMode_Disable; ETH_InitStructure.ETH_RetryTransmission = ETH_RetryTransmission_Disable; ETH_InitStructure.ETH_AutomaticPadCRCStrip = ETH_AutomaticPadCRCStrip_Disable; ETH_InitStructure.ETH_ReceiveAll = ETH_ReceiveAll_Enable; ETH_InitStructure.ETH_BroadcastFramesReception = ETH_BroadcastFramesReception_Enable; ETH_InitStructure.ETH_PromiscuousMode = ETH_PromiscuousMode_Enable; ETH_InitStructure.ETH_MulticastFramesFilter = ETH_MulticastFramesFilter_Perfect; ETH_InitStructure.ETH_UnicastFramesFilter = ETH_UnicastFramesFilter_Perfect; #ifdef CHECKSUM_BY_HARDWARE ETH_InitStructure.ETH_ChecksumOffload = ETH_ChecksumOffload_Enable; #endif /*------------------------ DMA -----------------------------------*/ /* When we use the Checksum offload feature, we need to enable the Store and Forward mode: the store and forward guarantee that a whole frame is stored in the FIFO, so the MAC can insert/verify the checksum, if the checksum is OK the DMA can handle the frame otherwise the frame is dropped */ ETH_InitStructure.ETH_DropTCPIPChecksumErrorFrame = ETH_DropTCPIPChecksumErrorFrame_Enable; ETH_InitStructure.ETH_ReceiveStoreForward = ETH_ReceiveStoreForward_Enable; ETH_InitStructure.ETH_TransmitStoreForward = ETH_TransmitStoreForward_Enable; ETH_InitStructure.ETH_ForwardErrorFrames = ETH_ForwardErrorFrames_Enable; ETH_InitStructure.ETH_ForwardUndersizedGoodFrames = ETH_ForwardUndersizedGoodFrames_Enable; ETH_InitStructure.ETH_SecondFrameOperate = ETH_SecondFrameOperate_Disable; ETH_InitStructure.ETH_AddressAlignedBeats = ETH_AddressAlignedBeats_Enable; ETH_InitStructure.ETH_FixedBurst = ETH_FixedBurst_Enable; ETH_InitStructure.ETH_RxDMABurstLength = ETH_RxDMABurstLength_32Beat; ETH_InitStructure.ETH_TxDMABurstLength = ETH_TxDMABurstLength_32Beat; ETH_InitStructure.ETH_DMAArbitration = ETH_DMAArbitration_RoundRobin_RxTx_2_1; /* Configure Ethernet */ ETH_Init(Ð_InitStructure, PHY_ADDRESS); /* Enable the Ethernet Rx Interrupt */ ETH_DMAITConfig(ETH_DMA_IT_NIS | ETH_DMA_IT_R | ETH_DMA_IT_T ,ENABLE); NVIC_SetPriority(ETH_IRQn,1<<4); NVIC_EnableIRQ(ETH_IRQn); ETH_DMATxDescChainInit(DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB); ETH_DMARxDescChainInit(DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB); #ifdef USE_GIGA_MAC RGMII_TXC_Delay(0,2); #endif ETH_Start(); return RT_EOK; } static rt_err_t rt_ch32_eth_open(rt_device_t dev, rt_uint16_t oflag) { LOG_D("eth open\r\n"); return RT_EOK; } static rt_err_t rt_ch32_eth_close(rt_device_t dev) { LOG_D("eth close\r\n"); return RT_EOK; } static rt_ssize_t rt_ch32_eth_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) { LOG_D("eth read\r\n"); rt_set_errno(-RT_ENOSYS); return 0; } static rt_ssize_t rt_ch32_eth_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) { LOG_D("eth write\r\n"); rt_set_errno(-RT_ENOSYS); return 0; } static rt_err_t rt_ch32_eth_control(rt_device_t dev, int cmd, void *args) { switch (cmd) { case NIOCTL_GADDR: /* get mac address */ if (args) rt_memcpy(args, ch32v30x_eth_device.dev_addr, 6); else return -RT_ERROR; break; default : break; } return RT_EOK; } rt_err_t rt_ch32_eth_tx(rt_device_t dev, struct pbuf *p) { rt_err_t ret = RT_ERROR; struct pbuf *q; uint8_t *buffer = (uint8_t *)(DMATxDescToSet->Buffer1Addr); uint8_t *pdata; uint32_t framelength = 0,len=0; /* copy frame from pbufs to driver buffers */ for (q = p; q != NULL; q = q->next) { /* Is this buffer available? If not, goto error */ if ((DMATxDescToSet->Status & ETH_DMATxDesc_OWN) != (uint32_t)RESET) { LOG_E("buffer not valid\r\n"); ret = ERR_USE; goto Tx_error; } pdata = q->payload; len = q->len; framelength += len; rt_memcpy(buffer,pdata,len); buffer += len; } #ifdef ETH_TX_DUMP dump_hex(buffer, p->tot_len); #endif DMATxDescToSet->ControlBufferSize = (framelength & ETH_DMATxDesc_TBS1); DMATxDescToSet->Status |= ETH_DMATxDesc_LS | ETH_DMATxDesc_FS; DMATxDescToSet->Status |= ETH_DMATxDesc_OWN; ret = ERR_OK; Tx_error: /* When Transmit Underflow flag is set, clear it and issue a Transmit Poll Demand to resume transmission */ if ((ETH->DMASR & ETH_DMASR_TBUS) != (uint32_t)RESET) { /* Clear TUS ETHERNET DMA flag */ ETH->DMASR = ETH_DMASR_TUS; /* Resume DMA transmission*/ ETH->DMATPDR = 0; } DMATxDescToSet = (ETH_DMADESCTypeDef*) (DMATxDescToSet->Buffer2NextDescAddr); return ret; } volatile FrameTypeDef frame; struct pbuf *rt_ch32_eth_rx(rt_device_t dev) { struct pbuf *p = NULL; struct pbuf *q = NULL; uint16_t len = 0; uint8_t *buffer; uint8_t *pdata; if(!frame.length) { return NULL; } len=frame.length; frame.length=0; buffer=(uint8_t *)frame.buffer; if (len > 0) { /* We allocate a pbuf chain of pbufs from the Lwip buffer pool */ p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); } #ifdef ETH_RX_DUMP dump_hex(buffer, p->tot_len); #endif if (p != NULL) { for (q = p; q != NULL; q = q->next) { pdata = q->payload; rt_memcpy(pdata,buffer,q->len); pdata += (q->len); buffer += (q->len); } } else { LOG_E("p=null\r\n"); } return p; } /* interrupt service routine */ void ETH_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast"))); void ETH_IRQHandler(void) { GET_INT_SP(); /* enter interrupt */ rt_err_t result; rt_interrupt_enter(); if(ETH->DMASRÐ_DMA_IT_R) { ETH_DMAClearITPendingBit(ETH_DMA_IT_R); frame = ETH_RxPkt_ChainMode(); result = eth_device_ready(&(ch32v30x_eth_device.parent)); if (result != RT_EOK) rt_kprintf("RxCpltCallback err = %d\r\n", result); } if(ETH->DMASRÐ_DMA_IT_T) { ETH_DMAClearITPendingBit(ETH_DMA_IT_T); } ETH_DMAClearITPendingBit(ETH_DMA_IT_NIS); /* leave interrupt */ rt_interrupt_leave(); FREE_INT_SP(); } /* Register the EMAC device */ static int rt_hw_ch32_eth_init(void) { rt_err_t state = RT_EOK; /* 84-c2-e4 WCH. */ ch32v30x_eth_device.dev_addr[0] = 0x84; ch32v30x_eth_device.dev_addr[1] = 0xc2; ch32v30x_eth_device.dev_addr[2] = 0xe4; /* generate MAC (only for test). */ ch32v30x_eth_device.dev_addr[3] = 0x1; ch32v30x_eth_device.dev_addr[4] = 0x2; ch32v30x_eth_device.dev_addr[5] = 0x3; ch32v30x_eth_device.parent.parent.init = rt_ch32_eth_init; ch32v30x_eth_device.parent.parent.open = rt_ch32_eth_open; ch32v30x_eth_device.parent.parent.close = rt_ch32_eth_close; ch32v30x_eth_device.parent.parent.read = rt_ch32_eth_read; ch32v30x_eth_device.parent.parent.write = rt_ch32_eth_write; ch32v30x_eth_device.parent.parent.control = rt_ch32_eth_control; ch32v30x_eth_device.parent.parent.user_data = RT_NULL; ch32v30x_eth_device.parent.eth_rx = rt_ch32_eth_rx; ch32v30x_eth_device.parent.eth_tx = rt_ch32_eth_tx; /* register eth device */ state = eth_device_init(&(ch32v30x_eth_device.parent), "e0"); if (RT_EOK == state) { LOG_D("emac device init success"); } else { LOG_E("emac device init faild: %d\r\n", state); state = -RT_ERROR; } return state; } INIT_DEVICE_EXPORT(rt_hw_ch32_eth_init); #endif /* BSP_USING_ETH */