MakingThings
  • 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.