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

📄 macb.c

📁 FreeRTOS is a portable, open source, mini Real Time Kernel - a free to download and royalty free RTO
💻 C
📖 第 1 页 / 共 3 页
字号:
  // to read a new frame.  Any fragments remaining in the frame we were
  // processing during the last call should be dropped.
  if( pcTo == NULL )
  {
    // How many bytes are indicated as being in this buffer?  
    // If none then the buffer is completely full and the frame is contained within more
    // than one buffer.
    // Reset our state variables ready for the next read from this buffer.
    pcSource = ( char * )( xRxDescriptors[ ulNextRxBuffer ].addr & ADDRESS_MASK );
    ulFameBytesReadSoFar = ( unsigned long ) 0;
    ulBufferPosition = ( unsigned long ) 0;
  }
  else
  {
    // Loop until we have obtained the required amount of data.
    ulSectionBytesReadSoFar = 0;
    while( ulSectionBytesReadSoFar < ulSectionLength )
    {
      // We may have already read some data from this buffer.
      // How much data remains in the buffer?
      ulBytesRemainingInBuffer = ( RX_BUFFER_SIZE - ulBufferPosition );

      // How many more bytes do we need to read before we have the
      // required amount of data?
      ulRemainingSectionBytes = ulSectionLength - ulSectionBytesReadSoFar;

      // Do we want more data than remains in the buffer? 
      if( ulRemainingSectionBytes > ulBytesRemainingInBuffer )
      {
        // We want more data than remains in the buffer so we can
        // write the remains of the buffer to the destination, then move
        // onto the next buffer to get the rest.
        memcpy( &( pcTo[ ulSectionBytesReadSoFar ] ), &( pcSource[ ulBufferPosition ] ), ulBytesRemainingInBuffer );
        ulSectionBytesReadSoFar += ulBytesRemainingInBuffer;
        ulFameBytesReadSoFar += ulBytesRemainingInBuffer;

        // Mark the buffer as free again.
        uiTemp = xRxDescriptors[ ulNextRxBuffer ].addr;
        xRxDescriptors[ ulNextRxBuffer ].addr = uiTemp & ~( AVR32_OWNERSHIP_BIT );
        // Move onto the next buffer.
        ulNextRxBuffer++;
       
        if( ulNextRxBuffer >= ETHERNET_CONF_NB_RX_BUFFERS )
        {
          ulNextRxBuffer = ( unsigned long ) 0;
        }
      
        // Reset the variables for the new buffer.
        pcSource = ( char * )( xRxDescriptors[ ulNextRxBuffer ].addr & ADDRESS_MASK );
        ulBufferPosition = ( unsigned long ) 0;
      }
      else
      {
        // We have enough data in this buffer to send back.
        // Read out enough data and remember how far we read up to.
        memcpy( &( pcTo[ ulSectionBytesReadSoFar ] ), &( pcSource[ ulBufferPosition ] ), ulRemainingSectionBytes );

        // There may be more data in this buffer yet.
        // Increment our position in this buffer past the data we have just read.
        ulBufferPosition += ulRemainingSectionBytes;
        ulSectionBytesReadSoFar += ulRemainingSectionBytes;
        ulFameBytesReadSoFar += ulRemainingSectionBytes;

        // Have we now finished with this buffer?
        if( ( ulBufferPosition >= RX_BUFFER_SIZE ) || ( ulFameBytesReadSoFar >= ulTotalFrameLength ) )
        {
          // Mark the buffer as free again.
          uiTemp = xRxDescriptors[ ulNextRxBuffer ].addr;
          xRxDescriptors[ ulNextRxBuffer ].addr = uiTemp & ~( AVR32_OWNERSHIP_BIT );
          // Move onto the next buffer.
          ulNextRxBuffer++;
         
          if( ulNextRxBuffer >= ETHERNET_CONF_NB_RX_BUFFERS )
          {
            ulNextRxBuffer = 0;
          }
       
          pcSource = ( char * )( xRxDescriptors[ ulNextRxBuffer ].addr & ADDRESS_MASK );
          ulBufferPosition = 0;
        }
      }
    }
  }
}
/*-----------------------------------------------------------*/
void vMACBSetMACAddress(const char * MACAddress)
{
  memcpy(cMACAddress, MACAddress, sizeof(cMACAddress));
}

Bool xMACBInit( volatile avr32_macb_t * macb )
{
volatile unsigned long status;

  // set up registers
  macb->ncr = 0;
  macb->tsr = ~0UL;
  macb->rsr = ~0UL;
  macb->idr = ~0UL;
  status = macb->isr;


#if ETHERNET_CONF_USE_RMII_INTERFACE
  // RMII used, set 0 to the USRIO Register
  macb->usrio &= ~AVR32_MACB_RMII_MASK;
#else
  // RMII not used, set 1 to the USRIO Register
  macb->usrio |= AVR32_MACB_RMII_MASK;
#endif

  // Load our MAC address into the MACB. 
  prvSetupMACAddress(macb);

  // Setup the buffers and descriptors.
  prvSetupDescriptors(macb);

#if ETHERNET_CONF_SYSTEM_CLOCK <= 20000000
  macb->ncfgr |= (AVR32_MACB_NCFGR_CLK_DIV8 << AVR32_MACB_NCFGR_CLK_OFFSET);
#elif ETHERNET_CONF_SYSTEM_CLOCK <= 40000000
  macb->ncfgr |= (AVR32_MACB_NCFGR_CLK_DIV16 << AVR32_MACB_NCFGR_CLK_OFFSET);
#elif ETHERNET_CONF_SYSTEM_CLOCK <= 80000000
  macb->ncfgr |= AVR32_MACB_NCFGR_CLK_DIV32 << AVR32_MACB_NCFGR_CLK_OFFSET;
#elif ETHERNET_CONF_SYSTEM_CLOCK <= 160000000
  macb->ncfgr |= AVR32_MACB_NCFGR_CLK_DIV64 << AVR32_MACB_NCFGR_CLK_OFFSET;
#else
# error System clock too fast
#endif

  // Are we connected?
  if( prvProbePHY(macb) == TRUE )
  {
    // Enable the interrupt!
    portENTER_CRITICAL();
    {
      prvSetupMACBInterrupt(macb);
    }
    portEXIT_CRITICAL();
    // Enable Rx and Tx, plus the stats register.
    macb->ncr = AVR32_MACB_NCR_TE_MASK | AVR32_MACB_NCR_RE_MASK;
    return (TRUE);
  }
  return (FALSE);
}

void vDisableMACBOperations(volatile avr32_macb_t * macb)
{
#if ETHERNET_CONF_USE_PHY_IT
volatile avr32_gpio_t *gpio = &AVR32_GPIO;
volatile avr32_gpio_port_t *gpio_port = &gpio->port[MACB_INTERRUPT_PIN/32];

  gpio_port->ierc =  1 << (MACB_INTERRUPT_PIN%32);
#endif

  // write the MACB control register : disable Tx & Rx
  macb->ncr &= ~((1 << AVR32_MACB_RE_OFFSET) | (1 << AVR32_MACB_TE_OFFSET));
  // We no more want to interrupt on Rx and Tx events.
  macb->idr = AVR32_MACB_IER_RCOMP_MASK | AVR32_MACB_IER_TCOMP_MASK;
}


void vClearMACBTxBuffer( void )
{
static unsigned long uxNextBufferToClear = 0;

  // Called on Tx interrupt events to set the AVR32_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 >= ETHERNET_CONF_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 >= ETHERNET_CONF_NB_TX_BUFFERS )
    {
      uxNextBufferToClear = 0;
    }
  }
}

static void prvSetupDescriptors(volatile avr32_macb_t * macb)
{
unsigned long xIndex;
unsigned long ulAddress;

  // Initialise xRxDescriptors descriptor.
  for( xIndex = 0; xIndex < ETHERNET_CONF_NB_RX_BUFFERS; ++xIndex )
  {
    // Calculate the address of the nth buffer within the array.
    ulAddress = ( unsigned long )( pcRxBuffer + ( xIndex * 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 & ADDRESS_MASK;
  }

  // The last buffer has the wrap bit set so the MACB knows to wrap back
  // to the first buffer.
  xRxDescriptors[ ETHERNET_CONF_NB_RX_BUFFERS - 1 ].addr |= RX_WRAP_BIT;

  // Initialise xTxDescriptors.
  for( xIndex = 0; xIndex < ETHERNET_CONF_NB_TX_BUFFERS; ++xIndex )
  {
    // Calculate the address of the nth buffer within the array.
    ulAddress = ( unsigned long )( pcTxBuffer + ( xIndex * ETHERNET_CONF_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 & ADDRESS_MASK;
    xTxDescriptors[ xIndex ].U_Status.status = AVR32_TRANSMIT_OK;
  }

  // The last buffer has the wrap bit set so the MACB knows to wrap back
  // to the first buffer.
  xTxDescriptors[ ETHERNET_CONF_NB_TX_BUFFERS - 1 ].U_Status.status = AVR32_TRANSMIT_WRAP | AVR32_TRANSMIT_OK;

  // Tell the MACB where to find the descriptors.
  macb->rbqp =   ( unsigned long )xRxDescriptors;
  macb->tbqp =   ( unsigned long )xTxDescriptors;

  // Enable the copy of data into the buffers, ignore broadcasts,
  // and don't copy FCS.
  macb->ncfgr |= (AVR32_MACB_CAF_MASK |  AVR32_MACB_NBC_MASK | AVR32_MACB_NCFGR_DRFCS_MASK);

} 

static void prvSetupMACAddress( volatile avr32_macb_t * macb )
{
  // Must be written SA1L then SA1H.
  macb->sa1b =  ( ( unsigned long ) cMACAddress[ 3 ] << 24 ) |
                ( ( unsigned long ) cMACAddress[ 2 ] << 16 ) |
                ( ( unsigned long ) cMACAddress[ 1 ] << 8  ) |
                                    cMACAddress[ 0 ];

  macb->sa1t =  ( ( unsigned long ) cMACAddress[ 5 ] << 8 ) |
                                    cMACAddress[ 4 ];
}

static void prvSetupMACBInterrupt( volatile avr32_macb_t * macb )
{
#ifdef FREERTOS_USED
  // Create the semaphore used to trigger the MACB task. 
  if (xSemaphore == NULL)
  {
    vSemaphoreCreateBinary( xSemaphore );
  }
#else 
  // Create the flag used to trigger the MACB polling task. 
  DataToRead = FALSE;
#endif


#ifdef FREERTOS_USED
  if( xSemaphore != NULL)
  {
    // We start by 'taking' the semaphore so the ISR can 'give' it when the
    // first interrupt occurs.
    xSemaphoreTake( xSemaphore, 0 );
#endif
    // Setup the interrupt for MACB.
    // Register the interrupt handler to the interrupt controller at interrupt level 2
    INTC_register_interrupt((__int_handler)&vMACB_ISR, AVR32_MACB_IRQ, INT2);

#if ETHERNET_CONF_USE_PHY_IT
    /* GPIO enable interrupt upon rising edge */
    gpio_enable_pin_interrupt(MACB_INTERRUPT_PIN, GPIO_FALLING_EDGE);
    // Setup the interrupt for PHY.
    // Register the interrupt handler to the interrupt controller at interrupt level 2
    INTC_register_interrupt((__int_handler)&vPHY_ISR, (AVR32_GPIO_IRQ_0 + (MACB_INTERRUPT_PIN/8)), INT2);
    /* enable interrupts on INT pin */
    vWriteMDIO( macb, PHY_MICR , ( MICR_INTEN | MICR_INTOE ));
    /* enable "link change" interrupt for Phy */
    vWriteMDIO( macb, PHY_MISR , MISR_LINK_INT_EN );
#endif

    // We want to interrupt on Rx and Tx events
    macb->ier = AVR32_MACB_IER_RCOMP_MASK | AVR32_MACB_IER_TCOMP_MASK;
#ifdef FREERTOS_USED
  }
#endif
}

/*! Read a register on MDIO bus (access to the PHY)
 *         This function is looping until PHY gets ready
 *
 * \param macb         Input. instance of the MACB to use
 * \param usAddress    Input. register to set.
 *
 * \return unsigned long data that has been read
 */
static unsigned long ulReadMDIO(volatile avr32_macb_t * macb, unsigned short usAddress)
{
unsigned long value, 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
            | (2 << AVR32_MACB_RW_OFFSET)                            // Read operation
            | ((ETHERNET_CONF_PHY_ADDR & 0x1f) << AVR32_MACB_PHYA_OFFSET)  // Phy Add
            | (usAddress << AVR32_MACB_REGA_OFFSET);                 // Reg Add
  // wait for PHY to be ready
  do {
    status = macb->nsr;
  } while (!(status & AVR32_MACB_NSR_IDLE_MASK));
  // read the register value in maintenance register
  value = macb->man & 0x0000ffff;
  // disable management port
  macb->ncr &= ~AVR32_MACB_NCR_MPE_MASK;
  // return the read value
  return (value);
}

/*! Write a given value to a register on MDIO bus (access to the PHY)
 *         This function is looping until PHY gets ready
 *
 * \param *macb        Input. instance of the MACB to use

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -