📄 macb.c
字号:
* \param usAddress Input. register to set.
* \param usValue Input. value to write.
*
*/
static void vWriteMDIO(volatile avr32_macb_t * macb, unsigned short usAddress, unsigned short usValue)
{
unsigned long status;
// initiate transaction : enable management port
macb->ncr |= AVR32_MACB_NCR_MPE_MASK;
// Write the PHY configuration frame to the MAN register
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
| ((ETHERNET_CONF_PHY_ADDR & 0x1f) << AVR32_MACB_PHYA_OFFSET) // Phy Add
| (usAddress << AVR32_MACB_REGA_OFFSET)) // Reg Add
| (usValue & 0xffff); // Data
// wait for PHY to be ready
do {
status = macb->nsr;
} while (!(status & AVR32_MACB_NSR_IDLE_MASK));
// disable management port
macb->ncr &= ~AVR32_MACB_NCR_MPE_MASK;
}
static Bool prvProbePHY( volatile avr32_macb_t * macb )
{
volatile unsigned long mii_status, phy_ctrl;
volatile unsigned long config;
unsigned long upper, lower, mode, advertise, lpa;
volatile unsigned long physID;
// Read Phy Identifier register 1 & 2
lower = ulReadMDIO(macb, PHY_PHYSID2);
upper = ulReadMDIO(macb, PHY_PHYSID1);
// get Phy ID, ignore Revision
physID = ((upper << 16) & 0xFFFF0000) | (lower & 0xFFF0);
// check if it match config
if (physID == ETHERNET_CONF_PHY_ID)
{
// read RBR
mode = ulReadMDIO(macb, 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;
vWriteMDIO(macb, 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
vWriteMDIO(macb, PHY_ADVERTISE, advertise);
// read Control register
config = ulReadMDIO(macb, PHY_BMCR);
// read Phy Control register
phy_ctrl = ulReadMDIO(macb, 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
vWriteMDIO(macb, PHY_PHYCR, phy_ctrl);
// update ctrl register
vWriteMDIO(macb, PHY_BMCR, config);
// loop while link status isn't OK
do {
mii_status = ulReadMDIO(macb, PHY_BMSR);
} while (!(mii_status & BMSR_LSTATUS));
// read the LPA configuration of the PHY
lpa = ulReadMDIO(macb, 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
macb->ncfgr = config;
return TRUE;
}
return FALSE;
}
void vMACBWaitForInput( unsigned long ulTimeOut )
{
#ifdef FREERTOS_USED
// Just wait until we are signled from an ISR that data is available, or
// we simply time out.
xSemaphoreTake( xSemaphore, ulTimeOut );
#else
unsigned long i;
gpio_clr_gpio_pin(LED0_GPIO);
i = ulTimeOut * 1000;
// wait for an interrupt to occurs
do
{
if ( DataToRead == TRUE )
{
// IT occurs, reset interrupt flag
portENTER_CRITICAL();
DataToRead = FALSE;
portEXIT_CRITICAL();
break;
}
i--;
}
while(i != 0);
gpio_set_gpio_pin(LED0_GPIO);
#endif
}
/*
* The MACB ISR. Handles both Tx and Rx complete interrupts.
*/
#ifdef FREERTOS_USED
#if __GNUC__
__attribute__((naked))
#elif __ICCAVR32__
#pragma shadow_registers = full // Naked.
#endif
#else
#if __GNUC__
__attribute__((__interrupt__))
#elif __ICCAVR32__
__interrupt
#endif
#endif
void vMACB_ISR( void )
{
// This ISR can cause a context switch, so the first statement must be a
// call to the portENTER_SWITCHING_ISR() macro. This must be BEFORE any
// variable declarations.
portENTER_SWITCHING_ISR();
// the return value is used by FreeRTOS to change the context if needed after rete instruction
// in standalone use, this value should be ignored
prvMACB_ISR_NonNakedBehaviour();
// Exit the ISR. If a task was woken by either a character being received
// or transmitted then a context switch will occur.
portEXIT_SWITCHING_ISR();
}
/*-----------------------------------------------------------*/
#if __GNUC__
__attribute__((__noinline__))
#elif __ICCAVR32__
#pragma optimize = no_inline
#endif
static long prvMACB_ISR_NonNakedBehaviour( void )
{
// Variable definitions can be made now.
volatile unsigned long ulIntStatus, ulEventStatus;
long xHigherPriorityTaskWoken = FALSE;
// Find the cause of the interrupt.
ulIntStatus = AVR32_MACB.isr;
ulEventStatus = AVR32_MACB.rsr;
if( ( ulIntStatus & AVR32_MACB_IDR_RCOMP_MASK ) || ( ulEventStatus & AVR32_MACB_REC_MASK ) )
{
// A frame has been received, signal the IP task so it can process
// the Rx descriptors.
portENTER_CRITICAL();
#ifdef FREERTOS_USED
xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken );
#else
DataToRead = TRUE;
#endif
portEXIT_CRITICAL();
AVR32_MACB.rsr = AVR32_MACB_REC_MASK;
AVR32_MACB.rsr;
}
if( ulIntStatus & AVR32_MACB_TCOMP_MASK )
{
// A frame has been transmitted. Mark all the buffers used by the
// frame just transmitted as free again.
vClearMACBTxBuffer();
AVR32_MACB.tsr = AVR32_MACB_TSR_COMP_MASK;
AVR32_MACB.tsr;
}
return ( xHigherPriorityTaskWoken );
}
#if ETHERNET_CONF_USE_PHY_IT
/*
* The PHY ISR. Handles Phy interrupts.
*/
#ifdef FREERTOS_USED
#if __GNUC__
__attribute__((naked))
#elif __ICCAVR32__
#pragma shadow_registers = full // Naked.
#endif
#else
#if __GNUC__
__attribute__((__interrupt__))
#elif __ICCAVR32__
__interrupt
#endif
#endif
void vPHY_ISR( void )
{
// This ISR can cause a context switch, so the first statement must be a
// call to the portENTER_SWITCHING_ISR() macro. This must be BEFORE any
// variable declarations.
portENTER_SWITCHING_ISR();
// the return value is used by FreeRTOS to change the context if needed after rete instruction
// in standalone use, this value should be ignored
prvPHY_ISR_NonNakedBehaviour();
// Exit the ISR. If a task was woken by either a character being received
// or transmitted then a context switch will occur.
portEXIT_SWITCHING_ISR();
}
/*-----------------------------------------------------------*/
#if __GNUC__
__attribute__((__noinline__))
#elif __ICCAVR32__
#pragma optimize = no_inline
#endif
static long prvPHY_ISR_NonNakedBehaviour( void )
{
// Variable definitions can be made now.
volatile unsigned long ulIntStatus, ulEventStatus;
long xSwitchRequired = FALSE;
volatile avr32_gpio_t *gpio = &AVR32_GPIO;
volatile avr32_gpio_port_t *gpio_port = &gpio->port[MACB_INTERRUPT_PIN/32];
// read Phy Interrupt register Status
ulIntStatus = ulReadMDIO(&AVR32_MACB, PHY_MISR);
// read Phy status register
ulEventStatus = ulReadMDIO(&AVR32_MACB, PHY_BMSR);
// dummy read
ulEventStatus = ulReadMDIO(&AVR32_MACB, PHY_BMSR);
// clear interrupt flag on GPIO
gpio_port->ifrc = 1 << (MACB_INTERRUPT_PIN%32);
return ( xSwitchRequired );
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -