📄 macb.c
字号:
// 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 + -