diff --git a/Ubiquitous/XiZi_IIoT/arch/risc-v/ch32v307vct6/User/ch32v30x_it.c b/Ubiquitous/XiZi_IIoT/arch/risc-v/ch32v307vct6/User/ch32v30x_it.c index dfdb9587f..d2f42f67b 100644 --- a/Ubiquitous/XiZi_IIoT/arch/risc-v/ch32v307vct6/User/ch32v30x_it.c +++ b/Ubiquitous/XiZi_IIoT/arch/risc-v/ch32v307vct6/User/ch32v30x_it.c @@ -1,16 +1,16 @@ /********************************** (C) COPYRIGHT ******************************* -* File Name : ch32v10x_it.c -* Author : WCH -* Version : V1.0.0 -* Date : 2020/04/30 -* Description : Main Interrupt Service Routines. -* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. -* SPDX-License-Identifier: Apache-2.0 -*******************************************************************************/ + * File Name : ch32v10x_it.c + * Author : WCH + * Version : V1.0.0 + * Date : 2020/04/30 + * Description : Main Interrupt Service Routines. + * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. + * SPDX-License-Identifier: Apache-2.0 + *******************************************************************************/ /************************************************* File name: ch32v30x_it.c -Description: include peripheral supports for ch32v30x -History: +Description: include peripheral supports for ch32v30x +History: 1. Date: 2022-08-09 Author: AIIT XUOS Lab Modification: @@ -18,12 +18,16 @@ Modification: *************************************************/ #include "ch32v30x_it.h" #include "board.h" +#include "ch32v30x_exti.h" +#include "ch32v30x_tim.h" +#include "eth_driver.h" #include - - -void NMI_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast"))); -void HardFault_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast"))); +void NMI_Handler(void) __attribute__((interrupt())); +void HardFault_Handler(void) __attribute__((interrupt())); +void ETH_IRQHandler(void) __attribute__((interrupt())); +void TIM2_IRQHandler(void) __attribute__((interrupt())); +void EXTI9_5_IRQHandler(void) __attribute__((interrupt())); /********************************************************************* * @fn NMI_Handler @@ -53,9 +57,51 @@ void HardFault_Handler(void) GET_INT_SP(); isrManager.done->incCounter(); KPrintf("HardFault_Handler.\n"); + + KPrintf("mepc :%08x\r\n", __get_MEPC()); + KPrintf("mcause:%08x\r\n", __get_MCAUSE()); + KPrintf("mtval :%08x\r\n", __get_MTVAL()); + while (1) + ; + isrManager.done->decCounter(); FREE_INT_SP(); } +/********************************************************************* + * @fn ETH_IRQHandler + * + * @brief This function handles ETH exception. + * + * @return none + */ +void ETH_IRQHandler(void) +{ + WCHNET_ETHIsr(); +} +/********************************************************************* + * @fn TIM2_IRQHandler + * + * @brief This function handles TIM2 exception. + * + * @return none + */ +void TIM2_IRQHandler(void) +{ + WCHNET_TimeIsr(WCHNETTIMERPERIOD); + TIM_ClearITPendingBit(TIM2, TIM_IT_Update); +} +/********************************************************************* + * @fn EXTI9_5_IRQHandler + * + * @brief This function handles GPIO exception. + * + * @return none + */ +void EXTI9_5_IRQHandler(void) +{ + ETH_PHYLink(); + EXTI_ClearITPendingBit(EXTI_Line7); /* Clear Flag */ +} \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/arch/risc-v/ch32v307vct6/tick.c b/Ubiquitous/XiZi_IIoT/arch/risc-v/ch32v307vct6/tick.c index 518f2f632..49c27966b 100644 --- a/Ubiquitous/XiZi_IIoT/arch/risc-v/ch32v307vct6/tick.c +++ b/Ubiquitous/XiZi_IIoT/arch/risc-v/ch32v307vct6/tick.c @@ -19,7 +19,7 @@ extern void KTaskOsAssignAfterIrq(void *); -void SysTick_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast"))); +void SysTick_Handler(void) __attribute__((interrupt())); void SysTick_Handler(void) { GET_INT_SP(); diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/board.c b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/board.c index 85ddfc11a..1f36ec74a 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/board.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/board.c @@ -9,48 +9,48 @@ * 2018-11-12 Ernest Chen modify copyright */ /* -* Copyright (c) 2020 AIIT XUOS Lab -* XiUOS is licensed under Mulan PSL v2. -* You can use this software according to the terms and conditions of the Mulan PSL v2. -* You may obtain a copy of Mulan PSL v2 at: -* http://license.coscl.org.cn/MulanPSL2 -* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, -* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, -* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. -* See the Mulan PSL v2 for more details. -*/ + * Copyright (c) 2020 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ /** -* @file board.c -* @brief support ch32v307 init configure and start-up -* @version 1.0 -* @author AIIT XUOS Lab -* @date 2022-08-08 -*/ -#include -#include -#include -#include -#include "connect_uart.h" -#include "xsconfig.h" + * @file board.c + * @brief support ch32v307 init configure and start-up + * @version 1.0 + * @author AIIT XUOS Lab + * @date 2022-08-08 + */ #include "ch32v30x.h" +#include "connect_ether.h" +#include "connect_uart.h" #include "core_riscv.h" - // #include +#include "xsconfig.h" +#include +#include +#include +#include - // core clock. +// core clock. extern uint32_t SystemCoreClock; static uint32_t _SysTick_Config(uint32_t ticks) { - NVIC_SetPriority(SysTicK_IRQn,0xf0); - NVIC_SetPriority(Software_IRQn,0xf0); + NVIC_SetPriority(SysTicK_IRQn, 0xf0); + NVIC_SetPriority(Software_IRQn, 0xf0); NVIC_EnableIRQ(SysTicK_IRQn); NVIC_EnableIRQ(Software_IRQn); - SysTick->CTLR=0; - SysTick->SR=0; - SysTick->CNT=0; - SysTick->CMP=ticks-1; - SysTick->CTLR=0xF; + SysTick->CTLR = 0; + SysTick->SR = 0; + SysTick->CNT = 0; + SysTick->CMP = ticks - 1; + SysTick->CTLR = 0xF; return 0; } @@ -67,12 +67,15 @@ void InitBoardHardware() InitHwUart(); InstallConsole("uart1", "uart1_drv", "uart1_dev1"); +#ifdef BSP_USING_ETH + InitHwEth(); +#endif + KPrintf("consle init completed.\n"); KPrintf("board initialization......\n"); // KPrintf("memory address range: [0x%08x - 0x%08x], size: %d\n", (x_ubase) MEMORY_START_ADDRESS, (x_ubase) MEMORY_END_ADDRESS, gd32vf103_SRAM_SIZE); /* initialize memory system */ - - KPrintf("board init done.\n"); - KPrintf("start okernel...\n"); -} + KPrintf("board init done.\n"); + KPrintf("start okernel...\n"); +} diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/config.mk b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/config.mk index 5e4eba29b..630327afc 100755 --- a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/config.mk +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/config.mk @@ -15,6 +15,8 @@ export CROSS_COMPILE ?=/opt/riscv-embedded-gcc/bin/riscv-none-embed- export DEFINES := -DHAVE_CCONFIG_H -DHAVE_SIGINFO +export LINK_WCH_NET := $(KERNEL_ROOT)/board/ch32v307vct6/third_party_driver/ethernet/libwchnet.a + export ARCH = risc-v export MCU = GH32V307 diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/Kconfig b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/Kconfig index ef7bb1505..64a20aaa9 100755 --- a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/Kconfig +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/Kconfig @@ -14,5 +14,9 @@ menuconfig BSP_USING_GPIO if BSP_USING_GPIO source "$BSP_DIR/third_party_driver/gpio/Kconfig" endif + +menuconfig BSP_USING_ETH + bool "Using Ethernet" + default y \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/Makefile b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/Makefile index bb2d5c7b2..7167d1e93 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/Makefile +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/Makefile @@ -9,4 +9,8 @@ ifeq ($(CONFIG_BSP_USING_GPIO),y) SRC_DIR += gpio endif +ifeq ($(CONFIG_BSP_USING_ETH),y) + SRC_DIR += ethernet +endif + include $(KERNEL_ROOT)/compiler.mk \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/Peripheral/inc/ch32v30x_eth.h b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/Peripheral/inc/ch32v30x_eth.h index 62ae39348..2f1621797 100755 --- a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/Peripheral/inc/ch32v30x_eth.h +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/Peripheral/inc/ch32v30x_eth.h @@ -319,6 +319,9 @@ typedef struct /* PHY basic register */ #define PHY_BCR 0x0 /*PHY transceiver Basic Control Register */ #define PHY_BSR 0x01 /*PHY transceiver Basic Status Register */ +#define PHY_ANAR 0x04 /* Auto-Negotiation Advertisement Register */ +#define PHY_ANLPAR 0x05 /* Auto-Negotiation Link Partner Base Page Ability Register*/ +#define PHY_ANER 0x06 /* Auto-Negotiation Expansion Register */ #define PHY_BMCR PHY_BCR #define PHY_BMSR PHY_BSR #define PHY_STATUS 0x10 diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/ethernet/Makefile b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/ethernet/Makefile new file mode 100755 index 000000000..17b175216 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/ethernet/Makefile @@ -0,0 +1,4 @@ +SRC_FILES := eth_driver.c connect_ether.c +SRC_DIR := test + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/ethernet/connect_ether.c b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/ethernet/connect_ether.c new file mode 100644 index 000000000..b4c52ba63 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/ethernet/connect_ether.c @@ -0,0 +1,268 @@ +/********************************** (C) COPYRIGHT ******************************* + * File Name : main.c + * Author : WCH + * Version : V1.0.0 + * Date : 2022/05/31 + * Description : Main program body. + ********************************************************************************* + * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. + * Attention: This software (modified or not) and binary are used for + * microcontroller manufactured by Nanjing Qinheng Microelectronics. + *******************************************************************************/ +/* + *@Note +TCP Client example, demonstrating that TCP Client connects +to the server and receives data and then sends it back. +For details on the selection of engineering chips, +please refer to the "CH32V30x Evaluation Board Manual" under the CH32V307EVT\EVT\PUB folder. + */ + +#include "connect_ether.h" +#include "ch32v30x_rcc.h" +#include "ch32v30x_tim.h" +#include "core_riscv.h" +#include "eth_driver.h" +#include "string.h" +#include "xs_base.h" + +extern uint32_t SystemCoreClock; +#define KEEPALIVE_ENABLE 1 // Enable keep alive function + +uint8_t MACAddr[6]; // MAC address +uint8_t IPAddr[4] = { 192, 168, 1, 10 }; // IP address +uint8_t GWIPAddr[4] = { 192, 168, 1, 1 }; // Gateway IP address +uint8_t IPMask[4] = { 255, 255, 255, 0 }; // subnet mask + +uint8_t MyBuf[RECE_BUF_LEN]; +uint8_t socket[WCHNET_MAX_SOCKET_NUM]; // Save the currently connected socket +uint8_t SocketRecvBuf[WCHNET_MAX_SOCKET_NUM][RECE_BUF_LEN]; // socket receive buffer + +/********************************************************************* + * @fn mStopIfError + * + * @brief check if error. + * + * @param iError - error constants. + * + * @return none + */ +void mStopIfError(uint8_t iError) +{ + if (iError == WCHNET_ERR_SUCCESS) + return; + KPrintf("Error: %02X\r\n", (uint16_t)iError); +} + +/********************************************************************* + * @fn TIM2_Init + * + * @brief Initializes TIM2. + * + * @return none + */ +void TIM2_Init(void) +{ + TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = { 0 }; + + RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); + + TIM_TimeBaseStructure.TIM_Period = SystemCoreClock / 1000000; + TIM_TimeBaseStructure.TIM_Prescaler = WCHNETTIMERPERIOD * 1000 - 1; + TIM_TimeBaseStructure.TIM_ClockDivision = 0; + TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; + TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); + TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); + + TIM_Cmd(TIM2, ENABLE); + TIM_ClearITPendingBit(TIM2, TIM_IT_Update); + NVIC_EnableIRQ(TIM2_IRQn); +} + +/********************************************************************* + * @fn WCHNET_CreateTcpSocket + * + * @brief Create TCP Socket + * + * @return none + */ +void WCHNET_CreateTcpSocket(uint8_t* DESIP, uint16_t srcport, uint16_t desport, uint8_t* SocketId) +{ + uint8_t i; + SOCK_INF TmpSocketInf; + + memset((void*)&TmpSocketInf, 0, sizeof(SOCK_INF)); + memcpy((void*)TmpSocketInf.IPAddr, DESIP, 4); + TmpSocketInf.DesPort = desport; + TmpSocketInf.SourPort = srcport++; + TmpSocketInf.ProtoType = PROTO_TYPE_TCP; + TmpSocketInf.RecvBufLen = RECE_BUF_LEN; + i = WCHNET_SocketCreat(SocketId, &TmpSocketInf); + KPrintf("SocketId %d\r\n", *SocketId); + mStopIfError(i); + i = WCHNET_SocketConnect(*SocketId); // make a TCP connection + mStopIfError(i); +} + +/********************************************************************* + * @fn WCHNET_DataLoopback + * + * @brief Data loopback function. + * + * @param id - socket id. + * + * @return none + */ +void WCHNET_DataLoopback(uint8_t id) +{ + u32 len, totallen; + uint8_t *p = MyBuf, TransCnt = 255; + + len = WCHNET_SocketRecvLen(id, NULL); // query length + KPrintf("Receive Len = %d\r\n", len); + totallen = len; + WCHNET_SocketRecv(id, MyBuf, &len); // Read the data of the receive buffer into MyBuf + while (1) { + len = totallen; + WCHNET_SocketSend(id, p, &len); // Send the data + totallen -= len; // Subtract the sent length from the total length + p += len; // offset buffer pointer + if (!--TransCnt) + break; // Timeout exit + if (totallen) + continue; // If the data is not sent, continue to send + break; // After sending, exit + } +} + +/********************************************************************* + * @fn WCHNET_HandleSockInt + * + * @brief Socket Interrupt Handle + * + * @param socketid - socket id. + * intstat - interrupt status + * + * @return 0 or TIME_OUT + */ +int WCHNET_HandleSockInt(uint8_t socketid, uint8_t intstat) +{ + uint8_t i; + + if (intstat & SINT_STAT_RECV) // receive data + { + WCHNET_DataLoopback(socketid); // Data loopback + } + if (intstat & SINT_STAT_CONNECT) // connect successfully + { +#if KEEPALIVE_ENABLE + WCHNET_SocketSetKeepLive(socketid, ENABLE); +#endif + WCHNET_ModifyRecvBuf(socketid, (u32)SocketRecvBuf[socketid], RECE_BUF_LEN); + for (i = 0; i < WCHNET_MAX_SOCKET_NUM; i++) { + if (socket[i] == 0xff) { // save connected socket id + socket[i] = socketid; + break; + } + } + KPrintf("TCP Connect Success\r\n"); + KPrintf("socket id: %d\r\n", socket[i]); + } + if (intstat & SINT_STAT_DISCONNECT) // disconnect + { + for (i = 0; i < WCHNET_MAX_SOCKET_NUM; i++) { // delete disconnected socket id + if (socket[i] == socketid) { + socket[i] = 0xff; + break; + } + } + KPrintf("TCP Disconnect\r\n"); + } + if (intstat & SINT_STAT_TIM_OUT) // timeout disconnect + { + for (i = 0; i < WCHNET_MAX_SOCKET_NUM; i++) { // delete disconnected socket id + if (socket[i] == socketid) { + socket[i] = 0xff; + break; + } + } + KPrintf("TCP Timeout\r\n"); + return TIME_OUT; + } + return 0; +} + +/********************************************************************* + * @fn WCHNET_HandleGlobalInt + * + * @brief Global Interrupt Handle + * + * @return 0 or SockInt + */ +int WCHNET_HandleGlobalInt(void) +{ + uint8_t intstat; + uint16_t i; + uint8_t socketint; + + intstat = WCHNET_GetGlobalInt(); // get global interrupt flag + if (intstat & GINT_STAT_UNREACH) // Unreachable interrupt + { + KPrintf("GINT_STAT_UNREACH\r\n"); + } + if (intstat & GINT_STAT_IP_CONFLI) // IP conflict + { + KPrintf("GINT_STAT_IP_CONFLI\r\n"); + } + if (intstat & GINT_STAT_PHY_CHANGE) // PHY status change + { + i = WCHNET_GetPHYStatus(); + if (i & PHY_Linked_Status) + KPrintf("PHY Link Success\r\n"); + } + if (intstat & GINT_STAT_SOCKET) { // socket related interrupt + for (i = 0; i < WCHNET_MAX_SOCKET_NUM; i++) { + socketint = WCHNET_GetSocketInt(i); + if (socketint) { + return WCHNET_HandleSockInt(i, socketint); + } + } + } + return 0; +} + +uint8_t InitHwEth() +{ + uint8_t i = 0; + + KPrintf("net version:%x\n", WCHNET_GetVer()); + if (WCHNET_LIB_VER != WCHNET_GetVer()) { + KPrintf("version error.\n"); + } + + WCHNET_GetMacAddr(MACAddr); // get the chip MAC address + KPrintf("mac addr:"); + for (i = 0; i < 6; i++) + KPrintf("%x ", MACAddr[i]); + KPrintf("\n"); + + TIM2_Init(); + + i = ETH_LibInit(IPAddr, GWIPAddr, IPMask, MACAddr); // Ethernet library initialize + mStopIfError(i); + if (i == WCHNET_ERR_SUCCESS) + KPrintf("WCHNET_LibInit Success\r\n"); +#if KEEPALIVE_ENABLE // Configure keep alive parameters + { + struct _KEEP_CFG cfg; + + cfg.KLIdle = 20000; + cfg.KLIntvl = 15000; + cfg.KLCount = 9; + WCHNET_ConfigKeepLive(&cfg); + } +#endif + + memset(socket, 0xff, WCHNET_MAX_SOCKET_NUM); + + return i; +} diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/ethernet/eth_driver.c b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/ethernet/eth_driver.c new file mode 100644 index 000000000..2b719e6d6 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/ethernet/eth_driver.c @@ -0,0 +1,1257 @@ +// /********************************** (C) COPYRIGHT ******************************* +// * File Name : eth_driver.c +// * Author : WCH +// * Version : V1.3.0 +// * Date : 2022/06/02 +// * Description : eth program body. +// ********************************************************************************* +// * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +// * Attention: This software (modified or not) and binary are used for +// * microcontroller manufactured by Nanjing Qinheng Microelectronics. +// *******************************************************************************/ + +#include "eth_driver.h" +#include "ch32v30x_eth.h" +#include "ch32v30x_gpio.h" +#include "ch32v30x_rcc.h" +#include "debug.h" +#include "net_config.h" +#include "stdint.h" +#include "wchnet.h" +#include "xs_base.h" +#include + +__attribute__((__aligned__(4))) ETH_DMADESCTypeDef DMARxDscrTab[ETH_RXBUFNB]; /* MAC receive descriptor, 4-byte aligned*/ +__attribute__((__aligned__(4))) ETH_DMADESCTypeDef DMATxDscrTab[ETH_TXBUFNB]; /* MAC send descriptor, 4-byte aligned */ + +__attribute__((__aligned__(4))) uint8_t MACRxBuf[ETH_RXBUFNB * ETH_RX_BUF_SZE]; /* MAC receive buffer, 4-byte aligned */ +__attribute__((__aligned__(4))) uint8_t MACTxBuf[ETH_TXBUFNB * ETH_TX_BUF_SZE]; /* MAC send buffer, 4-byte aligned */ + +__attribute__((__aligned__(4))) SOCK_INF SocketInf[WCHNET_MAX_SOCKET_NUM]; /* Socket information table, 4-byte alignment */ + +const uint16_t MemNum[8] = { WCHNET_NUM_IPRAW, + WCHNET_NUM_UDP, + WCHNET_NUM_TCP, + WCHNET_NUM_TCP_LISTEN, + WCHNET_NUM_TCP_SEG, + WCHNET_NUM_IP_REASSDATA, + WCHNET_NUM_PBUF, + WCHNET_NUM_POOL_BUF }; +const uint16_t MemSize[8] = { WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_IPRAW_PCB), + WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_UDP_PCB), + WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_TCP_PCB), + WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_TCP_PCB_LISTEN), + WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_TCP_SEG), + WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_IP_REASSDATA), + WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_PBUF), + WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_PBUF) + WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_POOL_BUF) }; + +__attribute__((__aligned__(4))) uint8_t Memp_Memory[WCHNET_MEMP_SIZE]; +__attribute__((__aligned__(4))) uint8_t Mem_Heap_Memory[WCHNET_RAM_HEAP_SIZE]; +__attribute__((__aligned__(4))) uint8_t Mem_ArpTable[WCHNET_RAM_ARP_TABLE_SIZE]; + +uint16_t gPHYAddress; +uint32_t volatile LocalTime; + +ETH_DMADESCTypeDef* pDMARxSet; +ETH_DMADESCTypeDef* pDMATxSet; + +#if (PHY_MODE == USE_10M_BASE) +/* PHY negotiation function */ +uint8_t phyLinkStatus = 0; +uint8_t phyStatus = 0; +uint8_t phyLinkCnt = 0; +uint8_t phySucCnt = 0; +uint8_t phyPN = PHY_PN_SWITCH_AUTO; +uint8_t TRDetectStep = 0; +uint8_t TRDetectCnt = 0; +uint8_t LinkTaskPeriod = 50; +uint32_t RandVal = 0; +volatile uint8_t phyLinkReset; +volatile uint32_t phyLinkTime; +/* PHY receive processing */ +uint8_t RBUFlag = 0; +uint8_t RecStopFlag = 0; +uint8_t ReInitMACFlag = 0; +uint8_t DuplexMode = 0; +uint8_t PhyPolarityDetect = 0; +uint32_t LinkSuccTime = 0; +extern uint8_t MACAddr[6]; +void ReInitMACReg(void); +#define IDLE_DES_NUM 2 // The number of descriptors that need to be free +#endif + +#if ENABLE_POLLING_TO_QUERY_PHY_LINK_STAT +uint16_t LastPhyStat = 0; +uint32_t LastQueryPhyTime = 0; +#endif + +/********************************************************************* + * @fn WCHNET_GetMacAddr + * + * @brief Get the MAC address + * + * @return none. + */ +void WCHNET_GetMacAddr(uint8_t* macaddr) +{ + uint8_t i; + uint8_t* mac_addr = (uint8_t*)(ROM_CFG_USERADR_ID + 5); + KPrintf("WCHNET_GetMacAddr %x. \n", mac_addr); + + for (i = 0; i < 6; i++) { + *macaddr = *mac_addr; + macaddr++; + mac_addr--; + } +} + +/********************************************************************* + * @fn WCHNET_TimeIsr + * + * @brief + * + * @return none. + */ +void WCHNET_TimeIsr(uint16_t timperiod) +{ + LocalTime += timperiod; +} + +/********************************************************************* + * @fn WCHNET_QueryPhySta + * + * @brief Query external PHY status + * + * @return none. + */ +#if ENABLE_POLLING_TO_QUERY_PHY_LINK_STAT +void WCHNET_QueryPhySta(void) +{ + uint16_t phy_stat; + if (QUERY_STAT_FLAG) { /* Query the PHY link status every 1s */ + LastQueryPhyTime = LocalTime / 1000; +#if ((PHY_MODE == USE_MAC_MII) || (PHY_MODE == USE_MAC_RMII)) + phy_stat = ETH_ReadPHYRegister(PHY_ADDRESS, PHY_BSR); + if (phy_stat != LastPhyStat) { + ETH_PHYLink(); + } +#elif (PHY_MODE == USE_MAC_RGMII) + ETH_WritePHYRegister(PHY_ADDRESS, 0x1F, 0x0a43); + /*In some cases the status is not updated in time, + * so read this register twice to get the correct status value.*/ + ETH_ReadPHYRegister(PHY_ADDRESS, 0x1A); + phy_stat = ETH_ReadPHYRegister(PHY_ADDRESS, 0x1A) & 0x04; + if (phy_stat != LastPhyStat) { + ETH_PHYLink(); + } +#endif + } +} +#endif + +#if (PHY_MODE == USE_10M_BASE) +/********************************************************************* + * @fn WCHNET_PhyPNProcess + * + * @brief Phy PN Polarity related processing + * + * @param none. + * + * @return none. + */ +void WCHNET_PhyPNProcess(void) +{ + uint32_t PhyVal; + + LinkSuccTime = LocalTime; + if ((ETH->MMCRGUFCR == 0) && (ETH->MMCRFCECR >= 3)) { + PhyVal = ETH_ReadPHYRegister(gPHYAddress, PHY_MDIX); + if ((PhyVal >> 2) & 0x01) + PhyVal &= ~(3 << 2); // change PHY PN Polarity to normal + else + PhyVal |= 1 << 2; // change PHY PN Polarity to reverse + ETH_WritePHYRegister(gPHYAddress, PHY_MDIX, PhyVal); + ETH->MMCCR |= ETH_MMCCR_CR; // Counters Reset + while (ETH->MMCCR & ETH_MMCCR_CR) + ; // Wait for counters reset to complete + } + if (ETH->MMCRGUFCR != 0) { + PhyPolarityDetect = 0; + /* enable Filter function */ + ETH->MACFFR &= ~(ETH_ReceiveAll_Enable | ETH_PromiscuousMode_Enable); + } +} + +/********************************************************************* + * @fn WCHNET_RecProcess + * + * @brief Receiving related processing + * + * @param none. + * + * @return none. + */ +void WCHNET_RecProcess(void) +{ + if (RBUFlag) { + RBUFlag = 0; + RecStopFlag = 0; + if (PhyPolarityDetect) + WCHNET_PhyPNProcess(); + ReInitMACReg(); + } + + if (RecStopFlag) { + if ((pDMARxSet == (ETH_DMADESCTypeDef*)ETH->DMACHRDR) && (pDMARxSet->Status & ETH_DMARxDesc_OWN)) { + RecStopFlag = 0; + ETH_MACReceptionCmd(ENABLE); + } + } +} + +/********************************************************************* + * @fn WCHNET_LinkProcess + * + * @brief link process. + * + * @param none. + * + * @return none. + */ +void WCHNET_LinkProcess(void) +{ + uint16_t phy_anlpar, phy_bmsr, phy_mdix, RegVal; + phy_anlpar = ETH_ReadPHYRegister(gPHYAddress, PHY_ANLPAR); + phy_bmsr = ETH_ReadPHYRegister(gPHYAddress, PHY_BMSR); + + if ((phy_anlpar & PHY_ANLPAR_SELECTOR_FIELD)) { + if (TRDetectStep == 0) { + TRDetectStep = 1; + TRDetectCnt = 1; + PHY_TR_SWITCH(); + LinkTaskPeriod = RandVal % 100 + 50; + return; + } else if (TRDetectStep == 1) { + TRDetectStep = 2; + TRDetectCnt = 0; + } + if (!(phyLinkStatus & PHY_LINK_WAIT_SUC)) { + if (phyPN == PHY_PN_SWITCH_AUTO) { + PHY_PN_SWITCH(PHY_PN_SWITCH_P); + } else if (phyPN == PHY_PN_SWITCH_P) { + phyLinkStatus = PHY_LINK_WAIT_SUC; + } else { + phyLinkStatus = PHY_LINK_WAIT_SUC; + } + } else { + if ((phySucCnt++ == 5) && ((phy_bmsr & (1 << 5)) == 0)) { + phySucCnt = 0; + if (phyPN == PHY_PN_SWITCH_N) + PHY_PN_SWITCH(PHY_PN_SWITCH_P); + else + PHY_PN_SWITCH(PHY_PN_SWITCH_N); + } + } + phyLinkCnt = 0; + } else { + if (TRDetectStep == 1) { + TRDetectCnt++; + if (TRDetectCnt == 8) { + TRDetectCnt = 0; + TRDetectStep = 0; + ETH_WritePHYRegister(gPHYAddress, PHY_MDIX, PHY_PN_SWITCH_AUTO); + return; + } + PHY_TR_SWITCH(); + return; + } + if (phyLinkStatus == PHY_LINK_WAIT_SUC) { + if (phyLinkCnt++ == 15) { + phyLinkCnt = 0; + phySucCnt = 0; + TRDetectStep = 0; + phyLinkStatus = PHY_LINK_INIT; + PHY_PN_SWITCH(PHY_PN_SWITCH_AUTO); + } + } else { + if (phyPN == PHY_PN_SWITCH_P) { + if (phyLinkCnt++ == 4) { + phyLinkCnt = 0; + PHY_PN_SWITCH(PHY_PN_SWITCH_N); + } + } else if (phyPN == PHY_PN_SWITCH_N) { + if (phyLinkCnt++ == 15) { + phyLinkCnt = 0; + phySucCnt = 0; + TRDetectStep = 0; + phyLinkStatus = PHY_LINK_INIT; + PHY_PN_SWITCH(PHY_PN_SWITCH_AUTO); + } + } else { + if (phyLinkCnt++ == (5000 / PHY_LINK_TASK_PERIOD)) + PHY_LINK_RESET(); + } + } + } +} + +/********************************************************************* + * @fn WCHNET_HandlePhyNegotiation + * + * @brief Handle PHY Negotiation. + * + * @param none. + * + * @return none. + */ +void WCHNET_HandlePhyNegotiation(void) +{ + if (phyLinkReset) /* After the PHY link is disconnected, wait 500ms before turning on the PHY clock*/ + { + if (LocalTime - phyLinkTime >= 500) { + phyLinkReset = 0; + EXTEN->EXTEN_CTR |= EXTEN_ETH_10M_EN; + PHY_LINK_RESET(); + } + } else { + if (!phyStatus) /* Handling PHY Negotiation Exceptions */ + { + ACCELERATE_LINK_PROCESS(); + if (LocalTime - phyLinkTime >= LinkTaskPeriod) { + UPDATE_LINKTASKPERIOD(); + phyLinkTime = LocalTime; + WCHNET_LinkProcess(); + } + if (ReInitMACFlag) + ReInitMACFlag = 0; + } else { /* PHY link complete */ + if (ReInitMACFlag) { + if (LocalTime - phyLinkTime >= 5 * PHY_LINK_TASK_PERIOD) { + uint32_t phy_stat; + ReInitMACFlag = 0; + phy_stat = ETH_ReadPHYRegister(gPHYAddress, PHY_BMSR); + if ((phy_stat & PHY_Linked_Status) == 0) { + WCHNET_PhyStatus(phy_stat); + PHY_LINK_RESET(); + } + } + } + if (PhyPolarityDetect) { + if (LocalTime - LinkSuccTime >= 2 * PHY_LINK_TASK_PERIOD) { + WCHNET_PhyPNProcess(); + } + } + } + } +} +#endif + +/********************************************************************* + * @fn WCHNET_MainTask + * + * @brief library main task function + * + * @param none. + * + * @return none. + */ +void WCHNET_MainTask(void) +{ + WCHNET_NetInput(); /* Ethernet data input */ + WCHNET_PeriodicHandle(); /* Protocol stack time-related task processing */ + +#if (PHY_MODE == USE_10M_BASE) + WCHNET_HandlePhyNegotiation(); + WCHNET_RecProcess(); +#endif + +#if ENABLE_POLLING_TO_QUERY_PHY_LINK_STAT + WCHNET_QueryPhySta(); /* Query external PHY status */ +#endif +} + +#if (PHY_MODE == USE_10M_BASE) +/********************************************************************* + * @fn ETH_LedLinkSet + * + * @brief set eth link led,setbit 0 or 1,the link led turn on or turn off + * + * @return none + */ +void ETH_LedLinkSet(uint8_t mode) +{ + if (mode == LED_OFF) { + GPIO_SetBits(GPIOC, GPIO_Pin_0); + } else { + GPIO_ResetBits(GPIOC, GPIO_Pin_0); + } +} + +/********************************************************************* + * @fn ETH_LedDataSet + * + * @brief set eth data led,setbit 0 or 1,the data led turn on or turn off + * + * @return none + */ +void ETH_LedDataSet(uint8_t mode) +{ + if (mode == LED_OFF) { + GPIO_SetBits(GPIOC, GPIO_Pin_1); + } else { + GPIO_ResetBits(GPIOC, GPIO_Pin_1); + } +} + +/********************************************************************* + * @fn ETH_LedConfiguration + * + * @brief set eth data and link led pin + * + * @param none. + * + * @return none. + */ +void ETH_LedConfiguration(void) +{ + GPIO_InitTypeDef GPIO = { 0 }; + + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); + GPIO.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; + GPIO.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOC, &GPIO); + ETH_LedDataSet(LED_OFF); + ETH_LedLinkSet(LED_OFF); +} + +/********************************************************************* + * @fn ETH_SetClock + * + * @brief Set ETH Clock(60MHZ). + * + * @param none. + * + * @return none. + */ +void ETH_SetClock(void) +{ + RCC_PLL3Cmd(DISABLE); + RCC_PREDIV2Config(RCC_PREDIV2_Div2); /* HSE = 8M */ + RCC_PLL3Config(RCC_PLL3Mul_15); /* 4M*15 = 60MHz */ + RCC_PLL3Cmd(ENABLE); + while (RESET == RCC_GetFlagStatus(RCC_FLAG_PLL3RDY)) + ; +} + +#elif (PHY_MODE == USE_MAC_MII) +/********************************************************************* + * @fn ETH_MIIPinInit + * + * @brief PHY MII interface GPIO initialization. + * + * @param none. + * + * @return none. + */ +void ETH_MIIPinInit(void) +{ + GPIO_InitTypeDef GPIO_InitStructure; + + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC, ENABLE); + + GPIO_Output(GPIOA, GPIO_Pin_2); /* MDIO */ + GPIO_Output(GPIOC, GPIO_Pin_1); /* MDC */ + + GPIO_Input(GPIOC, GPIO_Pin_3); /* TXCLK */ + GPIO_Output(GPIOB, GPIO_Pin_11); /* TXEN */ + GPIO_Output(GPIOB, GPIO_Pin_12); /* TXD0 */ + GPIO_Output(GPIOB, GPIO_Pin_13); /* TXD1 */ + GPIO_Output(GPIOC, GPIO_Pin_2); /* TXD2 */ + GPIO_Output(GPIOB, GPIO_Pin_8); /* TXD3 */ + GPIO_Input(GPIOA, GPIO_Pin_1); /* RXC */ + GPIO_Input(GPIOA, GPIO_Pin_7); /* RXDV */ + GPIO_Input(GPIOC, GPIO_Pin_4); /* RXD0 */ + GPIO_Input(GPIOC, GPIO_Pin_5); /* RXD1 */ + GPIO_Input(GPIOB, GPIO_Pin_0); /* RXD2 */ + GPIO_Input(GPIOB, GPIO_Pin_1); /* RXD3 */ + GPIO_Input(GPIOB, GPIO_Pin_10); /* RXER */ + + GPIO_Output(GPIOA, GPIO_Pin_0); /* CRS */ + GPIO_Output(GPIOA, GPIO_Pin_3); /* COL */ +} + +#elif (PHY_MODE == USE_MAC_RMII) +/********************************************************************* + * @fn ETH_RMIIPinInit + * + * @brief PHY RMII interface GPIO initialization. + * + * @param none. + * + * @return none. + */ +void ETH_RMIIPinInit(void) +{ + GPIO_InitTypeDef GPIO_InitStructure; + + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE); + GPIO_ETH_MediaInterfaceConfig(GPIO_ETH_MediaInterface_RMII); + GPIO_Output(GPIOA, GPIO_Pin_2); /* MDIO */ + GPIO_Output(GPIOC, GPIO_Pin_1); /* MDC */ + + GPIO_Output(GPIOB, GPIO_Pin_11); /* TXEN */ + GPIO_Output(GPIOB, GPIO_Pin_12); /* TXD0 */ + GPIO_Output(GPIOB, GPIO_Pin_13); /* TXD1 */ + + GPIO_Input(GPIOA, GPIO_Pin_1); /* REFCLK */ + GPIO_Input(GPIOA, GPIO_Pin_7); /* CRSDV */ + GPIO_Input(GPIOC, GPIO_Pin_4); /* RXD0 */ + GPIO_Input(GPIOC, GPIO_Pin_5); /* RXD1 */ +} + +#elif (PHY_MODE == USE_MAC_RGMII) +/********************************************************************* + * @fn ETH_RGMIIPinInit + * + * @brief PHY RGMII interface GPIO initialization. + * + * @param none. + * + * @return none. + */ +void ETH_RGMIIPinInit(void) +{ + GPIO_InitTypeDef GPIO_InitStructure; + + 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); + + GPIO_Output(GPIOA, GPIO_Pin_2); + GPIO_Output(GPIOA, GPIO_Pin_3); + GPIO_Output(GPIOA, GPIO_Pin_7); + GPIO_Output(GPIOC, GPIO_Pin_4); + GPIO_Output(GPIOC, GPIO_Pin_5); + GPIO_Output(GPIOB, GPIO_Pin_0); + + GPIO_Input(GPIOC, GPIO_Pin_0); + GPIO_Input(GPIOC, GPIO_Pin_1); + GPIO_Input(GPIOC, GPIO_Pin_2); + GPIO_Input(GPIOC, GPIO_Pin_3); + GPIO_Input(GPIOA, GPIO_Pin_0); + GPIO_Input(GPIOA, GPIO_Pin_1); + + GPIO_Input(GPIOB, GPIO_Pin_1); /* 125m in */ + + GPIO_Input(GPIOC, GPIO_Pin_7); /* interrupt pin */ +} +#endif + +#if (((PHY_MODE == USE_MAC_RMII) || (PHY_MODE == USE_MAC_RGMII)) && !ENABLE_POLLING_TO_QUERY_PHY_LINK_STAT) +/********************************************************************* + * @fn EXTI_Line_Init + * + * @brief Configure EXTI Line7. + * + * @param none. + * + * @return none. + */ +void EXTI_Line_Init(void) +{ + GPIO_InitTypeDef GPIO_InitStructure = { 0 }; + EXTI_InitTypeDef EXTI_InitStructure = { 0 }; + NVIC_InitTypeDef NVIC_InitStructure = { 0 }; + + RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOC, ENABLE); + + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; + GPIO_Init(GPIOC, &GPIO_InitStructure); + + /* GPIOC 7 ----> EXTI_Line7 */ + GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource7); + EXTI_InitStructure.EXTI_Line = EXTI_Line7; + EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; + EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; + EXTI_InitStructure.EXTI_LineCmd = ENABLE; + EXTI_Init(&EXTI_InitStructure); + + NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); +} + +/********************************************************************* + * @fn PHY_InterruptInit + * + * @brief Configure PHY interrupt function,Supported chip is:RTL8211FS + * + * @param none. + * + * @return none. + */ +void PHY_InterruptInit(void) +{ + uint16_t RegValue; +#if (PHY_MODE == USE_MAC_RGMII) + ETH_WritePHYRegister(gPHYAddress, 0x1F, 0x0a42); + RegValue = ETH_ReadPHYRegister(gPHYAddress, 0x12); + /* enable Link Status Change Interrupt and + * Auto-Negotiation Completed Interrupt*/ + RegValue |= (1 << 4) | (1 << 3); + ETH_WritePHYRegister(gPHYAddress, 0x12, RegValue); + /* Clear the Interrupt status */ + ETH_WritePHYRegister(gPHYAddress, 0x1F, 0x0a43); + ETH_ReadPHYRegister(gPHYAddress, 0x1D); +#elif (PHY_MODE == USE_MAC_RMII) + ETH_WritePHYRegister(gPHYAddress, 0x1F, 0x07); + /* Configure RMII mode */ + RegValue = ETH_ReadPHYRegister(gPHYAddress, 0x10); + RegValue |= 0x01 << 3; + ETH_WritePHYRegister(gPHYAddress, 0x10, RegValue); + /* Configure interrupt function */ + RegValue = ETH_ReadPHYRegister(gPHYAddress, 0x13); + RegValue |= 0x0f << 11; + ETH_WritePHYRegister(gPHYAddress, 0x13, RegValue); + /* Clear the Interrupt status */ + ETH_WritePHYRegister(gPHYAddress, 0x1F, 0x00); + ETH_ReadPHYRegister(gPHYAddress, 0x1E); +#endif +} +#endif + +/********************************************************************* + * @fn ETH_PHYLink + * + * @brief Configure MAC parameters after the PHY Link is successful. + * + * @param none. + * + * @return none. + */ +void ETH_PHYLink(void) +{ + uint32_t phy_stat; + +#if (PHY_MODE == USE_10M_BASE) + uint16_t phy_anlpar; + phy_anlpar = ETH_ReadPHYRegister(gPHYAddress, PHY_ANLPAR); + phy_stat = ETH_ReadPHYRegister(gPHYAddress, PHY_BSR); + + if ((phy_stat & (PHY_Linked_Status)) && (phy_anlpar == 0)) { /* restart negotiation */ + EXTEN->EXTEN_CTR &= ~EXTEN_ETH_10M_EN; + phyLinkReset = 1; + phyLinkTime = LocalTime; + return; + } + WCHNET_PhyStatus(phy_stat); + + if ((phy_stat & PHY_Linked_Status) && (phy_stat & PHY_AutoNego_Complete)) { + phy_stat = ETH_ReadPHYRegister(gPHYAddress, PHY_STATUS); + if (phy_stat & (1 << 2)) { + ETH->MACCR |= ETH_Mode_FullDuplex; + } else { + if ((phy_anlpar & PHY_ANLPAR_SELECTOR_FIELD) != PHY_ANLPAR_SELECTOR_VALUE) { + ETH->MACCR |= ETH_Mode_FullDuplex; + } else { + ETH->MACCR &= ~ETH_Mode_FullDuplex; + } + } + ETH->MACCR &= ~(ETH_Speed_100M | ETH_Speed_1000M); + phyStatus = PHY_Linked_Status; + + /* disable Filter function */ + ETH->MACFFR |= (ETH_ReceiveAll_Enable | ETH_PromiscuousMode_Enable); + + ETH->MMCCR |= ETH_MMCCR_CR; // Counters Reset + while (ETH->MMCCR & ETH_MMCCR_CR) + ; // Wait for counters reset to complete + PhyPolarityDetect = 1; + LinkSuccTime = LocalTime; + ETH_Start(); + } else { + EXTEN->EXTEN_CTR &= ~EXTEN_ETH_10M_EN; + phyLinkReset = 1; + phyLinkTime = LocalTime; + } + DuplexMode = (ETH->MACCR >> 11) & 0x01; /* Record duplex mode*/ +#elif (PHY_MODE == USE_MAC_MII) + phy_stat = ETH_ReadPHYRegister(PHY_ADDRESS, PHY_BSR); + LastPhyStat = phy_stat; + WCHNET_PhyStatus(phy_stat); + if ((phy_stat & PHY_Linked_Status) && (phy_stat & PHY_AutoNego_Complete)) { + phy_stat = ETH_ReadPHYRegister(PHY_ADDRESS, PHY_BCR); + /* PHY negotiation result */ + if (phy_stat & (1 << 13)) /* 100M */ + { + ETH->MACCR &= ~(ETH_Speed_100M | ETH_Speed_1000M); + ETH->MACCR |= ETH_Speed_100M; + } else /* 10M */ + { + ETH->MACCR &= ~(ETH_Speed_100M | ETH_Speed_1000M); + } + if (phy_stat & (1 << 8)) /* full duplex */ + { + ETH->MACCR |= ETH_Mode_FullDuplex; + } else /* half duplex */ + { + ETH->MACCR &= ~ETH_Mode_FullDuplex; + } + ETH_Start(); + } +#elif (PHY_MODE == USE_MAC_RMII) + ETH_WritePHYRegister(gPHYAddress, 0x1F, 0x00); + phy_stat = ETH_ReadPHYRegister(PHY_ADDRESS, PHY_BSR); +#if ENABLE_POLLING_TO_QUERY_PHY_LINK_STAT + LastPhyStat = phy_stat; +#endif + WCHNET_PhyStatus(phy_stat); + if ((phy_stat & PHY_Linked_Status) && (phy_stat & PHY_AutoNego_Complete)) { + phy_stat = ETH_ReadPHYRegister(PHY_ADDRESS, PHY_BCR); + /* PHY negotiation result */ + if (phy_stat & (1 << 13)) /* 100M */ + { + ETH->MACCR &= ~(ETH_Speed_100M | ETH_Speed_1000M); + ETH->MACCR |= ETH_Speed_100M; + } else /* 10M */ + { + ETH->MACCR &= ~(ETH_Speed_100M | ETH_Speed_1000M); + } + if (phy_stat & (1 << 8)) /* full duplex */ + { + ETH->MACCR |= ETH_Mode_FullDuplex; + } else /* half duplex */ + { + ETH->MACCR &= ~ETH_Mode_FullDuplex; + } + ETH_Start(); + } + phy_stat = ETH_ReadPHYRegister(gPHYAddress, 0x1E); /* Clear the Interrupt status */ +#elif (PHY_MODE == USE_MAC_RGMII) + ETH_WritePHYRegister(gPHYAddress, 0x1F, 0x0a43); + /*In some cases the status is not updated in time, + * so read this register twice to get the correct status value.*/ + ETH_ReadPHYRegister(gPHYAddress, 0x1A); + phy_stat = ETH_ReadPHYRegister(gPHYAddress, 0x1A); +#if ENABLE_POLLING_TO_QUERY_PHY_LINK_STAT + LastPhyStat = phy_stat & 0x04; +#endif + WCHNET_PhyStatus(phy_stat); + + if (phy_stat & 0x04) { + if (phy_stat & 0x08) { + ETH->MACCR |= ETH_Mode_FullDuplex; + } else { + ETH->MACCR &= ~ETH_Mode_FullDuplex; + } + if ((phy_stat & 0x30) == 0x00) { + ETH->MACCR &= ~(ETH_Speed_100M | ETH_Speed_1000M); + } else if ((phy_stat & 0x30) == 0x10) { + ETH->MACCR &= ~(ETH_Speed_100M | ETH_Speed_1000M); + ETH->MACCR |= ETH_Speed_100M; + } else if ((phy_stat & 0x30) == 0x20) { + ETH->MACCR &= ~(ETH_Speed_100M | ETH_Speed_1000M); + ETH->MACCR |= ETH_Speed_1000M; + } + ETH_Start(); + } + phy_stat = ETH_ReadPHYRegister(gPHYAddress, 0x1D); /* Clear the Interrupt status */ +#endif +} + +#if (PHY_MODE == USE_10M_BASE) +/********************************************************************* + * @fn ReInitMACReg + * + * @brief Reinitialize MAC register. + * + * @param none. + * + * @return none. + */ +void ReInitMACReg(void) +{ + ETH_InitTypeDef ETH_InitStructure; + uint16_t timeout = 10000; + uint16_t RegVal; + uint32_t tmpreg = 0; + + /* Wait for sending data to complete */ + while ((ETH->DMASR & (7 << 20)) != ETH_DMA_TransmitProcess_Suspended) + ; + + PHY_TR_REVERSE(); + + /* Software reset */ + ETH_SoftwareReset(); + /* Wait for software reset */ + do { + // Delay_Us(10); + if (!--timeout) + break; + } while (ETH->DMABMR & ETH_DMABMR_SR); + + /* ETHERNET Configuration */ + /* Call ETH_StructInit if you don't like to configure all ETH_InitStructure parameter */ + ETH_StructInit(Ð_InitStructure); + /* Fill ETH_InitStructure parameters */ + /*------------------------ MAC -----------------------------------*/ + ETH_InitStructure.ETH_Mode = ETH_Mode_FullDuplex; + ETH_InitStructure.ETH_Speed = ETH_Speed_10M; +#if HARDWARE_CHECKSUM_CONFIG + ETH_InitStructure.ETH_ChecksumOffload = ETH_ChecksumOffload_Enable; +#endif + 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; + /* Filter function configuration */ + ETH_InitStructure.ETH_ReceiveAll = ETH_ReceiveAll_Disable; + ETH_InitStructure.ETH_BroadcastFramesReception = ETH_BroadcastFramesReception_Enable; + ETH_InitStructure.ETH_PromiscuousMode = ETH_PromiscuousMode_Disable; + ETH_InitStructure.ETH_MulticastFramesFilter = ETH_MulticastFramesFilter_Perfect; + ETH_InitStructure.ETH_UnicastFramesFilter = ETH_UnicastFramesFilter_Perfect; + /*------------------------ 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; + /* Configure Ethernet */ + /*---------------------- Physical layer configuration -------------------*/ + /* Set the SMI interface clock, set as the main frequency divided by 42 */ + tmpreg = ETH->MACMIIAR; + tmpreg &= MACMIIAR_CR_MASK; + tmpreg |= (uint32_t)ETH_MACMIIAR_CR_Div42; + ETH->MACMIIAR = (uint32_t)tmpreg; + + /*------------------------ MAC register configuration ----------------------- --------------------*/ + tmpreg = ETH->MACCR; + tmpreg &= MACCR_CLEAR_MASK; + tmpreg |= (uint32_t)(ETH_InitStructure.ETH_AutoNegotiation | ETH_InitStructure.ETH_Watchdog | ETH_InitStructure.ETH_Jabber | ETH_InitStructure.ETH_InterFrameGap | ETH_InitStructure.ETH_CarrierSense | ETH_InitStructure.ETH_Speed | ETH_InitStructure.ETH_ReceiveOwn | ETH_InitStructure.ETH_LoopbackMode | ETH_InitStructure.ETH_Mode | ETH_InitStructure.ETH_ChecksumOffload | ETH_InitStructure.ETH_RetryTransmission | ETH_InitStructure.ETH_AutomaticPadCRCStrip | ETH_InitStructure.ETH_BackOffLimit | ETH_InitStructure.ETH_DeferralCheck); + /* Write MAC Control Register */ + ETH->MACCR = (uint32_t)tmpreg; +#if (PHY_MODE == USE_10M_BASE) + ETH->MACCR |= ETH_Internal_Pull_Up_Res_Enable; /*Turn on the internal pull-up resistor*/ +#endif + ETH->MACFFR = (uint32_t)(ETH_InitStructure.ETH_ReceiveAll | ETH_InitStructure.ETH_SourceAddrFilter | ETH_InitStructure.ETH_PassControlFrames | ETH_InitStructure.ETH_BroadcastFramesReception | ETH_InitStructure.ETH_DestinationAddrFilter | ETH_InitStructure.ETH_PromiscuousMode | ETH_InitStructure.ETH_MulticastFramesFilter | ETH_InitStructure.ETH_UnicastFramesFilter); + /*--------------- ETHERNET MACHTHR and MACHTLR Configuration ---------------*/ + /* Write to ETHERNET MACHTHR */ + ETH->MACHTHR = (uint32_t)ETH_InitStructure.ETH_HashTableHigh; + /* Write to ETHERNET MACHTLR */ + ETH->MACHTLR = (uint32_t)ETH_InitStructure.ETH_HashTableLow; + /*----------------------- ETHERNET MACFCR Configuration --------------------*/ + /* Get the ETHERNET MACFCR value */ + tmpreg = ETH->MACFCR; + /* Clear xx bits */ + tmpreg &= MACFCR_CLEAR_MASK; + tmpreg |= (uint32_t)((ETH_InitStructure.ETH_PauseTime << 16) | ETH_InitStructure.ETH_ZeroQuantaPause | ETH_InitStructure.ETH_PauseLowThreshold | ETH_InitStructure.ETH_UnicastPauseFrameDetect | ETH_InitStructure.ETH_ReceiveFlowControl | ETH_InitStructure.ETH_TransmitFlowControl); + ETH->MACFCR = (uint32_t)tmpreg; + + ETH->MACVLANTR = (uint32_t)(ETH_InitStructure.ETH_VLANTagComparison | ETH_InitStructure.ETH_VLANTagIdentifier); + + tmpreg = ETH->DMAOMR; + tmpreg &= DMAOMR_CLEAR_MASK; + tmpreg |= (uint32_t)(ETH_InitStructure.ETH_DropTCPIPChecksumErrorFrame | ETH_InitStructure.ETH_ReceiveStoreForward | ETH_InitStructure.ETH_FlushReceivedFrame | ETH_InitStructure.ETH_TransmitStoreForward | ETH_InitStructure.ETH_TransmitThresholdControl | ETH_InitStructure.ETH_ForwardErrorFrames | ETH_InitStructure.ETH_ForwardUndersizedGoodFrames | ETH_InitStructure.ETH_ReceiveThresholdControl | ETH_InitStructure.ETH_SecondFrameOperate); + ETH->DMAOMR = (uint32_t)tmpreg; + + /* Configure MAC address */ + ETH->MACA0HR = (uint32_t)((MACAddr[5] << 8) | MACAddr[4]); + ETH->MACA0LR = (uint32_t)(MACAddr[0] | (MACAddr[1] << 8) | (MACAddr[2] << 16) | (MACAddr[3] << 24)); + + /* Mask the interrupt that Tx good frame count counter reaches half the maximum value */ + ETH->MMCTIMR = ETH_MMCTIMR_TGFM; + /* Mask the interrupt that Rx good unicast frames counter reaches half the maximum value */ + /* Mask the interrupt that Rx crc error counter reaches half the maximum value */ + ETH->MMCRIMR = ETH_MMCRIMR_RGUFM | ETH_MMCRIMR_RFCEM; + + ETH_DMAITConfig(ETH_DMA_IT_NIS | ETH_DMA_IT_R | ETH_DMA_IT_T | ETH_DMA_IT_AIS | ETH_DMA_IT_RBU | ETH_DMA_IT_PHYLINK, + ENABLE); + + ETH_DMATxDescChainInit(DMATxDscrTab, MACTxBuf, ETH_TXBUFNB); + ETH_DMARxDescChainInit(DMARxDscrTab, MACRxBuf, ETH_RXBUFNB); + pDMARxSet = DMARxDscrTab; + pDMATxSet = DMATxDscrTab; + + ETH->MACCR &= ~ETH_Mode_FullDuplex; // configure working mode based on the link result + if (DuplexMode) { + ETH->MACCR |= ETH_Mode_FullDuplex; + } + + ETH->MACCR &= ~(ETH_Speed_100M | ETH_Speed_1000M); + + ETH_Start(); + + PHY_TR_REVERSE(); + + if (!phyStatus) { + PHY_LINK_RESET(); + } + + ReInitMACFlag = 1; + phyLinkTime = LocalTime; +} +#endif + +/********************************************************************* + * @fn ETH_RegInit + * + * @brief ETH register initialization. + * + * @param ETH_InitStruct:initialization struct. + * PHYAddress:PHY address. + * + * @return Initialization status. + */ +uint32_t ETH_RegInit(ETH_InitTypeDef* ETH_InitStruct, uint16_t PHYAddress) +{ + uint32_t tmpreg = 0; + + /*---------------------- Physical layer configuration -------------------*/ + /* Set the SMI interface clock, set as the main frequency divided by 42 */ + tmpreg = ETH->MACMIIAR; + tmpreg &= MACMIIAR_CR_MASK; + tmpreg |= (uint32_t)ETH_MACMIIAR_CR_Div42; + ETH->MACMIIAR = (uint32_t)tmpreg; + + /*------------------------ MAC register configuration ----------------------- --------------------*/ + tmpreg = ETH->MACCR; + tmpreg &= MACCR_CLEAR_MASK; + tmpreg |= (uint32_t)(ETH_InitStruct->ETH_AutoNegotiation | 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); + /* Write MAC Control Register */ + ETH->MACCR = (uint32_t)tmpreg; +#if (PHY_MODE == USE_10M_BASE) + ETH->MACCR |= ETH_Internal_Pull_Up_Res_Enable; /*Turn on the internal pull-up resistor*/ +#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); + /*--------------- ETHERNET MACHTHR and MACHTLR Configuration ---------------*/ + /* Write to ETHERNET MACHTHR */ + ETH->MACHTHR = (uint32_t)ETH_InitStruct->ETH_HashTableHigh; + /* Write to ETHERNET MACHTLR */ + ETH->MACHTLR = (uint32_t)ETH_InitStruct->ETH_HashTableLow; + /*----------------------- ETHERNET MACFCR Configuration --------------------*/ + /* 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; + 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; + + /* Reset the physical layer */ + ETH_WritePHYRegister(PHYAddress, PHY_BCR, PHY_Reset); +#if (PHY_MODE == USE_10M_BASE) + ETH_WritePHYRegister(PHYAddress, PHY_MDIX, PHY_PN_SWITCH_AUTO); +#endif + return ETH_SUCCESS; +} + +/********************************************************************* + * @fn ETH_Configuration + * + * @brief Ethernet configure. + * + * @return none + */ +void ETH_Configuration(uint8_t* macAddr) +{ + ETH_InitTypeDef ETH_InitStructure; + uint16_t timeout = 10000; + + /* Enable Ethernet MAC clock */ + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ETH_MAC | RCC_AHBPeriph_ETH_MAC_Tx | RCC_AHBPeriph_ETH_MAC_Rx, ENABLE); + + gPHYAddress = PHY_ADDRESS; +#if (PHY_MODE == USE_10M_BASE) + ETH_SetClock(); + /* Enable internal 10BASE-T PHY*/ + EXTEN->EXTEN_CTR |= EXTEN_ETH_10M_EN; /* Enable 10M Ethernet physical layer */ +#elif (PHY_MODE == USE_MAC_MII) + /* Enable MII GPIO */ + ETH_MIIPinInit(); +#elif (PHY_MODE == USE_MAC_RMII) + /* Enable RMII GPIO */ + ETH_RMIIPinInit(); +#elif (PHY_MODE == USE_MAC_RGMII) + /* Enable 1G MAC*/ + EXTEN->EXTEN_CTR |= EXTEN_ETH_RGMII_SEL; + RCC_ETH1GCLKConfig(RCC_ETH1GCLKSource_PB1_IN); + RCC_ETH1G_125Mcmd(ENABLE); + /* Enable RGMII GPIO */ + ETH_RGMIIPinInit(); +#endif + /* Reset ETHERNET on AHB Bus */ + ETH_DeInit(); + + /* Software reset */ + ETH_SoftwareReset(); + + /* Wait for software reset */ + do { + // Delay_Us(10); + if (!--timeout) + break; + } while (ETH->DMABMR & ETH_DMABMR_SR); + + /* ETHERNET Configuration */ + /* Call ETH_StructInit if you don't like to configure all ETH_InitStructure parameter */ + ETH_StructInit(Ð_InitStructure); + /* Fill ETH_InitStructure parameters */ + /*------------------------ MAC -----------------------------------*/ + ETH_InitStructure.ETH_Mode = ETH_Mode_FullDuplex; +#if (PHY_MODE == USE_10M_BASE) + ETH_InitStructure.ETH_Speed = ETH_Speed_10M; +#elif ((PHY_MODE == USE_MAC_MII) || (PHY_MODE == USE_MAC_RMII)) + ETH_InitStructure.ETH_Speed = ETH_Speed_100M; +#elif (PHY_MODE == USE_MAC_RGMII) + ETH_InitStructure.ETH_Speed = ETH_Speed_1000M; +#endif +#if HARDWARE_CHECKSUM_CONFIG + ETH_InitStructure.ETH_ChecksumOffload = ETH_ChecksumOffload_Enable; +#endif + 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; + /* Filter function configuration */ + ETH_InitStructure.ETH_ReceiveAll = ETH_ReceiveAll_Disable; + ETH_InitStructure.ETH_PromiscuousMode = ETH_PromiscuousMode_Disable; + ETH_InitStructure.ETH_BroadcastFramesReception = ETH_BroadcastFramesReception_Enable; + ETH_InitStructure.ETH_MulticastFramesFilter = ETH_MulticastFramesFilter_Perfect; + ETH_InitStructure.ETH_UnicastFramesFilter = ETH_UnicastFramesFilter_Perfect; + /*------------------------ 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; + /* Configure Ethernet */ + ETH_RegInit(Ð_InitStructure, gPHYAddress); + + /* Configure MAC address */ + ETH->MACA0HR = (uint32_t)((macAddr[5] << 8) | macAddr[4]); + ETH->MACA0LR = (uint32_t)(macAddr[0] | (macAddr[1] << 8) | (macAddr[2] << 16) | (macAddr[3] << 24)); + + /* Mask the interrupt that Tx good frame count counter reaches half the maximum value */ + ETH->MMCTIMR = ETH_MMCTIMR_TGFM; + /* Mask the interrupt that Rx good unicast frames counter reaches half the maximum value */ + /* Mask the interrupt that Rx crc error counter reaches half the maximum value */ + ETH->MMCRIMR = ETH_MMCRIMR_RGUFM | ETH_MMCRIMR_RFCEM; + +#if (PHY_MODE == USE_10M_BASE) + ETH_DMAITConfig(ETH_DMA_IT_NIS | ETH_DMA_IT_R | ETH_DMA_IT_T | ETH_DMA_IT_AIS | ETH_DMA_IT_RBU | ETH_DMA_IT_PHYLINK, + ENABLE); +#else + ETH_DMAITConfig(ETH_DMA_IT_NIS | ETH_DMA_IT_R | ETH_DMA_IT_T | ETH_DMA_IT_AIS | ETH_DMA_IT_RBU, + ENABLE); +#if (PHY_MODE == USE_MAC_RMII) +#if ENABLE_POLLING_TO_QUERY_PHY_LINK_STAT + uint16_t RegValue; + ETH_WritePHYRegister(gPHYAddress, 0x1F, 0x07); + /* Configure RMII mode */ + RegValue = ETH_ReadPHYRegister(gPHYAddress, 0x10); + RegValue |= 0x01 << 3; + ETH_WritePHYRegister(gPHYAddress, 0x10, RegValue); +#else + /* Configure the PHY interrupt function, the supported chip is: CH182H RMII */ + PHY_InterruptInit(); + /* Configure EXTI Line7. */ + EXTI_Line_Init(); +#endif +#elif (PHY_MODE == USE_MAC_RGMII) + /* Configure the polarity and delay of TXC */ + RGMII_TXC_Delay(0, 4); +#if !ENABLE_POLLING_TO_QUERY_PHY_LINK_STAT + /* Configure the PHY interrupt function, the supported chip is: RTL8211FS */ + PHY_InterruptInit(); + /* Configure EXTI Line7. */ + EXTI_Line_Init(); +#endif +#endif +#endif +} + +/********************************************************************* + * @fn ETH_TxPktChainMode + * + * @brief Ethernet sends data frames in chain mode. + * + * @param len Send data length + * pBuff send buffer pointer + * + * @return Send status. + */ +uint32_t ETH_TxPktChainMode(uint16_t len, uint32_t* pBuff) +{ + /* Check if the descriptor is owned by the ETHERNET DMA (when set) or CPU (when reset) */ + if ((DMATxDescToSet->Status & ETH_DMATxDesc_OWN) != (uint32_t)RESET) { + /* Return ERROR: OWN bit set */ + return ETH_ERROR; + } + /* Setting the Frame Length: bits[12:0] */ + DMATxDescToSet->ControlBufferSize = (len & ETH_DMATxDesc_TBS1); + DMATxDescToSet->Buffer1Addr = (uint32_t)pBuff; + + /* Setting the last segment and first segment bits (in this case a frame is transmitted in one descriptor) */ +#if HARDWARE_CHECKSUM_CONFIG + DMATxDescToSet->Status |= ETH_DMATxDesc_LS | ETH_DMATxDesc_FS | ETH_DMATxDesc_CIC_TCPUDPICMP_Full; +#else + DMATxDescToSet->Status |= ETH_DMATxDesc_LS | ETH_DMATxDesc_FS; +#endif + + /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */ + DMATxDescToSet->Status |= ETH_DMATxDesc_OWN; + + /* Clear TBUS ETHERNET DMA flag */ + ETH->DMASR = ETH_DMASR_TBUS; + /* Resume DMA transmission*/ + ETH->DMATPDR = 0; + + /* Update the ETHERNET DMA global Tx descriptor with next Tx descriptor */ + /* Chained Mode */ + /* Selects the next DMA Tx descriptor list for next buffer to send */ + DMATxDescToSet = (ETH_DMADESCTypeDef*)(DMATxDescToSet->Buffer2NextDescAddr); + /* Return SUCCESS */ + return ETH_SUCCESS; +} + +/********************************************************************* + * @fn WCHNET_ETHIsr + * + * @brief Ethernet Interrupt Service Routine + * + * @return none + */ +void WCHNET_ETHIsr(void) +{ + uint32_t int_sta; +#if (PHY_MODE == USE_10M_BASE) + uint8_t i; + ETH_DMADESCTypeDef* TempDesPtr; +#endif + + int_sta = ETH->DMASR; + if (int_sta & ETH_DMA_IT_AIS) { + if (int_sta & ETH_DMA_IT_RBU) { +#if (PHY_MODE == USE_10M_BASE) + RBUFlag = 1; + ETH_MACReceptionCmd(DISABLE); +#endif + ETH_DMAClearITPendingBit(ETH_DMA_IT_RBU); + } + ETH_DMAClearITPendingBit(ETH_DMA_IT_AIS); + } + + if (int_sta & ETH_DMA_IT_NIS) { + if (int_sta & ETH_DMA_IT_R) { +#if (PHY_MODE == USE_10M_BASE) + TempDesPtr = (ETH_DMADESCTypeDef*)(ETH->DMACHRDR); + for (i = 0; i < (IDLE_DES_NUM + 1); i++) { + if ((TempDesPtr->Status & ETH_DMARxDesc_OWN) == RESET) // Descriptor is occupied + { + if ((RecStopFlag == 0) && (RBUFlag == 0)) { + RecStopFlag = 1; + ETH_MACReceptionCmd(DISABLE); + } + break; + } + TempDesPtr = (ETH_DMADESCTypeDef*)(TempDesPtr->Buffer2NextDescAddr); + } +#endif + /*If you don't use the Ethernet library, + * you can do some data processing operations here*/ + ETH_DMAClearITPendingBit(ETH_DMA_IT_R); + } + if (int_sta & ETH_DMA_IT_T) { + ETH_DMAClearITPendingBit(ETH_DMA_IT_T); + } +#if (PHY_MODE == USE_10M_BASE) + if (int_sta & ETH_DMA_IT_PHYLINK) { + ETH_PHYLink(); + ETH_DMAClearITPendingBit(ETH_DMA_IT_PHYLINK); + } +#endif + ETH_DMAClearITPendingBit(ETH_DMA_IT_NIS); + } +} + +/********************************************************************* + * @fn ETH_Init + * + * @brief Ethernet initialization. + * + * @return none + */ +void ETH_Init(uint8_t* macAddr) +{ +#if (PHY_MODE == USE_10M_BASE) + // todo: delay func + // Delay_Ms(100); + ETH_LedConfiguration(); + RandVal = (macAddr[3] ^ macAddr[4] ^ macAddr[5]) * 214017 + 2531017; +#endif + ETH_Configuration(macAddr); + ETH_DMATxDescChainInit(DMATxDscrTab, MACTxBuf, ETH_TXBUFNB); + ETH_DMARxDescChainInit(DMARxDscrTab, MACRxBuf, ETH_RXBUFNB); + pDMARxSet = DMARxDscrTab; + pDMATxSet = DMATxDscrTab; + NVIC_EnableIRQ(ETH_IRQn); + NVIC_SetPriority(ETH_IRQn, 0); +} + +/********************************************************************* + * @fn ETH_LibInit + * + * @brief Ethernet library initialization program + * + * @return command status + */ +uint8_t ETH_LibInit(uint8_t* ip, uint8_t* gwip, uint8_t* mask, uint8_t* macaddr) +{ + uint8_t s; + struct _WCH_CFG cfg; + + memset(&cfg, 0, sizeof(cfg)); + cfg.TxBufSize = ETH_TX_BUF_SZE; + cfg.TCPMss = WCHNET_TCP_MSS; + cfg.HeapSize = WCHNET_MEM_HEAP_SIZE; + cfg.ARPTableNum = WCHNET_NUM_ARP_TABLE; + cfg.MiscConfig0 = WCHNET_MISC_CONFIG0; + cfg.MiscConfig1 = WCHNET_MISC_CONFIG1; +#if (PHY_MODE == USE_10M_BASE) + cfg.led_link = ETH_LedLinkSet; + cfg.led_data = ETH_LedDataSet; +#endif + cfg.net_send = ETH_TxPktChainMode; + cfg.CheckValid = WCHNET_CFG_VALID; + s = WCHNET_ConfigLIB(&cfg); + if (s) { + return (s); + } + s = WCHNET_Init(ip, gwip, mask, macaddr); + ETH_Init(macaddr); + return (s); +} + +// /******************************** endfile @ eth_driver ******************************/ diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/ethernet/libwchnet.a b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/ethernet/libwchnet.a new file mode 100644 index 000000000..ccab70a97 Binary files /dev/null and b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/ethernet/libwchnet.a differ diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/ethernet/test/Makefile b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/ethernet/test/Makefile new file mode 100755 index 000000000..bf55d6f89 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/ethernet/test/Makefile @@ -0,0 +1,4 @@ +SRC_FILES := wch_tcp_test.c + + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/ethernet/test/wch_tcp_test.c b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/ethernet/test/wch_tcp_test.c new file mode 100644 index 000000000..298c1b37e --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/ethernet/test/wch_tcp_test.c @@ -0,0 +1,47 @@ +#include "connect_ether.h" +#include "eth_driver.h" +#include "shell.h" +#include "wchnet.h" +#include "xs_base.h" + +uint8_t DESIP[4] = { 192, 168, 1, 100 }; // destination IP address +uint16_t desport = 1000; // destination port +uint16_t srcport = 1000; // source port + +uint8_t SocketId; + +/********************************************************************* + * @fn TCP client + * + * + * @return none + */ +int Tcp_Client(void) +{ + uint8_t i; + for (i = 0; i < WCHNET_MAX_SOCKET_NUM; i++) + WCHNET_CreateTcpSocket(DESIP, srcport, desport, &SocketId); // Create TCP Socket + + while (1) { + /*Ethernet library main task function, + * which needs to be called cyclically*/ + WCHNET_MainTask(); + /*Query the Ethernet global interrupt, + * if there is an interrupt, call the global interrupt handler*/ + if (WCHNET_QueryGlobalInt()) { + if (WCHNET_HandleGlobalInt() == TIME_OUT) { + WCHNET_CreateTcpSocket(DESIP, srcport, desport, &SocketId); + } + } + } +} + +int test_tcp_client(int argc, char* argv[]) +{ + KPrintf("TCPClient Test\r\n"); + Tcp_Client(); + return 0; +} + +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), + test_tcp_client, test_tcp_client, test tcp client); \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/include/connect_ether.h b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/include/connect_ether.h new file mode 100644 index 000000000..074822c5d --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/include/connect_ether.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +/** + * @file connect_ethernet.h + * @brief define rvstar uart function + * @version 1.0 + * @author AIIT XUOS Lab + * @date 2022-08-01 + */ + +#ifndef CONNECT_ETH_H +#define CONNECT_ETH_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +uint8_t InitHwEth(); +void WCHNET_CreateTcpSocket(uint8_t* DESIP, uint16_t srcport, uint16_t desport, uint8_t* SocketId); +void WCHNET_CreateTcpSocketListen(uint16_t srcport, uint8_t* SocketId); + +int WCHNET_HandleGlobalInt(void); + +#define TIME_OUT -1 + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/include/eth_driver.h b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/include/eth_driver.h new file mode 100644 index 000000000..8da2ecf72 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/include/eth_driver.h @@ -0,0 +1,181 @@ +/********************************** (C) COPYRIGHT ************* ****************** + * File Name : eth_driver.h + * Author : WCH + * Version : V1.3.0 + * Date : 2022/06/02 + * Description : This file contains the headers of the ETH Driver. + ********************************************************************************* + * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. + * Attention: This software (modified or not) and binary are used for + * microcontroller manufactured by Nanjing Qinheng Microelectronics. + *******************************************************************************/ +#ifndef __ETH_DRIVER__ +#define __ETH_DRIVER__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ch32v30x_eth.h" +#include "debug.h" +#include "wchnet.h" + +/* Internal 10M PHY */ +#define USE_10M_BASE 1 +/* The chips supported by the MII/RMII driver are: CH182/RTL8201F, etc. */ +#define USE_MAC_MII 2 +#define USE_MAC_RMII 3 +#define USE_MAC_RGMII 4 + +#ifndef PHY_MODE +#define PHY_MODE USE_10M_BASE +#endif + +/* 1: interrupt 0: polling in RMII or RGMII mode */ +#define LINK_STAT_ACQUISITION_METHOD 1 + +#define PHY_ADDRESS 1 + +#define ETH_DMARxDesc_FrameLengthShift 16 + +#define ROM_CFG_USERADR_ID 0x1FFFF7E8 + +#define PHY_LINK_TASK_PERIOD 50 + +#define PHY_ANLPAR_SELECTOR_FIELD 0x1F +#define PHY_ANLPAR_SELECTOR_VALUE 0x01 /* 5B'00001 */ + +#define PHY_LINK_INIT 0x00 +#define PHY_LINK_SUC_P (1 << 0) +#define PHY_LINK_SUC_N (1 << 1) +#define PHY_LINK_WAIT_SUC (1 << 7) + +#define PHY_PN_SWITCH_P (0 << 2) +#define PHY_PN_SWITCH_N (1 << 2) +#define PHY_PN_SWITCH_AUTO (2 << 2) + +#ifndef WCHNETTIMERPERIOD +#define WCHNETTIMERPERIOD 10 /* Timer period, in Ms. */ +#endif + +#define GPIO_Output(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 GPIO_Input(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) + +#define QUERY_STAT_FLAG ((LastQueryPhyTime == (LocalTime / 1000)) ? 0 : 1) + +#define ENABLE_POLLING_TO_QUERY_PHY_LINK_STAT ((PHY_MODE == USE_MAC_MII) || (((PHY_MODE == USE_MAC_RMII) || (PHY_MODE == USE_MAC_RGMII)) && !LINK_STAT_ACQUISITION_METHOD)) + +#define ACCELERATE_LINK_PROCESS() \ + do { \ + if ((TRDetectStep < 2) && (ETH_ReadPHYRegister(gPHYAddress, PHY_ANLPAR) & PHY_ANLPAR_SELECTOR_FIELD)) \ + LinkTaskPeriod = 0; \ + } while (0) + +#define UPDATE_LINKTASKPERIOD() \ + do { \ + if (TRDetectStep == 1) { \ + RandVal = RandVal * 214017 + 2531017; \ + LinkTaskPeriod = RandVal % 100 + 50; \ + } else { \ + LinkTaskPeriod = 50; \ + } \ + } while (0) + +#define PHY_RESTART_AUTONEGOTIATION() \ + do { \ + RegVal = ETH_ReadPHYRegister(gPHYAddress, PHY_BCR); \ + RegVal &= ~0x01; \ + RegVal |= PHY_Restart_AutoNegotiation; \ + ETH_WritePHYRegister(gPHYAddress, PHY_BCR, RegVal); \ + RegVal = ETH_ReadPHYRegister(gPHYAddress, PHY_BCR); \ + RegVal |= 0x03 | PHY_Restart_AutoNegotiation; \ + ETH_WritePHYRegister(gPHYAddress, PHY_BCR, RegVal); \ + } while (0) + +#define PHY_TR_SWITCH() \ + do { \ + phy_mdix = ETH_ReadPHYRegister(gPHYAddress, PHY_MDIX); \ + if (phy_mdix & 0x01) { \ + phy_mdix &= ~0x03; \ + phy_mdix |= 1 << 1; \ + } else { \ + phy_mdix &= ~0x03; \ + phy_mdix |= 1 << 0; \ + } \ + ETH_WritePHYRegister(gPHYAddress, PHY_MDIX, phy_mdix); \ + PHY_RESTART_AUTONEGOTIATION(); \ + } while (0) + +#define PHY_TR_REVERSE() \ + do { \ + RegVal = ETH_ReadPHYRegister(gPHYAddress, PHY_MDIX); \ + if (RegVal & 0x01) { \ + RegVal &= ~0x03; \ + RegVal |= 1 << 1; \ + } else { \ + RegVal &= ~0x03; \ + RegVal |= 1 << 0; \ + } \ + ETH_WritePHYRegister(gPHYAddress, PHY_MDIX, RegVal); \ + } while (0) + +#define PHY_PN_SWITCH(PNMode) \ + do { \ + if (PNMode == PHY_PN_SWITCH_AUTO) { \ + phyPN = PHY_PN_SWITCH_AUTO; \ + } else { \ + phyPN = (ETH_ReadPHYRegister(gPHYAddress, PHY_MDIX) & (~(0x03 << 2))) | PNMode; \ + } \ + ETH_WritePHYRegister(gPHYAddress, PHY_MDIX, phyPN); \ + phyPN = PNMode; \ + PHY_RESTART_AUTONEGOTIATION(); \ + } while (0) + +#define PHY_NEGOTIATION_PARAM_INIT() \ + do { \ + phyStatus = 0; \ + phySucCnt = 0; \ + phyLinkCnt = 0; \ + TRDetectStep = 0; \ + PhyPolarityDetect = 0; \ + phyLinkStatus = PHY_LINK_INIT; \ + phyPN = PHY_PN_SWITCH_AUTO; \ + ETH_WritePHYRegister(gPHYAddress, PHY_MDIX, phyPN); \ + } while (0) + +#define PHY_LINK_RESET() \ + do { \ + ETH_WritePHYRegister(gPHYAddress, PHY_BCR, PHY_Reset); \ + PHY_NEGOTIATION_PARAM_INIT(); \ + } while (0) + +extern ETH_DMADESCTypeDef* DMATxDescToSet; +extern ETH_DMADESCTypeDef* DMARxDescToGet; +extern SOCK_INF SocketInf[]; + +void ETH_PHYLink(void); +void WCHNET_ETHIsr(void); +void WCHNET_MainTask(void); +void ETH_LedConfiguration(void); +void ETH_Init(uint8_t* macAddr); +void ETH_LedLinkSet(uint8_t mode); +void ETH_LedDataSet(uint8_t mode); +void WCHNET_TimeIsr(uint16_t timperiod); +void ETH_Configuration(uint8_t* macAddr); +uint8_t ETH_LibInit(uint8_t* ip, uint8_t* gwip, uint8_t* mask, uint8_t* macaddr); +void WCHNET_MainTask(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/include/net_config.h b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/include/net_config.h new file mode 100644 index 000000000..d9af02575 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/include/net_config.h @@ -0,0 +1,160 @@ +/********************************** (C) COPYRIGHT ******************************* + * File Name : net_config.h + * Author : WCH + * Version : V1.30 + * Date : 2022/06/02 + * Description : This file contains the configurations of + * Ethernet protocol stack library + ********************************************************************************* + * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. + * Attention: This software (modified or not) and binary are used for + * microcontroller manufactured by Nanjing Qinheng Microelectronics. + *******************************************************************************/ +#ifndef __NET_CONFIG_H__ +#define __NET_CONFIG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/********************************************************************* + * socket configuration, IPRAW + UDP + TCP + TCP_LISTEN = number of sockets + */ +#define WCHNET_NUM_IPRAW 0 /* Number of IPRAW connections */ + +#define WCHNET_NUM_UDP 0 /* The number of UDP connections */ + +#define WCHNET_NUM_TCP 1 /* Number of TCP connections */ + +#define WCHNET_NUM_TCP_LISTEN 0 /* Number of TCP listening */ + +/* The number of sockets, the maximum is 31 */ +#define WCHNET_MAX_SOCKET_NUM (WCHNET_NUM_IPRAW + WCHNET_NUM_UDP + WCHNET_NUM_TCP + WCHNET_NUM_TCP_LISTEN) + +#define WCHNET_TCP_MSS 1460 /* Size of TCP MSS*/ + +#define WCHNET_NUM_POOL_BUF (WCHNET_NUM_TCP * 2 + 2) /* The number of POOL BUFs, the number of receive queues */ + +/********************************************************************* + * MAC queue configuration + */ +#define ETH_TXBUFNB 2 /* The number of descriptors sent by the MAC */ + +#define ETH_RXBUFNB 4 /* Number of MAC received descriptors */ + +#ifndef ETH_MAX_PACKET_SIZE +#define ETH_RX_BUF_SZE 1520 /* MAC receive buffer length, an integer multiple of 4 */ +#define ETH_TX_BUF_SZE 1520 /* MAC send buffer length, an integer multiple of 4 */ +#else +#define ETH_RX_BUF_SZE ETH_MAX_PACKET_SIZE +#define ETH_TX_BUF_SZE ETH_MAX_PACKET_SIZE +#endif + +/********************************************************************* + * Functional configuration + */ +#define WCHNET_PING_ENABLE 1 /* PING is enabled, PING is enabled by default */ + +#define TCP_RETRY_COUNT 20 /* The number of TCP retransmissions, the default value is 20 */ + +#define TCP_RETRY_PERIOD 10 /* TCP retransmission period, the default value is 10, the unit is 50ms */ + +#define SOCKET_SEND_RETRY 0 /* Send failed retry configuration, 1: enable, 0: disable */ + +#define HARDWARE_CHECKSUM_CONFIG 0 /* Hardware checksum checking and insertion configuration, 1: enable, 0: disable */ + +#define FINE_DHCP_PERIOD 8 /* Fine DHCP period, the default value is 8, the unit is 250ms */ + +#define CFG0_TCP_SEND_COPY 1 /* TCP send buffer copy, 1: copy, 0: not copy */ + +#define CFG0_TCP_RECV_COPY 1 /* TCP receive replication optimization, internal debugging use */ + +#define CFG0_TCP_OLD_DELETE 0 /* Delete oldest TCP connection, 1: enable, 0: disable */ + +#define CFG0_IP_REASS_PBUFS 0 /* Number of reassembled IP PBUFs */ + +#define CFG0_TCP_DEALY_ACK_DISABLE 1 /* 1: disable TCP delay ACK 0: enable TCP delay ACK */ + +/********************************************************************* + * Memory related configuration + */ +/* If you want to achieve a higher transmission speed, + * try to increase RECE_BUF_LEN to (WCHNET_TCP_MSS*4) + * and increase WCHNET_NUM_TCP_SEG to (WCHNET_NUM_TCP*4)*/ +#define RECE_BUF_LEN (WCHNET_TCP_MSS * 2) /* socket receive buffer size */ + +#define WCHNET_NUM_PBUF WCHNET_NUM_POOL_BUF /* Number of PBUF structures */ + +#define WCHNET_NUM_TCP_SEG (WCHNET_NUM_TCP * 2) /* The number of TCP segments used to send */ + +#define WCHNET_MEM_HEAP_SIZE (((WCHNET_TCP_MSS + 0x10 + 54 + 8) * WCHNET_NUM_TCP_SEG) + ETH_TX_BUF_SZE + 64 + 2 * 0x18) /* memory heap size */ + +#define WCHNET_NUM_ARP_TABLE 50 /* Number of ARP lists */ + +#define WCHNET_MEM_ALIGNMENT 4 /* 4 byte alignment */ + +#if CFG0_IP_REASS_PBUFS +#define WCHNET_NUM_IP_REASSDATA 2 /* Number of reassembled IP structures */ +/*1: When using the fragmentation function, + * ensure that the size of WCHNET_SIZE_POOL_BUF is large enough to store a single fragmented packet*/ +#define WCHNET_SIZE_POOL_BUF (((1500 + 14 + 4) + 3) & ~3) /* Buffer size for receiving a single packet */ +/*2: When creating a socket that can receive fragmented packets, + * ensure that "RecvBufLen" member of the "struct _SOCK_INF" structure + * (the parameter initialized when calling WCHNET_SocketCreat) is sufficient + * to receive a complete fragmented packet */ +#else +#define WCHNET_NUM_IP_REASSDATA 0 /* Number of reassembled IP structures */ +#define WCHNET_SIZE_POOL_BUF (((WCHNET_TCP_MSS + 40 + 14 + 4) + 3) & ~3) /* Buffer size for receiving a single packet */ +#endif + +/* Check receive buffer */ +#if (WCHNET_NUM_POOL_BUF * WCHNET_SIZE_POOL_BUF < ETH_RX_BUF_SZE) +#error "WCHNET_NUM_POOL_BUF or WCHNET_TCP_MSS Error" +#error "Please Increase WCHNET_NUM_POOL_BUF or WCHNET_TCP_MSS to make sure the receive buffer is sufficient" +#endif +/* Check the configuration of the SOCKET quantity */ +#if (WCHNET_NUM_TCP_LISTEN && !WCHNET_NUM_TCP) +#error "WCHNET_NUM_TCP Error,Please Configure WCHNET_NUM_TCP >= 1" +#endif +/* Check byte alignment must be a multiple of 4 */ +#if ((WCHNET_MEM_ALIGNMENT % 4) || (WCHNET_MEM_ALIGNMENT == 0)) +#error "WCHNET_MEM_ALIGNMENT Error,Please Configure WCHNET_MEM_ALIGNMENT = 4 * N, N >=1" +#endif +/* TCP maximum segment length */ +#if ((WCHNET_TCP_MSS > 1460) || (WCHNET_TCP_MSS < 60)) +#error "WCHNET_TCP_MSS Error,Please Configure WCHNET_TCP_MSS >= 60 && WCHNET_TCP_MSS <= 1460" +#endif +/* Number of ARP cache tables */ +#if ((WCHNET_NUM_ARP_TABLE > 0X7F) || (WCHNET_NUM_ARP_TABLE < 1)) +#error "WCHNET_NUM_ARP_TABLE Error,Please Configure WCHNET_NUM_ARP_TABLE >= 1 && WCHNET_NUM_ARP_TABLE <= 0X7F" +#endif +/* Check POOL BUF configuration */ +#if (WCHNET_NUM_POOL_BUF < 1) +#error "WCHNET_NUM_POOL_BUF Error,Please Configure WCHNET_NUM_POOL_BUF >= 1" +#endif +/* Check PBUF structure configuration */ +#if (WCHNET_NUM_PBUF < 1) +#error "WCHNET_NUM_PBUF Error,Please Configure WCHNET_NUM_PBUF >= 1" +#endif +/* Check IP Assignment Configuration */ +#if (CFG0_IP_REASS_PBUFS && ((WCHNET_NUM_IP_REASSDATA > 10) || (WCHNET_NUM_IP_REASSDATA < 1))) +#error "WCHNET_NUM_IP_REASSDATA Error,Please Configure WCHNET_NUM_IP_REASSDATA < 10 && WCHNET_NUM_IP_REASSDATA >= 1 " +#endif +/* Check the number of reassembled IP PBUFs */ +#if (CFG0_IP_REASS_PBUFS > WCHNET_NUM_POOL_BUF) +#error "WCHNET_NUM_POOL_BUF Error,Please Configure CFG0_IP_REASS_PBUFS < WCHNET_NUM_POOL_BUF" +#endif +/* Check Timer period, in Ms. */ +#if (WCHNETTIMERPERIOD > 50) +#error "WCHNETTIMERPERIOD Error,Please Configure WCHNETTIMERPERIOD < 50" +#endif + +/* Configuration value 0 */ +#define WCHNET_MISC_CONFIG0 (((CFG0_TCP_SEND_COPY) << 0) | ((CFG0_TCP_RECV_COPY) << 1) | ((CFG0_TCP_OLD_DELETE) << 2) | ((CFG0_IP_REASS_PBUFS) << 3) | ((CFG0_TCP_DEALY_ACK_DISABLE) << 8)) +/* Configuration value 1 */ +#define WCHNET_MISC_CONFIG1 (((WCHNET_MAX_SOCKET_NUM) << 0) | ((WCHNET_PING_ENABLE) << 13) | ((TCP_RETRY_COUNT) << 14) | ((TCP_RETRY_PERIOD) << 19) | ((SOCKET_SEND_RETRY) << 25) | ((HARDWARE_CHECKSUM_CONFIG) << 26) | ((FINE_DHCP_PERIOD) << 27)) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/include/wchnet.h b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/include/wchnet.h new file mode 100644 index 000000000..4d52a19da --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/include/wchnet.h @@ -0,0 +1,591 @@ +/********************************** (C) COPYRIGHT ******************************* + * File Name : wchnet.h + * Author : WCH + * Version : V1.80 + * Date : 2023/05/12 + * Description : This file contains the headers of + * the Ethernet protocol stack library. + ********************************************************************************* + * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. + * Attention: This software (modified or not) and binary are used for + * microcontroller manufactured by Nanjing Qinheng Microelectronics. + *******************************************************************************/ +#ifndef __WCHNET_H__ +#define __WCHNET_H__ + +#include "stdint.h" +#ifndef NET_LIB +#include "net_config.h" +#endif +#ifdef __cplusplus +extern "C" { +#endif + +#define WCHNET_LIB_VER 0x18 // the library version number +#define WCHNET_CFG_VALID 0x12345678 // Configuration value valid flag + +/* LED state @LED_STAT */ +#define LED_ON 0 +#define LED_OFF 1 + +/* PHY state @PHY_STAT */ +#define PHY_LINK_SUCCESS (1 << 2) // PHY connection success +#define PHY_AUTO_SUCCESS (1 << 5) // PHY auto negotiation completed + +/* Library initialization state @CFG_INIT_STAT */ +#define INIT_OK 0x00 +#define INIT_ERR_RX_BUF_SIZE 0x01 +#define INIT_ERR_TCP_MSS 0x02 +#define INIT_ERR_HEAP_SIZE 0x03 +#define INIT_ERR_ARP_TABLE_NEM 0x04 +#define INIT_ERR_MISC_CONFIG0 0x05 +#define INIT_ERR_MISC_CONFIG1 0x06 +#define INIT_ERR_FUNC_SEND 0x09 +#define INIT_ERR_CHECK_VALID 0xFF + +/* Socket protocol type */ +#define PROTO_TYPE_IP_RAW 0 // IP layer raw data +#define PROTO_TYPE_UDP 2 // UDP protocol +#define PROTO_TYPE_TCP 3 // TCP protocol + +/* interrupt status */ +/* The following are the states + * that GLOB_INT will generate */ +#define GINT_STAT_UNREACH (1 << 0) // unreachable interrupt +#define GINT_STAT_IP_CONFLI (1 << 1) // IP conflict interrupt +#define GINT_STAT_PHY_CHANGE (1 << 2) // PHY state change interrupt +#define GINT_STAT_SOCKET (1 << 4) // socket related interrupt + +/* The following are the states + * that Sn_INT will generate*/ +#define SINT_STAT_RECV (1 << 2) // the socket receives data or the receive buffer is not empty +#define SINT_STAT_CONNECT (1 << 3) // connect successfully,generated in TCP mode +#define SINT_STAT_DISCONNECT (1 << 4) // disconnect,generated in TCP mode +#define SINT_STAT_TIM_OUT (1 << 6) // timeout disconnect,generated in TCP mode + +/* Definitions for error constants. @ERR_T */ +#define ERR_T +#define WCHNET_ERR_SUCCESS 0x00 // No error, everything OK +#define WCHNET_ERR_BUSY 0x10 // busy +#define WCHNET_ERR_MEM 0x11 // Out of memory error +#define WCHNET_ERR_BUF 0x12 // Buffer error +#define WCHNET_ERR_TIMEOUT 0x13 // Timeout +#define WCHNET_ERR_RTE 0x14 // Routing problem +#define WCHNET_ERR_ABRT 0x15 // Connection aborted +#define WCHNET_ERR_RST 0x16 // Connection reset +#define WCHNET_ERR_CLSD 0x17 // Connection closed +#define WCHNET_ERR_CONN 0x18 // Not connected +#define WCHNET_ERR_VAL 0x19 // Illegal value +#define WCHNET_ERR_ARG 0x1a // Illegal argument +#define WCHNET_ERR_USE 0x1b // Address in use +#define WCHNET_ERR_IF 0x1c // Low-level netif error +#define WCHNET_ERR_ISCONN 0x1d // Already connected +#define WCHNET_ERR_INPROGRESS 0x1e // Operation in progress +#define WCHNET_ERR_SOCKET_MEM 0X20 // Socket information error +#define WCHNET_ERR_UNSUPPORT_PROTO 0X21 // unsupported protocol type +#define WCHNET_RET_ABORT 0x5F // command process fail +#define WCHNET_ERR_UNKNOW 0xFA // unknow + +/* unreachable condition related codes */ +#define UNREACH_CODE_HOST 0 // host unreachable +#define UNREACH_CODE_NET 1 // network unreachable +#define UNREACH_CODE_PROTOCOL 2 // protocol unreachable +#define UNREACH_CODE_PROT 3 // port unreachable +/*For other values, please refer to the RFC792 document*/ + +/* TCP disconnect related codes */ +#define TCP_CLOSE_NORMAL 0 // normal disconnect,a four-way handshake +#define TCP_CLOSE_RST 1 // reset the connection and close +#define TCP_CLOSE_ABANDON 2 // drop connection, and no termination message is sent + +/* socket state code */ +#define SOCK_STAT_CLOSED 0X00 // socket close +#define SOCK_STAT_OPEN 0X05 // socket open + +/* TCP state code */ +#define TCP_CLOSED 0 // TCP close +#define TCP_LISTEN 1 // TCP listening +#define TCP_SYN_SENT 2 // SYN send, connect request +#define TCP_SYN_RCVD 3 // SYN received, connection request received +#define TCP_ESTABLISHED 4 // TCP connection establishment +#define TCP_FIN_WAIT_1 5 // WAIT_1 state +#define TCP_FIN_WAIT_2 6 // WAIT_2 state +#define TCP_CLOSE_WAIT 7 // wait to close +#define TCP_CLOSING 8 // closing +#define TCP_LAST_ACK 9 // LAST_ACK +#define TCP_TIME_WAIT 10 // 2MSL wait + +/* The following values are fixed and cannot be changed */ +#define WCHNET_MEM_ALIGN_SIZE(size) (((size) + WCHNET_MEM_ALIGNMENT - 1) & ~(WCHNET_MEM_ALIGNMENT - 1)) +#define WCHNET_SIZE_IPRAW_PCB 0x1C // IPRAW PCB size +#define WCHNET_SIZE_UDP_PCB 0x20 // UDP PCB size +#define WCHNET_SIZE_TCP_PCB 0xB4 // TCP PCB size +#define WCHNET_SIZE_TCP_PCB_LISTEN 0x24 // TCP LISTEN PCB size +#define WCHNET_SIZE_IP_REASSDATA 0x20 // IP reassembled Management +#define WCHNET_SIZE_PBUF 0x10 // Packet Buf +#define WCHNET_SIZE_TCP_SEG 0x14 // TCP SEG structure +#define WCHNET_SIZE_MEM 0x08 // sizeof(struct mem) +#define WCHNET_SIZE_ARP_TABLE 0x18 // sizeof ARP table + +#define WCHNET_MEMP_SIZE ((WCHNET_MEM_ALIGNMENT - 1) + (WCHNET_NUM_IPRAW * WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_IPRAW_PCB)) + (WCHNET_NUM_UDP * WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_UDP_PCB)) + (WCHNET_NUM_TCP * WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_TCP_PCB)) + (WCHNET_NUM_TCP_LISTEN * WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_TCP_PCB_LISTEN)) + (WCHNET_NUM_TCP_SEG * WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_TCP_SEG)) + (WCHNET_NUM_IP_REASSDATA * WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_IP_REASSDATA)) + (WCHNET_NUM_PBUF * WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_PBUF)) + (WCHNET_NUM_POOL_BUF * (WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_PBUF) + WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_POOL_BUF)))) + +#define HEAP_MEM_ALIGN_SIZE (WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_MEM)) +#define WCHNET_RAM_HEAP_SIZE (WCHNET_MEM_ALIGN_SIZE(WCHNET_MEM_HEAP_SIZE) + HEAP_MEM_ALIGN_SIZE) +#define WCHNET_RAM_ARP_TABLE_SIZE (WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_ARP_TABLE) * WCHNET_NUM_ARP_TABLE) + +typedef struct +{ + uint32_t length; + uint32_t buffer; +} ETHFrameType; + +/* LED callback type */ +typedef void (*led_callback)(uint8_t setbit); + +/* net send callback type */ +typedef uint32_t (*eth_tx_set)(uint16_t len, uint32_t* pBuff); + +/* net receive callback type */ +typedef uint32_t (*eth_rx_set)(ETHFrameType* pkt); + +/* DNS callback type */ +typedef void (*dns_callback)(const char* name, uint8_t* ipaddr, void* callback_arg); + +/* DHCP callback type */ +typedef uint8_t (*dhcp_callback)(uint8_t status, void*); + +/* socket receive callback type */ +struct _SOCK_INF; +typedef void (*pSockRecv)(struct _SOCK_INF*, uint32_t, uint16_t, uint8_t*, uint32_t); + +/* Socket information struct */ +typedef struct _SOCK_INF { + uint32_t IntStatus; // interrupt state + uint32_t SockIndex; // Socket index value + uint32_t RecvStartPoint; // Start pointer of the receive buffer + uint32_t RecvBufLen; // Receive buffer length + uint32_t RecvCurPoint; // current pointer to receive buffer + uint32_t RecvReadPoint; // The read pointer of the receive buffer + uint32_t RecvRemLen; // The length of the remaining data in the receive buffer + uint32_t ProtoType; // protocol type + uint32_t SockStatus; // Low byte Socket state, the next low byte is TCP state, only meaningful in TCP mode + uint32_t DesPort; // destination port + uint32_t SourPort; // Source port, protocol type in IPRAW mode + uint8_t IPAddr[4]; // Socket destination IP address + void* Resv1; // Reserved, for internal use, for saving individual PCBs + void* Resv2; // Reserved, used internally, used by TCP Server + pSockRecv AppCallBack; // receive callback function +} SOCK_INF; + +struct _WCH_CFG { + uint32_t TxBufSize; // MAC send buffer size, reserved for use + uint32_t TCPMss; // TCP MSS size + uint32_t HeapSize; // heap memory size + uint32_t ARPTableNum; // Number of ARP lists + uint32_t MiscConfig0; // Miscellaneous Configuration 0 + /* Bit 0 TCP send buffer copy 1: copy, 0: not copy */ + /* Bit 1 TCP receive replication optimization, used for internal debugging */ + /* bit 2 delete oldest TCP connection 1: enable, 0: disable */ + /* Bits 3-7 Number of PBUFs of IP segments */ + /* Bit 8 TCP Delay ACK disable */ + uint32_t MiscConfig1; // Miscellaneous Configuration 1 + /* Bits 0-7 Number of Sockets*/ + /* Bits 8-12 Reserved */ + /* Bit 13 PING enable, 1: On 0: Off */ + /* Bits 14-18 TCP retransmission times */ + /* Bits 19-23 TCP retransmission period, in 50 milliseconds */ + /* bit 25 send failed retry, 1: enable, 0: disable */ + /* bit 26 Select whether to perform IPv4 checksum check on + * the TCP/UDP/ICMP header of the received frame payload by hardware, + * and calculate and insert the checksum of the IP header and payload of the sent frame by hardware.*/ + /* Bits 27-31 period (in 250 milliseconds) of Fine DHCP periodic process */ + led_callback led_link; // PHY Link Status Indicator + led_callback led_data; // Ethernet communication indicator + eth_tx_set net_send; // Ethernet send + eth_rx_set net_recv; // Ethernet receive + uint32_t CheckValid; // Configuration value valid flag, fixed value @WCHNET_CFG_VALID +}; + +struct _NET_SYS { + uint8_t IPAddr[4]; // IP address + uint8_t GWIPAddr[4]; // Gateway IP address + uint8_t MASKAddr[4]; // subnet mask + uint8_t MacAddr[8]; // MAC address + uint8_t UnreachIPAddr[4]; // Unreachable IP address + uint32_t RetranCount; // number of retries,default is 10 times + uint32_t RetranPeriod; // Retry period, unit MS, default 500MS + uint32_t PHYStat; // PHY state code + uint32_t NetStat; // The status of the Ethernet, including whether it is open, etc. + uint32_t MackFilt; // MAC filtering, the default is to receive broadcasts, receive local MAC + uint32_t GlobIntStatus; // global interrupt + uint32_t UnreachCode; // unreachable code + uint32_t UnreachProto; // unreachable protocol + uint32_t UnreachPort; // unreachable port + uint32_t SendFlag; + uint32_t Flags; +}; + +/* KEEP LIVE configuration structure */ +struct _KEEP_CFG { + uint32_t KLIdle; // KEEPLIVE idle time, in ms + uint32_t KLIntvl; // KEEPLIVE period, in ms + uint32_t KLCount; // KEEPLIVE times +}; + +/** + * @brief Library initialization . + * + * @param ip - IP address pointer + * @param gwip - Gateway address pointer + * @param mask - Subnet mask pointer + * @param macaddr - MAC address pointer + * + * @return @ERR_T + */ +uint8_t WCHNET_Init(const uint8_t* ip, const uint8_t* gwip, const uint8_t* mask, const uint8_t* macaddr); + +/** + * @brief get library version + * + * @param None + * + * @return library version + */ +uint8_t WCHNET_GetVer(void); + +/** + * @brief Get MAC address. + * + * @param(in) macaddr - MAC address + * + * @param(out) MAC address + * + * @return None + */ +void WCHNET_GetMacAddr(uint8_t* macaddr); + +/** + * @brief Library parameter configuration. + * + * @param cfg - Configuration parameter @_WCH_CFG + * + * @return Library configuration initialization state @CFG_INIT_STAT + */ +uint8_t WCHNET_ConfigLIB(struct _WCH_CFG* cfg); + +/** + * @brief Handle periodic tasks in the protocol stack + * + * @param None + * + * @return None + */ +void WCHNET_PeriodicHandle(void); + +/** + * @brief Ethernet data input. Always called in the main program, + * or called after the reception interrupt is detected. + * + * @param + * + * @return None + */ +void WCHNET_NetInput(void); + +/** + * @brief Ethernet interrupt service function. Called after + * Ethernet interrupt is generated. + * + * @param None + * + * @return None + */ +void WCHNET_ETHIsr(void); + +/** + * @brief Get PHY status + * + * @param None + * + * @return PHY status @PHY_STAT + */ +uint8_t WCHNET_GetPHYStatus(void); + +/** + * @brief Query global interrupt status. + * + * @param None + * + * @return GLOB_INT + */ +uint8_t WCHNET_QueryGlobalInt(void); + +/** + * @brief Read global interrupt and clear it. + * + * @param None + * + * @return GLOB_INT + */ +uint8_t WCHNET_GetGlobalInt(void); + +/** + * @brief create socket + * + * @param(in) *socketid - socket variable pointer + * @param socinf - Configuration parameters for creating sockets @SOCK_INF + * + * @param(out) *socketid - socket value + * + * @return @ERR_T + */ +uint8_t WCHNET_SocketCreat(uint8_t* socketid, SOCK_INF* socinf); + +/** + * @brief Socket sends data. + * + * @param socketid - socket id value + * @param *buf - the first address of send buffer + * @param(in) *len - pointer to the length of the data expected to be sent + * + * @param(out) *len - pointer to the length of the data sent actually + * + * @return @ERR_T + */ +uint8_t WCHNET_SocketSend(uint8_t socketid, uint8_t* buf, uint32_t* len); + +/** + * @brief Socket receives data. + * + * @param socketid - socket id value + * @param *buf - the first address of receive buffer + * @param(in) *len - pointer to the length of the data expected to be read + * + * @param(out) *buf - the first address of data buffer + * @param(out) *len - pointer to the length of the data read actually + * + * @return @ERR_T + */ +uint8_t WCHNET_SocketRecv(uint8_t socketid, uint8_t* buf, uint32_t* len); + +/** + * @brief Get socket interrupt, and clear socket interrupt. + * + * @param socketid - socket id value + * + * @return Sn_INT + */ +uint8_t WCHNET_GetSocketInt(uint8_t socketid); + +/** + * @brief Get the length of the data received by socket. + * + * @param socketid - socket id value + * @param(in) *bufaddr - the first address of receive buffer + * + * @param(out) *bufaddr - the first address of data buffer + * + * @return the length of the data + */ +uint32_t WCHNET_SocketRecvLen(uint8_t socketid, uint32_t* bufaddr); + +/** + * @brief TCP connect. Used in TCP Client mode. + * + * @param socketid - socket id value + * + * @return @ERR_T + */ +uint8_t WCHNET_SocketConnect(uint8_t socketid); + +/** + * @brief TCP listen. Used in TCP SERVER mode. + * + * @param socketid - socket id value + * + * @return @ERR_T + */ +uint8_t WCHNET_SocketListen(uint8_t socketid); + +/** + * @brief Close socket. + * + * @param socketid - socket id value + * @param mode - the way of disconnection.Used in TCP connection. + * @TCP disconnect related codes + * + * @return @ERR_T + */ +uint8_t WCHNET_SocketClose(uint8_t socketid, uint8_t mode); + +/** + * @brief Modify socket receive buffer. + * + * @param socketid - socket id value + * @param bufaddr - Address of the receive buffer + * @param bufsize - Size of the receive buffer + * + * @return None + */ +void WCHNET_ModifyRecvBuf(uint8_t socketid, uint32_t bufaddr, uint32_t bufsize); + +/** + * @brief UDP send, specify the target IP and target port + * + * @param socketid - socket id value + * @param *buf - Address of the sent data + * @param(in) *slen - Address of the sent length + * @param *sip - destination IP address + * @param port - destination port + * + * @param(out) *slen - actual length sent + * + * @return @ERR_T + */ +uint8_t WCHNET_SocketUdpSendTo(uint8_t socketid, uint8_t* buf, uint32_t* slen, uint8_t* sip, uint16_t port); + +/** + * @brief Convert ASCII address to network address. + * + * @param *cp - ASCII address to be converted, such as "192.168.1.2" + * @param(in) *addr - First address of the memory stored in the converted network address + * @param(out) *addr - Converted network address, such as 0xC0A80102 + * @return 0 - Success. Others - Failure. + */ +uint8_t WCHNET_Aton(const char* cp, uint8_t* addr); + +/** + * @brief Convert network address to ASCII address. + * + * @param *ipaddr - socket id value + * + * @return Converted ASCII address + */ +uint8_t* WCHNET_Ntoa(uint8_t* ipaddr); + +/** + * @brief Set socket TTL. + * + * @param socketid - socket id value + * @param ttl - TTL value + * + * @return @ERR_T + */ +uint8_t WCHNET_SetSocketTTL(uint8_t socketid, uint8_t ttl); + +/** + * @brief Start TCP retry sending immediately. + * + * @param socketid - TTL value + * + * @return None + */ +void WCHNET_RetrySendUnack(uint8_t socketid); + +/** + * @brief Query the packets that are not sent successfully. + * + * @param socketid - TTL value + * @param(in) *addrlist - pointer to the address of the address list + * @param lislen - Length of the list + * + * @param(out) *addrlist - Address list of the data packets that are not sent successfully + * + * @return Number of unsent and unacknowledged segments + */ +uint8_t WCHNET_QueryUnack(uint8_t socketid, uint32_t* addrlist, uint16_t lislen); + +/** + * @brief Start DHCP. + * + * @param dhcp - Application layer callback function + * + * @return @ERR_T + */ +uint8_t WCHNET_DHCPStart(dhcp_callback dhcp); + +/** + * @brief Stop DHCP. + * + * @param None + * + * @return @ERR_T + */ +uint8_t WCHNET_DHCPStop(void); + +/** + * @brief Configure DHCP host name. + * + * @param *name - First address of DHCP host name + * + * @return 0 - Success. Others - Failure. + */ +uint8_t WCHNET_DHCPSetHostname(char* name); + +/** + * @brief Initialize the resolver: set up the UDP pcb and configure the default server + * + * @param *dnsip - the IP address of dns server + * @param port - the port number of dns server + * + * @return None + */ +void WCHNET_InitDNS(uint8_t* dnsip, uint16_t port); + +/** + * @brief Stop DNS. + * + * @param None + * + * @return None + */ +void WCHNET_DNSStop(void); + +/** + * Resolve a hostname (string) into an IP address. + * + * @param hostname - the hostname that is to be queried + * @param addr - pointer to a struct ip_addr where to store the address if it is already + * cached in the dns_table (only valid if ERR_OK is returned!) + * @param found - a callback function to be called on success, failure or timeout (only if + * ERR_INPROGRESS is returned!) + * @param arg - argument to pass to the callback function + * + * @return @ERR_T + * WCHNET_ERR_SUCCESS if hostname is a valid IP address string or the host name is already in the local names table. + * ERR_INPROGRESS enqueue a request to be sent to the DNS server for resolution if no errors are present. + */ +uint8_t WCHNET_HostNameGetIp(const char* hostname, uint8_t* addr, dns_callback found, void* arg); + +/** + * @brief Configure KEEP LIVE parameter. + * + * @param *cfg - KEEPLIVE configuration parameter + * + * @return None + */ +void WCHNET_ConfigKeepLive(struct _KEEP_CFG* cfg); + +/** + * @brief Configure socket KEEP LIVE enable. + * + * @param socketid - socket id value + * @param enable - 1: Enabled. 0: Disabled. + * + * @return @ERR_T + */ +uint8_t WCHNET_SocketSetKeepLive(uint8_t socketid, uint8_t enable); + +/** + * @brief Configure PHY state + * + * @param phy_stat - PHY state + * + * @return None + */ +void WCHNET_PhyStatus(uint32_t phy_stat); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/connect_uart.c b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/connect_uart.c index 23d6fa900..f36a7722d 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/connect_uart.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/uart/connect_uart.c @@ -1,35 +1,35 @@ /* -* Copyright (c) 2020 AIIT XUOS Lab -* XiUOS is licensed under Mulan PSL v2. -* You can use this software according to the terms and conditions of the Mulan PSL v2. -* You may obtain a copy of Mulan PSL v2 at: -* http://license.coscl.org.cn/MulanPSL2 -* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, -* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, -* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. -* See the Mulan PSL v2 for more details. -*/ + * Copyright (c) 2020 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ /** -* @file connect_usart.c -* @brief support ch32v307 vct6 uart function and register to bus framework -* @version 1.0 -* @author AIIT XUOS Lab -* @date 2022-08-01 -*/ + * @file connect_usart.c + * @brief support ch32v307 vct6 uart function and register to bus framework + * @version 1.0 + * @author AIIT XUOS Lab + * @date 2022-08-01 + */ -#include -#include "ch32v30x.h" -#include "xsconfig.h" #include "connect_uart.h" +#include "ch32v30x.h" #include "ch32v30x_usart.h" +#include "xsconfig.h" +#include /* uart driver */ static void SerialCfgParamCheck(struct SerialCfgParam* serial_cfg_default, struct SerialCfgParam* serial_cfg_new) { - struct SerialDataCfg *data_cfg_default = &serial_cfg_default->data_cfg; - struct SerialDataCfg *data_cfg_new = &serial_cfg_new->data_cfg; + struct SerialDataCfg* data_cfg_default = &serial_cfg_default->data_cfg; + struct SerialDataCfg* data_cfg_new = &serial_cfg_new->data_cfg; if ((data_cfg_default->serial_baud_rate != data_cfg_new->serial_baud_rate) && (data_cfg_new->serial_baud_rate)) { data_cfg_default->serial_baud_rate = data_cfg_new->serial_baud_rate; @@ -64,40 +64,39 @@ static void SerialCfgParamCheck(struct SerialCfgParam* serial_cfg_default, struc } } -static void UartIsr(struct SerialDriver *serial_drv, struct SerialHardwareDevice *serial_dev) +static void UartIsr(struct SerialDriver* serial_drv, struct SerialHardwareDevice* serial_dev) { - struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_drv->private_data; - - if (RESET != USART_GetITStatus((USART_TypeDef *)serial_cfg->hw_cfg.serial_register_base, USART_IT_RXNE)) - { + struct SerialCfgParam* serial_cfg = (struct SerialCfgParam*)serial_drv->private_data; + + if (RESET != USART_GetITStatus((USART_TypeDef*)serial_cfg->hw_cfg.serial_register_base, USART_IT_RXNE)) { SerialSetIsr(serial_dev, SERIAL_EVENT_RX_IND); - USART_ClearITPendingBit((USART_TypeDef *)serial_cfg->hw_cfg.serial_register_base, USART_IT_RXNE); + USART_ClearITPendingBit((USART_TypeDef*)serial_cfg->hw_cfg.serial_register_base, USART_IT_RXNE); } } -static uint32 SerialInit(struct SerialDriver *serial_drv, struct BusConfigureInfo *configure_info) +static uint32 SerialInit(struct SerialDriver* serial_drv, struct BusConfigureInfo* configure_info) { NULL_PARAM_CHECK(serial_drv); struct SerialCfgParam* serial_cfg = (struct SerialCfgParam*)serial_drv->private_data; // struct UsartHwCfg *serial_hw_cfg = (struct UsartHwCfg *)serial_cfg->hw_cfg.private_data; - struct SerialHardwareDevice *serial_dev = (struct SerialHardwareDevice *)serial_drv->driver.owner_bus->owner_haldev; - struct SerialDevParam *dev_param = (struct SerialDevParam *)serial_dev->haldev.private_data; + struct SerialHardwareDevice* serial_dev = (struct SerialHardwareDevice*)serial_drv->driver.owner_bus->owner_haldev; + struct SerialDevParam* dev_param = (struct SerialDevParam*)serial_dev->haldev.private_data; if (configure_info->private_data) { - struct SerialCfgParam *serial_cfg_new = (struct SerialCfgParam *)configure_info->private_data; + struct SerialCfgParam* serial_cfg_new = (struct SerialCfgParam*)configure_info->private_data; SerialCfgParamCheck(serial_cfg, serial_cfg_new); - + if (serial_cfg_new->data_cfg.dev_recv_callback) { BusDevRecvCallback(&(serial_dev->haldev), serial_cfg_new->data_cfg.dev_recv_callback); } } - // config serial receive sem timeout - dev_param->serial_timeout = serial_cfg->data_cfg.serial_timeout; + // config serial receive sem timeout + dev_param->serial_timeout = serial_cfg->data_cfg.serial_timeout; // init usart type def - GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); @@ -109,8 +108,7 @@ static uint32 SerialInit(struct SerialDriver *serial_drv, struct BusConfigureInf USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate = serial_cfg->data_cfg.serial_baud_rate; - switch (serial_cfg->data_cfg.serial_data_bits) - { + switch (serial_cfg->data_cfg.serial_data_bits) { case DATA_BITS_8: USART_InitStructure.USART_WordLength = USART_WordLength_8b; break; @@ -122,9 +120,8 @@ static uint32 SerialInit(struct SerialDriver *serial_drv, struct BusConfigureInf USART_InitStructure.USART_WordLength = USART_WordLength_8b; break; } - - switch (serial_cfg->data_cfg.serial_stop_bits) - { + + switch (serial_cfg->data_cfg.serial_stop_bits) { case STOP_BITS_1: USART_InitStructure.USART_StopBits = USART_StopBits_1; break; @@ -135,9 +132,8 @@ static uint32 SerialInit(struct SerialDriver *serial_drv, struct BusConfigureInf USART_InitStructure.USART_StopBits = USART_StopBits_1; break; } - - switch (serial_cfg->data_cfg.serial_parity_mode) - { + + switch (serial_cfg->data_cfg.serial_parity_mode) { case PARITY_NONE: USART_InitStructure.USART_Parity = USART_Parity_No; break; @@ -160,81 +156,77 @@ static uint32 SerialInit(struct SerialDriver *serial_drv, struct BusConfigureInf // usart_hardware_flow_rts_config(serial_cfg->hw_cfg.serial_register_base, USART_RTS_DISABLE); // usart_hardware_flow_cts_config(serial_cfg->hw_cfg.serial_register_base, USART_CTS_DISABLE); - return EOK; } -static uint32 SerialConfigure(struct SerialDriver *serial_drv, int serial_operation_cmd) +static uint32 SerialConfigure(struct SerialDriver* serial_drv, int serial_operation_cmd) { NULL_PARAM_CHECK(serial_drv); - struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_drv->private_data; + struct SerialCfgParam* serial_cfg = (struct SerialCfgParam*)serial_drv->private_data; - switch (serial_operation_cmd) - { + switch (serial_operation_cmd) { case OPER_CLR_INT: NVIC_DisableIRQ(serial_cfg->hw_cfg.serial_irq_interrupt); - USART_ITConfig((USART_TypeDef *)serial_cfg->hw_cfg.serial_register_base, USART_IT_RXNE, DISABLE); + USART_ITConfig((USART_TypeDef*)serial_cfg->hw_cfg.serial_register_base, USART_IT_RXNE, DISABLE); break; case OPER_SET_INT: NVIC_EnableIRQ(serial_cfg->hw_cfg.serial_irq_interrupt); /* enable USART0 receive interrupt */ - USART_ITConfig((USART_TypeDef *)serial_cfg->hw_cfg.serial_register_base, USART_IT_RXNE, ENABLE); + USART_ITConfig((USART_TypeDef*)serial_cfg->hw_cfg.serial_register_base, USART_IT_RXNE, ENABLE); break; } - + return EOK; } -static uint32 SerialDrvConfigure(void *drv, struct BusConfigureInfo *configure_info) +static uint32 SerialDrvConfigure(void* drv, struct BusConfigureInfo* configure_info) { NULL_PARAM_CHECK(drv); NULL_PARAM_CHECK(configure_info); x_err_t ret = EOK; int serial_operation_cmd; - struct SerialDriver *serial_drv = (struct SerialDriver *)drv; + struct SerialDriver* serial_drv = (struct SerialDriver*)drv; - switch (configure_info->configure_cmd) - { - case OPE_INT: - ret = SerialInit(serial_drv, configure_info); - break; - case OPE_CFG: - serial_operation_cmd = *(int *)configure_info->private_data; - ret = SerialConfigure(serial_drv, serial_operation_cmd); - break; - default: - break; + switch (configure_info->configure_cmd) { + case OPE_INT: + ret = SerialInit(serial_drv, configure_info); + break; + case OPE_CFG: + serial_operation_cmd = *(int*)configure_info->private_data; + ret = SerialConfigure(serial_drv, serial_operation_cmd); + break; + default: + break; } return ret; } -static int SerialPutChar(struct SerialHardwareDevice *serial_dev, char c) +static int SerialPutChar(struct SerialHardwareDevice* serial_dev, char c) { struct SerialCfgParam* serial_cfg = (struct SerialCfgParam*)serial_dev->private_data; - while (USART_GetFlagStatus((USART_TypeDef *)serial_cfg->hw_cfg.serial_register_base, USART_FLAG_TXE) == RESET); - USART_SendData((USART_TypeDef *)serial_cfg->hw_cfg.serial_register_base, (uint8_t) c); + while (USART_GetFlagStatus((USART_TypeDef*)serial_cfg->hw_cfg.serial_register_base, USART_FLAG_TXE) == RESET) + ; + USART_SendData((USART_TypeDef*)serial_cfg->hw_cfg.serial_register_base, (uint8_t)c); return 0; } -static int SerialGetChar(struct SerialHardwareDevice *serial_dev) +static int SerialGetChar(struct SerialHardwareDevice* serial_dev) { int ch = -1; - struct SerialCfgParam *serial_cfg = (struct SerialCfgParam *)serial_dev->private_data; + struct SerialCfgParam* serial_cfg = (struct SerialCfgParam*)serial_dev->private_data; - if (RESET != USART_GetFlagStatus((USART_TypeDef *)serial_cfg->hw_cfg.serial_register_base, USART_FLAG_RXNE)) - { + if (RESET != USART_GetFlagStatus((USART_TypeDef*)serial_cfg->hw_cfg.serial_register_base, USART_FLAG_RXNE)) { ch = USART_ReceiveData((USART_TypeDef*)serial_cfg->hw_cfg.serial_register_base) & 0xff; } return ch; } -static const struct SerialDataCfg data_cfg_init = -{ +static const struct SerialDataCfg data_cfg_init = { .serial_baud_rate = BAUD_RATE_115200, .serial_data_bits = DATA_BITS_8, .serial_stop_bits = STOP_BITS_1, @@ -246,20 +238,18 @@ static const struct SerialDataCfg data_cfg_init = }; /*manage the serial device operations*/ -static const struct SerialDrvDone drv_done = -{ +static const struct SerialDrvDone drv_done = { .init = SerialInit, .configure = SerialConfigure, }; /*manage the serial device hal operations*/ -static struct SerialHwDevDone hwdev_done = -{ +static struct SerialHwDevDone hwdev_done = { .put_char = SerialPutChar, .get_char = SerialGetChar, }; -static int BoardSerialBusInit(struct SerialBus *serial_bus, struct SerialDriver *serial_driver, const char *bus_name, const char *drv_name) +static int BoardSerialBusInit(struct SerialBus* serial_bus, struct SerialDriver* serial_driver, const char* bus_name, const char* drv_name) { x_err_t ret = EOK; @@ -282,13 +272,13 @@ static int BoardSerialBusInit(struct SerialBus *serial_bus, struct SerialDriver if (EOK != ret) { KPrintf("InitHwUart SerialDriverAttachToBus error %d\n", ret); return ERROR; - } + } return ret; } /*Attach the serial device to the serial bus*/ -static int BoardSerialDevBend(struct SerialHardwareDevice *serial_device, void *serial_param, const char *bus_name, const char *dev_name) +static int BoardSerialDevBend(struct SerialHardwareDevice* serial_device, void* serial_param, const char* bus_name, const char* dev_name) { x_err_t ret = EOK; @@ -296,27 +286,27 @@ static int BoardSerialDevBend(struct SerialHardwareDevice *serial_device, void * if (EOK != ret) { KPrintf("InitHwUart SerialDeviceInit device %s error %d\n", dev_name, ret); return ERROR; - } + } ret = SerialDeviceAttachToBus(dev_name, bus_name); if (EOK != ret) { KPrintf("InitHwUart SerialDeviceAttachToBus device %s error %d\n", dev_name, ret); return ERROR; - } + } - return ret; + return ret; } #ifdef BSP_USING_UART1 struct SerialDriver serial_driver_1; struct SerialHardwareDevice serial_device_1; -void USART1_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast"))); +void USART1_IRQHandler(void) __attribute__((interrupt())); void USART1_IRQHandler(void) { GET_INT_SP(); x_base level; - level= DisableLocalInterrupt(); + level = DisableLocalInterrupt(); isrManager.done->incCounter(); EnableLocalInterrupt(level); UartIsr(&serial_driver_1, &serial_device_1); @@ -333,7 +323,7 @@ int InitHwUart(void) static struct SerialBus serial_bus; memset(&serial_bus, 0, sizeof(struct SerialBus)); - + memset(&serial_driver_1, 0, sizeof(struct SerialDriver)); memset(&serial_device_1, 0, sizeof(struct SerialHardwareDevice)); @@ -343,7 +333,7 @@ int InitHwUart(void) static struct SerialDevParam serial_dev_param; memset(&serial_dev_param, 0, sizeof(struct SerialDevParam)); - + serial_driver_1.drv_done = &drv_done; serial_driver_1.configure = &SerialDrvConfigure; serial_device_1.hwdev_done = &hwdev_done; @@ -354,11 +344,11 @@ int InitHwUart(void) serial_cfg.hw_cfg.serial_register_base = (uint32)USART1; serial_cfg.hw_cfg.serial_irq_interrupt = USART1_IRQn; #endif - + serial_driver_1.private_data = (void*)&serial_cfg; serial_dev_param.serial_work_mode = SIGN_OPER_INT_RX; - serial_device_1.haldev.private_data = (void *)&serial_dev_param; + serial_device_1.haldev.private_data = (void*)&serial_dev_param; ret = BoardSerialBusInit(&serial_bus, &serial_driver_1, SERIAL_BUS_NAME_1, SERIAL_DRV_NAME_1); if (EOK != ret) { @@ -366,7 +356,7 @@ int InitHwUart(void) return ERROR; } - ret = BoardSerialDevBend(&serial_device_1, (void *)&serial_cfg, SERIAL_BUS_NAME_1, SERIAL_1_DEVICE_NAME_0); + ret = BoardSerialDevBend(&serial_device_1, (void*)&serial_cfg, SERIAL_BUS_NAME_1, SERIAL_1_DEVICE_NAME_0); if (EOK != ret) { KPrintf("InitHwUart uarths error ret %u\n", ret); return ERROR; @@ -384,14 +374,14 @@ int InitHwUart(void) GPIO_Init(GPIOA, &gpio_init_struct); USART_InitTypeDef usart_init_struct; - usart_init_struct.USART_BaudRate = 115200; - usart_init_struct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; - usart_init_struct.USART_Mode = USART_Mode_Tx|USART_Mode_Rx; - usart_init_struct.USART_WordLength = USART_WordLength_8b; - usart_init_struct.USART_StopBits = USART_StopBits_1; - usart_init_struct.USART_Parity = USART_Parity_No; - USART_Init((USART_TypeDef *)serial_cfg.hw_cfg.serial_register_base, &usart_init_struct); + usart_init_struct.USART_BaudRate = 115200; + usart_init_struct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; + usart_init_struct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; + usart_init_struct.USART_WordLength = USART_WordLength_8b; + usart_init_struct.USART_StopBits = USART_StopBits_1; + usart_init_struct.USART_Parity = USART_Parity_No; + USART_Init((USART_TypeDef*)serial_cfg.hw_cfg.serial_register_base, &usart_init_struct); USART_Cmd((USART_TypeDef*)serial_cfg.hw_cfg.serial_register_base, ENABLE); - + return ret; } \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/link.mk b/Ubiquitous/XiZi_IIoT/link.mk index 09e643226..97dcbba8f 100644 --- a/Ubiquitous/XiZi_IIoT/link.mk +++ b/Ubiquitous/XiZi_IIoT/link.mk @@ -3,7 +3,7 @@ OBJS := $(shell cat make.obj) $(TARGET): $(OBJS) @echo ------------------------------------------------ @echo link $(TARGET) - @$(CROSS_COMPILE)g++ -o $@ $($(LINK_FLAGS)) $(OBJS) $(LINK_LWIP) $(LINK_MUSLLIB) $(LINK_MONGOOSE) $(LIBCC) + @$(CROSS_COMPILE)g++ -o $@ $($(LINK_FLAGS)) $(OBJS) $(LINK_LWIP) $(LINK_MUSLLIB) $(LINK_MONGOOSE) $(LINK_WCH_NET) $(LIBCC) @echo ------------------------------------------------ @$(CROSS_COMPILE)objcopy -O binary $@ XiZi-$(BOARD)$(COMPILE_TYPE).bin @$(CROSS_COMPILE)objdump -S $@ > XiZi-$(BOARD)$(COMPILE_TYPE).asm