📄 avr32_emac.c
字号:
{
unsigned long status;
/* enable GPIO's */
gpio_enable_module_pin(AVR32_MACB_TX_CLK_0_PIN, AVR32_MACB_TX_CLK_0_FUNCTION); //PB0
gpio_enable_module_pin(AVR32_MACB_TX_EN_0_PIN, AVR32_MACB_TX_EN_0_FUNCTION); //PB1
gpio_enable_module_pin(AVR32_MACB_TXD_0_PIN, AVR32_MACB_TXD_0_FUNCTION); //PB2
gpio_enable_module_pin(AVR32_MACB_TXD_1_PIN, AVR32_MACB_TXD_1_FUNCTION); //PB3
gpio_enable_module_pin(AVR32_MACB_RXD_0_PIN, AVR32_MACB_RXD_0_FUNCTION); //PB5
gpio_enable_module_pin(AVR32_MACB_RXD_1_PIN, AVR32_MACB_RXD_1_FUNCTION); //PB6
gpio_enable_module_pin(AVR32_MACB_RX_ER_0_PIN, AVR32_MACB_RX_ER_0_FUNCTION); //PB7
gpio_enable_module_pin(AVR32_MACB_MDC_0_PIN, AVR32_MACB_MDC_0_FUNCTION); //PB8
gpio_enable_module_pin(AVR32_MACB_MDIO_0_PIN, AVR32_MACB_MDIO_0_FUNCTION); //PB9
gpio_enable_module_pin(AVR32_MACB_RX_DV_0_PIN, AVR32_MACB_RX_DV_0_FUNCTION); //PB15
/* set up registers */
AVR32_MACB.ncr = 0;
AVR32_MACB.tsr = ~0UL;
AVR32_MACB.rsr = ~0UL;
AVR32_MACB.idr = ~0UL;
status = AVR32_MACB.isr;
#ifndef USE_RMII_INTERFACE
// RMII not used, set 1 to the USRIO Register
AVR32_MACB.usrio |= AVR32_MACB_RMII_MASK;
#else
// RMII used, set 0 to the USRIO Register
AVR32_MACB.usrio &= ~AVR32_MACB_RMII_MASK;
#endif
/* Load our MAC address into the EMAC. */
prvSetupMACAddress();
/* Setup the buffers and descriptors. */
prvSetupDescriptors();
#if configCPU_CLOCK_HZ <= 20000000
AVR32_MACB.ncfgr |= (AVR32_MACB_NCFGR_CLK_DIV8 << AVR32_MACB_NCFGR_CLK_OFFSET);
#elif configCPU_CLOCK_HZ <= 40000000
AVR32_MACB.ncfgr |= (AVR32_MACB_NCFGR_CLK_DIV16 << AVR32_MACB_NCFGR_CLK_OFFSET);
#elif configCPU_CLOCK_HZ <= 80000000
AVR32_MACB.ncfgr |= AVR32_MACB_NCFGR_CLK_DIV32 << AVR32_MACB_NCFGR_CLK_OFFSET;
#elif configCPU_CLOCK_HZ <= 160000000
AVR32_MACB.ncfgr |= AVR32_MACB_NCFGR_CLK_DIV64 << AVR32_MACB_NCFGR_CLK_OFFSET;
#else
# error System clock too fast
#endif
/* Are we connected? */
if( prvProbePHY() )
{
/* Enable the interrupt! */
portENTER_CRITICAL();
{
prvSetupEMACInterrupt();
vPassEMACSemaphore( xSemaphore );
}
portEXIT_CRITICAL();
/* Enable Rx and Tx, plus the stats register. */
AVR32_MACB.ncr = AVR32_MACB_NCR_TE_MASK | AVR32_MACB_NCR_RE_MASK;
}
return xSemaphore;
}
/* See the header file for descriptions of public functions. */
void vClearEMACTxBuffer( void )
{
static unsigned portBASE_TYPE uxNextBufferToClear = 0;
/* Called on Tx interrupt events to set the AT91C_TRANSMIT_OK bit in each
Tx buffer within the frame just transmitted. This marks all the buffers
as available again.
The first buffer in the frame should have the bit set automatically. */
if( xTxDescriptors[ uxNextBufferToClear ].U_Status.status & AVR32_TRANSMIT_OK )
{
/* Loop through the other buffers in the frame. */
while( !( xTxDescriptors[ uxNextBufferToClear ].U_Status.status & AVR32_LAST_BUFFER ) )
{
uxNextBufferToClear++;
if( uxNextBufferToClear >= NB_TX_BUFFERS )
{
uxNextBufferToClear = 0;
}
xTxDescriptors[ uxNextBufferToClear ].U_Status.status |= AVR32_TRANSMIT_OK;
}
/* Start with the next buffer the next time a Tx interrupt is called. */
uxNextBufferToClear++;
/* Do we need to wrap back to the first buffer? */
if( uxNextBufferToClear >= NB_TX_BUFFERS )
{
uxNextBufferToClear = 0;
}
}
}
/*-----------------------------------------------------------*/
static void prvSetupDescriptors(void)
{
unsigned portBASE_TYPE xIndex;
unsigned portLONG ulAddress;
/* Initialise xRxDescriptors descriptor. */
for( xIndex = 0; xIndex < NB_RX_BUFFERS; ++xIndex )
{
/* Calculate the address of the nth buffer within the array. */
ulAddress = ( unsigned portLONG )( pcRxBuffer + ( xIndex * ETH_RX_BUFFER_SIZE ) );
/* Write the buffer address into the descriptor. The DMA will place
the data at this address when this descriptor is being used. Mask off
the bottom bits of the address as these have special meaning. */
xRxDescriptors[ xIndex ].addr = ulAddress & emacADDRESS_MASK;
}
/* The last buffer has the wrap bit set so the EMAC knows to wrap back
to the first buffer. */
xRxDescriptors[ NB_RX_BUFFERS - 1 ].addr |= emacRX_WRAP_BIT;
/* Initialise xTxDescriptors. */
for( xIndex = 0; xIndex < NB_TX_BUFFERS; ++xIndex )
{
/* Calculate the address of the nth buffer within the array. */
ulAddress = ( unsigned portLONG )( pcTxBuffer + ( xIndex * ETH_TX_BUFFER_SIZE ) );
/* Write the buffer address into the descriptor. The DMA will read
data from here when the descriptor is being used. */
xTxDescriptors[ xIndex ].addr = ulAddress & emacADDRESS_MASK;
xTxDescriptors[ xIndex ].U_Status.status = AVR32_TRANSMIT_OK;
}
/* The last buffer has the wrap bit set so the EMAC knows to wrap back
to the first buffer. */
xTxDescriptors[ NB_TX_BUFFERS - 1 ].U_Status.status = AVR32_TRANSMIT_WRAP | AVR32_TRANSMIT_OK;
/* Tell the EMAC where to find the descriptors. */
AVR32_MACB.rbqp = ( unsigned portLONG )xRxDescriptors;
AVR32_MACB.tbqp = ( unsigned portLONG )xTxDescriptors;
/* Enable the copy of data into the buffers, ignore broadcasts,
and don't copy FCS. */
AVR32_MACB.ncfgr |= (AVR32_MACB_CAF_MASK | AVR32_MACB_NBC_MASK | AVR32_MACB_NCFGR_DRFCS_MASK);
}
/*-----------------------------------------------------------*/
static void prvSetupMACAddress( void )
{
/* Must be written SA1L then SA1H. */
AVR32_MACB.sa1b = ( ( unsigned portLONG ) cMACAddress[ 3 ] << 24 ) |
( ( unsigned portLONG ) cMACAddress[ 2 ] << 16 ) |
( ( unsigned portLONG ) cMACAddress[ 1 ] << 8 ) |
cMACAddress[ 0 ];
AVR32_MACB.sa1t = ( ( unsigned portLONG ) cMACAddress[ 5 ] << 8 ) |
cMACAddress[ 4 ];
}
/*-----------------------------------------------------------*/
static void prvSetupEMACInterrupt( void )
{
/* Create the semaphore used to trigger the EMAC task. */
if (xSemaphore == NULL)
{
vSemaphoreCreateBinary( xSemaphore );
}
if( xSemaphore )
{
/* We start by 'taking' the semaphore so the ISR can 'give' it when the
first interrupt occurs. */
xSemaphoreTake( xSemaphore, emacNO_DELAY );
portENTER_CRITICAL();
{
/* Setup the interrupt for USART0.
Register the USART0 interrupt handler to the interrupt controller
at interrupt level 2. */
INTC_register_interrupt(&vEMAC_ISR, AVR32_MACB_IRQ, INT2);
/* We want to interrupt on Rx and Tx events. */
AVR32_MACB.ier = AVR32_MACB_IER_RCOMP_MASK | AVR32_MACB_IER_TCOMP_MASK;
}
portEXIT_CRITICAL();
}
}
/*
* The following functions are initialisation functions taken from the Atmel
* EMAC sample code.
*/
static portBASE_TYPE prvProbePHY( void )
{
unsigned long mii_status, advertise, lpa, phy_ctrl;
unsigned long config;
unsigned long upper, lower,mode;
unsigned long physID;
/* Read Phy Identifier register 1 & 2 */
lower = vReadPHY(PHY_PHYSID2);
upper = vReadPHY(PHY_PHYSID1);
/* get Phy ID, ignore Revision */
physID = ((upper << 16) & 0xFFFF0000) | (lower & 0xFFF0);
/* check if it match config */
if (physID == MII_DP83848_ID)
{
/* read RBR */
mode = vReadPHY(PHY_RBR);
/* set RMII mode if not done */
if ((mode & RBR_RMII) != RBR_RMII)
{
/* force RMII flag if strap options are wrong */
mode |= RBR_RMII;
vWritePHY(PHY_RBR,mode);
}
/* set advertise register */
#if ETHERNET_CONF_AN_ENABLE == 1
advertise = ADVERTISE_CSMA | ADVERTISE_ALL;
#else
advertise = ADVERTISE_CSMA;
#if ETHERNET_CONF_USE_100MB
#if ETHERNET_CONF_USE_FULL_DUPLEX
advertise |= ADVERTISE_100FULL;
#else
advertise |= ADVERTISE_100HALF;
#endif
#else
#if ETHERNET_CONF_USE_FULL_DUPLEX
advertise |= ADVERTISE_10FULL;
#else
advertise |= ADVERTISE_10HALF;
#endif
#endif
#endif
/* write advertise register */
vWritePHY(PHY_ADVERTISE, advertise);
/* read Control register */
config = vReadPHY(PHY_BMCR);
/* read Phy Control register */
phy_ctrl = vReadPHY(PHY_PHYCR);
#if ETHERNET_CONF_AN_ENABLE
#if ETHERNET_CONF_AUTO_CROSS_ENABLE
/* enable Auto MDIX */
phy_ctrl |= PHYCR_MDIX_EN;
#else
/* disable Auto MDIX */
phy_ctrl &= ~PHYCR_MDIX_EN;
#if ETHERNET_CONF_CROSSED_LINK
/* force direct link = Use crossed RJ45 cable */
phy_ctrl &= ~PHYCR_MDIX_FORCE;
#else
/* force crossed link = Use direct RJ45 cable */
phy_ctrl |= PHYCR_MDIX_FORCE;
#endif
#endif
/* reset auto-negociation capability */
config |= (BMCR_ANRESTART | BMCR_ANENABLE);
#else
/* disable Auto MDIX */
phy_ctrl &= ~PHYCR_MDIX_EN;
#if ETHERNET_CONF_CROSSED_LINK
/* force direct link = Use crossed RJ45 cable */
phy_ctrl &= ~PHYCR_MDIX_FORCE;
#else
/* force crossed link = Use direct RJ45 cable */
phy_ctrl |= PHYCR_MDIX_FORCE;
#endif
/* clear AN bit */
config &= ~BMCR_ANENABLE;
#if ETHERNET_CONF_USE_100MB
config |= BMCR_SPEED100;
#else
config &= ~BMCR_SPEED100;
#endif
#if ETHERNET_CONF_USE_FULL_DUPLEX
config |= BMCR_FULLDPLX;
#else
config &= ~BMCR_FULLDPLX;
#endif
#endif
/* update Phy ctrl register */
vWritePHY(PHY_PHYCR, phy_ctrl);
/* update ctrl register */
vWritePHY(PHY_BMCR, config);
/* loop while link status isn't OK */
do {
mii_status = vReadPHY(PHY_BMSR);
} while (!(mii_status & BMSR_LSTATUS));
/* read the LPA configuration of the PHY */
lpa = vReadPHY(PHY_LPA);
/* read the MACB config register */
config = AVR32_MACB.ncfgr;
/* if 100MB needed */
if ((lpa & advertise) & (LPA_100HALF | LPA_100FULL))
{
config |= AVR32_MACB_SPD_MASK;
}
else
{
config &= ~(AVR32_MACB_SPD_MASK);
}
/* if FULL DUPLEX needed */
if ((lpa & advertise) & (LPA_10FULL | LPA_100FULL))
{
config |= AVR32_MACB_FD_MASK;
}
else
{
config &= ~(AVR32_MACB_FD_MASK);
}
/* write the MACB config register */
AVR32_MACB.ncfgr = config;
return pdPASS;
}
return pdFAIL;
}
static unsigned portLONG vReadPHY( unsigned portCHAR ucAddress )
{
unsigned portLONG pulValue;
/* Enable management port */
AVR32_MACB.ncr |= AVR32_MACB_NCR_MPE_MASK;
/* configure MDIO frame in MAN register */
AVR32_MACB.man = (AVR32_MACB_SOF_MASK & (0x01<<AVR32_MACB_SOF_OFFSET)) // SOF
| (2 << AVR32_MACB_CODE_OFFSET) // Code
| (2 << AVR32_MACB_RW_OFFSET) // Read operation
| ((DP83848_PHY_ADDR & 0x1f) << AVR32_MACB_PHYA_OFFSET) // Phy Add
| (ucAddress << AVR32_MACB_REGA_OFFSET); // Reg Add
/* Wait until IDLE bit in Network Status register is cleared. */
while( !( AVR32_MACB.nsr & AVR32_MACB_NSR_IDLE_MASK ) )
{
__asm( "NOP" );
}
pulValue = (AVR32_MACB.man & 0x0000ffff );
/* Disable management port */
AVR32_MACB.ncr &= ~AVR32_MACB_NCR_MPE_MASK;
return (pulValue);
}
static void vWritePHY( unsigned portCHAR ucAddress, unsigned portLONG ulValue )
{
/* Enable management port */
AVR32_MACB.ncr |= AVR32_MACB_NCR_MPE_MASK;
/* configure MDIO frame in MAN register */
AVR32_MACB.man = (( AVR32_MACB_SOF_MASK & (0x01<<AVR32_MACB_SOF_OFFSET)) // SOF
| (2 << AVR32_MACB_CODE_OFFSET) // Code
| (1 << AVR32_MACB_RW_OFFSET) // Write operation
| ((DP83848_PHY_ADDR & 0x1f) << AVR32_MACB_PHYA_OFFSET) // Phy Add
| (ucAddress << AVR32_MACB_REGA_OFFSET)) // Reg Add
| (ulValue & 0xffff); // Data
/* Wait until IDLE bit in Network Status register is cleared */
while( !( AVR32_MACB.nsr & AVR32_MACB_NSR_IDLE_MASK ) )
{
__asm( "NOP" );
};
/* Disable management port */
AVR32_MACB.ncr &= ~AVR32_MACB_NCR_MPE_MASK;
}
void vEMACWaitForInput( void )
{
/* Just wait until we are signled from an ISR that data is available, or
we simply time out. */
xSemaphoreTake( xSemaphore, emacBLOCK_TIME_WAITING_FOR_INPUT );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -