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

📄 emac.c

📁 keil for at91sam9263ek ads and emac编程
💻 C
📖 第 1 页 / 共 3 页
字号:
/* ----------------------------------------------------------------------------
 *         ATMEL Microcontroller Software Support 
 * ----------------------------------------------------------------------------
 * Copyright (c) 2008, 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:
 *
 * - Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the disclaimer below.
 *
 * Atmel's name may not be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * 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.
 * ----------------------------------------------------------------------------
 */

//-----------------------------------------------------------------------------
//         Headers
//-----------------------------------------------------------------------------
#include <board.h>
#include "emac.h"
#include <utility/trace.h>
#include <utility/assert.h>
#include <string.h>

//------------------------------------------------------------------------------
//         Definitions
//------------------------------------------------------------------------------
/// The buffer addresses written into the descriptors must be aligned so the
/// last few bits are zero.  These bits have special meaning for the EMAC
/// peripheral and cannot be used as part of the address.
#define EMAC_ADDRESS_MASK   ((unsigned int)0xFFFFFFFC)
#define EMAC_LENGTH_FRAME   ((unsigned int)0x0FFF)    /// Length of frame mask

// receive buffer descriptor bits
#define EMAC_RX_OWNERSHIP_BIT   (1 <<  0)
#define EMAC_RX_WRAP_BIT        (1 <<  1)
#define EMAC_RX_SOF_BIT         (1 << 14)
#define EMAC_RX_EOF_BIT         (1 << 15)

// Transmit buffer descriptor bits
#define EMAC_TX_LAST_BUFFER_BIT (1 << 15)
#define EMAC_TX_WRAP_BIT        (1 << 30)
#define EMAC_TX_USED_BIT        (1 << 31)

//-----------------------------------------------------------------------------
// Circular buffer management
//-----------------------------------------------------------------------------
// Return count in buffer
#define CIRC_CNT(head,tail,size) (((head) - (tail)) & ((size)-1))

// Return space available, 0..size-1
// We always leave one free char as a completely full buffer 
// has head == tail, which is the same as empty
#define CIRC_SPACE(head,tail,size) CIRC_CNT((tail),((head)+1),(size))

// Return count up to the end of the buffer.  
// Carefully avoid accessing head and tail more than once,
// so they can change underneath us without returning inconsistent results
#define CIRC_CNT_TO_END(head,tail,size) \
   ({int end = (size) - (tail); \
     int n = ((head) + end) & ((size)-1); \
     n < end ? n : end;})

// Return space available up to the end of the buffer
#define CIRC_SPACE_TO_END(head,tail,size) \
   ({int end = (size) - 1 - (head); \
     int n = (end + (tail)) & ((size)-1); \
     n <= end ? n : end+1;})

// Increment head or tail
#define CIRC_INC(headortail,size) \
        headortail++;             \
        if(headortail >= size) {  \
            headortail = 0;       \
        }

#define CIRC_EMPTY(circ)     ((circ)->head == (circ)->tail)
#define CIRC_CLEAR(circ)     ((circ)->head = (circ)->tail = 0)


//------------------------------------------------------------------------------
//      Structures
//------------------------------------------------------------------------------
#ifdef __ICCARM__          // IAR
#pragma pack(4)            // IAR
#define __attribute__(...) // IAR
#endif                     // IAR
/// Describes the type and attribute of Receive Transfer descriptor.
typedef struct _EmacRxTDescriptor {
    unsigned int addr;
    unsigned int status;
} __attribute__((packed, aligned(8))) EmacRxTDescriptor, *PEmacRxTDescriptor;

/// Describes the type and attribute of Transmit Transfer descriptor.
typedef struct _EmacTxTDescriptor {
    unsigned int addr;
    unsigned int status;
} __attribute__((packed, aligned(8))) EmacTxTDescriptor, *PEmacTxTDescriptor;
#ifdef __ICCARM__          // IAR
#pragma pack()             // IAR
#endif                     // IAR

#ifdef __ICCARM__          // IAR
#pragma data_alignment=8   // IAR
#endif                     // IAR
/// Descriptors for RX (required aligned by 8)
typedef struct {
   volatile EmacRxTDescriptor td[RX_BUFFERS];
   EMAC_RxCallback rxCb; /// Callback function to be invoked once a frame has been received
   unsigned short idx;
} RxTd;

#ifdef __ICCARM__          // IAR
#pragma data_alignment=8   // IAR
#endif                     // IAR
/// Descriptors for TX (required aligned by 8)
typedef struct {
   volatile EmacTxTDescriptor td[TX_BUFFERS];
   EMAC_TxCallback txCb[TX_BUFFERS];    /// Callback function to be invoked once TD has been processed
   EMAC_WakeupCallback wakeupCb;        /// Callback function to be invoked once several TD have been released
   unsigned short wakeupThreshold; /// Number of free TD before wakeupCb is invoked
   unsigned short head;            /// Circular buffer head pointer incremented by the upper layer (buffer to be sent)
   unsigned short tail;            /// Circular buffer head pointer incremented by the IT handler (buffer sent)
} TxTd;

//------------------------------------------------------------------------------
//         Internal variables
//------------------------------------------------------------------------------
// Receive Transfer Descriptor buffer
static volatile RxTd rxTd; 
// Transmit Transfer Descriptor buffer
static volatile TxTd txTd; 
/// Send Buffer
// Section 3.6 of AMBA 2.0 spec states that burst should not cross 1K Boundaries.
// Receive buffer manager writes are burst of 2 words => 3 lsb bits of the address shall be set to 0
#ifdef __ICCARM__          // IAR
#pragma data_alignment=8   // IAR
#endif                     // IAR
static volatile unsigned char pTxBuffer[TX_BUFFERS * EMAC_TX_UNITSIZE] __attribute__((aligned(8)));

#ifdef __ICCARM__          // IAR
#pragma data_alignment=8   // IAR
#endif                     // IAR
/// Receive Buffer
static volatile unsigned char pRxBuffer[RX_BUFFERS * EMAC_RX_UNITSIZE] __attribute__((aligned(8)));
/// Statistics
static volatile EmacStats EmacStatistics;

//-----------------------------------------------------------------------------
//         Internal functions
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
/// Wait PHY operation complete.
/// Return 1 if the operation completed successfully.
/// May be need to re-implemented to reduce CPU load.
/// \param retry: the retry times, 0 to wait forever until complete.
//-----------------------------------------------------------------------------
static unsigned char EMAC_WaitPhy( unsigned int retry )
{
    unsigned int retry_count = 0;

    while((AT91C_BASE_EMAC->EMAC_NSR & AT91C_EMAC_IDLE) == 0) {

        // Dead LOOP!
        if (retry == 0) {

            continue;
        }

        // Timeout check
        retry_count++;
        if(retry_count >= retry) {

            TRACE_ERROR("E: Wait PHY time out\n\r");
            return 0;
        }
    }

    return 1;
}

//-----------------------------------------------------------------------------
//         Exported functions
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
//          PHY management functions
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
/// Set MDC clock according to current board clock. Per 802.3, MDC should be 
/// less then 2.5MHz.
/// Return 1 if successfully, 0 if MDC clock not found.
//-----------------------------------------------------------------------------
unsigned char EMAC_SetMdcClock( unsigned int mck )
{
    int clock_dividor;

    if (mck <= 20000000) {
        clock_dividor = AT91C_EMAC_CLK_HCLK_8;          /// MDC clock = MCK/8
    }
    else if (mck <= 40000000) {
        clock_dividor = AT91C_EMAC_CLK_HCLK_16;         /// MDC clock = MCK/16
    }
    else if (mck <= 80000000) {
        clock_dividor = AT91C_EMAC_CLK_HCLK_32;         /// MDC clock = MCK/32
    }
    else if (mck <= 160000000) {
        clock_dividor = AT91C_EMAC_CLK_HCLK_64;         /// MDC clock = MCK/64
    }
    else {
        TRACE_ERROR("E: No valid MDC clock.\n\r");
        return 0;
    }
    AT91C_BASE_EMAC->EMAC_NCFGR = (AT91C_BASE_EMAC->EMAC_NCFGR & (~AT91C_EMAC_CLK))
                                 | clock_dividor;
    return 1;
}

//-----------------------------------------------------------------------------
/// Enable MDI with PHY
//-----------------------------------------------------------------------------
void EMAC_EnableMdio( void )
{
    AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_MPE;
}

//-----------------------------------------------------------------------------
/// Enable MDI with PHY
//-----------------------------------------------------------------------------
void EMAC_DisableMdio( void )
{
    AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_MPE;
}

//-----------------------------------------------------------------------------
/// Enable MII mode for EMAC, called once after autonegotiate
//-----------------------------------------------------------------------------
void EMAC_EnableMII( void )
{
    AT91C_BASE_EMAC->EMAC_USRIO = AT91C_EMAC_CLKEN;
}

//-----------------------------------------------------------------------------
/// Enable RMII mode for EMAC, called once after autonegotiate
//-----------------------------------------------------------------------------
void EMAC_EnableRMII( void )
{
    AT91C_BASE_EMAC->EMAC_USRIO = AT91C_EMAC_CLKEN | AT91C_EMAC_RMII;
}

//-----------------------------------------------------------------------------
/// Read PHY register.
/// Return 1 if successfully, 0 if timeout.
/// \param PhyAddress PHY Address
/// \param Address Register Address
/// \param pValue Pointer to a 32 bit location to store read data
/// \param retry The retry times, 0 to wait forever until complete.
//-----------------------------------------------------------------------------
unsigned char EMAC_ReadPhy(unsigned char PhyAddress,
                           unsigned char Address,
                           unsigned int *pValue,
                           unsigned int retry)

⌨️ 快捷键说明

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