699 lines
23 KiB
C
699 lines
23 KiB
C
|
|
/********************************** (C) COPYRIGHT *******************************
|
|||
|
|
* File Name : eth_driver.c
|
|||
|
|
* Author : WCH
|
|||
|
|
* Version : V1.0.0
|
|||
|
|
* Date : 2024/05/05
|
|||
|
|
* 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 <string.h>
|
|||
|
|
#include "eth_driver.h"
|
|||
|
|
#include "net_config.h"
|
|||
|
|
|
|||
|
|
__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 */
|
|||
|
|
__attribute__((__aligned__(4))) uint8_t RemoteIp[4]; /* DNS 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;
|
|||
|
|
volatile uint32_t LocalTime;
|
|||
|
|
volatile uint8_t PhyWaitNegotiationSuc = 0;
|
|||
|
|
ETH_DMADESCTypeDef *pDMARxSet;
|
|||
|
|
ETH_DMADESCTypeDef *pDMATxSet;
|
|||
|
|
|
|||
|
|
volatile uint8_t LinkSta = 0; //0:Link down 1:Link up
|
|||
|
|
uint8_t LinkVaildFlag = 0; //0:invalid 1:valid
|
|||
|
|
uint8_t AccelerateLinkFlag = 0; //0:invalid 1:valid
|
|||
|
|
uint8_t LinkProcessingStep = 0;
|
|||
|
|
uint32_t LinkProcessingTime = 0;
|
|||
|
|
uint32_t TaskExecutionTime = 0;
|
|||
|
|
void ETH_LinkDownCfg(void);
|
|||
|
|
/*********************************************************************
|
|||
|
|
* @fn WCHNET_TimeIsr
|
|||
|
|
*
|
|||
|
|
* @brief
|
|||
|
|
*
|
|||
|
|
* @return none.
|
|||
|
|
*/
|
|||
|
|
void WCHNET_TimeIsr( uint16_t timperiod )
|
|||
|
|
{
|
|||
|
|
LocalTime += timperiod;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*********************************************************************
|
|||
|
|
* @fn WCHNET_QueryPhySta
|
|||
|
|
*
|
|||
|
|
* @brief Query external PHY status
|
|||
|
|
*
|
|||
|
|
* @return none.
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
void WCHNET_QueryPhySta(void)
|
|||
|
|
{
|
|||
|
|
if(PhyWaitNegotiationSuc)
|
|||
|
|
{
|
|||
|
|
ETH_PHYLink();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*********************************************************************
|
|||
|
|
* @fn WCHNET_CheckPHYPN
|
|||
|
|
*
|
|||
|
|
* @brief check PHY PN polarity
|
|||
|
|
*
|
|||
|
|
* @return none.
|
|||
|
|
*/
|
|||
|
|
void WCHNET_CheckPHYPN(uint16_t time)
|
|||
|
|
{
|
|||
|
|
uint16_t phy_stat;
|
|||
|
|
//check PHY PN
|
|||
|
|
if((LinkProcessingStep == 0)||(LocalTime >= LinkProcessingTime))
|
|||
|
|
{
|
|||
|
|
ETH_WritePHYRegister(gPHYAddress, PHY_PAG_SEL, PHY_REG_PAGE0 );
|
|||
|
|
phy_stat = ETH_ReadPHYRegister( gPHYAddress, PHY_STATUS1);
|
|||
|
|
if(phy_stat & (1<<4))
|
|||
|
|
{
|
|||
|
|
if(LinkProcessingStep == 0)
|
|||
|
|
{
|
|||
|
|
LinkProcessingStep = 1;
|
|||
|
|
LinkProcessingTime = LocalTime + time;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
LinkProcessingStep = 0;
|
|||
|
|
LinkProcessingTime = 0;
|
|||
|
|
phy_stat = ETH_ReadPHYRegister( gPHYAddress, PHY_ANER);
|
|||
|
|
if((time == 200) || ((phy_stat & 1) == 0))
|
|||
|
|
{
|
|||
|
|
phy_stat = ETH_ReadPHYRegister( gPHYAddress, PHY_CONTROL1);
|
|||
|
|
phy_stat |= 1;
|
|||
|
|
ETH_WritePHYRegister(gPHYAddress, PHY_CONTROL1, phy_stat );
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
LinkProcessingStep = 0;
|
|||
|
|
LinkProcessingTime = 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*********************************************************************
|
|||
|
|
* @fn WCHNET_AccelerateLink
|
|||
|
|
*
|
|||
|
|
* @brief accelerate Link processing
|
|||
|
|
*
|
|||
|
|
* @return none.
|
|||
|
|
*/
|
|||
|
|
void WCHNET_AccelerateLink(void)
|
|||
|
|
{
|
|||
|
|
uint16_t phy_stat;
|
|||
|
|
if(AccelerateLinkFlag == 0)
|
|||
|
|
{
|
|||
|
|
ETH_WritePHYRegister(gPHYAddress, PHY_PAG_SEL, 99 );
|
|||
|
|
phy_stat = ETH_ReadPHYRegister( gPHYAddress, 0x19);
|
|||
|
|
if((phy_stat & 0xf) == 3)
|
|||
|
|
{
|
|||
|
|
AccelerateLinkFlag = 1;
|
|||
|
|
ETH_WritePHYRegister(gPHYAddress, PHY_PAG_SEL, PHY_REG_PAGE0 );
|
|||
|
|
phy_stat = 0x4;
|
|||
|
|
ETH_WritePHYRegister(gPHYAddress, 0x16, phy_stat );
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*********************************************************************
|
|||
|
|
* @fn WCHNET_CheckLinkVaild
|
|||
|
|
*
|
|||
|
|
* @brief check whether Link is valid
|
|||
|
|
*
|
|||
|
|
* @return none.
|
|||
|
|
*/
|
|||
|
|
void WCHNET_CheckLinkVaild(void)
|
|||
|
|
{
|
|||
|
|
uint16_t phy_stat, phy_bcr;
|
|||
|
|
|
|||
|
|
if(LinkVaildFlag == 0)
|
|||
|
|
{
|
|||
|
|
phy_bcr = ETH_ReadPHYRegister( PHY_ADDRESS, PHY_BCR);
|
|||
|
|
if((phy_bcr & (1<<13)) == 0) //Do nothing if Link mode is 10M.
|
|||
|
|
{
|
|||
|
|
LinkVaildFlag = 1;
|
|||
|
|
LinkProcessingTime = 0;
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
ETH_WritePHYRegister(gPHYAddress, PHY_PAG_SEL, 99 );
|
|||
|
|
phy_stat = ETH_ReadPHYRegister( gPHYAddress, 0x1b);
|
|||
|
|
if((phy_stat & (1<<2)) == 0)
|
|||
|
|
{
|
|||
|
|
LinkProcessingTime++;
|
|||
|
|
if(LinkProcessingTime == 5)
|
|||
|
|
{
|
|||
|
|
LinkProcessingTime = 0;
|
|||
|
|
phy_stat = ETH_ReadPHYRegister(gPHYAddress, PHY_BCR);
|
|||
|
|
ETH_WritePHYRegister(gPHYAddress, PHY_BCR, PHY_Reset );
|
|||
|
|
Delay_Us(100);
|
|||
|
|
ETH_WritePHYRegister(gPHYAddress, PHY_BCR, phy_stat );
|
|||
|
|
ETH_LinkDownCfg();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
LinkVaildFlag = 1;
|
|||
|
|
LinkProcessingTime = 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*********************************************************************
|
|||
|
|
* @fn WCHNET_LinkProcessing
|
|||
|
|
*
|
|||
|
|
* @brief process Link stage task
|
|||
|
|
*
|
|||
|
|
* @return none.
|
|||
|
|
*/
|
|||
|
|
void WCHNET_LinkProcessing(void)
|
|||
|
|
{
|
|||
|
|
u16 phy_bcr;
|
|||
|
|
|
|||
|
|
if(LocalTime >= TaskExecutionTime)
|
|||
|
|
{
|
|||
|
|
TaskExecutionTime = LocalTime + 10; //execution cycle:10ms
|
|||
|
|
if(LinkSta == 0) //Link down
|
|||
|
|
{
|
|||
|
|
phy_bcr = ETH_ReadPHYRegister( PHY_ADDRESS, PHY_BCR);
|
|||
|
|
if(phy_bcr & PHY_AutoNegotiation) //auto-negotiation is enabled
|
|||
|
|
{
|
|||
|
|
WCHNET_CheckPHYPN(300); //check PHY PN
|
|||
|
|
WCHNET_AccelerateLink(); //accelerate Link processing
|
|||
|
|
}
|
|||
|
|
else { //auto-negotiation is disabled
|
|||
|
|
if((phy_bcr & (1<<13)) == 0) // 10M
|
|||
|
|
{
|
|||
|
|
WCHNET_CheckPHYPN(200); //check PHY PN
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else { //Link up
|
|||
|
|
WCHNET_CheckLinkVaild(); //check whether Link is valid
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*********************************************************************
|
|||
|
|
* @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 */
|
|||
|
|
WCHNET_QueryPhySta();
|
|||
|
|
WCHNET_LinkProcessing();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*********************************************************************
|
|||
|
|
* @fn ETH_LinkUpCfg
|
|||
|
|
*
|
|||
|
|
* @brief When the PHY is connected, configure the relevant functions.
|
|||
|
|
*
|
|||
|
|
* @param none.
|
|||
|
|
*
|
|||
|
|
* @return none.
|
|||
|
|
*/
|
|||
|
|
void ETH_LinkUpCfg(void)
|
|||
|
|
{
|
|||
|
|
uint16_t phy_stat;
|
|||
|
|
|
|||
|
|
LinkSta = 1;
|
|||
|
|
AccelerateLinkFlag = 0;
|
|||
|
|
LinkProcessingStep = 0;
|
|||
|
|
LinkProcessingTime = 0;
|
|||
|
|
PhyWaitNegotiationSuc = 0;
|
|||
|
|
ETH_Start( );
|
|||
|
|
|
|||
|
|
ETH_WritePHYRegister(gPHYAddress, PHY_PAG_SEL, PHY_REG_PAGE0 );
|
|||
|
|
phy_stat = 0x0;
|
|||
|
|
ETH_WritePHYRegister(gPHYAddress, 0x16, phy_stat );
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*********************************************************************
|
|||
|
|
* @fn ETH_LinkDownCfg
|
|||
|
|
*
|
|||
|
|
* @brief When the PHY is disconnected, configure the relevant functions.
|
|||
|
|
*
|
|||
|
|
* @param none.
|
|||
|
|
*
|
|||
|
|
* @return none.
|
|||
|
|
*/
|
|||
|
|
void ETH_LinkDownCfg(void)
|
|||
|
|
{
|
|||
|
|
LinkSta = 0;
|
|||
|
|
LinkVaildFlag = 0;
|
|||
|
|
LinkProcessingTime = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*********************************************************************
|
|||
|
|
* @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, phy_anlpar, phy_bcr;
|
|||
|
|
|
|||
|
|
phy_stat = ETH_ReadPHYRegister( PHY_ADDRESS, PHY_BSR );
|
|||
|
|
phy_anlpar = ETH_ReadPHYRegister( PHY_ADDRESS, PHY_ANLPAR);
|
|||
|
|
phy_bcr = ETH_ReadPHYRegister( gPHYAddress, PHY_BCR);
|
|||
|
|
WCHNET_PhyStatus( phy_stat );
|
|||
|
|
|
|||
|
|
if(phy_stat & PHY_Linked_Status) //LinkUp
|
|||
|
|
{
|
|||
|
|
if(phy_bcr & PHY_AutoNegotiation)
|
|||
|
|
{
|
|||
|
|
if(phy_anlpar == 0)
|
|||
|
|
{
|
|||
|
|
ETH_LinkUpCfg();
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
if(phy_stat & PHY_AutoNego_Complete)
|
|||
|
|
{
|
|||
|
|
ETH_LinkUpCfg();
|
|||
|
|
}
|
|||
|
|
else{
|
|||
|
|
PhyWaitNegotiationSuc = 1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
ETH_LinkUpCfg();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else { //LinkDown
|
|||
|
|
/*Link down*/
|
|||
|
|
ETH_LinkDownCfg();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*********************************************************************
|
|||
|
|
* @fn ETH_CheckPhyInterruptStatus
|
|||
|
|
*
|
|||
|
|
* @brief MAC check PHY interrupt status.
|
|||
|
|
*
|
|||
|
|
* @param none.
|
|||
|
|
*
|
|||
|
|
* @return none.
|
|||
|
|
*/
|
|||
|
|
void ETH_CheckPhyInterruptStatus( void )
|
|||
|
|
{
|
|||
|
|
uint16_t phyIntStat;
|
|||
|
|
|
|||
|
|
ETH_WritePHYRegister(gPHYAddress, PHY_PAG_SEL, PHY_REG_PAGE17 );
|
|||
|
|
phyIntStat = ETH_ReadPHYRegister( gPHYAddress, PHY_WOL_STATUS);
|
|||
|
|
|
|||
|
|
if(phyIntStat & WOL_DONE_INT)
|
|||
|
|
{
|
|||
|
|
/* Wol done */
|
|||
|
|
}
|
|||
|
|
else /* Link status change*/
|
|||
|
|
{
|
|||
|
|
ETH_PHYLink();
|
|||
|
|
}
|
|||
|
|
ETH_WritePHYRegister(gPHYAddress, PHY_PAG_SEL, PHY_REG_PAGE0 );
|
|||
|
|
phyIntStat = ETH_ReadPHYRegister( gPHYAddress, 0x1E); /* Clear the Interrupt status */
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*********************************************************************
|
|||
|
|
* @fn PHY_InterruptInit
|
|||
|
|
*
|
|||
|
|
* @brief Configure PHY interrupt function
|
|||
|
|
*
|
|||
|
|
* @param none.
|
|||
|
|
*
|
|||
|
|
* @return none.
|
|||
|
|
*/
|
|||
|
|
void PHY_InterruptInit(void)
|
|||
|
|
{
|
|||
|
|
uint16_t RegValue;
|
|||
|
|
|
|||
|
|
ETH_WritePHYRegister(gPHYAddress, PHY_PAG_SEL, PHY_REG_PAGE7 );
|
|||
|
|
/* Configure interrupt function */
|
|||
|
|
RegValue = ETH_ReadPHYRegister(gPHYAddress, PHY_INTERRUPT_MASK);
|
|||
|
|
RegValue |= 0x01 << 13;
|
|||
|
|
ETH_WritePHYRegister(gPHYAddress, PHY_INTERRUPT_MASK, RegValue );
|
|||
|
|
/* Clear the Interrupt status */
|
|||
|
|
ETH_WritePHYRegister(gPHYAddress, PHY_PAG_SEL, PHY_REG_PAGE0 );
|
|||
|
|
ETH_ReadPHYRegister( gPHYAddress, PHY_INTERRUPT_IND);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*********************************************************************
|
|||
|
|
* @fn PHY_LEDCfg
|
|||
|
|
*
|
|||
|
|
* @brief Configure PHY LED function
|
|||
|
|
*
|
|||
|
|
* @param none.
|
|||
|
|
*
|
|||
|
|
* @return none.
|
|||
|
|
*/
|
|||
|
|
void PHY_LEDCfg(void)
|
|||
|
|
{
|
|||
|
|
uint16_t RegValue;
|
|||
|
|
|
|||
|
|
ETH_WritePHYRegister(gPHYAddress, PHY_PAG_SEL, PHY_REG_PAGE7 );
|
|||
|
|
//turn on LED--PHY
|
|||
|
|
RegValue = ETH_ReadPHYRegister(gPHYAddress, PHY_INTERRUPT_MASK);
|
|||
|
|
RegValue |= 1<<9;
|
|||
|
|
ETH_WritePHYRegister(gPHYAddress, PHY_INTERRUPT_MASK, RegValue );
|
|||
|
|
|
|||
|
|
//<2F><>link_led<65><64>ӳ<EFBFBD>䵽PB17
|
|||
|
|
R32_AFIO_PCFR1 |= 1<<30;
|
|||
|
|
|
|||
|
|
//<2F><>act_led<65><64>ӳ<EFBFBD>䵽PB6
|
|||
|
|
R32_AFIO_PCFR2 |= 1<<1;
|
|||
|
|
|
|||
|
|
//turn on LED--MCU <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>CH564RM V1.1<EFBFBD>ֲ<EFBFBD><EFBFBD><EFBFBD>û<EFBFBD>ж<EFBFBD>Ӧ<EFBFBD><EFBFBD>˵<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʳ<EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
ETH_LED_CTRL = 0x05;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*********************************************************************
|
|||
|
|
* @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_Watchdog |
|
|||
|
|
ETH_InitStruct->ETH_Jabber |
|
|||
|
|
ETH_InitStruct->ETH_InterFrameGap |
|
|||
|
|
ETH_InitStruct->ETH_ChecksumOffload |
|
|||
|
|
ETH_InitStruct->ETH_AutomaticPadCRCStrip |
|
|||
|
|
ETH_InitStruct->ETH_DeferralCheck |
|
|||
|
|
(1 << 20));
|
|||
|
|
/* Write MAC Control Register */
|
|||
|
|
ETH->MACCR = (uint32_t)tmpreg;
|
|||
|
|
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_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_FlushReceivedFrame |
|
|||
|
|
ETH_InitStruct->ETH_TransmitStoreForward |
|
|||
|
|
ETH_InitStruct->ETH_ForwardErrorFrames |
|
|||
|
|
ETH_InitStruct->ETH_ForwardUndersizedGoodFrames);
|
|||
|
|
ETH->DMAOMR = (uint32_t)tmpreg;
|
|||
|
|
|
|||
|
|
/* Reset the physical layer */
|
|||
|
|
ETH_WritePHYRegister(PHYAddress, PHY_BCR, PHY_Reset);
|
|||
|
|
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;
|
|||
|
|
|
|||
|
|
/* Configure Ethernet for normal operating mode*/
|
|||
|
|
ETH->PHY_CR |= 1<<31;
|
|||
|
|
ETH->PHY_CR &= ~(1<<30);
|
|||
|
|
|
|||
|
|
gPHYAddress = PHY_ADDRESS;
|
|||
|
|
|
|||
|
|
/* 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 -----------------------------------*/
|
|||
|
|
#if HARDWARE_CHECKSUM_CONFIG
|
|||
|
|
ETH_InitStructure.ETH_ChecksumOffload = ETH_ChecksumOffload_Enable;
|
|||
|
|
#endif
|
|||
|
|
ETH_InitStructure.ETH_AutomaticPadCRCStrip = ETH_AutomaticPadCRCStrip_Disable;
|
|||
|
|
/* Filter function configuration */
|
|||
|
|
ETH_InitStructure.ETH_ReceiveAll = ETH_ReceiveAll_Enable;
|
|||
|
|
ETH_InitStructure.ETH_PromiscuousMode = ETH_PromiscuousMode_Enable;
|
|||
|
|
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_TransmitStoreForward = ETH_TransmitStoreForward_Enable;
|
|||
|
|
ETH_InitStructure.ETH_ForwardErrorFrames = ETH_ForwardErrorFrames_Enable;
|
|||
|
|
ETH_InitStructure.ETH_ForwardUndersizedGoodFrames = ETH_ForwardUndersizedGoodFrames_Enable;
|
|||
|
|
/* 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_RFAEM | ETH_MMCRIMR_RFCEM;
|
|||
|
|
|
|||
|
|
PHY_InterruptInit();
|
|||
|
|
|
|||
|
|
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_PHYSR,\
|
|||
|
|
ENABLE);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*********************************************************************
|
|||
|
|
* @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 intStat;
|
|||
|
|
|
|||
|
|
intStat = ETH->DMASR;
|
|||
|
|
if (intStat & ETH_DMA_FLAG_AIS)
|
|||
|
|
{
|
|||
|
|
if (intStat & ETH_DMA_FLAG_RBU)
|
|||
|
|
{
|
|||
|
|
ETH_DMAClearITPendingBit(ETH_DMA_FLAG_RBU);
|
|||
|
|
}
|
|||
|
|
ETH_DMAClearITPendingBit(ETH_DMA_FLAG_AIS);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if( intStat & ETH_DMA_FLAG_NIS )
|
|||
|
|
{
|
|||
|
|
if( intStat & ETH_DMA_FLAG_R )
|
|||
|
|
{
|
|||
|
|
/*If you don't use the Ethernet library,
|
|||
|
|
* you can do some data processing operations here*/
|
|||
|
|
ETH_DMAClearITPendingBit(ETH_DMA_FLAG_R);
|
|||
|
|
}
|
|||
|
|
if( intStat & ETH_DMA_FLAG_T )
|
|||
|
|
{
|
|||
|
|
ETH_DMAClearITPendingBit(ETH_DMA_FLAG_T);
|
|||
|
|
}
|
|||
|
|
if( intStat & ETH_DMA_FLAG_PHYSR)
|
|||
|
|
{
|
|||
|
|
ETH_CheckPhyInterruptStatus( );
|
|||
|
|
ETH_DMAClearITPendingBit(ETH_DMA_FLAG_PHYSR);
|
|||
|
|
}
|
|||
|
|
ETH_DMAClearITPendingBit(ETH_DMA_FLAG_NIS);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*********************************************************************
|
|||
|
|
* @fn ETH_Init
|
|||
|
|
*
|
|||
|
|
* @brief Ethernet initialization.
|
|||
|
|
*
|
|||
|
|
* @return none
|
|||
|
|
*/
|
|||
|
|
void ETH_Init( uint8_t *macAddr )
|
|||
|
|
{
|
|||
|
|
ETH_Configuration( macAddr );
|
|||
|
|
PHY_LEDCfg();
|
|||
|
|
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;
|
|||
|
|
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 ******************************/
|