📄 macb.c
字号:
/*This file has been prepared for Doxygen automatic documentation generation.*/
/*! \file *********************************************************************
*
* \brief MACB driver for EVK1100 board.
*
* This file defines a useful set of functions for the MACB interface on
* AVR32 devices.
*
* - Compiler: IAR EWAVR32 and GNU GCC for AVR32
* - Supported devices: All AVR32 devices with a MACB module can be used.
* - AppNote:
*
* \author Atmel Corporation: http://www.atmel.com \n
* Support and FAQ: http://support.atmel.no/
*
*****************************************************************************/
/* Copyright (c) 2007, Atmel Corporation All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of ATMEL may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND
* SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <avr32/io.h>
#ifdef FREERTOS_USED
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#endif
#include "macb.h"
#include "gpio.h"
#include "conf_eth.h"
#include "intc.h"
/* Size of each receive buffer - DO NOT CHANGE. */
#define RX_BUFFER_SIZE 128
/* The buffer addresses written into the descriptors must be aligned so the
last few bits are zero. These bits have special meaning for the MACB
peripheral and cannot be used as part of the address. */
#define ADDRESS_MASK ( ( unsigned long ) 0xFFFFFFFC )
/* Bit used within the address stored in the descriptor to mark the last
descriptor in the array. */
#define RX_WRAP_BIT ( ( unsigned long ) 0x02 )
/* A short delay is used to wait for a buffer to become available, should
one not be immediately available when trying to transmit a frame. */
#define BUFFER_WAIT_DELAY ( 2 )
#ifndef FREERTOS_USED
#define portENTER_CRITICAL Disable_global_interrupt
#define portEXIT_CRITICAL Enable_global_interrupt
#define portENTER_SWITCHING_ISR()
#define portEXIT_SWITCHING_ISR()
#endif
/* Buffer written to by the MACB DMA. Must be aligned as described by the
comment above the ADDRESS_MASK definition. */
#if __GNUC__
static volatile char pcRxBuffer[ ETHERNET_CONF_NB_RX_BUFFERS * RX_BUFFER_SIZE ] __attribute__ ((aligned (8)));
#elif __ICCAVR32__
#pragma data_alignment=8
static volatile char pcRxBuffer[ ETHERNET_CONF_NB_RX_BUFFERS * RX_BUFFER_SIZE ];
#endif
/* Buffer read by the MACB DMA. Must be aligned as described by the comment
above the ADDRESS_MASK definition. */
#if __GNUC__
static volatile char pcTxBuffer[ ETHERNET_CONF_NB_TX_BUFFERS * ETHERNET_CONF_TX_BUFFER_SIZE ] __attribute__ ((aligned (8)));
#elif __ICCAVR32__
#pragma data_alignment=8
static volatile char pcTxBuffer[ ETHERNET_CONF_NB_TX_BUFFERS * ETHERNET_CONF_TX_BUFFER_SIZE ];
#endif
/* Descriptors used to communicate between the program and the MACB peripheral.
These descriptors hold the locations and state of the Rx and Tx buffers. */
static volatile AVR32_TxTdDescriptor xTxDescriptors[ ETHERNET_CONF_NB_TX_BUFFERS ];
static volatile AVR32_RxTdDescriptor xRxDescriptors[ ETHERNET_CONF_NB_RX_BUFFERS ];
/* The IP and Ethernet addresses are read from the header files. */
char cMACAddress[ 6 ] = { ETHERNET_CONF_ETHADDR0,ETHERNET_CONF_ETHADDR1,ETHERNET_CONF_ETHADDR2,ETHERNET_CONF_ETHADDR3,ETHERNET_CONF_ETHADDR4,ETHERNET_CONF_ETHADDR5 };
/*-----------------------------------------------------------*/
/* See the header file for descriptions of public functions. */
/*
* Prototype for the MACB interrupt function - called by the asm wrapper.
*/
#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 );
static long prvMACB_ISR_NonNakedBehaviour( void );
#if ETHERNET_CONF_USE_PHY_IT
#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 );
static long prvPHY_ISR_NonNakedBehaviour( void );
#endif
/*
* Initialise both the Tx and Rx descriptors used by the MACB.
*/
static void prvSetupDescriptors(volatile avr32_macb_t * macb);
/*
* Write our MAC address into the MACB.
*/
static void prvSetupMACAddress( volatile avr32_macb_t * macb );
/*
* Configure the MACB for interrupts.
*/
static void prvSetupMACBInterrupt( volatile avr32_macb_t * macb );
/*
* Some initialisation functions.
*/
static Bool prvProbePHY( volatile avr32_macb_t * macb );
static unsigned long ulReadMDIO(volatile avr32_macb_t * macb, unsigned short usAddress);
static void vWriteMDIO(volatile avr32_macb_t * macb, unsigned short usAddress, unsigned short usValue);
#ifdef FREERTOS_USED
/* The semaphore used by the MACB ISR to wake the MACB task. */
static xSemaphoreHandle xSemaphore = NULL;
#else
static volatile Bool DataToRead = FALSE;
#endif
/* Holds the index to the next buffer from which data will be read. */
volatile unsigned long ulNextRxBuffer = 0;
long lMACBSend(volatile avr32_macb_t * macb, char *pcFrom, unsigned long ulLength, long lEndOfFrame )
{
static unsigned long uxTxBufferIndex = 0;
char *pcBuffer;
unsigned long ulLastBuffer, ulDataBuffered = 0, ulDataRemainingToSend, ulLengthToSend;
/* If the length of data to be transmitted is greater than each individual
transmit buffer then the data will be split into more than one buffer.
Loop until the entire length has been buffered. */
while( ulDataBuffered < ulLength )
{
// Is a buffer available ?
while( !( xTxDescriptors[ uxTxBufferIndex ].U_Status.status & AVR32_TRANSMIT_OK ) )
{
// There is no room to write the Tx data to the Tx buffer.
// Wait a short while, then try again.
#ifdef FREERTOS_USED
vTaskDelay( BUFFER_WAIT_DELAY );
#else
__asm__ __volatile__ ("nop");
#endif
}
portENTER_CRITICAL();
{
// Get the address of the buffer from the descriptor,
// then copy the data into the buffer.
pcBuffer = ( char * ) xTxDescriptors[ uxTxBufferIndex ].addr;
// How much can we write to the buffer ?
ulDataRemainingToSend = ulLength - ulDataBuffered;
if( ulDataRemainingToSend <= ETHERNET_CONF_TX_BUFFER_SIZE )
{
// We can write all the remaining bytes.
ulLengthToSend = ulDataRemainingToSend;
}
else
{
// We can't write more than ETH_TX_BUFFER_SIZE in one go.
ulLengthToSend = ETHERNET_CONF_TX_BUFFER_SIZE;
}
// Copy the data into the buffer.
memcpy( ( void * ) pcBuffer, ( void * ) &( pcFrom[ ulDataBuffered ] ), ulLengthToSend );
ulDataBuffered += ulLengthToSend;
// Is this the last data for the frame ?
if( lEndOfFrame && ( ulDataBuffered >= ulLength ) )
{
// No more data remains for this frame so we can start the transmission.
ulLastBuffer = AVR32_LAST_BUFFER;
}
else
{
// More data to come for this frame.
ulLastBuffer = 0;
}
// Fill out the necessary in the descriptor to get the data sent,
// then move to the next descriptor, wrapping if necessary.
if( uxTxBufferIndex >= ( ETHERNET_CONF_NB_TX_BUFFERS - 1 ) )
{
xTxDescriptors[ uxTxBufferIndex ].U_Status.status = ( ulLengthToSend & ( unsigned long ) AVR32_LENGTH_FRAME )
| ulLastBuffer
| AVR32_TRANSMIT_WRAP;
uxTxBufferIndex = 0;
}
else
{
xTxDescriptors[ uxTxBufferIndex ].U_Status.status = ( ulLengthToSend & ( unsigned long ) AVR32_LENGTH_FRAME )
| ulLastBuffer;
uxTxBufferIndex++;
}
/* If this is the last buffer to be sent for this frame we can
start the transmission. */
if( ulLastBuffer )
{
macb->ncr |= AVR32_MACB_TSTART_MASK;
}
}
portEXIT_CRITICAL();
}
return PASS;
}
unsigned long ulMACBInputLength( void )
{
register unsigned long ulIndex , ulLength = 0;
unsigned int uiTemp;
// Skip any fragments. We are looking for the first buffer that contains
// data and has the SOF (start of frame) bit set.
while( ( xRxDescriptors[ ulNextRxBuffer ].addr & AVR32_OWNERSHIP_BIT ) && !( xRxDescriptors[ ulNextRxBuffer ].U_Status.status & AVR32_SOF ) )
{
// Ignoring this buffer. Mark it as free again.
uiTemp = xRxDescriptors[ ulNextRxBuffer ].addr;
xRxDescriptors[ ulNextRxBuffer ].addr = uiTemp & ~( AVR32_OWNERSHIP_BIT );
ulNextRxBuffer++;
if( ulNextRxBuffer >= ETHERNET_CONF_NB_RX_BUFFERS )
{
ulNextRxBuffer = 0;
}
}
// We are going to walk through the descriptors that make up this frame,
// but don't want to alter ulNextRxBuffer as this would prevent vMACBRead()
// from finding the data. Therefore use a copy of ulNextRxBuffer instead.
ulIndex = ulNextRxBuffer;
// Walk through the descriptors until we find the last buffer for this frame.
// The last buffer will give us the length of the entire frame.
while( ( xRxDescriptors[ ulIndex ].addr & AVR32_OWNERSHIP_BIT ) && !ulLength )
{
ulLength = xRxDescriptors[ ulIndex ].U_Status.status & AVR32_LENGTH_FRAME;
// Increment to the next buffer, wrapping if necessary.
ulIndex++;
if( ulIndex >= ETHERNET_CONF_NB_RX_BUFFERS )
{
ulIndex = 0;
}
}
return ulLength;
}
/*-----------------------------------------------------------*/
void vMACBRead( char *pcTo, unsigned long ulSectionLength, unsigned long ulTotalFrameLength )
{
static unsigned long ulSectionBytesReadSoFar = 0, ulBufferPosition = 0, ulFameBytesReadSoFar = 0;
static char *pcSource;
register unsigned long ulBytesRemainingInBuffer, ulRemainingSectionBytes;
unsigned int uiTemp;
// Read ulSectionLength bytes from the Rx buffers.
// This is not necessarily any correspondence between the length of our Rx buffers,
// and the length of the data we are returning or the length of the data being requested.
// Therefore, between calls we have to remember not only which buffer we are currently
// processing, but our position within that buffer.
// This would be greatly simplified if PBUF_POOL_BUFSIZE could be guaranteed to be greater
// than the size of each Rx buffer, and that memory fragmentation did not occur.
// This function should only be called after a call to ulMACBInputLength().
// This will ensure ulNextRxBuffer is set to the correct buffer. */
// vMACBRead is called with pcTo set to NULL to indicate that we are about
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -