📄 lpc17xx_emac.c
字号:
// Write to MAC configuration register and reset
LPC_EMAC->MCFG = EMAC_MCFG_CLK_SEL(tout) | EMAC_MCFG_RES_MII;
// release reset
LPC_EMAC->MCFG &= ~(EMAC_MCFG_RES_MII);
LPC_EMAC->CLRT = EMAC_CLRT_DEF;
LPC_EMAC->IPGR = EMAC_IPGR_P2_DEF;
/* Enable Reduced MII interface. */
LPC_EMAC->Command = EMAC_CR_RMII | EMAC_CR_PASS_RUNT_FRM;
/* Reset Reduced MII Logic. */
LPC_EMAC->SUPP = EMAC_SUPP_RES_RMII;
for (tout = 100; tout; tout--);
LPC_EMAC->SUPP = 0;
/* Put the DP83848C in reset mode */
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_BMCR_RESET);
/* Wait for hardware reset to end. */
for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) {
regv = read_PHY (EMAC_PHY_REG_BMCR);
if (!(regv & (EMAC_PHY_BMCR_RESET | EMAC_PHY_BMCR_POWERDOWN))) {
/* Reset complete, device not Power Down. */
break;
}
if (tout == 0){
// Time out, return ERROR
return (ERROR);
}
}
// Set PHY mode
if (EMAC_SetPHYMode(EMAC_ConfigStruct->Mode) < 0){
return (ERROR);
}
// Set EMAC address
setEmacAddr(EMAC_ConfigStruct->pbEMAC_Addr);
/* Initialize Tx and Rx DMA Descriptors */
rx_descr_init ();
tx_descr_init ();
// Set Receive Filter register: enable broadcast and multicast
LPC_EMAC->RxFilterCtrl = EMAC_RFC_MCAST_EN | EMAC_RFC_BCAST_EN | EMAC_RFC_PERFECT_EN;
/* Enable Rx Done and Tx Done interrupt for EMAC */
LPC_EMAC->IntEnable = EMAC_INT_RX_DONE | EMAC_INT_TX_DONE;
/* Reset all interrupts */
LPC_EMAC->IntClear = 0xFFFF;
/* Enable receive and transmit mode of MAC Ethernet core */
LPC_EMAC->Command |= (EMAC_CR_RX_EN | EMAC_CR_TX_EN);
LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN;
return SUCCESS;
}
/*********************************************************************//**
* @brief De-initializes the EMAC peripheral registers to their
* default reset values.
* @param[in] None
* @return None
**********************************************************************/
void EMAC_DeInit(void)
{
// Disable all interrupt
LPC_EMAC->IntEnable = 0x00;
// Clear all pending interrupt
LPC_EMAC->IntClear = (0xFF) | (EMAC_INT_SOFT_INT | EMAC_INT_WAKEUP);
/* TurnOff clock and power for Ethernet module */
CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCENET, DISABLE);
}
/*********************************************************************//**
* @brief Check specified PHY status in EMAC peripheral
* @param[in] ulPHYState Specified PHY Status Type, should be:
* - EMAC_PHY_STAT_LINK: Link Status
* - EMAC_PHY_STAT_SPEED: Speed Status
* - EMAC_PHY_STAT_DUP: Duplex Status
* @return Status of specified PHY status (0 or 1).
* (-1) if error.
*
* Note:
* For EMAC_PHY_STAT_LINK, return value:
* - 0: Link Down
* - 1: Link Up
* For EMAC_PHY_STAT_SPEED, return value:
* - 0: 10Mbps
* - 1: 100Mbps
* For EMAC_PHY_STAT_DUP, return value:
* - 0: Half-Duplex
* - 1: Full-Duplex
**********************************************************************/
int32_t EMAC_CheckPHYStatus(uint32_t ulPHYState)
{
int32_t regv, tmp;
#ifdef MCB_LPC_1768
regv = read_PHY (EMAC_PHY_REG_STS);
switch(ulPHYState){
case EMAC_PHY_STAT_LINK:
tmp = (regv & EMAC_PHY_SR_LINK) ? 1 : 0;
break;
case EMAC_PHY_STAT_SPEED:
tmp = (regv & EMAC_PHY_SR_SPEED) ? 0 : 1;
break;
case EMAC_PHY_STAT_DUP:
tmp = (regv & EMAC_PHY_SR_FULL_DUP) ? 1 : 0;
break;
#elif defined(IAR_LPC_1768)
/* Use IAR_LPC_1768 board:
* FSZ8721BL doesn't have Status Register
* so we read Basic Mode Status Register (0x01h) instead
*/
regv = read_PHY (EMAC_PHY_REG_BMSR);
switch(ulPHYState){
case EMAC_PHY_STAT_LINK:
tmp = (regv & EMAC_PHY_BMSR_LINK_STATUS) ? 1 : 0;
break;
case EMAC_PHY_STAT_SPEED:
tmp = (regv & EMAC_PHY_SR_100_SPEED) ? 1 : 0;
break;
case EMAC_PHY_STAT_DUP:
tmp = (regv & EMAC_PHY_SR_FULL_DUP) ? 1 : 0;
break;
#endif
default:
tmp = -1;
break;
}
return (tmp);
}
/*********************************************************************//**
* @brief Set specified PHY mode in EMAC peripheral
* @param[in] ulPHYMode Specified PHY mode, should be:
* - EMAC_MODE_AUTO
* - EMAC_MODE_10M_FULL
* - EMAC_MODE_10M_HALF
* - EMAC_MODE_100M_FULL
* - EMAC_MODE_100M_HALF
* @return Return (0) if no error, otherwise return (-1)
**********************************************************************/
int32_t EMAC_SetPHYMode(uint32_t ulPHYMode)
{
int32_t id1, id2, tout, regv;
/* Check if this is a DP83848C PHY. */
id1 = read_PHY (EMAC_PHY_REG_IDR1);
id2 = read_PHY (EMAC_PHY_REG_IDR2);
#ifdef MCB_LPC_1768
if (((id1 << 16) | (id2 & 0xFFF0)) == EMAC_DP83848C_ID) {
switch(ulPHYMode){
case EMAC_MODE_AUTO:
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_AUTO_NEG);
#elif defined(IAR_LPC_1768) /* Use IAR LPC1768 KickStart board */
if (((id1 << 16) | id2) == EMAC_KSZ8721BL_ID) {
/* Configure the PHY device */
switch(ulPHYMode){
case EMAC_MODE_AUTO:
/* Use auto-negotiation about the link speed. */
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_AUTO_NEG);
// write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_BMCR_AN);
#endif
/* Wait to complete Auto_Negotiation */
for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) {
regv = read_PHY (EMAC_PHY_REG_BMSR);
if (regv & EMAC_PHY_BMSR_AUTO_DONE) {
/* Auto-negotiation Complete. */
break;
}
if (tout == 0){
// Time out, return error
return (-1);
}
/* *wait for link */
OSTimeDlyHMSM(0, 0, 0, 50); /* 50 MS */
}
break;
case EMAC_MODE_10M_FULL:
/* Connect at 10MBit full-duplex */
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_FULLD_10M);
break;
case EMAC_MODE_10M_HALF:
/* Connect at 10MBit half-duplex */
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_HALFD_10M);
break;
case EMAC_MODE_100M_FULL:
/* Connect at 100MBit full-duplex */
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_FULLD_100M);
break;
case EMAC_MODE_100M_HALF:
/* Connect at 100MBit half-duplex */
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_HALFD_100M);
break;
default:
// un-supported
return (-1);
}
}
// It's not correct module ID
else {
return (-1);
}
// Update EMAC configuration with current PHY status
if (EMAC_UpdatePHYStatus() < 0){
return (-1);
}
// Complete
return (0);
}
/*********************************************************************//**
* @brief Auto-Configures value for the EMAC configuration register to
* match with current PHY mode
* @param[in] None
* @return Return (0) if no error, otherwise return (-1)
*
* Note: The EMAC configuration will be auto-configured:
* - Speed mode.
* - Half/Full duplex mode
**********************************************************************/
int32_t EMAC_UpdatePHYStatus(void)
{
int32_t regv, tout;
/* Check the link status. */
#ifdef MCB_LPC_1768
for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) {
regv = read_PHY (EMAC_PHY_REG_STS);
if (regv & EMAC_PHY_SR_LINK) {
/* Link is on. */
break;
}
if (tout == 0){
// time out
return (-1);
}
}
/* Configure Full/Half Duplex mode. */
if (regv & EMAC_PHY_SR_DUP) {
/* Full duplex is enabled. */
LPC_EMAC->MAC2 |= EMAC_MAC2_FULL_DUP;
LPC_EMAC->Command |= EMAC_CR_FULL_DUP;
LPC_EMAC->IPGT = EMAC_IPGT_FULL_DUP;
} else {
/* Half duplex mode. */
LPC_EMAC->IPGT = EMAC_IPGT_HALF_DUP;
}
if (regv & EMAC_PHY_SR_SPEED) {
/* 10MBit mode. */
LPC_EMAC->SUPP = 0;
} else {
/* 100MBit mode. */
LPC_EMAC->SUPP = EMAC_SUPP_SPEED;
}
#elif defined(IAR_LPC_1768)
for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) {
regv = read_PHY (EMAC_PHY_REG_BMSR);
if (regv & EMAC_PHY_BMSR_LINK_STATUS) {
/* Link is on. */
break;
}
if (tout == 0){
// time out
return (-1);
}
}
/* Configure Full/Half Duplex mode. */
if (regv & EMAC_PHY_SR_FULL_DUP) {
/* Full duplex is enabled. */
LPC_EMAC->MAC2 |= EMAC_MAC2_FULL_DUP;
LPC_EMAC->Command |= EMAC_CR_FULL_DUP;
LPC_EMAC->IPGT = EMAC_IPGT_FULL_DUP;
} else {
/* Half duplex mode. */
LPC_EMAC->IPGT = EMAC_IPGT_HALF_DUP;
}
/* Configure 100MBit/10MBit mode. */
if (!(regv & EMAC_PHY_SR_100_SPEED)) {
/* 10MBit mode. */
LPC_EMAC->SUPP = 0;
} else {
/* 100MBit mode. */
LPC_EMAC->SUPP = EMAC_SUPP_SPEED;
}
#endif
// Complete
return (0);
}
/*********************************************************************//**
* @brief Enable/Disable hash filter functionality for specified destination
* MAC address in EMAC module
* @param[in] dstMAC_addr Pointer to the first MAC destination address, should
* be 6-bytes length, in order LSB to the MSB
* @param[in] NewState New State of this command, should be:
* - ENABLE.
* - DISABLE.
* @return None
*
* Note:
* The standard Ethernet cyclic redundancy check (CRC) function is calculated from
* the 6 byte destination address in the Ethernet frame (this CRC is calculated
* anyway as part of calculating the CRC of the whole frame), then bits [28:23] out of
* the 32 bits CRC result are taken to form the hash. The 6 bit hash is used to access
* the hash table: it is used as an index in the 64 bit HashFilter register that has been
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -