- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

# SAM7_EMAC.c

    00001 /*
    00002   FreeRTOS.org V4.6.0 - Copyright (C) 2003-2007 Richard Barry.
    00003
    00004   This file is part of the FreeRTOS.org distribution.
    00005
    00006   FreeRTOS.org is free software; you can redistribute it and/or modify
    00007   it under the terms of the GNU General Public License as published by
    00008   the Free Software Foundation; either version 2 of the License, or
    00009   (at your option) any later version.
    00010
    00011   FreeRTOS.org is distributed in the hope that it will be useful,
    00012   but WITHOUT ANY WARRANTY; without even the implied warranty of
    00013   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    00014   GNU General Public License for more details.
    00015
    00016   You should have received a copy of the GNU General Public License
    00017   along with FreeRTOS.org; if not, write to the Free Software
    00018   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    00019
    00020   A special exception to the GPL can be applied should you wish to distribute
    00021   a combined work that includes FreeRTOS.org, without being obliged to provide
    00022   the source code for any proprietary components.  See the licensing section
    00023   of http://www.FreeRTOS.org for full details of how and when the exception
    00024   can be applied.
    00025
    00026   ***************************************************************************
    00027   See http://www.FreeRTOS.org for documentation, latest information, license
    00028   and contact details.  Please ensure to read the configuration and relevant
    00029   port sections of the online documentation.
    00030
    00031   Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
    00032   with commercial development and support options.
    00033   ***************************************************************************
    00034 */
    00035
    00036 /*
    00037  * Interrupt driven driver for the EMAC peripheral.  This driver is not
    00038  * reentrant, re-entrancy is handled by a semaphore at the network interface
    00039  * level.
    00040  */
    00041
    00042
    00043 /*
    00044 Changes from V3.2.2
    00045
    00046   + Corrected the byte order when writing the MAC address to the MAC.
    00047   + Support added for MII interfaces.  Previously only RMII was supported.
    00048
    00049 Changes from V3.2.3
    00050
    00051   + The MII interface is now the default.
    00052   + Modified the initialisation sequence slightly to allow auto init more
    00053     time to complete.
    00054
    00055 Changes from V4.0.1
    00056
    00057   + Made the function vClearEMACTxBuffer() more robust by moving the index
    00058     manipulation into the if() statement.  This allows the tx interrupt to
    00059     execute even when there is no data to handle.
    00060
    00061 Changes from V4.0.4
    00062
    00063   + Corrected the Rx frame length mask when obtaining the length from the
    00064     rx descriptor.
    00065 */
    00066
    00067 #include "config.h" // MakingThings.
    00068 #ifdef MAKE_CTRL_NETWORK
    00069
    00070 /* Standard includes. */
    00071 #include <string.h>
    00072
    00073 /* Scheduler includes. */
    00074 #include "FreeRTOS.h"
    00075 #include "semphr.h"
    00076 #include "task.h"
    00077
    00078 /* Demo app includes. */
    00079 #include "SAM7_EMAC.h"
    00080
    00081 /* Hardware specific includes. */
    00082 #include "Emac.h"
    00083 #include "mii.h"
    00084 #include "AT91SAM7X256.h"
    00085
    00086 /* MAKINGTHING: ADDED */
    00087
    00088 #include "Board.h"
    00089
    00090 /* USE_RMII_INTERFACE must be defined as 1 to use an RMII interface, or 0
    00091 to use an MII interface. */
    00092 /* MAKINGTHINGS: Make Sure we're using RMII for Version 90 */
    00093 #if ( CONTROLLER_VERSION == 50 || CONTROLLER_VERSION == 100 || CONTROLLER_VERSION == 200 )
    00094  #define USE_RMII_INTERFACE 0
    00095 #elif ( CONTROLLER_VERSION == 90 || CONTROLLER_VERSION == 95 )
    00096   #define USE_RMII_INTERFACE 1
    00097 #endif
    00098
    00099 /* The buffer addresses written into the descriptors must be aligned so the
    00100 last few bits are zero.  These bits have special meaning for the EMAC
    00101 peripheral and cannot be used as part of the address. */
    00102 #define emacADDRESS_MASK      ( ( unsigned portLONG ) 0xFFFFFFFC )
    00103
    00104 /* Bit used within the address stored in the descriptor to mark the last
    00105 descriptor in the array. */
    00106 #define emacRX_WRAP_BIT       ( ( unsigned portLONG ) 0x02 )
    00107
    00108 /* Bit used within the Tx descriptor status to indicate whether the
    00109 descriptor is under the control of the EMAC or the software. */
    00110 #define emacTX_BUF_USED       ( ( unsigned portLONG ) 0x80000000 )
    00111
    00112 /* A short delay is used to wait for a buffer to become available, should
    00113 one not be immediately available when trying to transmit a frame. */
    00114 #define emacBUFFER_WAIT_DELAY   ( 2 )
    00115 #define emacMAX_WAIT_CYCLES     ( ( portBASE_TYPE ) ( configTICK_RATE_HZ / 40 ) )
    00116
    00117 /* The time to block waiting for input. */
    00118 #define emacBLOCK_TIME_WAITING_FOR_INPUT  ( ( portTickType ) 100 )
    00119
    00120 /* Peripheral setup for the EMAC. */
    00121
    00122 /* MAKINGTHINGS: ADDITION */
    00123 #if ( CONTROLLER_VERSION == 50 || CONTROLLER_VERSION == 95 || CONTROLLER_VERSION == 100 || CONTROLLER_VERSION == 200 )
    00124   #define emacPERIPHERAL_A_SETUP    \
    00125       ( ( unsigned portLONG ) AT91C_PB2_ETX0 ) | \
    00126       ( ( unsigned portLONG ) AT91C_PB3_ETX1      ) | \
    00127       ( ( unsigned portLONG ) AT91C_PB10_ETX2     ) | \
    00128       ( ( unsigned portLONG ) AT91C_PB11_ETX3     ) | \
    00129       ( ( unsigned portLONG ) AT91C_PB12_ETXER    ) | \
    00130       ( ( unsigned portLONG ) AT91C_PB1_ETXEN     ) | \
    00131       ( ( unsigned portLONG ) AT91C_PB0_ETXCK_EREFCK  ) | \
    00132       ( ( unsigned portLONG ) AT91C_PB16_ECOL     ) | \
    00133       ( ( unsigned portLONG ) AT91C_PB5_ERX0      ) | \
    00134       ( ( unsigned portLONG ) AT91C_PB6_ERX1      ) | \
    00135       ( ( unsigned portLONG ) AT91C_PB13_ERX2     ) | \
    00136       ( ( unsigned portLONG ) AT91C_PB14_ERX3     ) | \
    00137       ( ( unsigned portLONG ) AT91C_PB15_ERXDV    ) | \
    00138       ( ( unsigned portLONG ) AT91C_PB8_EMDC      ) | \
    00139       ( ( unsigned portLONG ) AT91C_PB4_ECRS_ECRSDV ) | \
    00140       ( ( unsigned portLONG ) AT91C_PB9_EMDIO     ) | \
    00141       ( ( unsigned portLONG ) AT91C_PB7_ERXER     ) | \
    00142       ( ( unsigned portLONG ) AT91C_PB17_ERXCK    );
    00143 #elif ( CONTROLLER_VERSION == 90 )
    00144 #define emacPERIPHERAL_A_SETUP  \
    00145       ( ( unsigned portLONG ) AT91C_PB2_ETX0  ) | \
    00146       ( ( unsigned portLONG ) AT91C_PB6_ERX1      ) | \
    00147       ( ( unsigned portLONG ) AT91C_PB15_ERXDV    ) | \
    00148       ( ( unsigned portLONG ) AT91C_PB3_ETX1      ) | \
    00149       ( ( unsigned portLONG ) AT91C_PB8_EMDC      ) | \
    00150       ( ( unsigned portLONG ) AT91C_PB4_ECRS_ECRSDV ) | \
    00151       ( ( unsigned portLONG ) AT91C_PB5_ERX0      ) | \
    00152       ( ( unsigned portLONG ) AT91C_PB1_ETXEN     ) | \
    00153       ( ( unsigned portLONG ) AT91C_PB0_ETXCK_EREFCK  ) | \
    00154       ( ( unsigned portLONG ) AT91C_PB9_EMDIO     ) | \
    00155       ( ( unsigned portLONG ) AT91C_PB7_ERXER     );
    00156 #endif
    00157
    00158 /* Misc defines. */
    00159 #define emacINTERRUPT_LEVEL     ( 5 )
    00160 #define emacNO_DELAY        ( 0 )
    00161 #define emacTOTAL_FRAME_HEADER_SIZE ( 54 )
    00162 #define emacPHY_INIT_DELAY      ( 5000 / portTICK_RATE_MS )
    00163 #define emacRESET_KEY       ( ( unsigned portLONG ) 0xA5000000 )
    00164 #define emacRESET_LENGTH      ( ( unsigned portLONG ) ( 0x01 << 8 ) )
    00165
    00166 /* The Atmel header file only defines the TX frame length mask. */
    00167 #define emacRX_LENGTH_FRAME     ( 0xfff )
    00168
    00169 /*-----------------------------------------------------------*/
    00170
    00171 /* Buffer written to by the EMAC DMA.  Must be aligned as described by the
    00172 comment above the emacADDRESS_MASK definition. */
    00173 static volatile portCHAR pcRxBuffer[ NB_RX_BUFFERS * ETH_RX_BUFFER_SIZE ] __attribute__ ((aligned (8)));
    00174
    00175 /* Buffer read by the EMAC DMA.  Must be aligned as described by the comment
    00176 above the emacADDRESS_MASK definition. */
    00177 static portCHAR pcTxBuffer[ NB_TX_BUFFERS * ETH_TX_BUFFER_SIZE ] __attribute__ ((aligned (8)));
    00178
    00179 /* Descriptors used to communicate between the program and the EMAC peripheral.
    00180 These descriptors hold the locations and state of the Rx and Tx buffers. */
    00181 static volatile AT91S_TxTdDescriptor xTxDescriptors[ NB_TX_BUFFERS ];
    00182 static volatile AT91S_RxTdDescriptor xRxDescriptors[ NB_RX_BUFFERS ];
    00183
    00184 /* The IP and Ethernet addresses are read from the header files. */
    00185 /* MakingThings: commented this out to accomodate being able to change the MAC address */
    00186 //const portCHAR cMACAddress[ 6 ] = { emacETHADDR0, emacETHADDR1, emacETHADDR2, emacETHADDR3, emacETHADDR4, emacETHADDR5 };
    00187 //const unsigned char ucIPAddress[ 4 ]  = { emacIPADDR0, emacIPADDR1, emacIPADDR2, emacIPADDR3 };
    00188
    00189 /*-----------------------------------------------------------*/
    00190
    00191 /* See the header file for descriptions of public functions. */
    00192
    00193 /*
    00194  * Prototype for the EMAC interrupt function.
    00195  */
    00196 void vEMACISR_Wrapper( void ) __attribute__ ((naked));
    00197
    00198 /*
    00199  * Initialise both the Tx and Rx descriptors used by the EMAC.
    00200  */
    00201 static void prvSetupDescriptors(void);
    00202
    00203 /*
    00204  * Write our MAC address into the EMAC.
    00205  */
    00206 static void prvSetupMACAddress( void );
    00207
    00208 /*
    00209  * Configure the EMAC and AIC for EMAC interrupts.
    00210  */
    00211 static void prvSetupEMACInterrupt( void );
    00212
    00213 /*
    00214  * Some initialisation functions taken from the Atmel EMAC sample code.
    00215  */
    00216 static void vReadPHY( unsigned portCHAR ucPHYAddress, unsigned portCHAR ucAddress, unsigned portLONG *pulValue );
    00217 static portBASE_TYPE xGetLinkSpeed( void );
    00218 static portBASE_TYPE prvProbePHY( void );
    00219 #if USE_RMII_INTERFACE != 1
    00220   static void vWritePHY( unsigned portCHAR ucPHYAddress, unsigned portCHAR ucAddress, unsigned portLONG ulValue);
    00221 #endif
    00222
    00223
    00224 /* The semaphore used by the EMAC ISR to wake the EMAC task. */
    00225 static xSemaphoreHandle xSemaphore = NULL;
    00226
    00227 /* Holds the index to the next buffer from which data will be read. */
    00228 static volatile unsigned portLONG ulNextRxBuffer = 0;
    00229
    00230 /*-----------------------------------------------------------*/
    00231
    00232 /* See the header file for descriptions of public functions. */
    00233 portLONG lEMACSend( portCHAR *pcFrom, unsigned portLONG ulLength, portLONG lEndOfFrame )
    00234 {
    00235 static unsigned portBASE_TYPE uxTxBufferIndex = 0;
    00236 portBASE_TYPE xWaitCycles = 0;
    00237 portLONG lReturn = pdPASS;
    00238 portCHAR *pcBuffer;
    00239 unsigned portLONG ulLastBuffer, ulDataBuffered = 0, ulDataRemainingToSend, ulLengthToSend;
    00240
    00241   /* If the length of data to be transmitted is greater than each individual
    00242   transmit buffer then the data will be split into more than one buffer.
    00243   Loop until the entire length has been buffered. */
    00244   while( ulDataBuffered < ulLength )
    00245   {
    00246     /* Is a buffer available? */
    00247     while( !( xTxDescriptors[ uxTxBufferIndex ].U_Status.status & AT91C_TRANSMIT_OK ) )
    00248     {
    00249       /* There is no room to write the Tx data to the Tx buffer.  Wait a
    00250       short while, then try again. */
    00251       xWaitCycles++;
    00252       if( xWaitCycles > emacMAX_WAIT_CYCLES )
    00253       {
    00254         /* Give up. */
    00255         lReturn = pdFAIL;
    00256         break;
    00257       }
    00258       else
    00259       {
    00260         vTaskDelay( emacBUFFER_WAIT_DELAY );
    00261       }
    00262     }
    00263
    00264     /* lReturn will only be pdPASS if a buffer is available. */
    00265     if( lReturn == pdPASS )
    00266     {
    00267       portENTER_CRITICAL();
    00268       {
    00269         /* Get the address of the buffer from the descriptor, then copy
    00270         the data into the buffer. */
    00271         pcBuffer = ( portCHAR * ) xTxDescriptors[ uxTxBufferIndex ].addr;
    00272
    00273         /* How much can we write to the buffer? */
    00274         ulDataRemainingToSend = ulLength - ulDataBuffered;
    00275         if( ulDataRemainingToSend <= ETH_TX_BUFFER_SIZE )
    00276         {
    00277           /* We can write all the remaining bytes. */
    00278           ulLengthToSend = ulDataRemainingToSend;
    00279         }
    00280         else
    00281         {
    00282           /* We can not write more than ETH_TX_BUFFER_SIZE in one go. */
    00283           ulLengthToSend = ETH_TX_BUFFER_SIZE;
    00284         }
    00285
    00286         /* Copy the data into the buffer. */
    00287         memcpy( ( void * ) pcBuffer, ( void * ) &( pcFrom[ ulDataBuffered ] ), ulLengthToSend );
    00288         ulDataBuffered += ulLengthToSend;
    00289
    00290         /* Is this the last data for the frame? */
    00291         if( lEndOfFrame && ( ulDataBuffered >= ulLength ) )
    00292         {
    00293           /* No more data remains for this frame so we can start the
    00294           transmission. */
    00295           ulLastBuffer = AT91C_LAST_BUFFER;
    00296         }
    00297         else
    00298         {
    00299           /* More data to come for this frame. */
    00300           ulLastBuffer = 0;
    00301         }
    00302
    00303         /* Fill out the necessary in the descriptor to get the data sent,
    00304         then move to the next descriptor, wrapping if necessary. */
    00305         if( uxTxBufferIndex >= ( NB_TX_BUFFERS - 1 ) )
    00306         {
    00307           xTxDescriptors[ uxTxBufferIndex ].U_Status.status =   ( ulLengthToSend & ( unsigned portLONG ) AT91C_LENGTH_FRAME )
    00308                                       | ulLastBuffer
    00309                                       | AT91C_TRANSMIT_WRAP;
    00310           uxTxBufferIndex = 0;
    00311         }
    00312         else
    00313         {
    00314           xTxDescriptors[ uxTxBufferIndex ].U_Status.status =   ( ulLengthToSend & ( unsigned portLONG ) AT91C_LENGTH_FRAME )
    00315                                       | ulLastBuffer;
    00316           uxTxBufferIndex++;
    00317         }
    00318
    00319         /* If this is the last buffer to be sent for this frame we can
    00320         start the transmission. */
    00321         if( ulLastBuffer )
    00322         {
    00323           AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_TSTART;
    00324         }
    00325       }
    00326       portEXIT_CRITICAL();
    00327     }
    00328     else
    00329     {
    00330       break;
    00331     }
    00332   }
    00333
    00334   return lReturn;
    00335 }
    00336 /*-----------------------------------------------------------*/
    00337
    00338 /* See the header file for descriptions of public functions. */
    00339 unsigned portLONG ulEMACInputLength( void )
    00340 {
    00341 register unsigned portLONG ulIndex, ulLength = 0;
    00342
    00343   /* Skip any fragments.  We are looking for the first buffer that contains
    00344   data and has the SOF (start of frame) bit set. */
    00345   while( ( xRxDescriptors[ ulNextRxBuffer ].addr & AT91C_OWNERSHIP_BIT ) && !( xRxDescriptors[ ulNextRxBuffer ].U_Status.status & AT91C_SOF ) )
    00346   {
    00347     /* Ignoring this buffer.  Mark it as free again. */
    00348     xRxDescriptors[ ulNextRxBuffer ].addr &= ~( AT91C_OWNERSHIP_BIT );
    00349     ulNextRxBuffer++;
    00350     if( ulNextRxBuffer >= NB_RX_BUFFERS )
    00351     {
    00352       ulNextRxBuffer = 0;
    00353     }
    00354   }
    00355
    00356   /* We are going to walk through the descriptors that make up this frame,
    00357   but don't want to alter ulNextRxBuffer as this would prevent vEMACRead()
    00358   from finding the data.  Therefore use a copy of ulNextRxBuffer instead. */
    00359   ulIndex = ulNextRxBuffer;
    00360
    00361   /* Walk through the descriptors until we find the last buffer for this
    00362   frame.  The last buffer will give us the length of the entire frame. */
    00363   int count = 0; // MAKINGTHINGS - if the buffer is not found, this just spins forever
    00364   while( ( xRxDescriptors[ ulIndex ].addr & AT91C_OWNERSHIP_BIT ) && !ulLength && count < NB_RX_BUFFERS)
    00365   {
    00366     ulLength = xRxDescriptors[ ulIndex ].U_Status.status & emacRX_LENGTH_FRAME;
    00367
    00368     /* Increment to the next buffer, wrapping if necessary. */
    00369     ulIndex++;
    00370     count++;
    00371     if( ulIndex >= NB_RX_BUFFERS )
    00372     {
    00373       ulIndex = 0;
    00374     }
    00375   }
    00376
    00377   return ulLength;
    00378 }
    00379 /*-----------------------------------------------------------*/
    00380
    00381 /* See the header file for descriptions of public functions. */
    00382 void vEMACRead( portCHAR *pcTo, unsigned portLONG ulSectionLength, unsigned portLONG ulTotalFrameLength )
    00383 {
    00384 static unsigned portLONG ulSectionBytesReadSoFar = 0, ulBufferPosition = 0, ulFameBytesReadSoFar = 0;
    00385 static portCHAR *pcSource;
    00386 register unsigned portLONG ulBytesRemainingInBuffer, ulRemainingSectionBytes;
    00387
    00388   /* Read ulSectionLength bytes from the Rx buffers.  This is not necessarily any
    00389   correspondence between the length of our Rx buffers, and the length of the
    00390   data we are returning or the length of the data being requested.  Therefore,
    00391   between calls  we have to remember not only which buffer we are currently
    00392   processing, but our position within that buffer.  This would be greatly
    00393   simplified if PBUF_POOL_BUFSIZE could be guaranteed to be greater than
    00394   the size of each Rx buffer, and that memory fragmentation did not occur.
    00395
    00396   This function should only be called after a call to ulEMACInputLength().
    00397   This will ensure ulNextRxBuffer is set to the correct buffer. */
    00398
    00399
    00400
    00401   /* vEMACRead is called with pcTo set to NULL to indicate that we are about
    00402   to read a new frame.  Any fragments remaining in the frame we were
    00403   processing during the last call should be dropped. */
    00404   if( pcTo == NULL )
    00405   {
    00406     /* How many bytes are indicated as being in this buffer?  If none then
    00407     the buffer is completely full and the frame is contained within more
    00408     than one buffer. */
    00409
    00410     /* Reset our state variables ready for the next read from this buffer. */
    00411         pcSource = ( portCHAR * )( xRxDescriptors[ ulNextRxBuffer ].addr & emacADDRESS_MASK );
    00412         ulFameBytesReadSoFar = ( unsigned portLONG ) 0;
    00413     ulBufferPosition = ( unsigned portLONG ) 0;
    00414   }
    00415   else
    00416   {
    00417     /* Loop until we have obtained the required amount of data. */
    00418         ulSectionBytesReadSoFar = 0;
    00419     while( ulSectionBytesReadSoFar < ulSectionLength )
    00420     {
    00421       /* We may have already read some data from this buffer.  How much
    00422       data remains in the buffer? */
    00423       ulBytesRemainingInBuffer = ( ETH_RX_BUFFER_SIZE - ulBufferPosition );
    00424
    00425       /* How many more bytes do we need to read before we have the
    00426       required amount of data? */
    00427             ulRemainingSectionBytes = ulSectionLength - ulSectionBytesReadSoFar;
    00428
    00429       /* Do we want more data than remains in the buffer? */
    00430       if( ulRemainingSectionBytes > ulBytesRemainingInBuffer )
    00431       {
    00432         /* We want more data than remains in the buffer so we can
    00433         write the remains of the buffer to the destination, then move
    00434         onto the next buffer to get the rest. */
    00435         memcpy( &( pcTo[ ulSectionBytesReadSoFar ] ), &( pcSource[ ulBufferPosition ] ), ulBytesRemainingInBuffer );
    00436         ulSectionBytesReadSoFar += ulBytesRemainingInBuffer;
    00437                 ulFameBytesReadSoFar += ulBytesRemainingInBuffer;
    00438
    00439         /* Mark the buffer as free again. */
    00440         xRxDescriptors[ ulNextRxBuffer ].addr &= ~( AT91C_OWNERSHIP_BIT );
    00441
    00442         /* Move onto the next buffer. */
    00443         ulNextRxBuffer++;
    00444         if( ulNextRxBuffer >= NB_RX_BUFFERS )
    00445         {
    00446           ulNextRxBuffer = ( unsigned portLONG ) 0;
    00447         }
    00448
    00449         /* Reset the variables for the new buffer. */
    00450         pcSource = ( portCHAR * )( xRxDescriptors[ ulNextRxBuffer ].addr & emacADDRESS_MASK );
    00451         ulBufferPosition = ( unsigned portLONG ) 0;
    00452       }
    00453       else
    00454       {
    00455         /* We have enough data in this buffer to send back.  Read out
    00456         enough data and remember how far we read up to. */
    00457         memcpy( &( pcTo[ ulSectionBytesReadSoFar ] ), &( pcSource[ ulBufferPosition ] ), ulRemainingSectionBytes );
    00458
    00459         /* There may be more data in this buffer yet.  Increment our
    00460         position in this buffer past the data we have just read. */
    00461         ulBufferPosition += ulRemainingSectionBytes;
    00462         ulSectionBytesReadSoFar += ulRemainingSectionBytes;
    00463                 ulFameBytesReadSoFar += ulRemainingSectionBytes;
    00464
    00465         /* Have we now finished with this buffer? */
    00466         if( ( ulBufferPosition >= ETH_RX_BUFFER_SIZE ) || ( ulFameBytesReadSoFar >= ulTotalFrameLength ) )
    00467         {
    00468           /* Mark the buffer as free again. */
    00469           xRxDescriptors[ ulNextRxBuffer ].addr &= ~( AT91C_OWNERSHIP_BIT );
    00470
    00471           /* Move onto the next buffer. */
    00472           ulNextRxBuffer++;
    00473           if( ulNextRxBuffer >= NB_RX_BUFFERS )
    00474           {
    00475             ulNextRxBuffer = 0;
    00476           }
    00477
    00478           pcSource = ( portCHAR * )( xRxDescriptors[ ulNextRxBuffer ].addr & emacADDRESS_MASK );
    00479           ulBufferPosition = 0;
    00480         }
    00481       }
    00482     }
    00483   }
    00484 }
    00485 /*-----------------------------------------------------------*/
    00486
    00487 /* See the header file for descriptions of public functions. */
    00488 xSemaphoreHandle xEMACInit( void )
    00489 {
    00490   unsigned portLONG saved_RSTC_RMR;
    00491
    00492   /* Code supplied by Atmel -------------------------------*/
    00493
    00494   /* Disable pull up on RXDV => PHY normal mode (not in test mode),
    00495   PHY has internal pull down. */
    00496   AT91C_BASE_PIOB->PIO_PPUDR = 1 << 15;
    00497
    00498   #if USE_RMII_INTERFACE != 1
    00499       /* PHY has internal pull down : set MII mode. */
    00500       AT91C_BASE_PIOB->PIO_PPUDR = 1 << 16;
    00501   #endif
    00502
    00503   /* MAKINGTHINGS: ADDITION */
    00504   /* Clear PB18 <=> PHY power up. */
    00505   #if ( CONTROLLER_VERSION == 50 || CONTROLLER_VERSION == 95 || CONTROLLER_VERSION == 100 || CONTROLLER_VERSION == 200 )
    00506     AT91C_BASE_PIOB->PIO_PER = 1 << 18;
    00507   AT91C_BASE_PIOB->PIO_OER = 1 << 18;
    00508   AT91C_BASE_PIOB->PIO_CODR = 1 << 18;
    00509   #endif
    00510   #if ( CONTROLLER_VERSION == 90 )
    00511     /* PB13 <=> PHY powerdown - so clearing it is power up. */
    00512     AT91C_BASE_PIOB->PIO_PER = 1 << 13;
    00513     AT91C_BASE_PIOB->PIO_OER = 1 << 13;
    00514     AT91C_BASE_PIOB->PIO_CODR = 1 << 13;
    00515   #endif
    00516
    00517   /* MAKINGTHINGS
    00518     Critical section while commandeering the RSTC. */
    00519     portENTER_CRITICAL();
    00520
    00521   /* We do not have to do anything special with the RSTC interrupt, since the following disables it in RSTC_RMR. */
    00522
    00523   /* Save prior RTSC setup to restore afterward. */
    00524   saved_RSTC_RMR = AT91C_BASE_RSTC->RSTC_RMR;
    00525
    00526   /* Wait until it is safe to write to RSTC_RCR. */
    00527   while(AT91C_BASE_RSTC->RSTC_RSR & AT91C_RSTC_SRCMP)
    00528   {
    00529     portNOP();
    00530   }
    00531
    00532   /* After PHY power up, hardware reset. */
    00533   AT91C_BASE_RSTC->RSTC_RMR = emacRESET_KEY | emacRESET_LENGTH;
    00534   AT91C_BASE_RSTC->RSTC_RCR = emacRESET_KEY | AT91C_RSTC_EXTRST;
    00535
    00536   /* Wait for hardware reset end and for NRST to not be asserted. */
    00537   while((AT91C_BASE_RSTC->RSTC_RSR & (AT91C_RSTC_SRCMP | AT91C_RSTC_NRSTL)) != (AT91C_RSTC_NRSTL))
    00538   {
    00539     portNOP();
    00540   }
    00541
    00542   /* Restore prior RTSC setup. */
    00543   AT91C_BASE_RSTC->RSTC_RMR = (saved_RSTC_RMR & ~(0xff << 24)) | (0xa5 << 24);
    00544
    00545     portEXIT_CRITICAL();
    00546   /* end MAKINGTHINGS */
    00547
    00548   /* Setup the pins. */
    00549   AT91C_BASE_PIOB->PIO_ASR = emacPERIPHERAL_A_SETUP;
    00550   AT91C_BASE_PIOB->PIO_PDR = emacPERIPHERAL_A_SETUP;
    00551
    00552   /* Enable com between EMAC PHY.
    00553
    00554   Enable management port. */
    00555   AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_MPE;
    00556
    00557   /* MDC = MCK/32. */
    00558   AT91C_BASE_EMAC->EMAC_NCFGR |= ( 2 ) << 10;
    00559
    00560   /* Wait for PHY auto init end (rather crude delay!). */
    00561   vTaskDelay( emacPHY_INIT_DELAY );
    00562
    00563   /* PHY configuration. */
    00564   #if USE_RMII_INTERFACE != 1
    00565   {
    00566     unsigned portLONG ulControl;
    00567
    00568     /* PHY has internal pull down : disable MII isolate. */
    00569     vReadPHY( AT91C_PHY_ADDR, MII_BMCR, &ulControl );
    00570     vReadPHY( AT91C_PHY_ADDR, MII_BMCR, &ulControl );
    00571     ulControl &= ~BMCR_ISOLATE;
    00572     vWritePHY( AT91C_PHY_ADDR, MII_BMCR, ulControl );
    00573   }
    00574   #endif
    00575
    00576   /* Disable management port again. */
    00577   AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_MPE;
    00578
    00579   #if USE_RMII_INTERFACE != 1
    00580     /* Enable EMAC in MII mode, enable clock ERXCK and ETXCK. */
    00581     AT91C_BASE_EMAC->EMAC_USRIO = AT91C_EMAC_CLKEN ;
    00582   #else
    00583     /* Enable EMAC in RMII mode, enable RMII clock (50MHz from oscillator
    00584     on ERFCK). */
    00585     AT91C_BASE_EMAC->EMAC_USRIO = AT91C_EMAC_RMII | AT91C_EMAC_CLKEN ;
    00586   #endif
    00587
    00588   /* End of code supplied by Atmel ------------------------*/
    00589
    00590   /* Setup the buffers and descriptors. */
    00591   prvSetupDescriptors();
    00592
    00593   /* Load our MAC address into the EMAC. */
    00594   prvSetupMACAddress();
    00595
    00596   /* Are we connected? */
    00597   if( prvProbePHY() )
    00598   {
    00599     /* Enable the interrupt! */
    00600     portENTER_CRITICAL();
    00601     {
    00602       prvSetupEMACInterrupt();
    00603       vPassEMACSemaphore( xSemaphore );
    00604     }
    00605     portEXIT_CRITICAL();
    00606   }
    00607
    00608   return xSemaphore;
    00609 }
    00610 /*-----------------------------------------------------------*/
    00611
    00612 /* See the header file for descriptions of public functions. */
    00613 void vClearEMACTxBuffer( void )
    00614 {
    00615 static unsigned portBASE_TYPE uxNextBufferToClear = 0;
    00616
    00617   /* Called on Tx interrupt events to reset the AT91C_TRANSMIT_OK bit in each
    00618   Tx buffer within the frame just transmitted.  This marks all the buffers
    00619   as available again.
    00620
    00621   The first buffer in the frame should have the bit set automatically. */
    00622   if( xTxDescriptors[ uxNextBufferToClear ].U_Status.status & AT91C_TRANSMIT_OK )
    00623   {
    00624     /* Loop through the other buffers in the frame. */
    00625     while( !( xTxDescriptors[ uxNextBufferToClear ].U_Status.status & AT91C_LAST_BUFFER ) )
    00626     {
    00627       uxNextBufferToClear++;
    00628
    00629       if( uxNextBufferToClear >= NB_TX_BUFFERS )
    00630       {
    00631         uxNextBufferToClear = 0;
    00632       }
    00633
    00634       xTxDescriptors[ uxNextBufferToClear ].U_Status.status |= AT91C_TRANSMIT_OK;
    00635     }
    00636
    00637     /* Start with the next buffer the next time a Tx interrupt is called. */
    00638     uxNextBufferToClear++;
    00639
    00640     /* Do we need to wrap back to the first buffer? */
    00641     if( uxNextBufferToClear >= NB_TX_BUFFERS )
    00642     {
    00643       uxNextBufferToClear = 0;
    00644     }
    00645   }
    00646 }
    00647 /*-----------------------------------------------------------*/
    00648
    00649 static void prvSetupDescriptors(void)
    00650 {
    00651 unsigned portBASE_TYPE xIndex;
    00652 unsigned portLONG ulAddress;
    00653
    00654   /* Initialise xRxDescriptors descriptor. */
    00655   for( xIndex = 0; xIndex < NB_RX_BUFFERS; ++xIndex )
    00656   {
    00657     /* Calculate the address of the nth buffer within the array. */
    00658     ulAddress = ( unsigned portLONG )( pcRxBuffer + ( xIndex * ETH_RX_BUFFER_SIZE ) );
    00659
    00660     /* Write the buffer address into the descriptor.  The DMA will place
    00661     the data at this address when this descriptor is being used.  Mask off
    00662     the bottom bits of the address as these have special meaning. */
    00663     xRxDescriptors[ xIndex ].addr = ulAddress & emacADDRESS_MASK;
    00664   }
    00665
    00666   /* The last buffer has the wrap bit set so the EMAC knows to wrap back
    00667   to the first buffer. */
    00668   xRxDescriptors[ NB_RX_BUFFERS - 1 ].addr |= emacRX_WRAP_BIT;
    00669
    00670   /* Initialise xTxDescriptors. */
    00671   for( xIndex = 0; xIndex < NB_TX_BUFFERS; ++xIndex )
    00672   {
    00673     /* Calculate the address of the nth buffer within the array. */
    00674     ulAddress = ( unsigned portLONG )( pcTxBuffer + ( xIndex * ETH_TX_BUFFER_SIZE ) );
    00675
    00676     /* Write the buffer address into the descriptor.  The DMA will read
    00677     data from here when the descriptor is being used. */
    00678     xTxDescriptors[ xIndex ].addr = ulAddress & emacADDRESS_MASK;
    00679     xTxDescriptors[ xIndex ].U_Status.status = AT91C_TRANSMIT_OK;
    00680   }
    00681
    00682   /* The last buffer has the wrap bit set so the EMAC knows to wrap back
    00683   to the first buffer. */
    00684   xTxDescriptors[ NB_TX_BUFFERS - 1 ].U_Status.status = AT91C_TRANSMIT_WRAP | AT91C_TRANSMIT_OK;
    00685
    00686   /* Tell the EMAC where to find the descriptors. */
    00687   AT91C_BASE_EMAC->EMAC_RBQP = ( unsigned portLONG ) xRxDescriptors;
    00688   AT91C_BASE_EMAC->EMAC_TBQP = ( unsigned portLONG ) xTxDescriptors;
    00689
    00690   /* Clear all the bits in the receive status register. */
    00691   AT91C_BASE_EMAC->EMAC_RSR = ( AT91C_EMAC_OVR | AT91C_EMAC_REC | AT91C_EMAC_BNA );
    00692
    00693   /* Enable the copy of data into the buffers, ignore broadcasts,
    00694   and don't copy FCS. */
    00695   AT91C_BASE_EMAC->EMAC_NCFGR |= ( AT91C_EMAC_CAF | AT91C_EMAC_NBC | AT91C_EMAC_DRFCS);
    00696
    00697   /* Enable Rx and Tx, plus the stats register. */
    00698   AT91C_BASE_EMAC->EMAC_NCR |= ( AT91C_EMAC_TE | AT91C_EMAC_RE | AT91C_EMAC_WESTAT );
    00699 }
    00700 /*-----------------------------------------------------------*/
    00701
    00702 static void prvSetupMACAddress( void )
    00703 {
    00704   /* Must be written SA1L then SA1H. */
    00705   /* MakingThings: Switch variables to load from */
    00706   AT91C_BASE_EMAC->EMAC_SA1L =  ( ( unsigned portLONG ) emacETHADDR3 << 24 ) |
    00707                   ( ( unsigned portLONG ) emacETHADDR2 << 16 ) |
    00708                   ( ( unsigned portLONG ) emacETHADDR1 << 8  ) |
    00709                   emacETHADDR0;
    00710
    00711   AT91C_BASE_EMAC->EMAC_SA1H =  ( ( unsigned portLONG ) emacETHADDR5 << 8 ) |
    00712                   emacETHADDR4;
    00713 }
    00714 /*-----------------------------------------------------------*/
    00715
    00716 static void prvSetupEMACInterrupt( void )
    00717 {
    00718   /* Create the semaphore used to trigger the EMAC task. */
    00719   vSemaphoreCreateBinary( xSemaphore );
    00720   if( xSemaphore )
    00721   {
    00722     /* We start by 'taking' the semaphore so the ISR can 'give' it when the
    00723     first interrupt occurs. */
    00724     xSemaphoreTake( xSemaphore, emacNO_DELAY );
    00725     portENTER_CRITICAL();
    00726     {
    00727       /* We want to interrupt on Rx and Tx events. */
    00728       AT91C_BASE_EMAC->EMAC_IER = AT91C_EMAC_RCOMP | AT91C_EMAC_TCOMP;
    00729
    00730       /* Enable the interrupts in the AIC. */
    00731       AT91F_AIC_ConfigureIt( AT91C_ID_EMAC, emacINTERRUPT_LEVEL, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, ( void (*)( void ) ) vEMACISR_Wrapper );
    00732             AT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_EMAC;
    00733     }
    00734     portEXIT_CRITICAL();
    00735   }
    00736 }
    00737
    00738
    00739
    00740
    00741
    00742 /*
    00743  * The following functions are initialisation functions taken from the Atmel
    00744  * EMAC sample code.
    00745  */
    00746
    00747
    00748 static portBASE_TYPE prvProbePHY( void )
    00749 {
    00750 unsigned portLONG ulPHYId1, ulPHYId2, ulStatus;
    00751 portBASE_TYPE xReturn = pdPASS;
    00752
    00753   /* Code supplied by Atmel (reformatted) -----------------*/
    00754
    00755   /* Enable management port */
    00756   AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_MPE;
    00757     AT91C_BASE_EMAC->EMAC_NCFGR |= ( 2 ) << 10;
    00758
    00759   /* Read the PHY ID. */
    00760   vReadPHY( AT91C_PHY_ADDR, MII_PHYSID1, &ulPHYId1 );
    00761   vReadPHY(AT91C_PHY_ADDR, MII_PHYSID2, &ulPHYId2 );
    00762
    00763   /* AMD AM79C875:
    00764       PHY_ID1 = 0x0022
    00765       PHY_ID2 = 0x5541
    00766       Bits 3:0 Revision Number Four bit manufacturer?s revision number.
    00767         0001 stands for Rev. A, etc.
    00768   */
    00769   if( ( ( ulPHYId1 << 16 ) | ( ulPHYId2 & 0xfff0 ) ) != MII_DM9161_ID )
    00770   {
    00771     /* Did not expect this ID. */
    00772     xReturn = pdFAIL;
    00773   }
    00774   else
    00775   {
    00776     ulStatus = xGetLinkSpeed();
    00777
    00778     if( ulStatus != pdPASS )
    00779     {
    00780       xReturn = pdFAIL;
    00781     }
    00782   }
    00783
    00784   /* Disable management port */
    00785   AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_MPE;
    00786
    00787   /* End of code supplied by Atmel ------------------------*/
    00788
    00789   return xReturn;
    00790 }
    00791 /*-----------------------------------------------------------*/
    00792
    00793 static void vReadPHY( unsigned portCHAR ucPHYAddress, unsigned portCHAR ucAddress, unsigned portLONG *pulValue )
    00794 {
    00795   /* Code supplied by Atmel (reformatted) ----------------------*/
    00796
    00797   AT91C_BASE_EMAC->EMAC_MAN =   (AT91C_EMAC_SOF & (0x01<<30))
    00798                   | (2 << 16) | (2 << 28)
    00799                   | ((ucPHYAddress & 0x1f) << 23)
    00800                   | (ucAddress << 18);
    00801
    00802   /* Wait until IDLE bit in Network Status register is cleared. */
    00803   while( !( AT91C_BASE_EMAC->EMAC_NSR & AT91C_EMAC_IDLE ) )
    00804   {
    00805     portNOP();
    00806   }
    00807
    00808   *pulValue = ( AT91C_BASE_EMAC->EMAC_MAN & 0x0000ffff );
    00809
    00810   /* End of code supplied by Atmel ------------------------*/
    00811 }
    00812 /*-----------------------------------------------------------*/
    00813
    00814 #if USE_RMII_INTERFACE != 1
    00815 static void vWritePHY( unsigned portCHAR ucPHYAddress, unsigned portCHAR ucAddress, unsigned portLONG ulValue )
    00816 {
    00817   /* Code supplied by Atmel (reformatted) ----------------------*/
    00818
    00819   AT91C_BASE_EMAC->EMAC_MAN = (( AT91C_EMAC_SOF & (0x01<<30))
    00820                 | (2 << 16) | (1 << 28)
    00821                 | ((ucPHYAddress & 0x1f) << 23)
    00822                 | (ucAddress << 18))
    00823                 | (ulValue & 0xffff);
    00824
    00825   /* Wait until IDLE bit in Network Status register is cleared */
    00826   while( !( AT91C_BASE_EMAC->EMAC_NSR & AT91C_EMAC_IDLE ) )
    00827   {
    00828     portNOP();
    00829   };
    00830
    00831   /* End of code supplied by Atmel ------------------------*/
    00832 }
    00833 #endif
    00834 /*-----------------------------------------------------------*/
    00835
    00836 static portBASE_TYPE xGetLinkSpeed( void )
    00837 {
    00838   unsigned portLONG ulBMSR, ulBMCR, ulLPA, ulMACCfg, ulSpeed, ulDuplex;
    00839
    00840   /* Code supplied by Atmel (reformatted) -----------------*/
    00841
    00842   /* Link status is latched, so read twice to get current value */
    00843   vReadPHY(AT91C_PHY_ADDR, MII_BMSR, &ulBMSR);
    00844   vReadPHY(AT91C_PHY_ADDR, MII_BMSR, &ulBMSR);
    00845
    00846   if( !( ulBMSR & BMSR_LSTATUS ) )
    00847   {
    00848     /* No Link. */
    00849     return pdFAIL;
    00850   }
    00851
    00852   vReadPHY(AT91C_PHY_ADDR, MII_BMCR, &ulBMCR);
    00853   if (ulBMCR & BMCR_ANENABLE)
    00854   {
    00855     /* AutoNegotiation is enabled. */
    00856     if (!(ulBMSR & BMSR_ANEGCOMPLETE))
    00857     {
    00858       /* Auto-negotitation in progress. */
    00859       return pdFAIL;
    00860     }
    00861
    00862     vReadPHY(AT91C_PHY_ADDR, MII_LPA, &ulLPA);
    00863     if( ( ulLPA & LPA_100FULL ) || ( ulLPA & LPA_100HALF ) )
    00864     {
    00865       ulSpeed = SPEED_100;
    00866     }
    00867     else
    00868     {
    00869       ulSpeed = SPEED_10;
    00870     }
    00871
    00872     if( ( ulLPA & LPA_100FULL ) || ( ulLPA & LPA_10FULL ) )
    00873     {
    00874       ulDuplex = DUPLEX_FULL;
    00875     }
    00876     else
    00877     {
    00878       ulDuplex = DUPLEX_HALF;
    00879     }
    00880   }
    00881   else
    00882   {
    00883     ulSpeed = ( ulBMCR & BMCR_SPEED100 ) ? SPEED_100 : SPEED_10;
    00884     ulDuplex = ( ulBMCR & BMCR_FULLDPLX ) ? DUPLEX_FULL : DUPLEX_HALF;
    00885   }
    00886
    00887   /* Update the MAC */
    00888   ulMACCfg = AT91C_BASE_EMAC->EMAC_NCFGR & ~( AT91C_EMAC_SPD | AT91C_EMAC_FD );
    00889   if( ulSpeed == SPEED_100 )
    00890   {
    00891     if( ulDuplex == DUPLEX_FULL )
    00892     {
    00893       /* 100 Full Duplex */
    00894       AT91C_BASE_EMAC->EMAC_NCFGR = ulMACCfg | AT91C_EMAC_SPD | AT91C_EMAC_FD;
    00895     }
    00896     else
    00897     {
    00898       /* 100 Half Duplex */
    00899       AT91C_BASE_EMAC->EMAC_NCFGR = ulMACCfg | AT91C_EMAC_SPD;
    00900     }
    00901   }
    00902   else
    00903   {
    00904     if (ulDuplex == DUPLEX_FULL)
    00905     {
    00906       /* 10 Full Duplex */
    00907       AT91C_BASE_EMAC->EMAC_NCFGR = ulMACCfg | AT91C_EMAC_FD;
    00908     }
    00909     else
    00910     {     /* 10 Half Duplex */
    00911       AT91C_BASE_EMAC->EMAC_NCFGR = ulMACCfg;
    00912     }
    00913   }
    00914
    00915   /* End of code supplied by Atmel ------------------------*/
    00916
    00917   return pdPASS;
    00918 }
    00919 /*-----------------------------------------------------------*/
    00920
    00921 void vEMACWaitForInput( void )
    00922 {
    00923   /* Just wait until we are signled from an ISR that data is available, or
    00924   we simply time out. */
    00925   xSemaphoreTake( xSemaphore, emacBLOCK_TIME_WAITING_FOR_INPUT );
    00926 }
    00927
    00928 #endif // MAKE_CTRL_NETWORK

The Make Controller Kit is an open source project maintained by MakingThings.
MakingThings code is released under the Apache 2.0 license.
Bug tracker, development wiki and status can be found at http://dev.makingthings.com.
This document was last updated on 18 May 2009.