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

📄 avr32_emac.c

📁 FreeRTOS V4.2.1,增加了AVR32 UC3 和 LPC2368 的支持
💻 C
📖 第 1 页 / 共 2 页
字号:
{
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 + -