⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 macb.c

📁 FreeRTOS is a portable, open source, mini Real Time Kernel - a free to download and royalty free RTO
💻 C
📖 第 1 页 / 共 3 页
字号:
 * \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 + -